@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.
- package/LICENCE +201 -0
- package/Readme.md +480 -0
- package/cli/README.md +348 -0
- package/cli/commands/address.mjs +16 -0
- package/cli/commands/blindreceive.mjs +15 -0
- package/cli/commands/btcbalance.mjs +11 -0
- package/cli/commands/createlightninginvoice.mjs +14 -0
- package/cli/commands/createutxos.mjs +13 -0
- package/cli/commands/decodergbinvoice.mjs +9 -0
- package/cli/commands/generate_keys.mjs +35 -0
- package/cli/commands/getlightningreceiverequest.mjs +10 -0
- package/cli/commands/getlightningsendrequest.mjs +10 -0
- package/cli/commands/getonchainsendstatus.mjs +20 -0
- package/cli/commands/listassets.mjs +11 -0
- package/cli/commands/listtransfers.mjs +10 -0
- package/cli/commands/listunspents.mjs +10 -0
- package/cli/commands/onchainreceive.mjs +16 -0
- package/cli/commands/onchainsend.mjs +11 -0
- package/cli/commands/onchainsendbegin.mjs +9 -0
- package/cli/commands/onchainsendend.mjs +9 -0
- package/cli/commands/paylightninginvoice.mjs +11 -0
- package/cli/commands/paylightninginvoicebegin.mjs +10 -0
- package/cli/commands/paylightninginvoiceend.mjs +9 -0
- package/cli/commands/refresh.mjs +9 -0
- package/cli/commands/send.mjs +31 -0
- package/cli/commands/sign-psbt.mjs +12 -0
- package/cli/commands/signpsbt.mjs +10 -0
- package/cli/commands/witnessreceive.mjs +15 -0
- package/cli/data/stage2-receiver.example.json +11 -0
- package/cli/data/stage2-sender.example.json +11 -0
- package/cli/generate_keys.mjs +66 -0
- package/cli/run.mjs +308 -0
- package/cli/utils.mjs +220 -0
- package/dist/index.cjs +1282 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +163 -0
- package/dist/index.d.ts +163 -0
- package/dist/index.mjs +1018 -0
- package/dist/index.mjs.map +1 -0
- 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
|