@dynamic-labs-wallet/node-btc 0.0.0 → 0.0.255

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/index.cjs.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./src/index";
package/index.cjs.js ADDED
@@ -0,0 +1,636 @@
1
+ 'use strict';
2
+
3
+ var node = require('@dynamic-labs-wallet/node');
4
+ var core = require('@dynamic-labs-wallet/core');
5
+ var btcUtils = require('@dynamic-labs-wallet/btc-utils');
6
+ var bitcoin = require('bitcoinjs-lib');
7
+ var ecc = require('tiny-secp256k1');
8
+ var logger$1 = require('@dynamic-labs/logger');
9
+ var axios = require('axios');
10
+
11
+ function _interopNamespaceDefault(e) {
12
+ var n = Object.create(null);
13
+ if (e) {
14
+ Object.keys(e).forEach(function (k) {
15
+ if (k !== 'default') {
16
+ var d = Object.getOwnPropertyDescriptor(e, k);
17
+ Object.defineProperty(n, k, d.get ? d : {
18
+ enumerable: true,
19
+ get: function () { return e[k]; }
20
+ });
21
+ }
22
+ });
23
+ }
24
+ n.default = e;
25
+ return Object.freeze(n);
26
+ }
27
+
28
+ var bitcoin__namespace = /*#__PURE__*/_interopNamespaceDefault(bitcoin);
29
+ var ecc__namespace = /*#__PURE__*/_interopNamespaceDefault(ecc);
30
+
31
+ function _extends() {
32
+ _extends = Object.assign || function assign(target) {
33
+ for(var i = 1; i < arguments.length; i++){
34
+ var source = arguments[i];
35
+ for(var key in source)if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key];
36
+ }
37
+ return target;
38
+ };
39
+ return _extends.apply(this, arguments);
40
+ }
41
+
42
+ const logger = new logger$1.Logger('DynamicWaasWalletClient');
43
+ const logError = ({ message, error, context })=>{
44
+ if (error instanceof axios.AxiosError) {
45
+ core.handleAxiosError(error, message, context, logger);
46
+ }
47
+ logger.error('[DynamicWaasWalletClient] Error in node-btc client', {
48
+ error: error instanceof Error ? error.message : String(error),
49
+ context
50
+ });
51
+ };
52
+
53
+ const ERROR_CREATE_WALLET_ACCOUNT = 'Error creating wallet account';
54
+ const ERROR_ACCOUNT_ADDRESS_REQUIRED = 'Account address is required';
55
+ const ERROR_SIGN_MESSAGE = 'Error signing message';
56
+ const ERROR_SIGN_TRANSACTION = 'Error signing transaction';
57
+ const ERROR_IMPORT_PRIVATE_KEY = 'Error importing private key';
58
+ const ERROR_KEYGEN_FAILED = 'Error with keygen';
59
+
60
+ // Initialize ECC library with tiny-secp256k1 for Node.js
61
+ btcUtils.initEccLib(ecc__namespace);
62
+ class DynamicBtcWalletClient extends node.DynamicWalletClient {
63
+ /**
64
+ * Derives the Bitcoin account address
65
+ * - BIP340 keys (32 bytes x-only): Only for Taproot addresses
66
+ * - ECDSA keys (33/65 bytes): For all other address types (Legacy, SegWit, Native SegWit)
67
+ * - Algorithm selection is automatic based on addressType
68
+ * @param rawPublicKey - The raw public key to derive the account address from
69
+ * @param addressType - The address type to derive the account address for
70
+ * @param network - The network to derive the account address for
71
+ * @returns The account address
72
+ */ deriveAccountAddress({ rawPublicKey, addressType, network }) {
73
+ // Derive address based on the chosen address type and network
74
+ const normalizedKey = btcUtils.normalizePublicKey(rawPublicKey, addressType);
75
+ const accountAddress = btcUtils.publicKeyToBitcoinAddress(normalizedKey, addressType, network);
76
+ return {
77
+ accountAddress
78
+ };
79
+ }
80
+ /**
81
+ * Gets wallet properties and derivation info for a given account address
82
+ * @param accountAddress - The account address
83
+ * @returns The wallet properties, derivation path, and address type
84
+ */ getWalletDerivationInfo(accountAddress) {
85
+ const walletProperties = this.walletMap[accountAddress];
86
+ if (!walletProperties) {
87
+ throw new Error('Wallet not found in walletMap');
88
+ }
89
+ const derivationPath = walletProperties.derivationPath;
90
+ if (!derivationPath) {
91
+ throw new Error('Derivation path missing in walletMap');
92
+ }
93
+ return {
94
+ walletProperties,
95
+ derivationPath,
96
+ addressType: btcUtils.getAddressTypeFromDerivationPath(derivationPath)
97
+ };
98
+ }
99
+ /**
100
+ * Verifies that the derived address matches the expected address
101
+ * @param rawPublicKey - The raw public key
102
+ * @param addressType - The address type
103
+ * @param network - The network
104
+ * @param expectedAddress - The expected address
105
+ */ verifyWalletAddress(rawPublicKey, addressType, network, expectedAddress) {
106
+ const normalizedKey = btcUtils.normalizePublicKey(rawPublicKey, addressType);
107
+ const derivedAddress = btcUtils.publicKeyToBitcoinAddress(normalizedKey, addressType, network);
108
+ if (derivedAddress !== expectedAddress) {
109
+ throw new Error(`Address verification failed: expected ${expectedAddress}, got ${derivedAddress}`);
110
+ }
111
+ }
112
+ /**
113
+ * Creates a new wallet account and stores the key shares in the wallet map.
114
+ * @param thresholdSignatureScheme - The threshold signature scheme to use for the wallet.
115
+ * @param password - The password to use for the wallet.
116
+ * @param onError - The function to call if an error occurs.
117
+ * @param backUpToClientShareService - Whether to back up the external server key shares to the client share service. By default, it is false.
118
+ * @param bitcoinConfig - Bitcoin configuration (addressType, network)
119
+ * @returns The account address, public key, raw public key, external server key shares, and wallet id.
120
+ */ async createWalletAccount({ thresholdSignatureScheme, password = undefined, onError, backUpToClientShareService = false, bitcoinConfig }) {
121
+ try {
122
+ const { addressType, network = core.BitcoinNetwork.MAINNET } = bitcoinConfig;
123
+ if (!addressType) {
124
+ throw new Error('addressType is required for BTC');
125
+ }
126
+ let ceremonyCeremonyCompleteResolver;
127
+ let ceremonyAccountAddress;
128
+ const ceremonyCompletePromise = new Promise((resolve)=>{
129
+ ceremonyCeremonyCompleteResolver = resolve;
130
+ });
131
+ // Generate key shares for given threshold signature scheme (TSS)
132
+ const { rawPublicKey, externalServerKeyShares } = await this.keyGen({
133
+ chainName: this.chainName,
134
+ thresholdSignatureScheme,
135
+ skipLock: true,
136
+ bitcoinConfig,
137
+ onError,
138
+ onCeremonyComplete: (accountAddress, walletId)=>{
139
+ // Store the ceremony account address to ensure consistency
140
+ ceremonyAccountAddress = accountAddress;
141
+ // update wallet map
142
+ const chainConfig = node.getMPCChainConfig(this.chainName, bitcoinConfig);
143
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
144
+ accountAddress,
145
+ walletId,
146
+ chainName: this.chainName,
147
+ thresholdSignatureScheme,
148
+ derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
149
+ index,
150
+ value
151
+ ]))),
152
+ externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
153
+ });
154
+ this.logger.debug('walletMap updated for wallet', {
155
+ context: {
156
+ accountAddress,
157
+ walletId,
158
+ walletMap: this.walletMap
159
+ }
160
+ });
161
+ ceremonyCeremonyCompleteResolver(undefined);
162
+ }
163
+ });
164
+ await ceremonyCompletePromise;
165
+ if (!rawPublicKey || !externalServerKeyShares) {
166
+ throw new Error(ERROR_KEYGEN_FAILED);
167
+ }
168
+ const accountAddress = ceremonyAccountAddress || this.deriveAccountAddress({
169
+ rawPublicKey,
170
+ addressType,
171
+ network
172
+ }).accountAddress;
173
+ await this.storeEncryptedBackupByWalletWithRetry({
174
+ accountAddress,
175
+ externalServerKeyShares,
176
+ password,
177
+ backUpToClientShareService
178
+ });
179
+ const publicKeyHex = btcUtils.extractPublicKeyHex(rawPublicKey);
180
+ return {
181
+ accountAddress,
182
+ rawPublicKey,
183
+ publicKeyHex,
184
+ externalServerKeyShares
185
+ };
186
+ } catch (error) {
187
+ logError({
188
+ message: ERROR_CREATE_WALLET_ACCOUNT,
189
+ error: error,
190
+ context: {}
191
+ });
192
+ throw new Error(ERROR_CREATE_WALLET_ACCOUNT);
193
+ }
194
+ }
195
+ /**
196
+ * Signs a message for BTC using BIP-322 format
197
+ *
198
+ * The address type is automatically derived from the wallet's derivation path.
199
+ * Supports both TAPROOT (BIP-86) and NATIVE_SEGWIT (BIP-84) address types.
200
+ *
201
+ * @param message - The message to sign
202
+ * @param accountAddress - The account address
203
+ * @param network - The Bitcoin network (MAINNET or TESTNET)
204
+ * @param password - Optional password for encrypted backup shares
205
+ * @param externalServerKeyShares - Optional external server key shares
206
+ * @param context - Optional. Sign message context for API tracking
207
+ * @param onError - Optional. Error callback function
208
+ * @returns Promise resolving to the BIP-322 signature as a base64 string
209
+ * @throws Error if required parameters are missing, derivation path is invalid, or signing fails
210
+ */ async signMessage({ message, accountAddress, network, password = undefined, externalServerKeyShares, context, onError }) {
211
+ try {
212
+ var _this_walletMap_accountAddress;
213
+ if (!accountAddress) {
214
+ throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
215
+ }
216
+ const { derivationPath, addressType } = this.getWalletDerivationInfo(accountAddress);
217
+ // Attempt to recover key shares from backup if not provided
218
+ await this.ensureKeySharesRecovered({
219
+ accountAddress,
220
+ password,
221
+ walletOperation: node.WalletOperation.SIGN_MESSAGE,
222
+ externalServerKeyShares,
223
+ errorMessage: 'External server key shares are required to sign a message. No backup shares available for recovery.'
224
+ });
225
+ const resolvedExternalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : (_this_walletMap_accountAddress = this.walletMap[accountAddress]) == null ? void 0 : _this_walletMap_accountAddress.externalServerKeyShares;
226
+ if (!resolvedExternalServerKeyShares || resolvedExternalServerKeyShares.length === 0) {
227
+ throw new Error('External server key shares are required to sign a message');
228
+ }
229
+ const bitcoinConfig = {
230
+ addressType,
231
+ network
232
+ };
233
+ const derivedPublicKey = await this.derivePublicKey({
234
+ chainName: this.chainName,
235
+ keyShare: resolvedExternalServerKeyShares[0],
236
+ derivationPath: new Uint32Array(Object.values(JSON.parse(derivationPath))),
237
+ bitcoinConfig
238
+ });
239
+ if (!derivedPublicKey) {
240
+ throw new Error('Failed to derive public key');
241
+ }
242
+ const pubKey = btcUtils.normalizePublicKey(derivedPublicKey, addressType);
243
+ this.verifyWalletAddress(derivedPublicKey, addressType, network, accountAddress);
244
+ // Prepare BIP-322 Transactions and calculate hash
245
+ const { formattedMessage, toSignPsbt } = btcUtils.calculateBip322Hash(message, pubKey, addressType, network, ecc__namespace);
246
+ // Prepare tweak for Taproot in case of BIP340
247
+ let tweak;
248
+ if (addressType === core.BitcoinAddressType.TAPROOT) {
249
+ tweak = btcUtils.calculateTaprootTweak(pubKey);
250
+ }
251
+ // Build complete bitcoinConfig with addressType and tweak
252
+ const completeBitcoinConfig = _extends({}, bitcoinConfig, {
253
+ addressType,
254
+ tweak
255
+ });
256
+ // Sign the message using MPC
257
+ const signature = await this.sign({
258
+ message: formattedMessage,
259
+ accountAddress,
260
+ chainName: this.chainName,
261
+ password,
262
+ externalServerKeyShares: resolvedExternalServerKeyShares,
263
+ isFormatted: true,
264
+ context: context != null ? context : {
265
+ btcMessage: message
266
+ },
267
+ bitcoinConfig: completeBitcoinConfig,
268
+ onError
269
+ });
270
+ const bip322Signature = btcUtils.encodeBip322Signature(toSignPsbt, pubKey, signature, addressType);
271
+ return bip322Signature;
272
+ } catch (error) {
273
+ logError({
274
+ message: ERROR_SIGN_MESSAGE,
275
+ error: error,
276
+ context: {
277
+ accountAddress
278
+ }
279
+ });
280
+ if (onError) {
281
+ onError(error);
282
+ }
283
+ throw new Error(ERROR_SIGN_MESSAGE);
284
+ }
285
+ }
286
+ /**
287
+ * Signs a Bitcoin transaction (PSBT)
288
+ *
289
+ * The address type is automatically derived from the wallet's derivation path.
290
+ * Only inputs belonging to the sender address are signed. Supports both TAPROOT
291
+ * (BIP-341) and Native SegWit (BIP-143) signing methods.
292
+ *
293
+ * @param transaction - The PSBT to sign as a base64 string
294
+ * @param senderAddress - The sender address (must match inputs to be signed)
295
+ * @param network - The Bitcoin network (MAINNET or TESTNET)
296
+ * @param password - Optional password for encrypted backup shares
297
+ * @param externalServerKeyShares - Optional external server key shares
298
+ * @param context - Optional. Sign message context for API tracking
299
+ * @param onError - Optional. Error callback function
300
+ * @returns Promise resolving to the signed PSBT as a base64 string
301
+ * @throws Error if required parameters are missing, no inputs belong to sender address, or signing fails
302
+ */ async signTransaction({ transaction, senderAddress, network, password = undefined, externalServerKeyShares, context, onError }) {
303
+ try {
304
+ await this.verifyPassword({
305
+ accountAddress: senderAddress,
306
+ password,
307
+ walletOperation: node.WalletOperation.SIGN_TRANSACTION
308
+ });
309
+ if (!senderAddress) {
310
+ throw new Error(ERROR_ACCOUNT_ADDRESS_REQUIRED);
311
+ }
312
+ const { derivationPath, addressType } = this.getWalletDerivationInfo(senderAddress);
313
+ // Attempt to recover key shares from backup if not provided
314
+ await this.ensureKeySharesRecovered({
315
+ accountAddress: senderAddress,
316
+ password,
317
+ walletOperation: node.WalletOperation.SIGN_TRANSACTION,
318
+ externalServerKeyShares,
319
+ errorMessage: 'External server key shares are required to sign transaction. No backup shares available for recovery.'
320
+ });
321
+ const updatedWalletProperties = this.walletMap[senderAddress];
322
+ if (!updatedWalletProperties) {
323
+ throw new Error('Wallet not found in walletMap after key share recovery');
324
+ }
325
+ const resolvedExternalServerKeyShares = externalServerKeyShares || updatedWalletProperties.externalServerKeyShares;
326
+ if (!resolvedExternalServerKeyShares || resolvedExternalServerKeyShares.length === 0) {
327
+ throw new Error('External server key shares are required to sign transaction. No backup shares available for recovery.');
328
+ }
329
+ const bitcoinConfig = {
330
+ addressType,
331
+ network
332
+ };
333
+ const psbt = bitcoin__namespace.Psbt.fromBase64(transaction);
334
+ const derivedPublicKey = await this.derivePublicKey({
335
+ chainName: this.chainName,
336
+ keyShare: resolvedExternalServerKeyShares[0],
337
+ derivationPath: new Uint32Array(Object.values(JSON.parse(derivationPath))),
338
+ bitcoinConfig
339
+ });
340
+ if (!derivedPublicKey) {
341
+ throw new Error('Failed to derive public key');
342
+ }
343
+ const pubKey = btcUtils.normalizePublicKey(derivedPublicKey, addressType);
344
+ const tx = psbt.__CACHE.__TX;
345
+ // Filter inputs to only sign those that belong to the current address
346
+ const inputsToSign = psbt.data.inputs.map((input, i)=>({
347
+ input,
348
+ index: i
349
+ })).filter(({ input })=>btcUtils.doesInputBelongToAddress(input, senderAddress, network));
350
+ if (inputsToSign.length === 0) {
351
+ throw new Error('No inputs found that belong to the sender address');
352
+ }
353
+ if (addressType === core.BitcoinAddressType.TAPROOT) {
354
+ const tweak = btcUtils.calculateTaprootTweak(pubKey);
355
+ const completeBitcoinConfig = _extends({}, bitcoinConfig, {
356
+ addressType,
357
+ tweak
358
+ });
359
+ const { prevOutScripts, values } = btcUtils.collectPSBTInputData(psbt);
360
+ await Promise.all(inputsToSign.map(async ({ input, index: i })=>{
361
+ if (!input.witnessUtxo) {
362
+ throw new Error(`Input ${i} missing witnessUtxo`);
363
+ }
364
+ const hash = Buffer.from(tx.hashForWitnessV1(i, prevOutScripts, values, bitcoin__namespace.Transaction.SIGHASH_DEFAULT));
365
+ const signature = await this.sign({
366
+ message: new Uint8Array(hash),
367
+ accountAddress: senderAddress,
368
+ chainName: this.chainName,
369
+ password,
370
+ externalServerKeyShares: resolvedExternalServerKeyShares,
371
+ isFormatted: true,
372
+ context,
373
+ bitcoinConfig: completeBitcoinConfig,
374
+ onError
375
+ });
376
+ const sigBuffer = btcUtils.convertSignatureToTaprootBuffer(signature);
377
+ psbt.updateInput(i, {
378
+ tapKeySig: sigBuffer
379
+ });
380
+ }));
381
+ } else {
382
+ // Native SegWit (P2WPKH) or other ECDSA-based signing
383
+ const completeBitcoinConfig = _extends({}, bitcoinConfig, {
384
+ addressType
385
+ });
386
+ await Promise.all(inputsToSign.map(async ({ input, index: i })=>{
387
+ if (!input.witnessUtxo) {
388
+ throw new Error(`Input ${i} missing witnessUtxo`);
389
+ }
390
+ const { script, value } = input.witnessUtxo;
391
+ const p2pkh = bitcoin__namespace.payments.p2pkh({
392
+ hash: script.slice(2),
393
+ network: btcUtils.getBitcoinNetwork(network)
394
+ });
395
+ const scriptCode = p2pkh.output;
396
+ if (!scriptCode) {
397
+ throw new Error('Failed to generate scriptCode');
398
+ }
399
+ const hash = tx.hashForWitnessV0(i, scriptCode, value, bitcoin__namespace.Transaction.SIGHASH_ALL);
400
+ const signature = await this.sign({
401
+ message: new Uint8Array(hash),
402
+ accountAddress: senderAddress,
403
+ chainName: this.chainName,
404
+ password,
405
+ externalServerKeyShares: resolvedExternalServerKeyShares,
406
+ isFormatted: true,
407
+ context,
408
+ bitcoinConfig: completeBitcoinConfig,
409
+ onError
410
+ });
411
+ const derSignature = btcUtils.convertSignatureToDER(signature);
412
+ psbt.updateInput(i, {
413
+ partialSig: [
414
+ {
415
+ pubkey: pubKey,
416
+ signature: new Uint8Array(derSignature)
417
+ }
418
+ ]
419
+ });
420
+ }));
421
+ }
422
+ // Return signed PSBT in base64 format (not finalized)
423
+ return psbt.toBase64();
424
+ } catch (error) {
425
+ logError({
426
+ message: ERROR_SIGN_TRANSACTION,
427
+ error: error,
428
+ context: {
429
+ senderAddress
430
+ }
431
+ });
432
+ if (onError) {
433
+ onError(error);
434
+ }
435
+ throw error;
436
+ }
437
+ }
438
+ /**
439
+ * Exports the private key for a wallet
440
+ * @param accountAddress - The account address to export the private key for
441
+ * @param password - The password for encrypted backup shares
442
+ * @param externalServerKeyShares - Optional external server key shares
443
+ * @returns The private key in WIF format
444
+ */ async exportPrivateKey({ accountAddress, password = undefined, externalServerKeyShares }) {
445
+ await this.verifyPassword({
446
+ accountAddress,
447
+ password,
448
+ walletOperation: node.WalletOperation.EXPORT_PRIVATE_KEY
449
+ });
450
+ // Attempt to recover key shares from backup if not provided
451
+ await this.ensureKeySharesRecovered({
452
+ accountAddress,
453
+ password,
454
+ walletOperation: node.WalletOperation.EXPORT_PRIVATE_KEY,
455
+ externalServerKeyShares,
456
+ errorMessage: 'External server key shares are required to export private key. No backup shares available for recovery.'
457
+ });
458
+ // Re-read wallet from map after recovery (it may have been updated with recovered shares)
459
+ const updatedWalletProperties = this.walletMap[accountAddress];
460
+ if (!updatedWalletProperties) {
461
+ throw new Error('Wallet not found in walletMap after recovery');
462
+ }
463
+ const derivationPath = updatedWalletProperties.derivationPath;
464
+ if (!derivationPath) {
465
+ throw new Error('Derivation path missing in walletMap');
466
+ }
467
+ // Derive address type from derivation path for bitcoinConfig
468
+ const addressType = btcUtils.getAddressTypeFromDerivationPath(derivationPath);
469
+ const network = core.BitcoinNetwork.MAINNET; // Default to mainnet, could be derived from wallet
470
+ const bitcoinConfig = {
471
+ addressType,
472
+ network
473
+ };
474
+ // Get key shares from wallet map if not provided (recovered from backup)
475
+ const resolvedExternalServerKeyShares = externalServerKeyShares != null ? externalServerKeyShares : updatedWalletProperties.externalServerKeyShares;
476
+ const { derivedPrivateKey } = await this.exportKey({
477
+ accountAddress,
478
+ chainName: this.chainName,
479
+ password,
480
+ externalServerKeyShares: resolvedExternalServerKeyShares,
481
+ bitcoinConfig
482
+ });
483
+ if (!derivedPrivateKey) {
484
+ throw new Error('Derived private key is undefined');
485
+ }
486
+ // Convert private key to WIF format
487
+ const wifPrivateKey = btcUtils.privateKeyToWIF(derivedPrivateKey, network);
488
+ return wifPrivateKey;
489
+ }
490
+ /**
491
+ * Exports the private key for a given account address offline using key shares
492
+ * @param keyShares - The key shares to export the private key for
493
+ * @param derivationPath - Optional derivation path
494
+ * @param bitcoinConfig - Bitcoin configuration (address type, network)
495
+ * @returns The private key in WIF format
496
+ */ async offlineExportPrivateKey({ keyShares, derivationPath, bitcoinConfig }) {
497
+ const { derivedPrivateKey } = await this.offlineExportKey({
498
+ chainName: this.chainName,
499
+ keyShares,
500
+ derivationPath
501
+ });
502
+ if (!derivedPrivateKey) {
503
+ throw new Error('Derived private key is undefined');
504
+ }
505
+ const network = (bitcoinConfig == null ? void 0 : bitcoinConfig.network) || core.BitcoinNetwork.MAINNET;
506
+ // Convert private key to WIF format
507
+ const wifPrivateKey = btcUtils.privateKeyToWIF(derivedPrivateKey, network);
508
+ return wifPrivateKey;
509
+ }
510
+ /**
511
+ * Imports a private key and stores the key shares in the wallet map.
512
+ * @param privateKey - The private key to import (WIF format)
513
+ * @param chainName - The chain name to use for the wallet
514
+ * @param thresholdSignatureScheme - The threshold signature scheme to use for the wallet
515
+ * @param password - The password to use for the wallet
516
+ * @param onError - The function to call if an error occurs
517
+ * @param backUpToClientShareService - Whether to back up the external server key shares to the client share service. By default, it is false.
518
+ * @param bitcoinConfig - Bitcoin configuration (addressType, network)
519
+ * @returns The account address, public key, raw public key, external server key shares
520
+ */ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password = undefined, backUpToClientShareService = false, onError, bitcoinConfig }) {
521
+ try {
522
+ const { addressType, network = core.BitcoinNetwork.MAINNET } = bitcoinConfig;
523
+ if (!addressType) {
524
+ throw new Error('addressType is required for BTC importPrivateKey');
525
+ }
526
+ if (addressType !== core.BitcoinAddressType.NATIVE_SEGWIT && addressType !== core.BitcoinAddressType.TAPROOT) {
527
+ throw new Error(`Invalid addressType: ${addressType}. Must be one of: ${core.BitcoinAddressType.NATIVE_SEGWIT}, ${core.BitcoinAddressType.TAPROOT}`);
528
+ }
529
+ let ceremonyCeremonyCompleteResolver;
530
+ let ceremonyAccountAddress;
531
+ const ceremonyCompletePromise = new Promise((resolve)=>{
532
+ ceremonyCeremonyCompleteResolver = resolve;
533
+ });
534
+ // Convert WIF to private key hex
535
+ const formattedPrivateKey = btcUtils.wifToPrivateKey(privateKey, network);
536
+ // Get public key from private key to verify address
537
+ const derivedPublicKey = await btcUtils.getPublicKeyFromPrivateKey(privateKey, addressType, ecc__namespace, network);
538
+ const { accountAddress: expectedAddress } = this.deriveAccountAddress({
539
+ rawPublicKey: derivedPublicKey,
540
+ addressType,
541
+ network
542
+ });
543
+ const { rawPublicKey, externalServerKeyShares } = await this.importRawPrivateKey({
544
+ chainName,
545
+ privateKey: formattedPrivateKey,
546
+ thresholdSignatureScheme,
547
+ bitcoinConfig,
548
+ onError,
549
+ onCeremonyComplete: (accountAddress, walletId)=>{
550
+ // Store the ceremony account address to ensure consistency
551
+ ceremonyAccountAddress = accountAddress;
552
+ // Verify address matches
553
+ if (accountAddress !== expectedAddress) {
554
+ throw new Error(`Public address mismatch: derived address ${accountAddress} !== expected address ${expectedAddress}`);
555
+ }
556
+ // update wallet map
557
+ const chainConfig = node.getMPCChainConfig(this.chainName, bitcoinConfig);
558
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress], {
559
+ accountAddress,
560
+ walletId,
561
+ chainName: this.chainName,
562
+ thresholdSignatureScheme,
563
+ derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
564
+ index,
565
+ value
566
+ ]))),
567
+ externalServerKeySharesBackupInfo: node.getExternalServerKeyShareBackupInfo()
568
+ });
569
+ ceremonyCeremonyCompleteResolver(undefined);
570
+ }
571
+ });
572
+ // Wait for the ceremony to complete before proceeding
573
+ await ceremonyCompletePromise;
574
+ if (!rawPublicKey || !externalServerKeyShares) {
575
+ throw new Error('Error creating wallet account');
576
+ }
577
+ // Use the ceremony account address if available, otherwise derive it from raw public key
578
+ const accountAddress = ceremonyAccountAddress || this.deriveAccountAddress({
579
+ rawPublicKey,
580
+ addressType,
581
+ network
582
+ }).accountAddress;
583
+ if (accountAddress !== expectedAddress) {
584
+ throw new Error(`Public address mismatch: derived address ${accountAddress} !== expected address ${expectedAddress}`);
585
+ }
586
+ await this.storeEncryptedBackupByWalletWithRetry({
587
+ accountAddress,
588
+ externalServerKeyShares,
589
+ password,
590
+ backUpToClientShareService
591
+ });
592
+ const publicKeyHex = btcUtils.extractPublicKeyHex(rawPublicKey);
593
+ return {
594
+ accountAddress,
595
+ rawPublicKey,
596
+ publicKeyHex,
597
+ externalServerKeyShares
598
+ };
599
+ } catch (error) {
600
+ logError({
601
+ message: ERROR_IMPORT_PRIVATE_KEY,
602
+ error: error,
603
+ context: {}
604
+ });
605
+ throw new Error(ERROR_IMPORT_PRIVATE_KEY);
606
+ }
607
+ }
608
+ /**
609
+ * Gets the Bitcoin wallets
610
+ * @returns The Bitcoin wallets
611
+ */ async getBitcoinWallets() {
612
+ const wallets = await this.getWallets(); // NOSONAR
613
+ const btcWallets = wallets.filter((wallet)=>{
614
+ var _wallet_chainName;
615
+ const chainName = (_wallet_chainName = wallet.chainName) == null ? void 0 : _wallet_chainName.toLowerCase();
616
+ return chainName === 'btc' || chainName === 'bip122';
617
+ });
618
+ return btcWallets;
619
+ }
620
+ constructor({ environmentId, baseApiUrl, baseMPCRelayApiUrl, enableMPCAccelerator }){
621
+ super({
622
+ environmentId,
623
+ baseApiUrl,
624
+ baseMPCRelayApiUrl,
625
+ enableMPCAccelerator
626
+ }), this.chainName = 'BTC';
627
+ }
628
+ }
629
+
630
+ exports.DynamicBtcWalletClient = DynamicBtcWalletClient;
631
+ exports.ERROR_ACCOUNT_ADDRESS_REQUIRED = ERROR_ACCOUNT_ADDRESS_REQUIRED;
632
+ exports.ERROR_CREATE_WALLET_ACCOUNT = ERROR_CREATE_WALLET_ACCOUNT;
633
+ exports.ERROR_IMPORT_PRIVATE_KEY = ERROR_IMPORT_PRIVATE_KEY;
634
+ exports.ERROR_KEYGEN_FAILED = ERROR_KEYGEN_FAILED;
635
+ exports.ERROR_SIGN_MESSAGE = ERROR_SIGN_MESSAGE;
636
+ exports.ERROR_SIGN_TRANSACTION = ERROR_SIGN_TRANSACTION;
package/index.esm.d.ts ADDED
@@ -0,0 +1 @@
1
+ export * from "./src/index";