@unicitylabs/sphere-sdk 0.2.1 → 0.2.3

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.
@@ -1,13 +1,20 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
1
3
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
4
  get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
5
  }) : x)(function(x) {
4
6
  if (typeof require !== "undefined") return require.apply(this, arguments);
5
7
  throw Error('Dynamic require of "' + x + '" is not supported');
6
8
  });
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
7
16
 
8
17
  // core/bech32.ts
9
- var CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
10
- var GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
11
18
  function convertBits(data, fromBits, toBits, pad) {
12
19
  let acc = 0;
13
20
  let bits = 0;
@@ -114,7 +121,15 @@ function getAddressHrp(addr) {
114
121
  const result = decodeBech32(addr);
115
122
  return result?.hrp ?? null;
116
123
  }
117
- var createBech32 = encodeBech32;
124
+ var CHARSET, GENERATOR, createBech32;
125
+ var init_bech32 = __esm({
126
+ "core/bech32.ts"() {
127
+ "use strict";
128
+ CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
129
+ GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
130
+ createBech32 = encodeBech32;
131
+ }
132
+ });
118
133
 
119
134
  // l1/addressToScriptHash.ts
120
135
  import CryptoJS from "crypto-js";
@@ -128,224 +143,30 @@ function addressToScriptHash(address) {
128
143
  const sha = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(scriptHex)).toString();
129
144
  return sha.match(/../g).reverse().join("");
130
145
  }
131
-
132
- // core/crypto.ts
133
- import * as bip39 from "bip39";
134
- import CryptoJS2 from "crypto-js";
135
- import elliptic from "elliptic";
136
- var ec = new elliptic.ec("secp256k1");
137
- var CURVE_ORDER = BigInt(
138
- "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
139
- );
140
- var DEFAULT_DERIVATION_PATH = "m/44'/0'/0'";
141
- function generateMnemonic2(strength = 128) {
142
- return bip39.generateMnemonic(strength);
143
- }
144
- function validateMnemonic2(mnemonic) {
145
- return bip39.validateMnemonic(mnemonic);
146
- }
147
- async function mnemonicToSeed2(mnemonic, passphrase = "") {
148
- const seedBuffer = await bip39.mnemonicToSeed(mnemonic, passphrase);
149
- return Buffer.from(seedBuffer).toString("hex");
150
- }
151
- function mnemonicToSeedSync2(mnemonic, passphrase = "") {
152
- const seedBuffer = bip39.mnemonicToSeedSync(mnemonic, passphrase);
153
- return Buffer.from(seedBuffer).toString("hex");
154
- }
155
- function mnemonicToEntropy2(mnemonic) {
156
- return bip39.mnemonicToEntropy(mnemonic);
157
- }
158
- function entropyToMnemonic2(entropy) {
159
- return bip39.entropyToMnemonic(entropy);
160
- }
161
- function generateMasterKey(seedHex) {
162
- const I = CryptoJS2.HmacSHA512(
163
- CryptoJS2.enc.Hex.parse(seedHex),
164
- CryptoJS2.enc.Utf8.parse("Bitcoin seed")
165
- ).toString();
166
- const IL = I.substring(0, 64);
167
- const IR = I.substring(64);
168
- const masterKeyBigInt = BigInt("0x" + IL);
169
- if (masterKeyBigInt === 0n || masterKeyBigInt >= CURVE_ORDER) {
170
- throw new Error("Invalid master key generated");
171
- }
172
- return {
173
- privateKey: IL,
174
- chainCode: IR
175
- };
176
- }
177
- function deriveChildKey(parentPrivKey, parentChainCode, index) {
178
- const isHardened = index >= 2147483648;
179
- let data;
180
- if (isHardened) {
181
- const indexHex = index.toString(16).padStart(8, "0");
182
- data = "00" + parentPrivKey + indexHex;
183
- } else {
184
- const keyPair = ec.keyFromPrivate(parentPrivKey, "hex");
185
- const compressedPubKey = keyPair.getPublic(true, "hex");
186
- const indexHex = index.toString(16).padStart(8, "0");
187
- data = compressedPubKey + indexHex;
188
- }
189
- const I = CryptoJS2.HmacSHA512(
190
- CryptoJS2.enc.Hex.parse(data),
191
- CryptoJS2.enc.Hex.parse(parentChainCode)
192
- ).toString();
193
- const IL = I.substring(0, 64);
194
- const IR = I.substring(64);
195
- const ilBigInt = BigInt("0x" + IL);
196
- const parentKeyBigInt = BigInt("0x" + parentPrivKey);
197
- if (ilBigInt >= CURVE_ORDER) {
198
- throw new Error("Invalid key: IL >= curve order");
199
- }
200
- const childKeyBigInt = (ilBigInt + parentKeyBigInt) % CURVE_ORDER;
201
- if (childKeyBigInt === 0n) {
202
- throw new Error("Invalid key: child key is zero");
203
- }
204
- const childPrivKey = childKeyBigInt.toString(16).padStart(64, "0");
205
- return {
206
- privateKey: childPrivKey,
207
- chainCode: IR
208
- };
209
- }
210
- function deriveKeyAtPath(masterPrivKey, masterChainCode, path) {
211
- const pathParts = path.replace("m/", "").split("/");
212
- let currentKey = masterPrivKey;
213
- let currentChainCode = masterChainCode;
214
- for (const part of pathParts) {
215
- const isHardened = part.endsWith("'") || part.endsWith("h");
216
- const indexStr = part.replace(/['h]$/, "");
217
- let index = parseInt(indexStr, 10);
218
- if (isHardened) {
219
- index += 2147483648;
220
- }
221
- const derived = deriveChildKey(currentKey, currentChainCode, index);
222
- currentKey = derived.privateKey;
223
- currentChainCode = derived.chainCode;
224
- }
225
- return {
226
- privateKey: currentKey,
227
- chainCode: currentChainCode
228
- };
229
- }
230
- function getPublicKey(privateKey, compressed = true) {
231
- const keyPair = ec.keyFromPrivate(privateKey, "hex");
232
- return keyPair.getPublic(compressed, "hex");
233
- }
234
- function createKeyPair(privateKey) {
235
- return {
236
- privateKey,
237
- publicKey: getPublicKey(privateKey)
238
- };
239
- }
240
- function sha256(data, inputEncoding = "hex") {
241
- const parsed = inputEncoding === "hex" ? CryptoJS2.enc.Hex.parse(data) : CryptoJS2.enc.Utf8.parse(data);
242
- return CryptoJS2.SHA256(parsed).toString();
243
- }
244
- function ripemd160(data, inputEncoding = "hex") {
245
- const parsed = inputEncoding === "hex" ? CryptoJS2.enc.Hex.parse(data) : CryptoJS2.enc.Utf8.parse(data);
246
- return CryptoJS2.RIPEMD160(parsed).toString();
247
- }
248
- function hash160(data) {
249
- const sha = sha256(data, "hex");
250
- return ripemd160(sha, "hex");
251
- }
252
- function doubleSha256(data, inputEncoding = "hex") {
253
- const first = sha256(data, inputEncoding);
254
- return sha256(first, "hex");
255
- }
256
- var computeHash160 = hash160;
257
- function hash160ToBytes(hash160Hex) {
258
- const matches = hash160Hex.match(/../g);
259
- if (!matches) return new Uint8Array(0);
260
- return Uint8Array.from(matches.map((x) => parseInt(x, 16)));
261
- }
262
- function publicKeyToAddress(publicKey, prefix = "alpha", witnessVersion = 0) {
263
- const pubKeyHash = hash160(publicKey);
264
- const programBytes = hash160ToBytes(pubKeyHash);
265
- return encodeBech32(prefix, witnessVersion, programBytes);
266
- }
267
- function privateKeyToAddressInfo(privateKey, prefix = "alpha") {
268
- const publicKey = getPublicKey(privateKey);
269
- const address = publicKeyToAddress(publicKey, prefix);
270
- return { address, publicKey };
271
- }
272
- function hexToBytes(hex) {
273
- const matches = hex.match(/../g);
274
- if (!matches) {
275
- return new Uint8Array(0);
276
- }
277
- return Uint8Array.from(matches.map((x) => parseInt(x, 16)));
278
- }
279
- function bytesToHex2(bytes) {
280
- return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
281
- }
282
- function randomBytes(length) {
283
- const words = CryptoJS2.lib.WordArray.random(length);
284
- return words.toString(CryptoJS2.enc.Hex);
285
- }
286
- async function identityFromMnemonic(mnemonic, passphrase = "") {
287
- if (!validateMnemonic2(mnemonic)) {
288
- throw new Error("Invalid mnemonic phrase");
146
+ var init_addressToScriptHash = __esm({
147
+ "l1/addressToScriptHash.ts"() {
148
+ "use strict";
149
+ init_bech32();
289
150
  }
290
- const seedHex = await mnemonicToSeed2(mnemonic, passphrase);
291
- return generateMasterKey(seedHex);
292
- }
293
- function identityFromMnemonicSync(mnemonic, passphrase = "") {
294
- if (!validateMnemonic2(mnemonic)) {
295
- throw new Error("Invalid mnemonic phrase");
296
- }
297
- const seedHex = mnemonicToSeedSync2(mnemonic, passphrase);
298
- return generateMasterKey(seedHex);
299
- }
300
- function deriveAddressInfo(masterKey, basePath, index, isChange = false, prefix = "alpha") {
301
- const chain = isChange ? 1 : 0;
302
- const fullPath = `${basePath}/${chain}/${index}`;
303
- const derived = deriveKeyAtPath(masterKey.privateKey, masterKey.chainCode, fullPath);
304
- const publicKey = getPublicKey(derived.privateKey);
305
- const address = publicKeyToAddress(publicKey, prefix);
306
- return {
307
- privateKey: derived.privateKey,
308
- publicKey,
309
- address,
310
- path: fullPath,
311
- index
312
- };
313
- }
314
- function generateAddressInfo(privateKey, index, path, prefix = "alpha") {
315
- const { address, publicKey } = privateKeyToAddressInfo(privateKey, prefix);
316
- return {
317
- privateKey,
318
- publicKey,
319
- address,
320
- path,
321
- index
322
- };
323
- }
324
-
325
- // l1/crypto.ts
326
- import CryptoJS3 from "crypto-js";
327
-
328
- // l1/address.ts
329
- import CryptoJS4 from "crypto-js";
151
+ });
330
152
 
331
153
  // l1/network.ts
332
- var DEFAULT_ENDPOINT = "wss://fulcrum.unicity.network:50004";
333
- var ws = null;
334
- var isConnected = false;
335
- var isConnecting = false;
336
- var requestId = 0;
337
- var intentionalClose = false;
338
- var reconnectAttempts = 0;
339
- var isBlockSubscribed = false;
340
- var lastBlockHeader = null;
341
- var pending = {};
342
- var blockSubscribers = [];
343
- var connectionCallbacks = [];
344
- var MAX_RECONNECT_ATTEMPTS = 10;
345
- var BASE_DELAY = 2e3;
346
- var MAX_DELAY = 6e4;
347
- var RPC_TIMEOUT = 3e4;
348
- var CONNECTION_TIMEOUT = 3e4;
154
+ var network_exports = {};
155
+ __export(network_exports, {
156
+ broadcast: () => broadcast,
157
+ connect: () => connect,
158
+ disconnect: () => disconnect,
159
+ getBalance: () => getBalance,
160
+ getBlockHeader: () => getBlockHeader,
161
+ getCurrentBlockHeight: () => getCurrentBlockHeight,
162
+ getTransaction: () => getTransaction,
163
+ getTransactionHistory: () => getTransactionHistory,
164
+ getUtxo: () => getUtxo,
165
+ isWebSocketConnected: () => isWebSocketConnected,
166
+ rpc: () => rpc,
167
+ subscribeBlocks: () => subscribeBlocks,
168
+ waitForConnection: () => waitForConnection
169
+ });
349
170
  function isWebSocketConnected() {
350
171
  return isConnected && ws !== null && ws.readyState === WebSocket.OPEN;
351
172
  }
@@ -536,6 +357,31 @@ async function getBalance(address) {
536
357
  async function broadcast(rawHex) {
537
358
  return await rpc("blockchain.transaction.broadcast", [rawHex]);
538
359
  }
360
+ async function subscribeBlocks(cb) {
361
+ if (!isConnected && !isConnecting) {
362
+ await connect();
363
+ }
364
+ if (!isWebSocketConnected()) {
365
+ await waitForConnection();
366
+ }
367
+ blockSubscribers.push(cb);
368
+ if (!isBlockSubscribed) {
369
+ isBlockSubscribed = true;
370
+ const header = await rpc("blockchain.headers.subscribe", []);
371
+ if (header) {
372
+ lastBlockHeader = header;
373
+ blockSubscribers.forEach((subscriber) => subscriber(header));
374
+ }
375
+ } else if (lastBlockHeader) {
376
+ cb(lastBlockHeader);
377
+ }
378
+ return () => {
379
+ const index = blockSubscribers.indexOf(cb);
380
+ if (index > -1) {
381
+ blockSubscribers.splice(index, 1);
382
+ }
383
+ };
384
+ }
539
385
  async function getTransactionHistory(address) {
540
386
  const scriptHash = addressToScriptHash(address);
541
387
  const result = await rpc("blockchain.scripthash.get_history", [scriptHash]);
@@ -543,45 +389,290 @@ async function getTransactionHistory(address) {
543
389
  console.warn("get_history returned non-array:", result);
544
390
  return [];
545
391
  }
546
- return result;
392
+ return result;
393
+ }
394
+ async function getTransaction(txid) {
395
+ return await rpc("blockchain.transaction.get", [txid, true]);
396
+ }
397
+ async function getBlockHeader(height) {
398
+ return await rpc("blockchain.block.header", [height, height]);
399
+ }
400
+ async function getCurrentBlockHeight() {
401
+ try {
402
+ const header = await rpc("blockchain.headers.subscribe", []);
403
+ return header?.height || 0;
404
+ } catch (err) {
405
+ console.error("Error getting current block height:", err);
406
+ return 0;
407
+ }
408
+ }
409
+ function disconnect() {
410
+ if (ws) {
411
+ intentionalClose = true;
412
+ ws.close();
413
+ ws = null;
414
+ }
415
+ isConnected = false;
416
+ isConnecting = false;
417
+ reconnectAttempts = 0;
418
+ isBlockSubscribed = false;
419
+ Object.values(pending).forEach((req) => {
420
+ if (req.timeoutId) clearTimeout(req.timeoutId);
421
+ });
422
+ Object.keys(pending).forEach((key) => delete pending[Number(key)]);
423
+ connectionCallbacks.forEach((cb) => {
424
+ if (cb.timeoutId) clearTimeout(cb.timeoutId);
425
+ });
426
+ connectionCallbacks.length = 0;
427
+ }
428
+ 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
+ var init_network = __esm({
430
+ "l1/network.ts"() {
431
+ "use strict";
432
+ init_addressToScriptHash();
433
+ DEFAULT_ENDPOINT = "wss://fulcrum.unicity.network:50004";
434
+ ws = null;
435
+ isConnected = false;
436
+ isConnecting = false;
437
+ requestId = 0;
438
+ intentionalClose = false;
439
+ reconnectAttempts = 0;
440
+ isBlockSubscribed = false;
441
+ lastBlockHeader = null;
442
+ pending = {};
443
+ blockSubscribers = [];
444
+ connectionCallbacks = [];
445
+ MAX_RECONNECT_ATTEMPTS = 10;
446
+ BASE_DELAY = 2e3;
447
+ MAX_DELAY = 6e4;
448
+ RPC_TIMEOUT = 3e4;
449
+ CONNECTION_TIMEOUT = 3e4;
450
+ }
451
+ });
452
+
453
+ // l1/index.ts
454
+ init_bech32();
455
+ init_addressToScriptHash();
456
+
457
+ // core/crypto.ts
458
+ init_bech32();
459
+ import * as bip39 from "bip39";
460
+ import CryptoJS2 from "crypto-js";
461
+ import elliptic from "elliptic";
462
+ var ec = new elliptic.ec("secp256k1");
463
+ var CURVE_ORDER = BigInt(
464
+ "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
465
+ );
466
+ var DEFAULT_DERIVATION_PATH = "m/44'/0'/0'";
467
+ function generateMnemonic2(strength = 128) {
468
+ return bip39.generateMnemonic(strength);
469
+ }
470
+ function validateMnemonic2(mnemonic) {
471
+ return bip39.validateMnemonic(mnemonic);
472
+ }
473
+ async function mnemonicToSeed2(mnemonic, passphrase = "") {
474
+ const seedBuffer = await bip39.mnemonicToSeed(mnemonic, passphrase);
475
+ return Buffer.from(seedBuffer).toString("hex");
476
+ }
477
+ function mnemonicToSeedSync2(mnemonic, passphrase = "") {
478
+ const seedBuffer = bip39.mnemonicToSeedSync(mnemonic, passphrase);
479
+ return Buffer.from(seedBuffer).toString("hex");
480
+ }
481
+ function mnemonicToEntropy2(mnemonic) {
482
+ return bip39.mnemonicToEntropy(mnemonic);
483
+ }
484
+ function entropyToMnemonic2(entropy) {
485
+ return bip39.entropyToMnemonic(entropy);
486
+ }
487
+ function generateMasterKey(seedHex) {
488
+ const I = CryptoJS2.HmacSHA512(
489
+ CryptoJS2.enc.Hex.parse(seedHex),
490
+ CryptoJS2.enc.Utf8.parse("Bitcoin seed")
491
+ ).toString();
492
+ const IL = I.substring(0, 64);
493
+ const IR = I.substring(64);
494
+ const masterKeyBigInt = BigInt("0x" + IL);
495
+ if (masterKeyBigInt === 0n || masterKeyBigInt >= CURVE_ORDER) {
496
+ throw new Error("Invalid master key generated");
497
+ }
498
+ return {
499
+ privateKey: IL,
500
+ chainCode: IR
501
+ };
502
+ }
503
+ function deriveChildKey(parentPrivKey, parentChainCode, index) {
504
+ const isHardened = index >= 2147483648;
505
+ let data;
506
+ if (isHardened) {
507
+ const indexHex = index.toString(16).padStart(8, "0");
508
+ data = "00" + parentPrivKey + indexHex;
509
+ } else {
510
+ const keyPair = ec.keyFromPrivate(parentPrivKey, "hex");
511
+ const compressedPubKey = keyPair.getPublic(true, "hex");
512
+ const indexHex = index.toString(16).padStart(8, "0");
513
+ data = compressedPubKey + indexHex;
514
+ }
515
+ const I = CryptoJS2.HmacSHA512(
516
+ CryptoJS2.enc.Hex.parse(data),
517
+ CryptoJS2.enc.Hex.parse(parentChainCode)
518
+ ).toString();
519
+ const IL = I.substring(0, 64);
520
+ const IR = I.substring(64);
521
+ const ilBigInt = BigInt("0x" + IL);
522
+ const parentKeyBigInt = BigInt("0x" + parentPrivKey);
523
+ if (ilBigInt >= CURVE_ORDER) {
524
+ throw new Error("Invalid key: IL >= curve order");
525
+ }
526
+ const childKeyBigInt = (ilBigInt + parentKeyBigInt) % CURVE_ORDER;
527
+ if (childKeyBigInt === 0n) {
528
+ throw new Error("Invalid key: child key is zero");
529
+ }
530
+ const childPrivKey = childKeyBigInt.toString(16).padStart(64, "0");
531
+ return {
532
+ privateKey: childPrivKey,
533
+ chainCode: IR
534
+ };
535
+ }
536
+ function deriveKeyAtPath(masterPrivKey, masterChainCode, path) {
537
+ const pathParts = path.replace("m/", "").split("/");
538
+ let currentKey = masterPrivKey;
539
+ let currentChainCode = masterChainCode;
540
+ for (const part of pathParts) {
541
+ const isHardened = part.endsWith("'") || part.endsWith("h");
542
+ const indexStr = part.replace(/['h]$/, "");
543
+ let index = parseInt(indexStr, 10);
544
+ if (isHardened) {
545
+ index += 2147483648;
546
+ }
547
+ const derived = deriveChildKey(currentKey, currentChainCode, index);
548
+ currentKey = derived.privateKey;
549
+ currentChainCode = derived.chainCode;
550
+ }
551
+ return {
552
+ privateKey: currentKey,
553
+ chainCode: currentChainCode
554
+ };
555
+ }
556
+ function getPublicKey(privateKey, compressed = true) {
557
+ const keyPair = ec.keyFromPrivate(privateKey, "hex");
558
+ return keyPair.getPublic(compressed, "hex");
559
+ }
560
+ function createKeyPair(privateKey) {
561
+ return {
562
+ privateKey,
563
+ publicKey: getPublicKey(privateKey)
564
+ };
565
+ }
566
+ function sha256(data, inputEncoding = "hex") {
567
+ const parsed = inputEncoding === "hex" ? CryptoJS2.enc.Hex.parse(data) : CryptoJS2.enc.Utf8.parse(data);
568
+ return CryptoJS2.SHA256(parsed).toString();
569
+ }
570
+ function ripemd160(data, inputEncoding = "hex") {
571
+ const parsed = inputEncoding === "hex" ? CryptoJS2.enc.Hex.parse(data) : CryptoJS2.enc.Utf8.parse(data);
572
+ return CryptoJS2.RIPEMD160(parsed).toString();
573
+ }
574
+ function hash160(data) {
575
+ const sha = sha256(data, "hex");
576
+ return ripemd160(sha, "hex");
577
+ }
578
+ function doubleSha256(data, inputEncoding = "hex") {
579
+ const first = sha256(data, inputEncoding);
580
+ return sha256(first, "hex");
581
+ }
582
+ var computeHash160 = hash160;
583
+ function hash160ToBytes(hash160Hex) {
584
+ const matches = hash160Hex.match(/../g);
585
+ if (!matches) return new Uint8Array(0);
586
+ return Uint8Array.from(matches.map((x) => parseInt(x, 16)));
587
+ }
588
+ function publicKeyToAddress(publicKey, prefix = "alpha", witnessVersion = 0) {
589
+ const pubKeyHash = hash160(publicKey);
590
+ const programBytes = hash160ToBytes(pubKeyHash);
591
+ return encodeBech32(prefix, witnessVersion, programBytes);
592
+ }
593
+ function privateKeyToAddressInfo(privateKey, prefix = "alpha") {
594
+ const publicKey = getPublicKey(privateKey);
595
+ const address = publicKeyToAddress(publicKey, prefix);
596
+ return { address, publicKey };
597
+ }
598
+ function hexToBytes(hex) {
599
+ const matches = hex.match(/../g);
600
+ if (!matches) {
601
+ return new Uint8Array(0);
602
+ }
603
+ return Uint8Array.from(matches.map((x) => parseInt(x, 16)));
547
604
  }
548
- async function getTransaction(txid) {
549
- return await rpc("blockchain.transaction.get", [txid, true]);
605
+ function bytesToHex2(bytes) {
606
+ return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
550
607
  }
551
- async function getCurrentBlockHeight() {
552
- try {
553
- const header = await rpc("blockchain.headers.subscribe", []);
554
- return header?.height || 0;
555
- } catch (err) {
556
- console.error("Error getting current block height:", err);
557
- return 0;
608
+ function randomBytes(length) {
609
+ const words = CryptoJS2.lib.WordArray.random(length);
610
+ return words.toString(CryptoJS2.enc.Hex);
611
+ }
612
+ async function identityFromMnemonic(mnemonic, passphrase = "") {
613
+ if (!validateMnemonic2(mnemonic)) {
614
+ throw new Error("Invalid mnemonic phrase");
558
615
  }
616
+ const seedHex = await mnemonicToSeed2(mnemonic, passphrase);
617
+ return generateMasterKey(seedHex);
559
618
  }
560
- function disconnect() {
561
- if (ws) {
562
- intentionalClose = true;
563
- ws.close();
564
- ws = null;
619
+ function identityFromMnemonicSync(mnemonic, passphrase = "") {
620
+ if (!validateMnemonic2(mnemonic)) {
621
+ throw new Error("Invalid mnemonic phrase");
565
622
  }
566
- isConnected = false;
567
- isConnecting = false;
568
- reconnectAttempts = 0;
569
- isBlockSubscribed = false;
570
- Object.values(pending).forEach((req) => {
571
- if (req.timeoutId) clearTimeout(req.timeoutId);
572
- });
573
- Object.keys(pending).forEach((key) => delete pending[Number(key)]);
574
- connectionCallbacks.forEach((cb) => {
575
- if (cb.timeoutId) clearTimeout(cb.timeoutId);
576
- });
577
- connectionCallbacks.length = 0;
623
+ const seedHex = mnemonicToSeedSync2(mnemonic, passphrase);
624
+ return generateMasterKey(seedHex);
625
+ }
626
+ function deriveAddressInfo(masterKey, basePath, index, isChange = false, prefix = "alpha") {
627
+ const chain = isChange ? 1 : 0;
628
+ const fullPath = `${basePath}/${chain}/${index}`;
629
+ const derived = deriveKeyAtPath(masterKey.privateKey, masterKey.chainCode, fullPath);
630
+ const publicKey = getPublicKey(derived.privateKey);
631
+ const address = publicKeyToAddress(publicKey, prefix);
632
+ return {
633
+ privateKey: derived.privateKey,
634
+ publicKey,
635
+ address,
636
+ path: fullPath,
637
+ index
638
+ };
639
+ }
640
+ function generateAddressInfo(privateKey, index, path, prefix = "alpha") {
641
+ const { address, publicKey } = privateKeyToAddressInfo(privateKey, prefix);
642
+ return {
643
+ privateKey,
644
+ publicKey,
645
+ address,
646
+ path,
647
+ index
648
+ };
649
+ }
650
+
651
+ // l1/crypto.ts
652
+ import CryptoJS3 from "crypto-js";
653
+
654
+ // l1/address.ts
655
+ import CryptoJS4 from "crypto-js";
656
+ function generateAddressFromMasterKey(masterPrivateKey, index) {
657
+ const derivationPath = `m/44'/0'/${index}'`;
658
+ const hmacInput = CryptoJS4.enc.Hex.parse(masterPrivateKey);
659
+ const hmacKey = CryptoJS4.enc.Utf8.parse(derivationPath);
660
+ const hmacOutput = CryptoJS4.HmacSHA512(hmacInput, hmacKey).toString();
661
+ const childPrivateKey = hmacOutput.substring(0, 64);
662
+ return generateAddressInfo(childPrivateKey, index, derivationPath);
578
663
  }
579
664
 
665
+ // l1/index.ts
666
+ init_network();
667
+
580
668
  // l1/tx.ts
669
+ init_network();
670
+ init_bech32();
581
671
  import CryptoJS5 from "crypto-js";
582
672
  import elliptic2 from "elliptic";
583
673
 
584
674
  // l1/vesting.ts
675
+ init_network();
585
676
  var VESTING_THRESHOLD = 28e4;
586
677
  var currentBlockHeight = null;
587
678
  var VestingClassifier = class {
@@ -800,6 +891,24 @@ var VestingClassifier = class {
800
891
  tx.objectStore(this.storeName).clear();
801
892
  }
802
893
  }
894
+ /**
895
+ * Destroy caches and delete the IndexedDB database entirely.
896
+ */
897
+ async destroy() {
898
+ this.memoryCache.clear();
899
+ if (this.db) {
900
+ this.db.close();
901
+ this.db = null;
902
+ }
903
+ if (typeof indexedDB !== "undefined") {
904
+ await new Promise((resolve) => {
905
+ const req = indexedDB.deleteDatabase(this.dbName);
906
+ req.onsuccess = () => resolve();
907
+ req.onerror = () => resolve();
908
+ req.onblocked = () => resolve();
909
+ });
910
+ }
911
+ }
803
912
  };
804
913
  var vestingClassifier = new VestingClassifier();
805
914
 
@@ -1352,7 +1461,7 @@ var L1PaymentsModule = class {
1352
1461
  _transport;
1353
1462
  constructor(config) {
1354
1463
  this._config = {
1355
- electrumUrl: config?.electrumUrl ?? "wss://fulcrum.alpha.unicity.network:50004",
1464
+ electrumUrl: config?.electrumUrl ?? "wss://fulcrum.unicity.network:50004",
1356
1465
  network: config?.network ?? "mainnet",
1357
1466
  defaultFeeRate: config?.defaultFeeRate ?? 10,
1358
1467
  enableVesting: config?.enableVesting ?? true
@@ -1384,10 +1493,17 @@ var L1PaymentsModule = class {
1384
1493
  });
1385
1494
  }
1386
1495
  }
1387
- if (this._config.electrumUrl) {
1496
+ this._initialized = true;
1497
+ }
1498
+ /**
1499
+ * Ensure the Fulcrum WebSocket is connected. Called lazily before any
1500
+ * operation that needs the network. If the singleton is already connected
1501
+ * (e.g. by the address scanner), this is a no-op.
1502
+ */
1503
+ async ensureConnected() {
1504
+ if (!isWebSocketConnected() && this._config.electrumUrl) {
1388
1505
  await connect(this._config.electrumUrl);
1389
1506
  }
1390
- this._initialized = true;
1391
1507
  }
1392
1508
  destroy() {
1393
1509
  if (isWebSocketConnected()) {
@@ -1445,6 +1561,7 @@ var L1PaymentsModule = class {
1445
1561
  }
1446
1562
  async send(request) {
1447
1563
  this.ensureInitialized();
1564
+ await this.ensureConnected();
1448
1565
  if (!this._wallet || !this._identity) {
1449
1566
  return { success: false, error: "No wallet available" };
1450
1567
  }
@@ -1479,6 +1596,7 @@ var L1PaymentsModule = class {
1479
1596
  }
1480
1597
  async getBalance() {
1481
1598
  this.ensureInitialized();
1599
+ await this.ensureConnected();
1482
1600
  const addresses = this._getWatchedAddresses();
1483
1601
  let totalAlpha = 0;
1484
1602
  let vestedSats = BigInt(0);
@@ -1510,6 +1628,7 @@ var L1PaymentsModule = class {
1510
1628
  }
1511
1629
  async getUtxos() {
1512
1630
  this.ensureInitialized();
1631
+ await this.ensureConnected();
1513
1632
  const result = [];
1514
1633
  const currentHeight = await getCurrentBlockHeight();
1515
1634
  const allUtxos = await this._getAllUtxos();
@@ -1545,42 +1664,73 @@ var L1PaymentsModule = class {
1545
1664
  return result;
1546
1665
  }
1547
1666
  async getHistory(limit) {
1667
+ await this.ensureConnected();
1548
1668
  this.ensureInitialized();
1549
1669
  const addresses = this._getWatchedAddresses();
1550
1670
  const transactions = [];
1551
1671
  const seenTxids = /* @__PURE__ */ new Set();
1552
1672
  const currentHeight = await getCurrentBlockHeight();
1673
+ const txCache = /* @__PURE__ */ new Map();
1674
+ const fetchTx = async (txid) => {
1675
+ if (txCache.has(txid)) return txCache.get(txid);
1676
+ const detail = await getTransaction(txid);
1677
+ txCache.set(txid, detail);
1678
+ return detail;
1679
+ };
1680
+ const addressSet = new Set(addresses.map((a) => a.toLowerCase()));
1553
1681
  for (const address of addresses) {
1554
1682
  const history = await getTransactionHistory(address);
1555
1683
  for (const item of history) {
1556
1684
  if (seenTxids.has(item.tx_hash)) continue;
1557
1685
  seenTxids.add(item.tx_hash);
1558
- const tx = await getTransaction(item.tx_hash);
1686
+ const tx = await fetchTx(item.tx_hash);
1559
1687
  if (!tx) continue;
1560
- const isSend = tx.vin?.some(
1561
- (vin) => addresses.includes(vin.txid ?? "")
1562
- );
1563
- let amount = "0";
1688
+ let isSend = false;
1689
+ for (const vin of tx.vin ?? []) {
1690
+ if (!vin.txid) continue;
1691
+ const prevTx = await fetchTx(vin.txid);
1692
+ if (prevTx?.vout?.[vin.vout]) {
1693
+ const prevOut = prevTx.vout[vin.vout];
1694
+ const prevAddrs = [
1695
+ ...prevOut.scriptPubKey?.addresses ?? [],
1696
+ ...prevOut.scriptPubKey?.address ? [prevOut.scriptPubKey.address] : []
1697
+ ];
1698
+ if (prevAddrs.some((a) => addressSet.has(a.toLowerCase()))) {
1699
+ isSend = true;
1700
+ break;
1701
+ }
1702
+ }
1703
+ }
1704
+ let amountToUs = 0;
1705
+ let amountToOthers = 0;
1564
1706
  let txAddress = address;
1707
+ let externalAddress = "";
1565
1708
  if (tx.vout) {
1566
1709
  for (const vout of tx.vout) {
1567
- const voutAddresses = vout.scriptPubKey?.addresses ?? [];
1568
- if (vout.scriptPubKey?.address) {
1569
- voutAddresses.push(vout.scriptPubKey.address);
1570
- }
1571
- const matchedAddr = voutAddresses.find((a) => addresses.includes(a));
1572
- if (matchedAddr) {
1573
- amount = Math.floor((vout.value ?? 0) * 1e8).toString();
1574
- txAddress = matchedAddr;
1575
- break;
1710
+ const voutAddresses = [
1711
+ ...vout.scriptPubKey?.addresses ?? [],
1712
+ ...vout.scriptPubKey?.address ? [vout.scriptPubKey.address] : []
1713
+ ];
1714
+ const isOurs = voutAddresses.some((a) => addressSet.has(a.toLowerCase()));
1715
+ const valueSats = Math.floor((vout.value ?? 0) * 1e8);
1716
+ if (isOurs) {
1717
+ amountToUs += valueSats;
1718
+ if (!txAddress) txAddress = voutAddresses[0];
1719
+ } else {
1720
+ amountToOthers += valueSats;
1721
+ if (!externalAddress && voutAddresses.length > 0) {
1722
+ externalAddress = voutAddresses[0];
1723
+ }
1576
1724
  }
1577
1725
  }
1578
1726
  }
1727
+ const amount = isSend ? amountToOthers.toString() : amountToUs.toString();
1728
+ const displayAddress = isSend ? externalAddress || txAddress : txAddress;
1579
1729
  transactions.push({
1580
1730
  txid: item.tx_hash,
1581
1731
  type: isSend ? "send" : "receive",
1582
1732
  amount,
1583
- address: txAddress,
1733
+ address: displayAddress,
1584
1734
  confirmations: item.height > 0 ? currentHeight - item.height : 0,
1585
1735
  timestamp: tx.time ? tx.time * 1e3 : Date.now(),
1586
1736
  blockHeight: item.height > 0 ? item.height : void 0
@@ -1592,6 +1742,7 @@ var L1PaymentsModule = class {
1592
1742
  }
1593
1743
  async getTransaction(txid) {
1594
1744
  this.ensureInitialized();
1745
+ await this.ensureConnected();
1595
1746
  const tx = await getTransaction(txid);
1596
1747
  if (!tx) return null;
1597
1748
  const addresses = this._getWatchedAddresses();
@@ -1627,6 +1778,7 @@ var L1PaymentsModule = class {
1627
1778
  }
1628
1779
  async estimateFee(to, amount) {
1629
1780
  this.ensureInitialized();
1781
+ await this.ensureConnected();
1630
1782
  if (!this._wallet) {
1631
1783
  return { fee: "0", feeRate: this._config.defaultFeeRate ?? 10 };
1632
1784
  }
@@ -2146,7 +2298,9 @@ var STORAGE_KEYS_GLOBAL = {
2146
2298
  /** Nametag cache per address (separate from tracked addresses registry) */
2147
2299
  ADDRESS_NAMETAGS: "address_nametags",
2148
2300
  /** Active addresses registry (JSON: TrackedAddressesStorage) */
2149
- TRACKED_ADDRESSES: "tracked_addresses"
2301
+ TRACKED_ADDRESSES: "tracked_addresses",
2302
+ /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
2303
+ LAST_WALLET_EVENT_TS: "last_wallet_event_ts"
2150
2304
  };
2151
2305
  var STORAGE_KEYS_ADDRESS = {
2152
2306
  /** Pending transfers for this address */
@@ -3550,7 +3704,7 @@ async function parseTokenInfo(tokenData) {
3550
3704
  try {
3551
3705
  const sdkToken = await SdkToken2.fromJSON(data);
3552
3706
  if (sdkToken.id) {
3553
- defaultInfo.tokenId = sdkToken.id.toString();
3707
+ defaultInfo.tokenId = sdkToken.id.toJSON();
3554
3708
  }
3555
3709
  if (sdkToken.coins && sdkToken.coins.coins) {
3556
3710
  const rawCoins = sdkToken.coins.coins;
@@ -3841,8 +3995,7 @@ var PaymentsModule = class _PaymentsModule {
3841
3995
  maxRetries: config?.maxRetries ?? 3,
3842
3996
  debug: config?.debug ?? false
3843
3997
  };
3844
- const l1Enabled = config?.l1?.electrumUrl && config.l1.electrumUrl.length > 0;
3845
- this.l1 = l1Enabled ? new L1PaymentsModule(config?.l1) : null;
3998
+ this.l1 = config?.l1 === null ? null : new L1PaymentsModule(config?.l1);
3846
3999
  }
3847
4000
  /** Get module configuration */
3848
4001
  getConfig() {
@@ -4044,7 +4197,7 @@ var PaymentsModule = class _PaymentsModule {
4044
4197
  memo: request.memo
4045
4198
  });
4046
4199
  console.log(`[Payments] Split token sent successfully`);
4047
- await this.removeToken(splitPlan.tokenToSplit.uiToken.id, recipientNametag);
4200
+ await this.removeToken(splitPlan.tokenToSplit.uiToken.id, recipientNametag, true);
4048
4201
  result.txHash = "split-" + Date.now().toString(16);
4049
4202
  this.log(`Split transfer completed`);
4050
4203
  }
@@ -4070,7 +4223,7 @@ var PaymentsModule = class _PaymentsModule {
4070
4223
  });
4071
4224
  console.log(`[Payments] Direct token sent successfully`);
4072
4225
  this.log(`Token ${token.id} transferred, txHash: ${result.txHash}`);
4073
- await this.removeToken(token.id, recipientNametag);
4226
+ await this.removeToken(token.id, recipientNametag, true);
4074
4227
  }
4075
4228
  result.status = "delivered";
4076
4229
  await this.save();
@@ -4219,7 +4372,7 @@ var PaymentsModule = class _PaymentsModule {
4219
4372
  );
4220
4373
  if (result.success) {
4221
4374
  const recipientNametag = request.recipient.startsWith("@") ? request.recipient.slice(1) : void 0;
4222
- await this.removeToken(tokenToSplit.id, recipientNametag);
4375
+ await this.removeToken(tokenToSplit.id, recipientNametag, true);
4223
4376
  await this.addToHistory({
4224
4377
  type: "SENT",
4225
4378
  amount: request.amount,
@@ -4504,13 +4657,16 @@ var PaymentsModule = class _PaymentsModule {
4504
4657
  if (this.paymentRequests.find((r) => r.id === transportRequest.id)) {
4505
4658
  return;
4506
4659
  }
4660
+ const coinId = transportRequest.request.coinId;
4661
+ const registry = TokenRegistry.getInstance();
4662
+ const coinDef = registry.getDefinition(coinId);
4507
4663
  const request = {
4508
4664
  id: transportRequest.id,
4509
4665
  senderPubkey: transportRequest.senderTransportPubkey,
4666
+ senderNametag: transportRequest.senderNametag,
4510
4667
  amount: transportRequest.request.amount,
4511
- coinId: transportRequest.request.coinId,
4512
- symbol: transportRequest.request.coinId,
4513
- // Use coinId as symbol for now
4668
+ coinId,
4669
+ symbol: coinDef?.symbol || coinId.slice(0, 8),
4514
4670
  message: transportRequest.request.message,
4515
4671
  recipientNametag: transportRequest.request.recipientNametag,
4516
4672
  requestId: transportRequest.request.requestId,
@@ -4725,35 +4881,39 @@ var PaymentsModule = class _PaymentsModule {
4725
4881
  const rawAssets = Array.from(assetsMap.values());
4726
4882
  let priceMap = null;
4727
4883
  if (this.priceProvider && rawAssets.length > 0) {
4728
- const registry = TokenRegistry.getInstance();
4729
- const nameToCoins = /* @__PURE__ */ new Map();
4730
- for (const asset of rawAssets) {
4731
- const def = registry.getDefinition(asset.coinId);
4732
- if (def?.name) {
4733
- const existing = nameToCoins.get(def.name);
4734
- if (existing) {
4735
- existing.push(asset.coinId);
4736
- } else {
4737
- nameToCoins.set(def.name, [asset.coinId]);
4884
+ try {
4885
+ const registry = TokenRegistry.getInstance();
4886
+ const nameToCoins = /* @__PURE__ */ new Map();
4887
+ for (const asset of rawAssets) {
4888
+ const def = registry.getDefinition(asset.coinId);
4889
+ if (def?.name) {
4890
+ const existing = nameToCoins.get(def.name);
4891
+ if (existing) {
4892
+ existing.push(asset.coinId);
4893
+ } else {
4894
+ nameToCoins.set(def.name, [asset.coinId]);
4895
+ }
4738
4896
  }
4739
4897
  }
4740
- }
4741
- if (nameToCoins.size > 0) {
4742
- const tokenNames = Array.from(nameToCoins.keys());
4743
- const prices = await this.priceProvider.getPrices(tokenNames);
4744
- priceMap = /* @__PURE__ */ new Map();
4745
- for (const [name, coinIds] of nameToCoins) {
4746
- const price = prices.get(name);
4747
- if (price) {
4748
- for (const cid of coinIds) {
4749
- priceMap.set(cid, {
4750
- priceUsd: price.priceUsd,
4751
- priceEur: price.priceEur,
4752
- change24h: price.change24h
4753
- });
4898
+ if (nameToCoins.size > 0) {
4899
+ const tokenNames = Array.from(nameToCoins.keys());
4900
+ const prices = await this.priceProvider.getPrices(tokenNames);
4901
+ priceMap = /* @__PURE__ */ new Map();
4902
+ for (const [name, coinIds] of nameToCoins) {
4903
+ const price = prices.get(name);
4904
+ if (price) {
4905
+ for (const cid of coinIds) {
4906
+ priceMap.set(cid, {
4907
+ priceUsd: price.priceUsd,
4908
+ priceEur: price.priceEur,
4909
+ change24h: price.change24h
4910
+ });
4911
+ }
4754
4912
  }
4755
4913
  }
4756
4914
  }
4915
+ } catch (error) {
4916
+ console.warn("[Payments] Failed to fetch prices, returning assets without price data:", error);
4757
4917
  }
4758
4918
  }
4759
4919
  return rawAssets.map((raw) => {
@@ -4956,6 +5116,12 @@ var PaymentsModule = class _PaymentsModule {
4956
5116
  updatedAt: Date.now(),
4957
5117
  sdkData: typeof tokenJson === "string" ? tokenJson : JSON.stringify(tokenJson)
4958
5118
  };
5119
+ const loadedTokenId = extractTokenIdFromSdkData(token.sdkData);
5120
+ const loadedStateHash = extractStateHashFromSdkData(token.sdkData);
5121
+ if (loadedTokenId && loadedStateHash && this.isStateTombstoned(loadedTokenId, loadedStateHash)) {
5122
+ this.log(`Skipping tombstoned token file ${tokenId} (${loadedTokenId.slice(0, 8)}...)`);
5123
+ continue;
5124
+ }
4959
5125
  this.tokens.set(token.id, token);
4960
5126
  this.log(`Loaded token from file: ${tokenId}`);
4961
5127
  } catch (tokenError) {
@@ -5013,6 +5179,7 @@ var PaymentsModule = class _PaymentsModule {
5013
5179
  this.log(`Warning: Could not create tombstone for token ${tokenId.slice(0, 8)}... (missing tokenId or stateHash)`);
5014
5180
  }
5015
5181
  this.tokens.delete(tokenId);
5182
+ await this.deleteTokenFiles(token);
5016
5183
  if (!skipHistory && token.coinId && token.amount) {
5017
5184
  await this.addToHistory({
5018
5185
  type: "SENT",
@@ -5025,6 +5192,31 @@ var PaymentsModule = class _PaymentsModule {
5025
5192
  }
5026
5193
  await this.save();
5027
5194
  }
5195
+ /**
5196
+ * Delete physical token file(s) from all storage providers.
5197
+ * Finds files by matching the SDK token ID prefix in the filename.
5198
+ */
5199
+ async deleteTokenFiles(token) {
5200
+ const sdkTokenId = extractTokenIdFromSdkData(token.sdkData);
5201
+ if (!sdkTokenId) return;
5202
+ const tokenIdPrefix = sdkTokenId.slice(0, 16);
5203
+ const providers = this.getTokenStorageProviders();
5204
+ for (const [providerId, provider] of providers) {
5205
+ if (!provider.listTokenIds || !provider.deleteToken) continue;
5206
+ try {
5207
+ const allIds = await provider.listTokenIds();
5208
+ const matchingFiles = allIds.filter(
5209
+ (id) => id.startsWith(`token-${tokenIdPrefix}`)
5210
+ );
5211
+ for (const fileId of matchingFiles) {
5212
+ await provider.deleteToken(fileId);
5213
+ this.log(`Deleted token file ${fileId} from ${providerId}`);
5214
+ }
5215
+ } catch (error) {
5216
+ console.warn(`[Payments] Failed to delete token files from ${providerId}:`, error);
5217
+ }
5218
+ }
5219
+ }
5028
5220
  // ===========================================================================
5029
5221
  // Public API - Tombstones
5030
5222
  // ===========================================================================
@@ -6529,6 +6721,20 @@ function decryptSimple(ciphertext, password) {
6529
6721
  }
6530
6722
  return result;
6531
6723
  }
6724
+ function decryptWithSalt(ciphertext, password, salt) {
6725
+ try {
6726
+ const key = CryptoJS6.PBKDF2(password, salt, {
6727
+ keySize: 256 / 32,
6728
+ iterations: 1e5,
6729
+ hasher: CryptoJS6.algo.SHA256
6730
+ }).toString();
6731
+ const decrypted = CryptoJS6.AES.decrypt(ciphertext, key);
6732
+ const result = decrypted.toString(CryptoJS6.enc.Utf8);
6733
+ return result || null;
6734
+ } catch {
6735
+ return null;
6736
+ }
6737
+ }
6532
6738
  function encryptMnemonic(mnemonic, password) {
6533
6739
  return encryptSimple(mnemonic, password);
6534
6740
  }
@@ -6556,6 +6762,81 @@ function generateRandomKey(bytes = 32) {
6556
6762
  return CryptoJS6.lib.WordArray.random(bytes).toString(CryptoJS6.enc.Hex);
6557
6763
  }
6558
6764
 
6765
+ // core/scan.ts
6766
+ async function scanAddressesImpl(deriveAddress, options = {}) {
6767
+ const maxAddresses = options.maxAddresses ?? 50;
6768
+ const gapLimit = options.gapLimit ?? 20;
6769
+ const includeChange = options.includeChange ?? true;
6770
+ const { onProgress, signal, resolveNametag } = options;
6771
+ const { connect: connect2, getBalance: getBalance2 } = await Promise.resolve().then(() => (init_network(), network_exports));
6772
+ await connect2();
6773
+ const foundAddresses = [];
6774
+ let totalBalance = 0;
6775
+ let totalScanned = 0;
6776
+ let nametagsFoundCount = 0;
6777
+ const chains = includeChange ? [false, true] : [false];
6778
+ const totalToScan = maxAddresses * chains.length;
6779
+ for (const isChange of chains) {
6780
+ let consecutiveEmpty = 0;
6781
+ for (let index = 0; index < maxAddresses; index++) {
6782
+ if (signal?.aborted) break;
6783
+ const addrInfo = deriveAddress(index, isChange);
6784
+ totalScanned++;
6785
+ onProgress?.({
6786
+ scanned: totalScanned,
6787
+ total: totalToScan,
6788
+ currentAddress: addrInfo.address,
6789
+ foundCount: foundAddresses.length,
6790
+ currentGap: consecutiveEmpty,
6791
+ nametagsFoundCount
6792
+ });
6793
+ try {
6794
+ const balance = await getBalance2(addrInfo.address);
6795
+ if (balance > 0) {
6796
+ let nametag;
6797
+ if (resolveNametag) {
6798
+ try {
6799
+ const tag = await resolveNametag(addrInfo.address);
6800
+ if (tag) {
6801
+ nametag = tag;
6802
+ nametagsFoundCount++;
6803
+ }
6804
+ } catch {
6805
+ }
6806
+ }
6807
+ foundAddresses.push({
6808
+ index,
6809
+ address: addrInfo.address,
6810
+ path: addrInfo.path,
6811
+ balance,
6812
+ isChange,
6813
+ nametag
6814
+ });
6815
+ totalBalance += balance;
6816
+ consecutiveEmpty = 0;
6817
+ } else {
6818
+ consecutiveEmpty++;
6819
+ }
6820
+ } catch (err) {
6821
+ console.warn(`[scanAddresses] Error checking ${addrInfo.address}:`, err);
6822
+ consecutiveEmpty++;
6823
+ }
6824
+ if (consecutiveEmpty >= gapLimit) {
6825
+ break;
6826
+ }
6827
+ if (totalScanned % 5 === 0) {
6828
+ await new Promise((resolve) => setTimeout(resolve, 0));
6829
+ }
6830
+ }
6831
+ if (signal?.aborted) break;
6832
+ }
6833
+ return {
6834
+ addresses: foundAddresses,
6835
+ totalBalance,
6836
+ scannedCount: totalScanned
6837
+ };
6838
+ }
6839
+
6559
6840
  // serialization/wallet-text.ts
6560
6841
  import CryptoJS7 from "crypto-js";
6561
6842
 
@@ -6812,10 +7093,11 @@ function parseWalletText(content) {
6812
7093
  );
6813
7094
  const descriptorPath = extractFromText(content, /DESCRIPTOR PATH:\s*([^\n]+)/);
6814
7095
  const isBIP32 = content.includes("WALLET TYPE: BIP32 hierarchical deterministic wallet") || content.includes("WALLET TYPE: Alpha descriptor wallet") || !!chainCode;
7096
+ const effectiveDescriptorPath = descriptorPath ?? (isBIP32 ? "84'/1'/0'" : void 0);
6815
7097
  const data = {
6816
7098
  masterKey,
6817
7099
  chainCode: chainCode ?? void 0,
6818
- descriptorPath: descriptorPath ?? void 0,
7100
+ descriptorPath: effectiveDescriptorPath,
6819
7101
  derivationMode: isBIP32 ? "bip32" : "wif_hmac"
6820
7102
  };
6821
7103
  return {
@@ -6858,10 +7140,11 @@ function parseAndDecryptWalletText(content, password) {
6858
7140
  );
6859
7141
  const descriptorPath = extractFromText(content, /DESCRIPTOR PATH:\s*([^\n]+)/);
6860
7142
  const isBIP32 = content.includes("WALLET TYPE: BIP32 hierarchical deterministic wallet") || content.includes("WALLET TYPE: Alpha descriptor wallet") || !!chainCode;
7143
+ const effectiveDescriptorPath = descriptorPath ?? (isBIP32 ? "84'/1'/0'" : void 0);
6861
7144
  const data = {
6862
7145
  masterKey,
6863
7146
  chainCode: chainCode ?? void 0,
6864
- descriptorPath: descriptorPath ?? void 0,
7147
+ descriptorPath: effectiveDescriptorPath,
6865
7148
  derivationMode: isBIP32 ? "bip32" : "wif_hmac"
6866
7149
  };
6867
7150
  return {
@@ -7402,8 +7685,8 @@ var Sphere = class _Sphere {
7402
7685
  if (options.nametag) {
7403
7686
  await sphere.registerNametag(options.nametag);
7404
7687
  } else {
7405
- await sphere.syncIdentityWithTransport();
7406
7688
  await sphere.recoverNametagFromTransport();
7689
+ await sphere.syncIdentityWithTransport();
7407
7690
  }
7408
7691
  return sphere;
7409
7692
  }
@@ -7450,7 +7733,15 @@ var Sphere = class _Sphere {
7450
7733
  if (!options.mnemonic && !options.masterKey) {
7451
7734
  throw new Error("Either mnemonic or masterKey is required");
7452
7735
  }
7736
+ console.log("[Sphere.import] Starting import...");
7737
+ console.log("[Sphere.import] Clearing existing wallet data...");
7453
7738
  await _Sphere.clear({ storage: options.storage, tokenStorage: options.tokenStorage });
7739
+ console.log("[Sphere.import] Clear done");
7740
+ if (!options.storage.isConnected()) {
7741
+ console.log("[Sphere.import] Reconnecting storage...");
7742
+ await options.storage.connect();
7743
+ console.log("[Sphere.import] Storage reconnected");
7744
+ }
7454
7745
  const sphere = new _Sphere(
7455
7746
  options.storage,
7456
7747
  options.transport,
@@ -7463,9 +7754,12 @@ var Sphere = class _Sphere {
7463
7754
  if (!_Sphere.validateMnemonic(options.mnemonic)) {
7464
7755
  throw new Error("Invalid mnemonic");
7465
7756
  }
7757
+ console.log("[Sphere.import] Storing mnemonic...");
7466
7758
  await sphere.storeMnemonic(options.mnemonic, options.derivationPath, options.basePath);
7759
+ console.log("[Sphere.import] Initializing identity from mnemonic...");
7467
7760
  await sphere.initializeIdentityFromMnemonic(options.mnemonic, options.derivationPath);
7468
7761
  } else if (options.masterKey) {
7762
+ console.log("[Sphere.import] Storing master key...");
7469
7763
  await sphere.storeMasterKey(
7470
7764
  options.masterKey,
7471
7765
  options.chainCode,
@@ -7473,24 +7767,35 @@ var Sphere = class _Sphere {
7473
7767
  options.basePath,
7474
7768
  options.derivationMode
7475
7769
  );
7770
+ console.log("[Sphere.import] Initializing identity from master key...");
7476
7771
  await sphere.initializeIdentityFromMasterKey(
7477
7772
  options.masterKey,
7478
7773
  options.chainCode,
7479
7774
  options.derivationPath
7480
7775
  );
7481
7776
  }
7777
+ console.log("[Sphere.import] Initializing providers...");
7482
7778
  await sphere.initializeProviders();
7779
+ console.log("[Sphere.import] Providers initialized. Initializing modules...");
7483
7780
  await sphere.initializeModules();
7781
+ console.log("[Sphere.import] Modules initialized");
7484
7782
  if (!options.nametag) {
7783
+ console.log("[Sphere.import] Recovering nametag from transport...");
7485
7784
  await sphere.recoverNametagFromTransport();
7785
+ console.log("[Sphere.import] Nametag recovery done");
7786
+ await sphere.syncIdentityWithTransport();
7486
7787
  }
7788
+ console.log("[Sphere.import] Finalizing wallet creation...");
7487
7789
  await sphere.finalizeWalletCreation();
7488
7790
  sphere._initialized = true;
7489
7791
  _Sphere.instance = sphere;
7792
+ console.log("[Sphere.import] Tracking address 0...");
7490
7793
  await sphere.ensureAddressTracked(0);
7491
7794
  if (options.nametag) {
7795
+ console.log("[Sphere.import] Registering nametag...");
7492
7796
  await sphere.registerNametag(options.nametag);
7493
7797
  }
7798
+ console.log("[Sphere.import] Import complete");
7494
7799
  return sphere;
7495
7800
  }
7496
7801
  /**
@@ -7515,6 +7820,10 @@ var Sphere = class _Sphere {
7515
7820
  static async clear(storageOrOptions) {
7516
7821
  const storage = "get" in storageOrOptions ? storageOrOptions : storageOrOptions.storage;
7517
7822
  const tokenStorage = "get" in storageOrOptions ? void 0 : storageOrOptions.tokenStorage;
7823
+ if (!storage.isConnected()) {
7824
+ await storage.connect();
7825
+ }
7826
+ console.log("[Sphere.clear] Removing storage keys...");
7518
7827
  await storage.remove(STORAGE_KEYS_GLOBAL.MNEMONIC);
7519
7828
  await storage.remove(STORAGE_KEYS_GLOBAL.MASTER_KEY);
7520
7829
  await storage.remove(STORAGE_KEYS_GLOBAL.CHAIN_CODE);
@@ -7527,11 +7836,30 @@ var Sphere = class _Sphere {
7527
7836
  await storage.remove(STORAGE_KEYS_GLOBAL.ADDRESS_NAMETAGS);
7528
7837
  await storage.remove(STORAGE_KEYS_ADDRESS.PENDING_TRANSFERS);
7529
7838
  await storage.remove(STORAGE_KEYS_ADDRESS.OUTBOX);
7839
+ console.log("[Sphere.clear] Storage keys removed");
7530
7840
  if (tokenStorage?.clear) {
7531
- await tokenStorage.clear();
7841
+ console.log("[Sphere.clear] Clearing token storage...");
7842
+ try {
7843
+ await Promise.race([
7844
+ tokenStorage.clear(),
7845
+ new Promise(
7846
+ (_, reject) => setTimeout(() => reject(new Error("tokenStorage.clear() timed out after 2s")), 2e3)
7847
+ )
7848
+ ]);
7849
+ console.log("[Sphere.clear] Token storage cleared");
7850
+ } catch (err) {
7851
+ console.warn("[Sphere.clear] Token storage clear failed/timed out:", err);
7852
+ }
7532
7853
  }
7854
+ console.log("[Sphere.clear] Destroying vesting classifier...");
7855
+ await vestingClassifier.destroy();
7856
+ console.log("[Sphere.clear] Vesting classifier destroyed");
7533
7857
  if (_Sphere.instance) {
7858
+ console.log("[Sphere.clear] Destroying Sphere instance...");
7534
7859
  await _Sphere.instance.destroy();
7860
+ console.log("[Sphere.clear] Sphere instance destroyed");
7861
+ } else {
7862
+ console.log("[Sphere.clear] No Sphere instance to destroy");
7535
7863
  }
7536
7864
  }
7537
7865
  /**
@@ -7712,7 +8040,7 @@ var Sphere = class _Sphere {
7712
8040
  return {
7713
8041
  source: this._source,
7714
8042
  hasMnemonic: this._mnemonic !== null,
7715
- hasChainCode: this._masterKey?.chainCode !== void 0,
8043
+ hasChainCode: !!this._masterKey?.chainCode,
7716
8044
  derivationMode: this._derivationMode,
7717
8045
  basePath: this._basePath,
7718
8046
  address0
@@ -7765,7 +8093,7 @@ var Sphere = class _Sphere {
7765
8093
  let chainCode;
7766
8094
  if (this._masterKey) {
7767
8095
  masterPrivateKey = this._masterKey.privateKey;
7768
- chainCode = this._masterKey.chainCode;
8096
+ chainCode = this._masterKey.chainCode || void 0;
7769
8097
  }
7770
8098
  let mnemonic;
7771
8099
  let encrypted = false;
@@ -7842,7 +8170,7 @@ var Sphere = class _Sphere {
7842
8170
  }
7843
8171
  }
7844
8172
  const masterPrivateKey = this._masterKey?.privateKey || "";
7845
- const chainCode = this._masterKey?.chainCode;
8173
+ const chainCode = this._masterKey?.chainCode || void 0;
7846
8174
  const isBIP32 = this._derivationMode === "bip32";
7847
8175
  const descriptorPath = this._basePath.replace(/^m\//, "");
7848
8176
  if (options.password) {
@@ -7912,7 +8240,8 @@ var Sphere = class _Sphere {
7912
8240
  storage: options.storage,
7913
8241
  transport: options.transport,
7914
8242
  oracle: options.oracle,
7915
- tokenStorage: options.tokenStorage
8243
+ tokenStorage: options.tokenStorage,
8244
+ l1: options.l1
7916
8245
  });
7917
8246
  return { success: true, mnemonic };
7918
8247
  }
@@ -7925,7 +8254,8 @@ var Sphere = class _Sphere {
7925
8254
  storage: options.storage,
7926
8255
  transport: options.transport,
7927
8256
  oracle: options.oracle,
7928
- tokenStorage: options.tokenStorage
8257
+ tokenStorage: options.tokenStorage,
8258
+ l1: options.l1
7929
8259
  });
7930
8260
  return { success: true };
7931
8261
  }
@@ -7984,7 +8314,8 @@ var Sphere = class _Sphere {
7984
8314
  transport: options.transport,
7985
8315
  oracle: options.oracle,
7986
8316
  tokenStorage: options.tokenStorage,
7987
- nametag: options.nametag
8317
+ nametag: options.nametag,
8318
+ l1: options.l1
7988
8319
  });
7989
8320
  return { success: true, sphere, mnemonic };
7990
8321
  }
@@ -8013,7 +8344,8 @@ var Sphere = class _Sphere {
8013
8344
  transport: options.transport,
8014
8345
  oracle: options.oracle,
8015
8346
  tokenStorage: options.tokenStorage,
8016
- nametag: options.nametag
8347
+ nametag: options.nametag,
8348
+ l1: options.l1
8017
8349
  });
8018
8350
  return { success: true, sphere };
8019
8351
  }
@@ -8044,25 +8376,94 @@ var Sphere = class _Sphere {
8044
8376
  transport: options.transport,
8045
8377
  oracle: options.oracle,
8046
8378
  tokenStorage: options.tokenStorage,
8047
- nametag: options.nametag
8379
+ nametag: options.nametag,
8380
+ l1: options.l1
8048
8381
  });
8049
8382
  return { success: true, sphere };
8050
8383
  }
8051
8384
  if (fileType === "json") {
8052
8385
  const content = typeof fileContent === "string" ? fileContent : new TextDecoder().decode(fileContent);
8053
- const result = await _Sphere.importFromJSON({
8054
- jsonContent: content,
8055
- password,
8386
+ let parsed;
8387
+ try {
8388
+ parsed = JSON.parse(content);
8389
+ } catch {
8390
+ return { success: false, error: "Invalid JSON file" };
8391
+ }
8392
+ if (parsed.type === "sphere-wallet") {
8393
+ const result = await _Sphere.importFromJSON({
8394
+ jsonContent: content,
8395
+ password,
8396
+ storage: options.storage,
8397
+ transport: options.transport,
8398
+ oracle: options.oracle,
8399
+ tokenStorage: options.tokenStorage,
8400
+ l1: options.l1
8401
+ });
8402
+ if (result.success) {
8403
+ const sphere2 = _Sphere.getInstance();
8404
+ return { success: true, sphere: sphere2, mnemonic: result.mnemonic };
8405
+ }
8406
+ if (!password && result.error?.includes("Password required")) {
8407
+ return { success: false, needsPassword: true, error: result.error };
8408
+ }
8409
+ return { success: false, error: result.error };
8410
+ }
8411
+ let masterKey;
8412
+ let mnemonic;
8413
+ if (parsed.encrypted && typeof parsed.encrypted === "object") {
8414
+ if (!password) {
8415
+ return { success: false, needsPassword: true, error: "Password required for encrypted wallet" };
8416
+ }
8417
+ const enc = parsed.encrypted;
8418
+ if (!enc.salt || !enc.masterPrivateKey) {
8419
+ return { success: false, error: "Invalid encrypted wallet format" };
8420
+ }
8421
+ const decryptedKey = decryptWithSalt(enc.masterPrivateKey, password, enc.salt);
8422
+ if (!decryptedKey) {
8423
+ return { success: false, error: "Failed to decrypt - incorrect password?" };
8424
+ }
8425
+ masterKey = decryptedKey;
8426
+ if (enc.mnemonic) {
8427
+ mnemonic = decryptWithSalt(enc.mnemonic, password, enc.salt) ?? void 0;
8428
+ }
8429
+ } else {
8430
+ masterKey = parsed.masterPrivateKey;
8431
+ mnemonic = parsed.mnemonic;
8432
+ }
8433
+ if (!masterKey) {
8434
+ return { success: false, error: "No master key found in wallet JSON" };
8435
+ }
8436
+ const chainCode = parsed.chainCode;
8437
+ const descriptorPath = parsed.descriptorPath;
8438
+ const derivationMode = parsed.derivationMode;
8439
+ const isBIP32 = derivationMode === "bip32" || !!chainCode;
8440
+ const basePath = descriptorPath ? `m/${descriptorPath}` : isBIP32 ? "m/84'/1'/0'" : DEFAULT_BASE_PATH;
8441
+ if (mnemonic) {
8442
+ const sphere2 = await _Sphere.import({
8443
+ mnemonic,
8444
+ basePath,
8445
+ storage: options.storage,
8446
+ transport: options.transport,
8447
+ oracle: options.oracle,
8448
+ tokenStorage: options.tokenStorage,
8449
+ nametag: options.nametag,
8450
+ l1: options.l1
8451
+ });
8452
+ return { success: true, sphere: sphere2, mnemonic };
8453
+ }
8454
+ const sphere = await _Sphere.import({
8455
+ masterKey,
8456
+ chainCode,
8457
+ basePath,
8458
+ derivationMode: derivationMode || (chainCode ? "bip32" : "wif_hmac"),
8056
8459
  storage: options.storage,
8057
8460
  transport: options.transport,
8058
8461
  oracle: options.oracle,
8059
- tokenStorage: options.tokenStorage
8462
+ tokenStorage: options.tokenStorage,
8463
+ nametag: options.nametag,
8464
+ l1: options.l1
8060
8465
  });
8061
- if (result.success) {
8062
- const sphere = _Sphere.getInstance();
8063
- return { success: true, sphere, mnemonic: result.mnemonic };
8064
- }
8065
- return result;
8466
+ return { success: true, sphere };
8066
8467
  }
8067
8468
  return { success: false, error: "Unsupported file type" };
8068
8469
  }
@@ -8360,7 +8761,7 @@ var Sphere = class _Sphere {
8360
8761
  transport: this._transport,
8361
8762
  oracle: this._oracle,
8362
8763
  emitEvent,
8363
- chainCode: this._masterKey?.chainCode,
8764
+ chainCode: this._masterKey?.chainCode || void 0,
8364
8765
  price: this._priceProvider ?? void 0
8365
8766
  });
8366
8767
  this._communications.initialize({
@@ -8405,6 +8806,9 @@ var Sphere = class _Sphere {
8405
8806
  if (!this._masterKey) {
8406
8807
  throw new Error("HD derivation requires master key with chain code");
8407
8808
  }
8809
+ if (this._derivationMode === "wif_hmac") {
8810
+ return generateAddressFromMasterKey(this._masterKey.privateKey, index);
8811
+ }
8408
8812
  const info = deriveAddressInfo(
8409
8813
  this._masterKey,
8410
8814
  this._basePath,
@@ -8476,6 +8880,66 @@ var Sphere = class _Sphere {
8476
8880
  }
8477
8881
  return addresses;
8478
8882
  }
8883
+ /**
8884
+ * Scan blockchain addresses to discover used addresses with balances.
8885
+ * Derives addresses sequentially and checks L1 balance via Fulcrum.
8886
+ * Uses gap limit to stop after N consecutive empty addresses.
8887
+ *
8888
+ * @param options - Scanning options
8889
+ * @returns Scan results with found addresses and total balance
8890
+ *
8891
+ * @example
8892
+ * ```ts
8893
+ * const result = await sphere.scanAddresses({
8894
+ * maxAddresses: 100,
8895
+ * gapLimit: 20,
8896
+ * onProgress: (p) => console.log(`Scanned ${p.scanned}/${p.total}, found ${p.foundCount}`),
8897
+ * });
8898
+ * console.log(`Found ${result.addresses.length} addresses, total: ${result.totalBalance} ALPHA`);
8899
+ * ```
8900
+ */
8901
+ async scanAddresses(options = {}) {
8902
+ this.ensureReady();
8903
+ if (!this._masterKey) {
8904
+ throw new Error("Address scanning requires HD master key");
8905
+ }
8906
+ const resolveNametag = options.resolveNametag ?? (this._transport.resolveAddressInfo ? async (l1Address) => {
8907
+ try {
8908
+ const info = await this._transport.resolveAddressInfo(l1Address);
8909
+ return info?.nametag ?? null;
8910
+ } catch {
8911
+ return null;
8912
+ }
8913
+ } : void 0);
8914
+ return scanAddressesImpl(
8915
+ (index, isChange) => this._deriveAddressInternal(index, isChange),
8916
+ { ...options, resolveNametag }
8917
+ );
8918
+ }
8919
+ /**
8920
+ * Bulk-track scanned addresses with visibility and nametag data.
8921
+ * Selected addresses get `hidden: false`, unselected get `hidden: true`.
8922
+ * Performs only 2 storage writes total (tracked addresses + nametags).
8923
+ */
8924
+ async trackScannedAddresses(entries) {
8925
+ this.ensureReady();
8926
+ for (const { index, hidden, nametag } of entries) {
8927
+ const tracked = await this.ensureAddressTracked(index);
8928
+ if (nametag) {
8929
+ let nametags = this._addressNametags.get(tracked.addressId);
8930
+ if (!nametags) {
8931
+ nametags = /* @__PURE__ */ new Map();
8932
+ this._addressNametags.set(tracked.addressId, nametags);
8933
+ }
8934
+ if (!nametags.has(0)) nametags.set(0, nametag);
8935
+ }
8936
+ if (tracked.hidden !== hidden) {
8937
+ tracked.hidden = hidden;
8938
+ }
8939
+ }
8940
+ await this.persistTrackedAddresses();
8941
+ await this.persistAddressNametags();
8942
+ }
8479
8943
  // ===========================================================================
8480
8944
  // Public Methods - Status
8481
8945
  // ===========================================================================
@@ -8860,35 +9324,40 @@ var Sphere = class _Sphere {
8860
9324
  if (this._identity?.nametag) {
8861
9325
  return;
8862
9326
  }
8863
- if (!this._transport.recoverNametag) {
9327
+ let recoveredNametag = null;
9328
+ if (this._transport.recoverNametag) {
9329
+ try {
9330
+ recoveredNametag = await this._transport.recoverNametag();
9331
+ } catch {
9332
+ }
9333
+ }
9334
+ if (!recoveredNametag && this._transport.resolveAddressInfo && this._identity?.l1Address) {
9335
+ try {
9336
+ const info = await this._transport.resolveAddressInfo(this._identity.l1Address);
9337
+ if (info?.nametag) {
9338
+ recoveredNametag = info.nametag;
9339
+ }
9340
+ } catch {
9341
+ }
9342
+ }
9343
+ if (!recoveredNametag) {
8864
9344
  return;
8865
9345
  }
8866
9346
  try {
8867
- const recoveredNametag = await this._transport.recoverNametag();
8868
- if (recoveredNametag) {
8869
- if (this._identity) {
8870
- this._identity.nametag = recoveredNametag;
8871
- await this._updateCachedProxyAddress();
8872
- }
8873
- const entry = await this.ensureAddressTracked(this._currentAddressIndex);
8874
- let nametags = this._addressNametags.get(entry.addressId);
8875
- if (!nametags) {
8876
- nametags = /* @__PURE__ */ new Map();
8877
- this._addressNametags.set(entry.addressId, nametags);
8878
- }
8879
- const nextIndex = nametags.size;
8880
- nametags.set(nextIndex, recoveredNametag);
8881
- await this.persistAddressNametags();
8882
- if (this._transport.publishIdentityBinding) {
8883
- await this._transport.publishIdentityBinding(
8884
- this._identity.chainPubkey,
8885
- this._identity.l1Address,
8886
- this._identity.directAddress || "",
8887
- recoveredNametag
8888
- );
8889
- }
8890
- this.emitEvent("nametag:recovered", { nametag: recoveredNametag });
9347
+ if (this._identity) {
9348
+ this._identity.nametag = recoveredNametag;
9349
+ await this._updateCachedProxyAddress();
8891
9350
  }
9351
+ const entry = await this.ensureAddressTracked(this._currentAddressIndex);
9352
+ let nametags = this._addressNametags.get(entry.addressId);
9353
+ if (!nametags) {
9354
+ nametags = /* @__PURE__ */ new Map();
9355
+ this._addressNametags.set(entry.addressId, nametags);
9356
+ }
9357
+ const nextIndex = nametags.size;
9358
+ nametags.set(nextIndex, recoveredNametag);
9359
+ await this.persistAddressNametags();
9360
+ this.emitEvent("nametag:recovered", { nametag: recoveredNametag });
8892
9361
  } catch {
8893
9362
  }
8894
9363
  }
@@ -9057,8 +9526,8 @@ var Sphere = class _Sphere {
9057
9526
  };
9058
9527
  this._masterKey = masterKey;
9059
9528
  }
9060
- async initializeIdentityFromMasterKey(masterKey, chainCode, derivationPath) {
9061
- const basePath = derivationPath ?? DEFAULT_BASE_PATH;
9529
+ async initializeIdentityFromMasterKey(masterKey, chainCode, _derivationPath) {
9530
+ const basePath = this._basePath;
9062
9531
  const fullPath = `${basePath}/0/0`;
9063
9532
  let privateKey;
9064
9533
  if (chainCode) {
@@ -9069,8 +9538,12 @@ var Sphere = class _Sphere {
9069
9538
  chainCode
9070
9539
  };
9071
9540
  } else {
9072
- privateKey = masterKey;
9073
- this._masterKey = null;
9541
+ const addr0 = generateAddressFromMasterKey(masterKey, 0);
9542
+ privateKey = addr0.privateKey;
9543
+ this._masterKey = {
9544
+ privateKey: masterKey,
9545
+ chainCode: ""
9546
+ };
9074
9547
  }
9075
9548
  const publicKey = getPublicKey(privateKey);
9076
9549
  const address = publicKeyToAddress(publicKey, "alpha");
@@ -9093,8 +9566,12 @@ var Sphere = class _Sphere {
9093
9566
  for (const provider of this._tokenStorageProviders.values()) {
9094
9567
  provider.setIdentity(this._identity);
9095
9568
  }
9096
- await this._storage.connect();
9097
- await this._transport.connect();
9569
+ if (!this._storage.isConnected()) {
9570
+ await this._storage.connect();
9571
+ }
9572
+ if (!this._transport.isConnected()) {
9573
+ await this._transport.connect();
9574
+ }
9098
9575
  await this._oracle.initialize();
9099
9576
  for (const provider of this._tokenStorageProviders.values()) {
9100
9577
  await provider.initialize();
@@ -9110,7 +9587,7 @@ var Sphere = class _Sphere {
9110
9587
  oracle: this._oracle,
9111
9588
  emitEvent,
9112
9589
  // Pass chain code for L1 HD derivation
9113
- chainCode: this._masterKey?.chainCode,
9590
+ chainCode: this._masterKey?.chainCode || void 0,
9114
9591
  price: this._priceProvider ?? void 0
9115
9592
  });
9116
9593
  this._communications.initialize({
@@ -9197,6 +9674,9 @@ var CurrencyUtils = {
9197
9674
  toHumanReadable,
9198
9675
  format: formatAmount
9199
9676
  };
9677
+
9678
+ // core/index.ts
9679
+ init_bech32();
9200
9680
  export {
9201
9681
  CHARSET,
9202
9682
  CurrencyUtils,
@@ -9217,6 +9697,7 @@ export {
9217
9697
  decryptJson,
9218
9698
  decryptMnemonic,
9219
9699
  decryptSimple,
9700
+ decryptWithSalt,
9220
9701
  deriveAddressInfo,
9221
9702
  deriveChildKey,
9222
9703
  deriveKeyAtPath,
@@ -9258,6 +9739,7 @@ export {
9258
9739
  randomHex,
9259
9740
  randomUUID,
9260
9741
  ripemd160,
9742
+ scanAddressesImpl,
9261
9743
  serializeEncrypted,
9262
9744
  sha256,
9263
9745
  sleep,