@utexo/rgb-sdk 1.0.0-beta.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.
Files changed (40) hide show
  1. package/LICENCE +201 -0
  2. package/Readme.md +480 -0
  3. package/cli/README.md +348 -0
  4. package/cli/commands/address.mjs +16 -0
  5. package/cli/commands/blindreceive.mjs +15 -0
  6. package/cli/commands/btcbalance.mjs +11 -0
  7. package/cli/commands/createlightninginvoice.mjs +14 -0
  8. package/cli/commands/createutxos.mjs +13 -0
  9. package/cli/commands/decodergbinvoice.mjs +9 -0
  10. package/cli/commands/generate_keys.mjs +35 -0
  11. package/cli/commands/getlightningreceiverequest.mjs +10 -0
  12. package/cli/commands/getlightningsendrequest.mjs +10 -0
  13. package/cli/commands/getonchainsendstatus.mjs +20 -0
  14. package/cli/commands/listassets.mjs +11 -0
  15. package/cli/commands/listtransfers.mjs +10 -0
  16. package/cli/commands/listunspents.mjs +10 -0
  17. package/cli/commands/onchainreceive.mjs +16 -0
  18. package/cli/commands/onchainsend.mjs +11 -0
  19. package/cli/commands/onchainsendbegin.mjs +9 -0
  20. package/cli/commands/onchainsendend.mjs +9 -0
  21. package/cli/commands/paylightninginvoice.mjs +11 -0
  22. package/cli/commands/paylightninginvoicebegin.mjs +10 -0
  23. package/cli/commands/paylightninginvoiceend.mjs +9 -0
  24. package/cli/commands/refresh.mjs +9 -0
  25. package/cli/commands/send.mjs +31 -0
  26. package/cli/commands/sign-psbt.mjs +12 -0
  27. package/cli/commands/signpsbt.mjs +10 -0
  28. package/cli/commands/witnessreceive.mjs +15 -0
  29. package/cli/data/stage2-receiver.example.json +11 -0
  30. package/cli/data/stage2-sender.example.json +11 -0
  31. package/cli/generate_keys.mjs +66 -0
  32. package/cli/run.mjs +308 -0
  33. package/cli/utils.mjs +220 -0
  34. package/dist/index.cjs +1282 -0
  35. package/dist/index.cjs.map +1 -0
  36. package/dist/index.d.mts +163 -0
  37. package/dist/index.d.ts +163 -0
  38. package/dist/index.mjs +1018 -0
  39. package/dist/index.mjs.map +1 -0
  40. package/package.json +124 -0
package/dist/index.mjs ADDED
@@ -0,0 +1,1018 @@
1
+ import * as path3 from 'path';
2
+ import path3__default from 'path';
3
+ import * as fs2 from 'fs';
4
+ import fs2__default from 'fs';
5
+ import { WalletError, ValidationError, validateMnemonic, bip39, normalizeNetwork, CryptoError, normalizeSeedInput, generateKeys, BaseWalletManager, buildVssConfigFromMnemonic, DEFAULT_VSS_SERVER_URL, getUtxoNetworkConfig, UTEXOWalletCore, validatePsbt, bip32Factory, normalizeSeedBuffer, getNetworkVersions, calculateMasterFingerprint, detectPsbtType, DEFAULT_TRANSPORT_ENDPOINTS, DEFAULT_INDEXER_URLS, logger, signMessage, verifyMessage, getBackupStoreId, deriveDescriptors } from '@utexo/rgb-sdk-core';
6
+ export { BIP32_VERSIONS, BadRequestError, COIN_BITCOIN_MAINNET, COIN_BITCOIN_TESTNET, COIN_RGB_MAINNET, COIN_RGB_TESTNET, ConfigurationError, ConflictError, CryptoError, DEFAULT_API_TIMEOUT, DEFAULT_LOG_LEVEL, DEFAULT_MAX_RETRIES, DEFAULT_NETWORK, DEFAULT_VSS_SERVER_URL, DERIVATION_ACCOUNT, DERIVATION_PURPOSE, KEYCHAIN_BTC, KEYCHAIN_RGB, LightningProtocol, LogLevel, NETWORK_MAP, NetworkError, NotFoundError, OnchainProtocol, RgbNodeError, SDKError, UTEXOProtocol, ValidationError, WalletError, accountXpubsFromMnemonic, bip39, configureLogging, deriveKeysFromMnemonic, deriveKeysFromMnemonicOrSeed, deriveKeysFromSeed, deriveKeysFromXpriv, deriveVssSigningKeyFromMnemonic, generateKeys, getDestinationAsset, getUtxoNetworkConfig, getXprivFromMnemonic, getXpubFromXpriv, isNetwork, logger, normalizeNetwork, restoreKeys, signMessage, utexoNetworkIdMap, utexoNetworkMap, validateBase64, validateHex, validateMnemonic, validateNetwork, validatePsbt, validateRequired, validateString, verifyMessage } from '@utexo/rgb-sdk-core';
7
+ import rgblib from '@utexo/rgb-lib';
8
+ import { Psbt } from 'bitcoinjs-lib';
9
+ import * as bdkNode from '@bitcoindevkit/bdk-wallet-node';
10
+
11
+ // src/binding/NodeRgbLibBinding.ts
12
+ function mapNetworkToRgbLib(network) {
13
+ const networkMap = {
14
+ mainnet: "Mainnet",
15
+ testnet: "Testnet",
16
+ testnet4: "Testnet4",
17
+ signet: "Signet",
18
+ utexo: "Signet",
19
+ regtest: "Regtest"
20
+ };
21
+ const networkStr = String(network).toLowerCase();
22
+ return networkMap[networkStr] || "Regtest";
23
+ }
24
+ var restoreWallet = (params) => {
25
+ const { backupFilePath, password, dataDir } = params;
26
+ if (!fs2.existsSync(backupFilePath)) {
27
+ throw new ValidationError("Backup file not found", "backup");
28
+ }
29
+ if (!fs2.existsSync(dataDir)) {
30
+ throw new ValidationError(
31
+ `Restore directory does not exist: ${dataDir}`,
32
+ "restoreDir"
33
+ );
34
+ }
35
+ rgblib.restoreBackup(backupFilePath, password, dataDir);
36
+ return {
37
+ message: "Wallet restored successfully"
38
+ };
39
+ };
40
+ var restoreFromVss = (params) => {
41
+ const anyLib = rgblib;
42
+ if (typeof anyLib.restoreFromVss !== "function") {
43
+ throw new WalletError(
44
+ "VSS restore is not available in the current rgb-lib build."
45
+ );
46
+ }
47
+ if (!params.targetDir) {
48
+ throw new ValidationError("targetDir is required", "targetDir");
49
+ }
50
+ const { config, targetDir } = params;
51
+ const mappedConfig = {
52
+ server_url: config.serverUrl,
53
+ store_id: config.storeId,
54
+ signing_key: config.signingKey
55
+ };
56
+ const walletPath = anyLib.restoreFromVss(mappedConfig, targetDir);
57
+ return {
58
+ message: "Wallet restored from VSS successfully",
59
+ walletPath
60
+ };
61
+ };
62
+ var NodeRgbLibBinding = class {
63
+ constructor(params) {
64
+ this.online = null;
65
+ this.xpubVan = params.xpubVan;
66
+ this.xpubCol = params.xpubCol;
67
+ this.masterFingerprint = params.masterFingerprint;
68
+ this.originalNetwork = params.network;
69
+ this.network = normalizeNetwork(this.originalNetwork);
70
+ this.dataDir = params.dataDir;
71
+ this.transportEndpoint = params.transportEndpoint || DEFAULT_TRANSPORT_ENDPOINTS[this.network] || DEFAULT_TRANSPORT_ENDPOINTS.signet;
72
+ if (params.indexerUrl) {
73
+ this.indexerUrl = params.indexerUrl;
74
+ } else {
75
+ this.indexerUrl = DEFAULT_INDEXER_URLS[this.network] || DEFAULT_INDEXER_URLS.signet;
76
+ }
77
+ if (!fs2.existsSync(this.dataDir)) {
78
+ fs2.mkdirSync(this.dataDir, { recursive: true });
79
+ }
80
+ const walletData = {
81
+ dataDir: this.dataDir,
82
+ bitcoinNetwork: mapNetworkToRgbLib(this.originalNetwork),
83
+ databaseType: rgblib.DatabaseType.Sqlite,
84
+ accountXpubVanilla: this.xpubVan,
85
+ accountXpubColored: this.xpubCol,
86
+ masterFingerprint: this.masterFingerprint,
87
+ maxAllocationsPerUtxo: "1",
88
+ vanillaKeychain: "0",
89
+ supportedSchemas: [
90
+ rgblib.AssetSchema.Cfa,
91
+ rgblib.AssetSchema.Nia,
92
+ rgblib.AssetSchema.Uda
93
+ ]
94
+ };
95
+ try {
96
+ this.wallet = new rgblib.Wallet(new rgblib.WalletData(walletData));
97
+ } catch (error) {
98
+ throw new WalletError(
99
+ "Failed to initialize rgb-lib wallet",
100
+ void 0,
101
+ error
102
+ );
103
+ }
104
+ }
105
+ /**
106
+ * Ensure online connection is established
107
+ */
108
+ ensureOnline() {
109
+ if (this.online) {
110
+ return;
111
+ }
112
+ try {
113
+ this.online = this.wallet.goOnline(false, this.indexerUrl);
114
+ } catch (error) {
115
+ throw new WalletError(
116
+ "Failed to establish online connection",
117
+ void 0,
118
+ error
119
+ );
120
+ }
121
+ }
122
+ /**
123
+ * Get online object, creating it if needed
124
+ */
125
+ getOnline() {
126
+ this.ensureOnline();
127
+ return this.online;
128
+ }
129
+ registerWallet() {
130
+ const online = this.getOnline();
131
+ const address = this.wallet.getAddress();
132
+ const btcBalance = this.wallet.getBtcBalance(online, false);
133
+ return {
134
+ address,
135
+ btcBalance
136
+ };
137
+ }
138
+ async getBtcBalance() {
139
+ const online = this.getOnline();
140
+ return this.wallet.getBtcBalance(online, false);
141
+ }
142
+ async getAddress() {
143
+ return this.wallet.getAddress();
144
+ }
145
+ listUnspents() {
146
+ const online = this.getOnline();
147
+ const raw = this.wallet.listUnspents(online, false, false);
148
+ return Promise.resolve(
149
+ raw.map((unspent) => ({
150
+ utxo: {
151
+ ...unspent.utxo,
152
+ exists: unspent.utxo.exists ?? true
153
+ },
154
+ rgbAllocations: unspent.rgbAllocations.map((allocation) => {
155
+ const assignmentKeys = Object.keys(allocation.assignment);
156
+ const assignmentType = assignmentKeys[0];
157
+ const assignment = {
158
+ type: assignmentType ?? "Any",
159
+ amount: assignmentType && allocation.assignment[assignmentType] ? Number(allocation.assignment[assignmentType]) : void 0
160
+ };
161
+ return {
162
+ assetId: allocation.assetId,
163
+ assignment,
164
+ settled: allocation.settled
165
+ };
166
+ }),
167
+ pendingBlinded: unspent.pendingBlinded ?? 0
168
+ }))
169
+ );
170
+ }
171
+ async createUtxosBegin(params) {
172
+ const online = this.getOnline();
173
+ const upTo = params.upTo ?? false;
174
+ const num = params.num !== void 0 ? String(params.num) : null;
175
+ const size = params.size !== void 0 ? String(params.size) : null;
176
+ const feeRate = params.feeRate ? String(params.feeRate) : "1";
177
+ const skipSync = false;
178
+ return this.wallet.createUtxosBegin(
179
+ online,
180
+ upTo,
181
+ num,
182
+ size,
183
+ feeRate,
184
+ skipSync
185
+ );
186
+ }
187
+ async createUtxosEnd(params) {
188
+ const online = this.getOnline();
189
+ const signedPsbt = params.signedPsbt;
190
+ const skipSync = params.skipSync ?? false;
191
+ return this.wallet.createUtxosEnd(online, signedPsbt, skipSync);
192
+ }
193
+ async sendBegin(params) {
194
+ const online = this.getOnline();
195
+ const feeRate = String(params.feeRate ?? 1);
196
+ const minConfirmations = String(params.minConfirmations ?? 1);
197
+ const donation = params.donation ?? false;
198
+ let assetId = params.assetId;
199
+ let amount = params.amount;
200
+ let recipientId;
201
+ let transportEndpoints = [];
202
+ let witnessData = null;
203
+ if (params.witnessData && params.witnessData.amountSat) {
204
+ witnessData = {
205
+ amountSat: String(params.witnessData.amountSat),
206
+ blinding: params.witnessData.blinding ? Number(params.witnessData.blinding) : null
207
+ };
208
+ }
209
+ if (params.invoice) {
210
+ const invoiceData = this.decodeRGBInvoiceRaw({ invoice: params.invoice });
211
+ recipientId = invoiceData.recipientId;
212
+ transportEndpoints = invoiceData.transportEndpoints;
213
+ }
214
+ if (transportEndpoints.length === 0) {
215
+ transportEndpoints = [this.transportEndpoint];
216
+ }
217
+ if (!assetId) {
218
+ throw new ValidationError(
219
+ "asset_id is required for send operation",
220
+ "asset_id"
221
+ );
222
+ }
223
+ if (!recipientId) {
224
+ throw new ValidationError(
225
+ "Could not extract recipient_id from invoice",
226
+ "invoice"
227
+ );
228
+ }
229
+ if (!amount) {
230
+ throw new ValidationError(
231
+ "amount is required for send operation",
232
+ "amount"
233
+ );
234
+ }
235
+ const assignment = { Fungible: amount };
236
+ const recipientMap = {
237
+ [assetId]: [
238
+ {
239
+ recipientId,
240
+ witnessData,
241
+ assignment,
242
+ transportEndpoints
243
+ }
244
+ ]
245
+ };
246
+ const psbt = this.wallet.sendBegin(
247
+ online,
248
+ recipientMap,
249
+ donation,
250
+ feeRate,
251
+ minConfirmations
252
+ );
253
+ return psbt;
254
+ }
255
+ /**
256
+ * Batch send: accepts an already-built recipientMap and calls sendBegin.
257
+ */
258
+ async sendBeginBatch(params) {
259
+ const online = this.getOnline();
260
+ const feeRate = String(params.feeRate ?? 1);
261
+ const minConfirmations = String(params.minConfirmations ?? 1);
262
+ const donation = params.donation ?? true;
263
+ const { recipientMap } = params;
264
+ if (!recipientMap || typeof recipientMap !== "object") {
265
+ throw new ValidationError(
266
+ "recipientMap is required and must be a non-empty object",
267
+ "recipientMap"
268
+ );
269
+ }
270
+ const assetIds = Object.keys(recipientMap);
271
+ if (assetIds.length === 0) {
272
+ throw new ValidationError(
273
+ "recipientMap must contain at least one asset id",
274
+ "recipientMap"
275
+ );
276
+ }
277
+ for (const assetId of assetIds) {
278
+ const recipients = recipientMap[assetId];
279
+ if (!Array.isArray(recipients) || recipients.length === 0) {
280
+ throw new ValidationError(
281
+ `recipientMap["${assetId}"] must be a non-empty array of recipients`,
282
+ "recipientMap"
283
+ );
284
+ }
285
+ }
286
+ const psbt = this.wallet.sendBegin(
287
+ online,
288
+ recipientMap,
289
+ donation,
290
+ feeRate,
291
+ minConfirmations
292
+ );
293
+ return psbt;
294
+ }
295
+ async sendEnd(params) {
296
+ const online = this.getOnline();
297
+ const signedPsbt = params.signedPsbt;
298
+ const skipSync = params.skipSync ?? false;
299
+ return this.wallet.sendEnd(online, signedPsbt, skipSync);
300
+ }
301
+ async sendBtcBegin(params) {
302
+ const online = this.getOnline();
303
+ const address = params.address;
304
+ const amount = String(params.amount);
305
+ const feeRate = String(params.feeRate);
306
+ const skipSync = params.skipSync ?? false;
307
+ return this.wallet.sendBtcBegin(online, address, amount, feeRate, skipSync);
308
+ }
309
+ async sendBtcEnd(params) {
310
+ const online = this.getOnline();
311
+ const signedPsbt = params.signedPsbt;
312
+ const skipSync = params.skipSync ?? false;
313
+ return this.wallet.sendBtcEnd(online, signedPsbt, skipSync);
314
+ }
315
+ async getFeeEstimation(params) {
316
+ const online = this.getOnline();
317
+ const blocks = String(params.blocks);
318
+ try {
319
+ const result = this.wallet.getFeeEstimation(online, blocks);
320
+ if (typeof result === "string") {
321
+ try {
322
+ return JSON.parse(result);
323
+ } catch {
324
+ return result;
325
+ }
326
+ }
327
+ return result;
328
+ } catch (_error) {
329
+ logger.warn(
330
+ "rgb-lib estimation fee are not available, using default fee rate 2"
331
+ );
332
+ return 2;
333
+ }
334
+ }
335
+ async blindReceive(params) {
336
+ const assetId = params.assetId || null;
337
+ const assignment = `{"Fungible":${params.amount}}`;
338
+ const durationSeconds = String(params.durationSeconds ?? 2e3);
339
+ const transportEndpoints = [this.transportEndpoint];
340
+ const minConfirmations = String(params.minConfirmations ?? 3);
341
+ const raw = this.wallet.blindReceive(
342
+ assetId,
343
+ assignment,
344
+ durationSeconds,
345
+ transportEndpoints,
346
+ minConfirmations
347
+ );
348
+ return {
349
+ invoice: raw.invoice,
350
+ recipientId: raw.recipientId,
351
+ expirationTimestamp: raw.expirationTimestamp ?? null,
352
+ batchTransferIdx: raw.batchTransferIdx
353
+ };
354
+ }
355
+ async witnessReceive(params) {
356
+ const assetId = params.assetId || null;
357
+ const assignment = `{"Fungible":${params.amount}}`;
358
+ const durationSeconds = String(params.durationSeconds ?? 2e3);
359
+ const transportEndpoints = [this.transportEndpoint];
360
+ const minConfirmations = String(params.minConfirmations ?? 3);
361
+ const raw = this.wallet.witnessReceive(
362
+ assetId,
363
+ assignment,
364
+ durationSeconds,
365
+ transportEndpoints,
366
+ minConfirmations
367
+ );
368
+ return {
369
+ invoice: raw.invoice,
370
+ recipientId: raw.recipientId,
371
+ expirationTimestamp: raw.expirationTimestamp ?? null,
372
+ batchTransferIdx: raw.batchTransferIdx
373
+ };
374
+ }
375
+ async getAssetBalance(asset_id) {
376
+ const balance = this.wallet.getAssetBalance(asset_id);
377
+ return {
378
+ settled: balance.settled ?? 0,
379
+ future: balance.future ?? 0,
380
+ spendable: balance.spendable ?? 0,
381
+ offchainOutbound: balance.offchainOutbound ?? 0,
382
+ offchainInbound: balance.offchainInbound ?? 0
383
+ };
384
+ }
385
+ async issueAssetNia(params) {
386
+ const ticker = params.ticker;
387
+ const name = params.name;
388
+ const precision = String(params.precision);
389
+ const amounts = params.amounts.map((a) => String(a));
390
+ return this.wallet.issueAssetNIA(ticker, name, precision, amounts);
391
+ }
392
+ async issueAssetIfa(_params) {
393
+ throw new ValidationError(
394
+ "issueAssetIfa is not fully supported in rgb-lib. Use RGB Node server for IFA assets.",
395
+ "asset"
396
+ );
397
+ }
398
+ async inflateBegin(_params) {
399
+ throw new ValidationError(
400
+ "inflateBegin is not fully supported in rgb-lib. Use RGB Node server for inflation operations.",
401
+ "asset"
402
+ );
403
+ }
404
+ async inflateEnd(_params) {
405
+ throw new ValidationError(
406
+ "inflateEnd is not fully supported in rgb-lib. Use RGB Node server for inflation operations.",
407
+ "asset"
408
+ );
409
+ }
410
+ async listAssets() {
411
+ const filterAssetSchemas = [];
412
+ return this.wallet.listAssets(filterAssetSchemas);
413
+ }
414
+ decodeRGBInvoiceRaw(params) {
415
+ const invoice = new rgblib.Invoice(params.invoice);
416
+ try {
417
+ return invoice.invoiceData();
418
+ } finally {
419
+ invoice.drop();
420
+ }
421
+ }
422
+ async decodeRGBInvoice(params) {
423
+ const raw = this.decodeRGBInvoiceRaw(params);
424
+ const assignmentKeys = Object.keys(raw.assignment);
425
+ const assignmentType = assignmentKeys[0];
426
+ const assignment = {
427
+ type: assignmentType ?? "Any",
428
+ amount: assignmentType && raw.assignment[assignmentType] ? Number(raw.assignment[assignmentType]) : void 0
429
+ };
430
+ return {
431
+ invoice: params.invoice,
432
+ recipientId: raw.recipientId,
433
+ assetSchema: raw.assetSchema,
434
+ assetId: raw.assetId,
435
+ network: raw.network,
436
+ assignment,
437
+ assignmentName: raw.assignmentName,
438
+ expirationTimestamp: raw.expirationTimestamp ?? null,
439
+ transportEndpoints: raw.transportEndpoints
440
+ };
441
+ }
442
+ refreshWallet() {
443
+ const online = this.getOnline();
444
+ const assetId = null;
445
+ const filter = [];
446
+ const skipSync = false;
447
+ return this.wallet.refresh(online, assetId, filter, skipSync);
448
+ }
449
+ dropWallet() {
450
+ if (this.online) {
451
+ rgblib.dropOnline(this.online);
452
+ this.online = null;
453
+ }
454
+ if (this.wallet) {
455
+ this.wallet.drop();
456
+ this.wallet = null;
457
+ }
458
+ }
459
+ async listTransactions() {
460
+ const online = this.getOnline();
461
+ const skipSync = false;
462
+ return this.wallet.listTransactions(online, skipSync);
463
+ }
464
+ async listTransfers(asset_id) {
465
+ return this.wallet.listTransfers(asset_id ? asset_id : null);
466
+ }
467
+ async failTransfers(params) {
468
+ const online = this.getOnline();
469
+ const batchTransferIdx = params.batchTransferIdx !== void 0 ? params.batchTransferIdx : null;
470
+ const noAssetOnly = params.noAssetOnly ?? false;
471
+ const skipSync = params.skipSync ?? false;
472
+ return this.wallet.failTransfers(
473
+ online,
474
+ batchTransferIdx,
475
+ noAssetOnly,
476
+ skipSync
477
+ );
478
+ }
479
+ deleteTransfers(params) {
480
+ const batchTransferIdx = params.batchTransferIdx !== void 0 ? params.batchTransferIdx : null;
481
+ const noAssetOnly = params.noAssetOnly ?? false;
482
+ return this.wallet.deleteTransfers(batchTransferIdx, noAssetOnly);
483
+ }
484
+ syncWallet() {
485
+ const online = this.getOnline();
486
+ this.wallet.sync(online);
487
+ }
488
+ async createBackup(params) {
489
+ if (!params.backupPath) {
490
+ throw new ValidationError("backupPath is required", "backupPath");
491
+ }
492
+ if (!params.password) {
493
+ throw new ValidationError("password is required", "password");
494
+ }
495
+ if (!fs2.existsSync(params.backupPath)) {
496
+ throw new ValidationError(
497
+ `Backup directory does not exist: ${params.backupPath}`,
498
+ "backupPath"
499
+ );
500
+ }
501
+ const fullBackupPath = path3.join(
502
+ params.backupPath,
503
+ `${this.masterFingerprint}.backup`
504
+ );
505
+ this.wallet.backup(fullBackupPath, params.password);
506
+ return {
507
+ message: "Backup created successfully",
508
+ backupPath: fullBackupPath
509
+ };
510
+ }
511
+ /**
512
+ * Ensure VSS backup support is available in the underlying rgb-lib bindings.
513
+ * Returns the wallet instance and rgb-lib namespace as `any` for internal use.
514
+ */
515
+ getVssBindingsOrThrow(methodName) {
516
+ const walletAny = this.wallet;
517
+ const anyLib = rgblib;
518
+ if (!walletAny || typeof anyLib.VssBackupClient !== "function" || typeof walletAny[methodName] !== "function") {
519
+ throw new WalletError(
520
+ "VSS backup is not available in the current rgb-lib build."
521
+ );
522
+ }
523
+ return { walletAny, anyLib };
524
+ }
525
+ /**
526
+ * Configure VSS cloud backup for this wallet.
527
+ */
528
+ configureVssBackup(config) {
529
+ const walletAny = this.wallet;
530
+ if (!walletAny || typeof walletAny.configureVssBackup !== "function") {
531
+ throw new WalletError(
532
+ "VSS backup is not available in the current rgb-lib build."
533
+ );
534
+ }
535
+ const mappedConfig = {
536
+ server_url: config.serverUrl,
537
+ store_id: config.storeId,
538
+ signing_key: config.signingKey
539
+ };
540
+ if (config.encryptionEnabled !== void 0) {
541
+ mappedConfig.encryptionEnabled = config.encryptionEnabled;
542
+ }
543
+ if (config.autoBackup !== void 0) {
544
+ mappedConfig.autoBackup = config.autoBackup;
545
+ }
546
+ if (config.backupMode !== void 0) {
547
+ mappedConfig.backupMode = config.backupMode;
548
+ }
549
+ walletAny.configureVssBackup(mappedConfig);
550
+ }
551
+ /**
552
+ * Disable automatic VSS backup for this wallet.
553
+ */
554
+ disableVssAutoBackup() {
555
+ const walletAny = this.wallet;
556
+ if (!walletAny || typeof walletAny.disableVssAutoBackup !== "function") {
557
+ throw new WalletError(
558
+ "VSS backup is not available in the current rgb-lib build."
559
+ );
560
+ }
561
+ walletAny.disableVssAutoBackup();
562
+ }
563
+ /**
564
+ * Trigger a VSS backup immediately using a one-off client created from config.
565
+ * Returns the server version of the stored backup.
566
+ */
567
+ async vssBackup(config) {
568
+ const { walletAny, anyLib } = this.getVssBindingsOrThrow("vssBackup");
569
+ const client = new anyLib.VssBackupClient({
570
+ server_url: config.serverUrl,
571
+ store_id: config.storeId,
572
+ signing_key: config.signingKey
573
+ });
574
+ try {
575
+ const version = walletAny.vssBackup(client);
576
+ return version;
577
+ } finally {
578
+ if (typeof client.drop === "function") {
579
+ client.drop();
580
+ }
581
+ }
582
+ }
583
+ /**
584
+ * Get VSS backup status information for this wallet using a one-off client.
585
+ */
586
+ async vssBackupInfo(config) {
587
+ const { walletAny, anyLib } = this.getVssBindingsOrThrow("vssBackupInfo");
588
+ const client = new anyLib.VssBackupClient({
589
+ server_url: config.serverUrl,
590
+ store_id: config.storeId,
591
+ signing_key: config.signingKey
592
+ });
593
+ try {
594
+ const info = walletAny.vssBackupInfo(client);
595
+ return {
596
+ backupExists: Boolean(info.backupExists ?? info.backup_exists),
597
+ serverVersion: info.serverVersion ?? info.server_version ?? null,
598
+ backupRequired: Boolean(info.backupRequired ?? info.backup_required)
599
+ };
600
+ } finally {
601
+ if (typeof client.drop === "function") {
602
+ client.drop();
603
+ }
604
+ }
605
+ }
606
+ /**
607
+ * Cleanup resources
608
+ */
609
+ dispose() {
610
+ this.dropWallet();
611
+ }
612
+ };
613
+ var bdk = bdkNode;
614
+ async function signPsbtFromSeedInternal(seed, psbtBase64, network, options) {
615
+ validatePsbt(psbtBase64, "psbtBase64");
616
+ let rootNode;
617
+ try {
618
+ rootNode = bip32Factory().fromSeed(
619
+ normalizeSeedBuffer(seed),
620
+ getNetworkVersions(network)
621
+ );
622
+ } catch (error) {
623
+ throw new CryptoError(
624
+ "Failed to derive root node from seed",
625
+ error
626
+ );
627
+ }
628
+ const fp = await calculateMasterFingerprint(rootNode);
629
+ const psbtType = detectPsbtType(psbtBase64);
630
+ const bdkNetwork = network === "utexo" ? "signet" : network;
631
+ const trySign = (type) => {
632
+ const { external, internal } = deriveDescriptors(
633
+ rootNode,
634
+ fp,
635
+ bdkNetwork,
636
+ type
637
+ );
638
+ let wallet2;
639
+ try {
640
+ wallet2 = bdk.Wallet.create(bdkNetwork, external, internal);
641
+ } catch (error) {
642
+ throw new CryptoError("Failed to create BDK wallet", error);
643
+ }
644
+ const pstb2 = bdk.Psbt.from_string(psbtBase64.trim());
645
+ wallet2.sign(pstb2, options.signOptions || new bdk.SignOptions());
646
+ return pstb2;
647
+ };
648
+ let pstb;
649
+ try {
650
+ pstb = trySign(psbtType);
651
+ } catch {
652
+ const fallback = psbtType === "create_utxo" ? "send" : "create_utxo";
653
+ try {
654
+ pstb = trySign(fallback);
655
+ } catch (error) {
656
+ throw new CryptoError(
657
+ "Failed to sign PSBT \u2014 both descriptor types failed",
658
+ error
659
+ );
660
+ }
661
+ }
662
+ return pstb.toString().trim();
663
+ }
664
+ async function signPsbt(mnemonic, psbtBase64, network = "testnet", options = {}) {
665
+ try {
666
+ validateMnemonic(mnemonic, "mnemonic");
667
+ let seed;
668
+ try {
669
+ seed = bip39.mnemonicToSeedSync(mnemonic);
670
+ } catch {
671
+ throw new ValidationError("Invalid mnemonic format", "mnemonic");
672
+ }
673
+ const normalizedNetwork = normalizeNetwork(network);
674
+ return await signPsbtFromSeedInternal(
675
+ seed,
676
+ psbtBase64,
677
+ normalizedNetwork,
678
+ options
679
+ );
680
+ } catch (error) {
681
+ if (error instanceof ValidationError || error instanceof CryptoError)
682
+ throw error;
683
+ throw new CryptoError(
684
+ "Unexpected error during PSBT signing",
685
+ error
686
+ );
687
+ }
688
+ }
689
+ async function signPsbtFromSeed(seed, psbtBase64, network = "testnet", options = {}) {
690
+ const normalizedSeed = normalizeSeedInput(seed);
691
+ const normalizedNetwork = normalizeNetwork(network);
692
+ return signPsbtFromSeedInternal(
693
+ normalizedSeed,
694
+ psbtBase64,
695
+ normalizedNetwork,
696
+ options
697
+ );
698
+ }
699
+ async function estimatePsbt(psbtBase64) {
700
+ if (!psbtBase64) throw new ValidationError("psbt is required", "psbt");
701
+ try {
702
+ const psbt = Psbt.fromBase64(psbtBase64.trim());
703
+ return {
704
+ fee: psbt.getFee(),
705
+ feeRate: psbt.getFeeRate(),
706
+ vbytes: psbt.extractTransaction().virtualSize()
707
+ };
708
+ } catch {
709
+ throw new ValidationError("Invalid PSBT provided", "psbt");
710
+ }
711
+ }
712
+
713
+ // src/signer/NodeSigner.ts
714
+ var NodeSigner = class {
715
+ async signPsbtWithMnemonic(mnemonic, psbt, network) {
716
+ return signPsbt(mnemonic, psbt, network);
717
+ }
718
+ async signPsbtWithSeed(seed, psbt, network) {
719
+ return signPsbtFromSeed(seed, psbt, network);
720
+ }
721
+ async signMessage(params) {
722
+ return signMessage(params);
723
+ }
724
+ async verifyMessage(params) {
725
+ return verifyMessage(params);
726
+ }
727
+ async estimateFee(psbt) {
728
+ return estimatePsbt(psbt);
729
+ }
730
+ };
731
+ var restoreFromBackup = (params) => {
732
+ const { backupFilePath, password, dataDir } = params;
733
+ if (!backupFilePath) {
734
+ throw new ValidationError("backup file is required", "backup");
735
+ }
736
+ if (!password) {
737
+ throw new ValidationError("password is required", "password");
738
+ }
739
+ if (!dataDir) {
740
+ throw new ValidationError("restore directory is required", "restoreDir");
741
+ }
742
+ return restoreWallet({ backupFilePath, password, dataDir });
743
+ };
744
+ var createWallet = async (network = "regtest") => {
745
+ return await generateKeys(network);
746
+ };
747
+ var WalletManager = class extends BaseWalletManager {
748
+ constructor(params) {
749
+ const dataDir = params.dataDir ?? path3__default.join(
750
+ process.cwd(),
751
+ ".rgb-wallet",
752
+ String(params.network ?? "regtest"),
753
+ params.masterFingerprint
754
+ );
755
+ const client = new NodeRgbLibBinding({
756
+ xpubVan: params.xpubVan,
757
+ xpubCol: params.xpubCol,
758
+ masterFingerprint: params.masterFingerprint,
759
+ network: String(params.network ?? "regtest"),
760
+ transportEndpoint: params.transportEndpoint,
761
+ indexerUrl: params.indexerUrl,
762
+ dataDir
763
+ });
764
+ super(params, client, new NodeSigner());
765
+ this.client = client;
766
+ }
767
+ async initialize() {
768
+ }
769
+ async goOnline(_indexerUrl, _skipConsistencyCheck) {
770
+ this.client.getOnline();
771
+ }
772
+ /**
773
+ * Register wallet with the network — Node-specific convenience method.
774
+ * Not part of IWalletManager; used directly by UTEXOWallet and callers
775
+ * that need the initial address + balance snapshot.
776
+ */
777
+ registerWallet() {
778
+ return this.client.registerWallet();
779
+ }
780
+ };
781
+ function createWalletManager(params) {
782
+ return new WalletManager(params);
783
+ }
784
+ var wallet = new Proxy({}, {
785
+ get(target, prop) {
786
+ {
787
+ throw new WalletError(
788
+ "The legacy singleton wallet instance is deprecated. Please use `new WalletManager(params)` or `createWalletManager(params)` instead. Example: const wallet = new WalletManager({ xpubVan, xpubCol, masterFingerprint, network, transportEndpoint, indexerUrl })"
789
+ );
790
+ }
791
+ }
792
+ });
793
+ var BACKUP_FILE_SUFFIX = ".backup";
794
+ var LAYER1_BACKUP_SUFFIX = "_layer1.backup";
795
+ var UTEXO_BACKUP_SUFFIX = "_utexo.backup";
796
+ var UTEXO_BACKUP_TMP_LAYER1 = ".layer1";
797
+ var UTEXO_BACKUP_TMP_UTEXO = ".utexo";
798
+ function prepareUtxoBackupDirs(backupPath, masterFingerprint) {
799
+ const storeId = getBackupStoreId(masterFingerprint);
800
+ if (!fs2__default.existsSync(backupPath)) {
801
+ fs2__default.mkdirSync(backupPath, { recursive: true });
802
+ }
803
+ const layer1TmpDir = path3__default.join(backupPath, UTEXO_BACKUP_TMP_LAYER1);
804
+ const utexoTmpDir = path3__default.join(backupPath, UTEXO_BACKUP_TMP_UTEXO);
805
+ fs2__default.mkdirSync(layer1TmpDir, { recursive: true });
806
+ fs2__default.mkdirSync(utexoTmpDir, { recursive: true });
807
+ return {
808
+ storeId,
809
+ layer1TmpDir,
810
+ utexoTmpDir,
811
+ layer1FinalPath: path3__default.join(
812
+ backupPath,
813
+ `${storeId}_layer1${BACKUP_FILE_SUFFIX}`
814
+ ),
815
+ utexoFinalPath: path3__default.join(
816
+ backupPath,
817
+ `${storeId}_utexo${BACKUP_FILE_SUFFIX}`
818
+ )
819
+ };
820
+ }
821
+ function finalizeUtxoBackupPaths(params) {
822
+ const {
823
+ layer1BackupPath,
824
+ utexoBackupPath,
825
+ layer1FinalPath,
826
+ utexoFinalPath,
827
+ layer1TmpDir,
828
+ utexoTmpDir
829
+ } = params;
830
+ fs2__default.renameSync(layer1BackupPath, layer1FinalPath);
831
+ fs2__default.renameSync(utexoBackupPath, utexoFinalPath);
832
+ fs2__default.rmdirSync(layer1TmpDir);
833
+ fs2__default.rmdirSync(utexoTmpDir);
834
+ }
835
+ async function restoreUtxoWalletFromVss(params) {
836
+ const {
837
+ mnemonic,
838
+ targetDir,
839
+ config: providedConfig,
840
+ networkPreset = "testnet",
841
+ vssServerUrl
842
+ } = params;
843
+ if (!mnemonic || !mnemonic.trim()) {
844
+ throw new ValidationError("mnemonic is required", "mnemonic");
845
+ }
846
+ if (!targetDir) {
847
+ throw new ValidationError("targetDir is required", "targetDir");
848
+ }
849
+ const serverUrl = vssServerUrl ?? DEFAULT_VSS_SERVER_URL;
850
+ const config = providedConfig ?? await buildVssConfigFromMnemonic(
851
+ mnemonic.trim(),
852
+ serverUrl,
853
+ networkPreset
854
+ );
855
+ const presetConfig = getUtxoNetworkConfig(networkPreset);
856
+ const layer1Network = String(presetConfig.networkMap.mainnet);
857
+ const utexoNetwork = String(presetConfig.networkMap.utexo);
858
+ const masterFingerprint = config.storeId.replace(/^wallet_/, "") || config.storeId;
859
+ const layer1Config = {
860
+ ...config,
861
+ storeId: `${config.storeId}_layer1`
862
+ };
863
+ const utexoConfig = {
864
+ ...config,
865
+ storeId: `${config.storeId}_utexo`
866
+ };
867
+ const { walletPath: layer1Path } = restoreFromVss({
868
+ config: layer1Config,
869
+ targetDir: path3__default.join(targetDir, layer1Network, masterFingerprint)
870
+ });
871
+ const { walletPath: utexoPath } = restoreFromVss({
872
+ config: utexoConfig,
873
+ targetDir: path3__default.join(targetDir, utexoNetwork, masterFingerprint)
874
+ });
875
+ return { layer1Path, utexoPath, targetDir };
876
+ }
877
+ function restoreUtxoWalletFromBackup(params) {
878
+ const { backupPath, password, targetDir, networkPreset = "testnet" } = params;
879
+ if (!backupPath || !password || !targetDir) {
880
+ throw new ValidationError(
881
+ "backupPath, password, and targetDir are required",
882
+ "restoreUtxoWalletFromBackup"
883
+ );
884
+ }
885
+ if (!fs2__default.existsSync(backupPath) || !fs2__default.statSync(backupPath).isDirectory()) {
886
+ throw new ValidationError(
887
+ "backupPath must be an existing directory",
888
+ "backupPath"
889
+ );
890
+ }
891
+ const files = fs2__default.readdirSync(backupPath);
892
+ const layer1File = files.find((f) => f.endsWith(LAYER1_BACKUP_SUFFIX));
893
+ const utexoFile = files.find((f) => f.endsWith(UTEXO_BACKUP_SUFFIX));
894
+ if (!layer1File || !utexoFile) {
895
+ throw new ValidationError(
896
+ `backupPath must contain wallet_<fp>_layer1.backup and wallet_<fp>_utexo.backup (from createBackup)`,
897
+ "backupPath"
898
+ );
899
+ }
900
+ const masterFingerprint = layer1File.slice(0, -LAYER1_BACKUP_SUFFIX.length).replace(/^wallet_/, "");
901
+ const expectedUtexoFile = `wallet_${masterFingerprint}${UTEXO_BACKUP_SUFFIX}`;
902
+ if (utexoFile !== expectedUtexoFile) {
903
+ throw new ValidationError(
904
+ `Layer1 and utexo backup filenames must share the same wallet id (expected ${expectedUtexoFile})`,
905
+ "backupPath"
906
+ );
907
+ }
908
+ const layer1BackupFile = path3__default.join(backupPath, layer1File);
909
+ const utexoBackupFile = path3__default.join(backupPath, utexoFile);
910
+ if (!fs2__default.existsSync(layer1BackupFile) || !fs2__default.existsSync(utexoBackupFile)) {
911
+ throw new ValidationError("Backup files not found", "backupPath");
912
+ }
913
+ const presetConfig = getUtxoNetworkConfig(networkPreset);
914
+ const layer1Network = String(presetConfig.networkMap.mainnet);
915
+ const utexoNetwork = String(presetConfig.networkMap.utexo);
916
+ const layer1DataDir = path3__default.join(targetDir, layer1Network, masterFingerprint);
917
+ const utexoDataDir = path3__default.join(targetDir, utexoNetwork, masterFingerprint);
918
+ for (const dir of [layer1DataDir, utexoDataDir]) {
919
+ if (!fs2__default.existsSync(path3__default.dirname(dir))) {
920
+ fs2__default.mkdirSync(path3__default.dirname(dir), { recursive: true });
921
+ }
922
+ if (!fs2__default.existsSync(dir)) {
923
+ fs2__default.mkdirSync(dir, { recursive: true });
924
+ }
925
+ }
926
+ restoreWallet({
927
+ backupFilePath: layer1BackupFile,
928
+ password,
929
+ dataDir: layer1DataDir
930
+ });
931
+ restoreWallet({
932
+ backupFilePath: utexoBackupFile,
933
+ password,
934
+ dataDir: utexoDataDir
935
+ });
936
+ return {
937
+ layer1Path: layer1DataDir,
938
+ utexoPath: utexoDataDir,
939
+ targetDir
940
+ };
941
+ }
942
+ var UTEXOWallet = class extends UTEXOWalletCore {
943
+ constructor() {
944
+ super(...arguments);
945
+ this._masterFingerprint = null;
946
+ }
947
+ async initialize() {
948
+ const layer1Keys = await this.derivePublicKeys(this.networkMap.mainnet);
949
+ const utexoKeys = await this.derivePublicKeys(this.networkMap.utexo);
950
+ this._masterFingerprint = utexoKeys.masterFingerprint;
951
+ const fp = utexoKeys.masterFingerprint;
952
+ const dataDir = this.options.dataDir;
953
+ this.utexoWallet = new WalletManager({
954
+ xpubVan: utexoKeys.accountXpubVanilla,
955
+ xpubCol: utexoKeys.accountXpubColored,
956
+ masterFingerprint: utexoKeys.masterFingerprint,
957
+ network: this.networkMap.utexo,
958
+ mnemonic: this.mnemonicOrSeed,
959
+ dataDir: dataDir ? path3__default.join(dataDir, String(this.networkMap.utexo), fp) : void 0
960
+ });
961
+ this.layer1Wallet = new WalletManager({
962
+ xpubVan: layer1Keys.accountXpubVanilla,
963
+ xpubCol: layer1Keys.accountXpubColored,
964
+ masterFingerprint: layer1Keys.masterFingerprint,
965
+ network: this.networkMap.mainnet,
966
+ mnemonic: this.mnemonicOrSeed,
967
+ dataDir: dataDir ? path3__default.join(dataDir, String(this.networkMap.mainnet), fp) : void 0
968
+ });
969
+ }
970
+ /**
971
+ * Create backup for both layer1 and utexo stores in one folder.
972
+ * Writes backupPath/wallet_{masterFingerprint}_layer1.backup and
973
+ * backupPath/wallet_{masterFingerprint}_utexo.backup
974
+ */
975
+ async createBackup(params) {
976
+ this.ensureInitialized();
977
+ const { backupPath, password } = params;
978
+ if (!backupPath || !password) {
979
+ throw new ValidationError(
980
+ "backupPath and password are required",
981
+ "createBackup"
982
+ );
983
+ }
984
+ const fp = this._masterFingerprint;
985
+ const { layer1TmpDir, utexoTmpDir, layer1FinalPath, utexoFinalPath } = prepareUtxoBackupDirs(backupPath, fp);
986
+ const layer1Result = await this.layer1Wallet.createBackup({
987
+ backupPath: layer1TmpDir,
988
+ password
989
+ });
990
+ const utexoResult = await this.utexoWallet.createBackup({
991
+ backupPath: utexoTmpDir,
992
+ password
993
+ });
994
+ finalizeUtxoBackupPaths({
995
+ layer1BackupPath: layer1Result.backupPath,
996
+ utexoBackupPath: utexoResult.backupPath,
997
+ layer1FinalPath,
998
+ utexoFinalPath,
999
+ layer1TmpDir,
1000
+ utexoTmpDir
1001
+ });
1002
+ return {
1003
+ message: "Backup created successfully (layer1 + utexo)",
1004
+ backupPath,
1005
+ layer1BackupPath: layer1FinalPath,
1006
+ utexoBackupPath: utexoFinalPath
1007
+ };
1008
+ }
1009
+ };
1010
+
1011
+ // src/utils/environment.ts
1012
+ function isNode() {
1013
+ return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
1014
+ }
1015
+
1016
+ export { UTEXOWallet, WalletManager, createWallet, createWalletManager, estimatePsbt, isNode, restoreFromBackup, restoreFromVss, restoreUtxoWalletFromBackup, restoreUtxoWalletFromVss, signPsbt, signPsbtFromSeed, wallet };
1017
+ //# sourceMappingURL=index.mjs.map
1018
+ //# sourceMappingURL=index.mjs.map