@dynamic-labs-wallet/btc 0.0.235 → 0.0.237

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 (25) hide show
  1. package/index.cjs.js +272 -6
  2. package/index.esm.js +273 -7
  3. package/package.json +2 -2
  4. package/src/client/client.d.ts +26 -0
  5. package/src/client/client.d.ts.map +1 -1
  6. package/src/utils/calculateBip322Hash/calculateBip322Hash.d.ts.map +1 -1
  7. package/src/utils/doesInputBelongToAddress/doesInputBelongToAddress.d.ts +11 -0
  8. package/src/utils/doesInputBelongToAddress/doesInputBelongToAddress.d.ts.map +1 -0
  9. package/src/utils/doesInputBelongToAddress/index.d.ts +2 -0
  10. package/src/utils/doesInputBelongToAddress/index.d.ts.map +1 -0
  11. package/src/utils/encodeBip322Signature/encodeBip322Signature.d.ts.map +1 -1
  12. package/src/utils/getAddressTypeFromDerivationPath/getAddressTypeFromDerivationPath.d.ts.map +1 -1
  13. package/src/utils/getPublicKeyFromPrivateKey/getPublicKeyFromPrivateKey.d.ts +16 -0
  14. package/src/utils/getPublicKeyFromPrivateKey/getPublicKeyFromPrivateKey.d.ts.map +1 -0
  15. package/src/utils/getPublicKeyFromPrivateKey/index.d.ts +2 -0
  16. package/src/utils/getPublicKeyFromPrivateKey/index.d.ts.map +1 -0
  17. package/src/utils/index.d.ts +3 -0
  18. package/src/utils/index.d.ts.map +1 -1
  19. package/src/utils/normalizePublicKey/normalizePublicKey.d.ts +1 -2
  20. package/src/utils/normalizePublicKey/normalizePublicKey.d.ts.map +1 -1
  21. package/src/utils/publicKeyToBitcoinAddress/publicKeyToBitcoinAddress.d.ts.map +1 -1
  22. package/src/utils/wifToPrivateKey/index.d.ts +2 -0
  23. package/src/utils/wifToPrivateKey/index.d.ts.map +1 -0
  24. package/src/utils/wifToPrivateKey/wifToPrivateKey.d.ts +19 -0
  25. package/src/utils/wifToPrivateKey/wifToPrivateKey.d.ts.map +1 -0
package/index.cjs.js CHANGED
@@ -122,6 +122,7 @@ let isInitialized = false;
122
122
  return address;
123
123
  };
124
124
 
125
+ // eslint-disable-next-line @nx/enforce-module-boundaries
125
126
  /**
126
127
  * Converts a public key to a Bitcoin address
127
128
  *
@@ -231,6 +232,7 @@ const compressPublicKey = (x, yLastByte)=>{
231
232
  ]);
232
233
  };
233
234
 
235
+ // eslint-disable @nx/enforce-module-boundaries
234
236
  /**
235
237
  * Normalizes a public key to a standard Buffer format
236
238
  * Handles various input types (Uint8Array, Buffer, object with pubKeyAsHex, etc.)
@@ -248,6 +250,7 @@ const compressPublicKey = (x, yLastByte)=>{
248
250
  return normalizeForCompressed(buffer);
249
251
  };
250
252
 
253
+ // eslint-disable-next-line @nx/enforce-module-boundaries
251
254
  /**
252
255
  * Infers the Bitcoin address type from a BIP-44 derivation path
253
256
  *
@@ -447,6 +450,101 @@ initEccLib();
447
450
  }
448
451
  };
449
452
 
453
+ /**
454
+ * Converts a Bitcoin WIF (Wallet Import Format) private key to hex format
455
+ * This is the reverse operation of `privateKeyToWIF`
456
+ *
457
+ * WIF decoding steps:
458
+ * 1. Base58 decode the WIF string
459
+ * 2. Validate network prefix
460
+ * 3. Validate checksum (double SHA-256, first 4 bytes)
461
+ * 4. Extract private key bytes (skip prefix, compression flag, and checksum)
462
+ * 5. Convert to hex string
463
+ *
464
+ * @param wif - Private key in WIF format (Base58 encoded)
465
+ * @param network - Bitcoin network (mainnet, testnet)
466
+ * @returns Private key as hex string (64 characters, 32 bytes)
467
+ * @throws Error if WIF format is invalid
468
+ */ const wifToPrivateKey = (wif, network = 'mainnet')=>{
469
+ try {
470
+ // 1. Decode Base58
471
+ const decoded = bs58.decode(wif);
472
+ // 2. Validate length (should be 37 bytes: 1 prefix + 32 key + 1 compression + 4 checksum)
473
+ // or 38 bytes (with compression flag)
474
+ if (decoded.length !== 37 && decoded.length !== 38) {
475
+ throw new Error(`Invalid WIF length: ${decoded.length}, expected 37 or 38 bytes`);
476
+ }
477
+ // 3. Get network config to validate prefix
478
+ const networkConfig = getBitcoinNetwork(network);
479
+ const expectedPrefix = networkConfig.wif;
480
+ // 4. Validate network prefix
481
+ if (decoded[0] !== expectedPrefix) {
482
+ throw new Error(`Invalid WIF network prefix: expected ${expectedPrefix}, got ${decoded[0]}`);
483
+ }
484
+ // 5. Validate checksum
485
+ const payload = decoded.slice(0, -4);
486
+ const checksum = decoded.slice(-4);
487
+ const firstHash = sha256.sha256(payload);
488
+ const secondHash = sha256.sha256(firstHash);
489
+ const calculatedChecksum = secondHash.slice(0, 4);
490
+ if (!calculatedChecksum.every((byte, index)=>byte === checksum[index])) {
491
+ throw new Error('Invalid WIF checksum');
492
+ }
493
+ // 6. Extract private key bytes (skip prefix, skip compression flag if present, skip checksum)
494
+ // Private key is always 32 bytes, starting at index 1
495
+ const privateKeyStart = 1;
496
+ const privateKeyEnd = 33; // 32 bytes of private key
497
+ const privateKeyBytes = decoded.slice(privateKeyStart, privateKeyEnd);
498
+ // 7. Convert to hex string
499
+ return Buffer.from(privateKeyBytes).toString('hex');
500
+ } catch (error) {
501
+ throw new Error(`Invalid WIF format: ${error instanceof Error ? error.message : String(error)}. Only WIF format is supported.`);
502
+ }
503
+ };
504
+
505
+ /**
506
+ * Derives a public key from a private key (WIF format) based on address type
507
+ *
508
+ * - For NATIVE_SEGWIT (ECDSA): Returns compressed public key (33 bytes)
509
+ * - For TAPROOT (BIP340): Returns x-only public key (32 bytes)
510
+ *
511
+ * @param privateKey - Private key in WIF format (Base58 encoded)
512
+ * @param addressType - Bitcoin address type (NATIVE_SEGWIT or TAPROOT)
513
+ * @param network - Bitcoin network (mainnet, testnet)
514
+ * @returns Public key as Buffer (33 bytes for NATIVE_SEGWIT, 32 bytes for TAPROOT)
515
+ * @throws Error if private key is invalid or derivation fails
516
+ */ const getPublicKeyFromPrivateKey = async (privateKey, addressType, network = 'mainnet')=>{
517
+ initEccLib();
518
+ try {
519
+ // 1. Decode WIF to hex
520
+ const privateKeyHex = wifToPrivateKey(privateKey, network);
521
+ const privateKeyBytes = new Uint8Array(Buffer.from(privateKeyHex, 'hex'));
522
+ // 2. Import secp256k1 library
523
+ const ecc = await import('@bitcoinerlab/secp256k1');
524
+ // 3. Derive public key based on address type
525
+ if (addressType === 'taproot') {
526
+ // BIP340/Taproot: Derive x-only public key (32 bytes)
527
+ // Get the public key point
528
+ const publicKeyPoint = ecc.pointFromScalar(privateKeyBytes);
529
+ if (!publicKeyPoint) {
530
+ throw new Error('Failed to derive public key from private key');
531
+ }
532
+ // For Taproot, we need the 32-byte x-only public key
533
+ // publicKeyPoint is 33 bytes (0x02/0x03 + 32 bytes x), we take the last 32 bytes
534
+ return Buffer.from(publicKeyPoint.subarray(1)); // Skip prefix, get x-coordinate
535
+ } else {
536
+ // NATIVE_SEGWIT (ECDSA): Derive compressed public key (33 bytes)
537
+ const publicKeyPoint = ecc.pointFromScalar(privateKeyBytes, true); // compressed = true
538
+ if (!publicKeyPoint) {
539
+ throw new Error('Failed to derive public key from private key');
540
+ }
541
+ return Buffer.from(publicKeyPoint); // 33 bytes compressed
542
+ }
543
+ } catch (error) {
544
+ throw new Error(`Failed to derive public key from private key: ${error instanceof Error ? error.message : String(error)}`);
545
+ }
546
+ };
547
+
450
548
  /**
451
549
  * Converts an ECDSA signature to DER format
452
550
  *
@@ -614,6 +712,48 @@ initEccLib();
614
712
  };
615
713
  };
616
714
 
715
+ /**
716
+ * Checks if a PSBT input belongs to a specific address
717
+ * @param input - The PSBT input (from psbt.data.inputs)
718
+ * @param address - The address to check against
719
+ * @param network - The Bitcoin network
720
+ * @returns True if the input belongs to the address, false otherwise
721
+ */ const doesInputBelongToAddress = (input, address, network)=>{
722
+ if (!input.witnessUtxo) {
723
+ return false;
724
+ }
725
+ const script = Buffer.isBuffer(input.witnessUtxo.script) ? input.witnessUtxo.script : Buffer.from(input.witnessUtxo.script);
726
+ const bitcoinNetwork = getBitcoinNetwork(network);
727
+ try {
728
+ // Try P2WPKH (Native SegWit) - script is OP_0 <20-byte hash>
729
+ if (script.length === 22 && script[0] === 0x00 && script[1] === 0x14) {
730
+ const p2wpkh = bitcoin__namespace.payments.p2wpkh({
731
+ output: script,
732
+ network: bitcoinNetwork
733
+ });
734
+ return p2wpkh.address === address;
735
+ }
736
+ // Try P2TR (Taproot) - script is OP_1 <32-byte x-only pubkey>
737
+ if (script.length === 34 && script[0] === 0x51 && script[1] === 0x20) {
738
+ const p2tr = bitcoin__namespace.payments.p2tr({
739
+ output: script,
740
+ network: bitcoinNetwork
741
+ });
742
+ return p2tr.address === address;
743
+ }
744
+ return false;
745
+ } catch (error) {
746
+ // eslint-disable-next-line no-console
747
+ console.log('[doesInputBelongToAddress] Error checking input', {
748
+ address,
749
+ network,
750
+ error: error instanceof Error ? error.message : String(error)
751
+ });
752
+ return false;
753
+ }
754
+ };
755
+
756
+ // eslint-disable-next-line @nx/enforce-module-boundaries
617
757
  class DynamicBtcWalletClient extends browser.DynamicWalletClient {
618
758
  /**
619
759
  * Creates a Bitcoin wallet account
@@ -914,6 +1054,117 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
914
1054
  return this.convertPrivateKeyToBitcoinFormat(derivedPrivateKey, browser.BitcoinNetwork.MAINNET);
915
1055
  }
916
1056
  /**
1057
+ * Imports a private key and creates a Bitcoin wallet account
1058
+ * @param privateKey - Private key in WIF format (Base58 encoded)
1059
+ * @param chainName - Chain name ('BTC')
1060
+ * @param thresholdSignatureScheme - The threshold signature scheme to use
1061
+ * @param password - Optional password for encrypted backup
1062
+ * @param onError - Optional error callback
1063
+ * @param signedSessionId - The signed session ID
1064
+ * @param publicAddressCheck - Optional address to validate against
1065
+ * @param addressType - Bitcoin address type (NATIVE_SEGWIT or TAPROOT)
1066
+ * @returns The account address, public key hex, and raw public key
1067
+ */ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password = undefined, onError, signedSessionId, publicAddressCheck, addressType }) {
1068
+ try {
1069
+ const network = browser.BitcoinNetwork.MAINNET;
1070
+ if (!addressType) {
1071
+ throw new Error('addressType is required for BTC importPrivateKey');
1072
+ }
1073
+ const bitcoinAddressType = addressType;
1074
+ if (bitcoinAddressType !== browser.BitcoinAddressType.NATIVE_SEGWIT && bitcoinAddressType !== browser.BitcoinAddressType.TAPROOT) {
1075
+ throw new Error(`Invalid addressType: ${addressType}. Must be one of: ${browser.BitcoinAddressType.NATIVE_SEGWIT}, ${browser.BitcoinAddressType.TAPROOT}`);
1076
+ }
1077
+ const addressTypeEnum = bitcoinAddressType;
1078
+ let ceremonyCeremonyCompleteResolver;
1079
+ let ceremonyAccountAddress;
1080
+ const ceremonyCompletePromise = new Promise((resolve)=>{
1081
+ ceremonyCeremonyCompleteResolver = resolve;
1082
+ });
1083
+ const formattedPrivateKey = wifToPrivateKey(privateKey, network);
1084
+ if (publicAddressCheck) {
1085
+ const derivedPublicKey = await getPublicKeyFromPrivateKey(privateKey, addressTypeEnum, network);
1086
+ const { accountAddress } = this.deriveAccountAddress({
1087
+ rawPublicKey: derivedPublicKey,
1088
+ addressType: addressTypeEnum,
1089
+ network
1090
+ });
1091
+ if (accountAddress !== publicAddressCheck) {
1092
+ throw new Error(`Public address mismatch: derived address ${accountAddress} !== public address ${publicAddressCheck}`);
1093
+ }
1094
+ }
1095
+ const { rawPublicKey, clientKeyShares } = await this.importRawPrivateKey({
1096
+ chainName,
1097
+ privateKey: formattedPrivateKey,
1098
+ thresholdSignatureScheme,
1099
+ bitcoinConfig: {
1100
+ addressType: addressTypeEnum,
1101
+ network
1102
+ },
1103
+ onCeremonyComplete: (accountAddress, walletId)=>{
1104
+ ceremonyAccountAddress = accountAddress;
1105
+ const chainConfig = browser.getMPCChainConfig(this.chainName, {
1106
+ addressType: addressTypeEnum,
1107
+ network
1108
+ });
1109
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
1110
+ accountAddress,
1111
+ walletId,
1112
+ chainName: this.chainName,
1113
+ thresholdSignatureScheme,
1114
+ derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
1115
+ index,
1116
+ value
1117
+ ]))),
1118
+ addressType: addressTypeEnum,
1119
+ clientKeySharesBackupInfo: browser.getClientKeyShareBackupInfo()
1120
+ });
1121
+ this.logger.debug('walletMap updated for wallet', {
1122
+ context: {
1123
+ accountAddress,
1124
+ walletId,
1125
+ walletMap: this.walletMap
1126
+ }
1127
+ });
1128
+ ceremonyCeremonyCompleteResolver(undefined);
1129
+ },
1130
+ onError
1131
+ });
1132
+ await ceremonyCompletePromise;
1133
+ if (!rawPublicKey || !clientKeyShares) {
1134
+ throw new Error(browser.ERROR_IMPORT_PRIVATE_KEY);
1135
+ }
1136
+ const accountAddress = ceremonyAccountAddress || this.deriveAccountAddress({
1137
+ rawPublicKey,
1138
+ addressType: addressTypeEnum,
1139
+ network
1140
+ }).accountAddress;
1141
+ if (publicAddressCheck && accountAddress !== publicAddressCheck) {
1142
+ throw new Error(`Public address mismatch: derived address ${accountAddress} !== public address ${publicAddressCheck}`);
1143
+ }
1144
+ await this.setClientKeySharesToLocalStorage({
1145
+ accountAddress,
1146
+ clientKeyShares,
1147
+ overwriteOrMerge: 'overwrite'
1148
+ });
1149
+ await this.storeEncryptedBackupByWalletWithRetry({
1150
+ accountAddress,
1151
+ clientKeyShares,
1152
+ password,
1153
+ signedSessionId
1154
+ });
1155
+ const publicKeyHex = this.extractPublicKeyHex(rawPublicKey);
1156
+ return {
1157
+ accountAddress,
1158
+ publicKeyHex,
1159
+ rawPublicKey
1160
+ };
1161
+ } catch (error) {
1162
+ this.logger.error(browser.ERROR_IMPORT_PRIVATE_KEY, error);
1163
+ onError == null ? void 0 : onError(error);
1164
+ throw new Error(browser.ERROR_IMPORT_PRIVATE_KEY);
1165
+ }
1166
+ }
1167
+ /**
917
1168
  * Converts MPC private key to Bitcoin WIF (Wallet Import Format)
918
1169
  * Uses the utility function from utils.ts for the core conversion logic
919
1170
  * @param privateKey - The private key to convert to a Bitcoin WIF format
@@ -1000,6 +1251,22 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1000
1251
  }
1001
1252
  const pubKey = normalizePublicKey(derivedPublicKey, addressType);
1002
1253
  const tx = psbt.__CACHE.__TX;
1254
+ // Filter inputs to only sign those that belong to the current address
1255
+ const inputsToSign = psbt.data.inputs.map((input, i)=>({
1256
+ input,
1257
+ index: i
1258
+ })).filter(({ input })=>doesInputBelongToAddress(input, senderAddress, network));
1259
+ this.logger.debug('[BTC Client] signTransaction - Filtering inputs', {
1260
+ totalInputs: psbt.data.inputs.length,
1261
+ inputsToSign: inputsToSign.length,
1262
+ senderAddress
1263
+ });
1264
+ if (inputsToSign.length === 0) {
1265
+ this.logger.warn('[BTC Client] signTransaction - No inputs found for address', {
1266
+ senderAddress,
1267
+ totalInputs: psbt.data.inputs.length
1268
+ });
1269
+ }
1003
1270
  if (addressType === browser.BitcoinAddressType.TAPROOT) {
1004
1271
  const tweak = calculateTaprootTweak(pubKey);
1005
1272
  const completeBitcoinConfig = _extends({}, bitcoinConfig, {
@@ -1007,7 +1274,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1007
1274
  tweak
1008
1275
  });
1009
1276
  const { prevOutScripts, values } = collectPSBTInputData(psbt);
1010
- await Promise.all(psbt.data.inputs.map(async (input, i)=>{
1277
+ await Promise.all(inputsToSign.map(async ({ input, index: i })=>{
1011
1278
  if (!input.witnessUtxo) {
1012
1279
  throw new Error(`Input ${i} missing witnessUtxo`);
1013
1280
  }
@@ -1036,17 +1303,16 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1036
1303
  addressType: addressType
1037
1304
  });
1038
1305
  // Iterate and sign inputs in parallel for better performance
1039
- await Promise.all(psbt.data.inputs.map(async (input, i)=>{
1306
+ await Promise.all(inputsToSign.map(async ({ input, index: i })=>{
1040
1307
  if (!input.witnessUtxo) {
1041
1308
  throw new Error(`Input ${i} missing witnessUtxo`);
1042
1309
  }
1043
1310
  const { script, value } = input.witnessUtxo;
1044
- // For Native SegWit (P2WPKH), use p2wpkh
1045
- const p2wpkh = bitcoin__namespace.payments.p2wpkh({
1046
- output: script,
1311
+ const p2pkh = bitcoin__namespace.payments.p2pkh({
1312
+ hash: script.slice(2),
1047
1313
  network: getBitcoinNetwork(network)
1048
1314
  });
1049
- const scriptCode = p2wpkh.output || script;
1315
+ const scriptCode = p2pkh.output;
1050
1316
  if (!scriptCode) throw new Error('Failed to generate scriptCode');
1051
1317
  const hash = tx.hashForWitnessV0(i, scriptCode, value, bitcoin__namespace.Transaction.SIGHASH_ALL);
1052
1318
  const signature = await this.sign({
package/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { BitcoinAddressType, DynamicWalletClient, BitcoinNetwork, getMPCChainConfig, getClientKeyShareBackupInfo, ERROR_CREATE_WALLET_ACCOUNT, WalletOperation, ERROR_ACCOUNT_ADDRESS_REQUIRED, ERROR_SIGN_MESSAGE, AuthMode } from '@dynamic-labs-wallet/browser';
1
+ import { BitcoinAddressType, DynamicWalletClient, BitcoinNetwork, getMPCChainConfig, getClientKeyShareBackupInfo, ERROR_CREATE_WALLET_ACCOUNT, WalletOperation, ERROR_ACCOUNT_ADDRESS_REQUIRED, ERROR_SIGN_MESSAGE, ERROR_IMPORT_PRIVATE_KEY, AuthMode } from '@dynamic-labs-wallet/browser';
2
2
  import * as bitcoin from 'bitcoinjs-lib';
3
3
  import { payments, initEccLib as initEccLib$1 } from 'bitcoinjs-lib';
4
4
  import ecc from '@bitcoinerlab/secp256k1';
@@ -102,6 +102,7 @@ let isInitialized = false;
102
102
  return address;
103
103
  };
104
104
 
105
+ // eslint-disable-next-line @nx/enforce-module-boundaries
105
106
  /**
106
107
  * Converts a public key to a Bitcoin address
107
108
  *
@@ -211,6 +212,7 @@ const compressPublicKey = (x, yLastByte)=>{
211
212
  ]);
212
213
  };
213
214
 
215
+ // eslint-disable @nx/enforce-module-boundaries
214
216
  /**
215
217
  * Normalizes a public key to a standard Buffer format
216
218
  * Handles various input types (Uint8Array, Buffer, object with pubKeyAsHex, etc.)
@@ -228,6 +230,7 @@ const compressPublicKey = (x, yLastByte)=>{
228
230
  return normalizeForCompressed(buffer);
229
231
  };
230
232
 
233
+ // eslint-disable-next-line @nx/enforce-module-boundaries
231
234
  /**
232
235
  * Infers the Bitcoin address type from a BIP-44 derivation path
233
236
  *
@@ -427,6 +430,101 @@ initEccLib();
427
430
  }
428
431
  };
429
432
 
433
+ /**
434
+ * Converts a Bitcoin WIF (Wallet Import Format) private key to hex format
435
+ * This is the reverse operation of `privateKeyToWIF`
436
+ *
437
+ * WIF decoding steps:
438
+ * 1. Base58 decode the WIF string
439
+ * 2. Validate network prefix
440
+ * 3. Validate checksum (double SHA-256, first 4 bytes)
441
+ * 4. Extract private key bytes (skip prefix, compression flag, and checksum)
442
+ * 5. Convert to hex string
443
+ *
444
+ * @param wif - Private key in WIF format (Base58 encoded)
445
+ * @param network - Bitcoin network (mainnet, testnet)
446
+ * @returns Private key as hex string (64 characters, 32 bytes)
447
+ * @throws Error if WIF format is invalid
448
+ */ const wifToPrivateKey = (wif, network = 'mainnet')=>{
449
+ try {
450
+ // 1. Decode Base58
451
+ const decoded = bs58.decode(wif);
452
+ // 2. Validate length (should be 37 bytes: 1 prefix + 32 key + 1 compression + 4 checksum)
453
+ // or 38 bytes (with compression flag)
454
+ if (decoded.length !== 37 && decoded.length !== 38) {
455
+ throw new Error(`Invalid WIF length: ${decoded.length}, expected 37 or 38 bytes`);
456
+ }
457
+ // 3. Get network config to validate prefix
458
+ const networkConfig = getBitcoinNetwork(network);
459
+ const expectedPrefix = networkConfig.wif;
460
+ // 4. Validate network prefix
461
+ if (decoded[0] !== expectedPrefix) {
462
+ throw new Error(`Invalid WIF network prefix: expected ${expectedPrefix}, got ${decoded[0]}`);
463
+ }
464
+ // 5. Validate checksum
465
+ const payload = decoded.slice(0, -4);
466
+ const checksum = decoded.slice(-4);
467
+ const firstHash = sha256(payload);
468
+ const secondHash = sha256(firstHash);
469
+ const calculatedChecksum = secondHash.slice(0, 4);
470
+ if (!calculatedChecksum.every((byte, index)=>byte === checksum[index])) {
471
+ throw new Error('Invalid WIF checksum');
472
+ }
473
+ // 6. Extract private key bytes (skip prefix, skip compression flag if present, skip checksum)
474
+ // Private key is always 32 bytes, starting at index 1
475
+ const privateKeyStart = 1;
476
+ const privateKeyEnd = 33; // 32 bytes of private key
477
+ const privateKeyBytes = decoded.slice(privateKeyStart, privateKeyEnd);
478
+ // 7. Convert to hex string
479
+ return Buffer.from(privateKeyBytes).toString('hex');
480
+ } catch (error) {
481
+ throw new Error(`Invalid WIF format: ${error instanceof Error ? error.message : String(error)}. Only WIF format is supported.`);
482
+ }
483
+ };
484
+
485
+ /**
486
+ * Derives a public key from a private key (WIF format) based on address type
487
+ *
488
+ * - For NATIVE_SEGWIT (ECDSA): Returns compressed public key (33 bytes)
489
+ * - For TAPROOT (BIP340): Returns x-only public key (32 bytes)
490
+ *
491
+ * @param privateKey - Private key in WIF format (Base58 encoded)
492
+ * @param addressType - Bitcoin address type (NATIVE_SEGWIT or TAPROOT)
493
+ * @param network - Bitcoin network (mainnet, testnet)
494
+ * @returns Public key as Buffer (33 bytes for NATIVE_SEGWIT, 32 bytes for TAPROOT)
495
+ * @throws Error if private key is invalid or derivation fails
496
+ */ const getPublicKeyFromPrivateKey = async (privateKey, addressType, network = 'mainnet')=>{
497
+ initEccLib();
498
+ try {
499
+ // 1. Decode WIF to hex
500
+ const privateKeyHex = wifToPrivateKey(privateKey, network);
501
+ const privateKeyBytes = new Uint8Array(Buffer.from(privateKeyHex, 'hex'));
502
+ // 2. Import secp256k1 library
503
+ const ecc = await import('@bitcoinerlab/secp256k1');
504
+ // 3. Derive public key based on address type
505
+ if (addressType === 'taproot') {
506
+ // BIP340/Taproot: Derive x-only public key (32 bytes)
507
+ // Get the public key point
508
+ const publicKeyPoint = ecc.pointFromScalar(privateKeyBytes);
509
+ if (!publicKeyPoint) {
510
+ throw new Error('Failed to derive public key from private key');
511
+ }
512
+ // For Taproot, we need the 32-byte x-only public key
513
+ // publicKeyPoint is 33 bytes (0x02/0x03 + 32 bytes x), we take the last 32 bytes
514
+ return Buffer.from(publicKeyPoint.subarray(1)); // Skip prefix, get x-coordinate
515
+ } else {
516
+ // NATIVE_SEGWIT (ECDSA): Derive compressed public key (33 bytes)
517
+ const publicKeyPoint = ecc.pointFromScalar(privateKeyBytes, true); // compressed = true
518
+ if (!publicKeyPoint) {
519
+ throw new Error('Failed to derive public key from private key');
520
+ }
521
+ return Buffer.from(publicKeyPoint); // 33 bytes compressed
522
+ }
523
+ } catch (error) {
524
+ throw new Error(`Failed to derive public key from private key: ${error instanceof Error ? error.message : String(error)}`);
525
+ }
526
+ };
527
+
430
528
  /**
431
529
  * Converts an ECDSA signature to DER format
432
530
  *
@@ -594,6 +692,48 @@ initEccLib();
594
692
  };
595
693
  };
596
694
 
695
+ /**
696
+ * Checks if a PSBT input belongs to a specific address
697
+ * @param input - The PSBT input (from psbt.data.inputs)
698
+ * @param address - The address to check against
699
+ * @param network - The Bitcoin network
700
+ * @returns True if the input belongs to the address, false otherwise
701
+ */ const doesInputBelongToAddress = (input, address, network)=>{
702
+ if (!input.witnessUtxo) {
703
+ return false;
704
+ }
705
+ const script = Buffer.isBuffer(input.witnessUtxo.script) ? input.witnessUtxo.script : Buffer.from(input.witnessUtxo.script);
706
+ const bitcoinNetwork = getBitcoinNetwork(network);
707
+ try {
708
+ // Try P2WPKH (Native SegWit) - script is OP_0 <20-byte hash>
709
+ if (script.length === 22 && script[0] === 0x00 && script[1] === 0x14) {
710
+ const p2wpkh = bitcoin.payments.p2wpkh({
711
+ output: script,
712
+ network: bitcoinNetwork
713
+ });
714
+ return p2wpkh.address === address;
715
+ }
716
+ // Try P2TR (Taproot) - script is OP_1 <32-byte x-only pubkey>
717
+ if (script.length === 34 && script[0] === 0x51 && script[1] === 0x20) {
718
+ const p2tr = bitcoin.payments.p2tr({
719
+ output: script,
720
+ network: bitcoinNetwork
721
+ });
722
+ return p2tr.address === address;
723
+ }
724
+ return false;
725
+ } catch (error) {
726
+ // eslint-disable-next-line no-console
727
+ console.log('[doesInputBelongToAddress] Error checking input', {
728
+ address,
729
+ network,
730
+ error: error instanceof Error ? error.message : String(error)
731
+ });
732
+ return false;
733
+ }
734
+ };
735
+
736
+ // eslint-disable-next-line @nx/enforce-module-boundaries
597
737
  class DynamicBtcWalletClient extends DynamicWalletClient {
598
738
  /**
599
739
  * Creates a Bitcoin wallet account
@@ -894,6 +1034,117 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
894
1034
  return this.convertPrivateKeyToBitcoinFormat(derivedPrivateKey, BitcoinNetwork.MAINNET);
895
1035
  }
896
1036
  /**
1037
+ * Imports a private key and creates a Bitcoin wallet account
1038
+ * @param privateKey - Private key in WIF format (Base58 encoded)
1039
+ * @param chainName - Chain name ('BTC')
1040
+ * @param thresholdSignatureScheme - The threshold signature scheme to use
1041
+ * @param password - Optional password for encrypted backup
1042
+ * @param onError - Optional error callback
1043
+ * @param signedSessionId - The signed session ID
1044
+ * @param publicAddressCheck - Optional address to validate against
1045
+ * @param addressType - Bitcoin address type (NATIVE_SEGWIT or TAPROOT)
1046
+ * @returns The account address, public key hex, and raw public key
1047
+ */ async importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password = undefined, onError, signedSessionId, publicAddressCheck, addressType }) {
1048
+ try {
1049
+ const network = BitcoinNetwork.MAINNET;
1050
+ if (!addressType) {
1051
+ throw new Error('addressType is required for BTC importPrivateKey');
1052
+ }
1053
+ const bitcoinAddressType = addressType;
1054
+ if (bitcoinAddressType !== BitcoinAddressType.NATIVE_SEGWIT && bitcoinAddressType !== BitcoinAddressType.TAPROOT) {
1055
+ throw new Error(`Invalid addressType: ${addressType}. Must be one of: ${BitcoinAddressType.NATIVE_SEGWIT}, ${BitcoinAddressType.TAPROOT}`);
1056
+ }
1057
+ const addressTypeEnum = bitcoinAddressType;
1058
+ let ceremonyCeremonyCompleteResolver;
1059
+ let ceremonyAccountAddress;
1060
+ const ceremonyCompletePromise = new Promise((resolve)=>{
1061
+ ceremonyCeremonyCompleteResolver = resolve;
1062
+ });
1063
+ const formattedPrivateKey = wifToPrivateKey(privateKey, network);
1064
+ if (publicAddressCheck) {
1065
+ const derivedPublicKey = await getPublicKeyFromPrivateKey(privateKey, addressTypeEnum, network);
1066
+ const { accountAddress } = this.deriveAccountAddress({
1067
+ rawPublicKey: derivedPublicKey,
1068
+ addressType: addressTypeEnum,
1069
+ network
1070
+ });
1071
+ if (accountAddress !== publicAddressCheck) {
1072
+ throw new Error(`Public address mismatch: derived address ${accountAddress} !== public address ${publicAddressCheck}`);
1073
+ }
1074
+ }
1075
+ const { rawPublicKey, clientKeyShares } = await this.importRawPrivateKey({
1076
+ chainName,
1077
+ privateKey: formattedPrivateKey,
1078
+ thresholdSignatureScheme,
1079
+ bitcoinConfig: {
1080
+ addressType: addressTypeEnum,
1081
+ network
1082
+ },
1083
+ onCeremonyComplete: (accountAddress, walletId)=>{
1084
+ ceremonyAccountAddress = accountAddress;
1085
+ const chainConfig = getMPCChainConfig(this.chainName, {
1086
+ addressType: addressTypeEnum,
1087
+ network
1088
+ });
1089
+ this.walletMap[accountAddress] = _extends({}, this.walletMap[accountAddress] || {}, {
1090
+ accountAddress,
1091
+ walletId,
1092
+ chainName: this.chainName,
1093
+ thresholdSignatureScheme,
1094
+ derivationPath: JSON.stringify(Object.fromEntries(chainConfig.derivationPath.map((value, index)=>[
1095
+ index,
1096
+ value
1097
+ ]))),
1098
+ addressType: addressTypeEnum,
1099
+ clientKeySharesBackupInfo: getClientKeyShareBackupInfo()
1100
+ });
1101
+ this.logger.debug('walletMap updated for wallet', {
1102
+ context: {
1103
+ accountAddress,
1104
+ walletId,
1105
+ walletMap: this.walletMap
1106
+ }
1107
+ });
1108
+ ceremonyCeremonyCompleteResolver(undefined);
1109
+ },
1110
+ onError
1111
+ });
1112
+ await ceremonyCompletePromise;
1113
+ if (!rawPublicKey || !clientKeyShares) {
1114
+ throw new Error(ERROR_IMPORT_PRIVATE_KEY);
1115
+ }
1116
+ const accountAddress = ceremonyAccountAddress || this.deriveAccountAddress({
1117
+ rawPublicKey,
1118
+ addressType: addressTypeEnum,
1119
+ network
1120
+ }).accountAddress;
1121
+ if (publicAddressCheck && accountAddress !== publicAddressCheck) {
1122
+ throw new Error(`Public address mismatch: derived address ${accountAddress} !== public address ${publicAddressCheck}`);
1123
+ }
1124
+ await this.setClientKeySharesToLocalStorage({
1125
+ accountAddress,
1126
+ clientKeyShares,
1127
+ overwriteOrMerge: 'overwrite'
1128
+ });
1129
+ await this.storeEncryptedBackupByWalletWithRetry({
1130
+ accountAddress,
1131
+ clientKeyShares,
1132
+ password,
1133
+ signedSessionId
1134
+ });
1135
+ const publicKeyHex = this.extractPublicKeyHex(rawPublicKey);
1136
+ return {
1137
+ accountAddress,
1138
+ publicKeyHex,
1139
+ rawPublicKey
1140
+ };
1141
+ } catch (error) {
1142
+ this.logger.error(ERROR_IMPORT_PRIVATE_KEY, error);
1143
+ onError == null ? void 0 : onError(error);
1144
+ throw new Error(ERROR_IMPORT_PRIVATE_KEY);
1145
+ }
1146
+ }
1147
+ /**
897
1148
  * Converts MPC private key to Bitcoin WIF (Wallet Import Format)
898
1149
  * Uses the utility function from utils.ts for the core conversion logic
899
1150
  * @param privateKey - The private key to convert to a Bitcoin WIF format
@@ -980,6 +1231,22 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
980
1231
  }
981
1232
  const pubKey = normalizePublicKey(derivedPublicKey, addressType);
982
1233
  const tx = psbt.__CACHE.__TX;
1234
+ // Filter inputs to only sign those that belong to the current address
1235
+ const inputsToSign = psbt.data.inputs.map((input, i)=>({
1236
+ input,
1237
+ index: i
1238
+ })).filter(({ input })=>doesInputBelongToAddress(input, senderAddress, network));
1239
+ this.logger.debug('[BTC Client] signTransaction - Filtering inputs', {
1240
+ totalInputs: psbt.data.inputs.length,
1241
+ inputsToSign: inputsToSign.length,
1242
+ senderAddress
1243
+ });
1244
+ if (inputsToSign.length === 0) {
1245
+ this.logger.warn('[BTC Client] signTransaction - No inputs found for address', {
1246
+ senderAddress,
1247
+ totalInputs: psbt.data.inputs.length
1248
+ });
1249
+ }
983
1250
  if (addressType === BitcoinAddressType.TAPROOT) {
984
1251
  const tweak = calculateTaprootTweak(pubKey);
985
1252
  const completeBitcoinConfig = _extends({}, bitcoinConfig, {
@@ -987,7 +1254,7 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
987
1254
  tweak
988
1255
  });
989
1256
  const { prevOutScripts, values } = collectPSBTInputData(psbt);
990
- await Promise.all(psbt.data.inputs.map(async (input, i)=>{
1257
+ await Promise.all(inputsToSign.map(async ({ input, index: i })=>{
991
1258
  if (!input.witnessUtxo) {
992
1259
  throw new Error(`Input ${i} missing witnessUtxo`);
993
1260
  }
@@ -1016,17 +1283,16 @@ class DynamicBtcWalletClient extends DynamicWalletClient {
1016
1283
  addressType: addressType
1017
1284
  });
1018
1285
  // Iterate and sign inputs in parallel for better performance
1019
- await Promise.all(psbt.data.inputs.map(async (input, i)=>{
1286
+ await Promise.all(inputsToSign.map(async ({ input, index: i })=>{
1020
1287
  if (!input.witnessUtxo) {
1021
1288
  throw new Error(`Input ${i} missing witnessUtxo`);
1022
1289
  }
1023
1290
  const { script, value } = input.witnessUtxo;
1024
- // For Native SegWit (P2WPKH), use p2wpkh
1025
- const p2wpkh = bitcoin.payments.p2wpkh({
1026
- output: script,
1291
+ const p2pkh = bitcoin.payments.p2pkh({
1292
+ hash: script.slice(2),
1027
1293
  network: getBitcoinNetwork(network)
1028
1294
  });
1029
- const scriptCode = p2wpkh.output || script;
1295
+ const scriptCode = p2pkh.output;
1030
1296
  if (!scriptCode) throw new Error('Failed to generate scriptCode');
1031
1297
  const hash = tx.hashForWitnessV0(i, scriptCode, value, bitcoin.Transaction.SIGHASH_ALL);
1032
1298
  const signature = await this.sign({
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@dynamic-labs-wallet/btc",
3
- "version": "0.0.235",
3
+ "version": "0.0.237",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "dependencies": {
8
8
  "@dynamic-labs/sdk-api-core": "^0.0.828",
9
- "@dynamic-labs-wallet/browser": "0.0.235",
9
+ "@dynamic-labs-wallet/browser": "0.0.237",
10
10
  "@bitcoinerlab/secp256k1": "^1.2.0",
11
11
  "bitcoinjs-lib": "^7.0.0",
12
12
  "bip322-js": "^3.0.0",
@@ -95,6 +95,32 @@ export declare class DynamicBtcWalletClient extends DynamicWalletClient {
95
95
  signedSessionId: string;
96
96
  mfaToken?: string;
97
97
  }): Promise<string>;
98
+ /**
99
+ * Imports a private key and creates a Bitcoin wallet account
100
+ * @param privateKey - Private key in WIF format (Base58 encoded)
101
+ * @param chainName - Chain name ('BTC')
102
+ * @param thresholdSignatureScheme - The threshold signature scheme to use
103
+ * @param password - Optional password for encrypted backup
104
+ * @param onError - Optional error callback
105
+ * @param signedSessionId - The signed session ID
106
+ * @param publicAddressCheck - Optional address to validate against
107
+ * @param addressType - Bitcoin address type (NATIVE_SEGWIT or TAPROOT)
108
+ * @returns The account address, public key hex, and raw public key
109
+ */
110
+ importPrivateKey({ privateKey, chainName, thresholdSignatureScheme, password, onError, signedSessionId, publicAddressCheck, addressType, }: {
111
+ privateKey: string;
112
+ chainName: string;
113
+ thresholdSignatureScheme: ThresholdSignatureScheme;
114
+ password?: string;
115
+ onError?: (error: Error) => void;
116
+ signedSessionId: string;
117
+ publicAddressCheck?: string;
118
+ addressType?: string;
119
+ }): Promise<{
120
+ accountAddress: string;
121
+ publicKeyHex: string;
122
+ rawPublicKey: EcdsaPublicKey | BIP340KeygenResult | Uint8Array | string | undefined;
123
+ }>;
98
124
  /**
99
125
  * Converts MPC private key to Bitcoin WIF (Wallet Import Format)
100
126
  * Uses the utility function from utils.ts for the core conversion logic
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client/client.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"calculateBip322Hash.d.ts","sourceRoot":"","sources":["../../../src/utils/calculateBip322Hash/calculateBip322Hash.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGlE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,YACrB,MAAM,UACP,GAAG,eACE,kBAAkB,WACtB,cAAc,KACtB;IAAE,gBAAgB,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,GAAG,CAAA;CAoEjD,CAAC"}
1
+ {"version":3,"file":"calculateBip322Hash.d.ts","sourceRoot":"","sources":["../../../src/utils/calculateBip322Hash/calculateBip322Hash.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGlE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,YACrB,MAAM,UACP,GAAG,eACE,kBAAkB,WACtB,cAAc,KACtB;IAAE,gBAAgB,EAAE,UAAU,CAAC;IAAC,UAAU,EAAE,GAAG,CAAA;CAoEjD,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Psbt } from 'bitcoinjs-lib';
2
+ import type { BitcoinNetwork } from '../../types/index.js';
3
+ /**
4
+ * Checks if a PSBT input belongs to a specific address
5
+ * @param input - The PSBT input (from psbt.data.inputs)
6
+ * @param address - The address to check against
7
+ * @param network - The Bitcoin network
8
+ * @returns True if the input belongs to the address, false otherwise
9
+ */
10
+ export declare const doesInputBelongToAddress: (input: Psbt["data"]["inputs"][number], address: string, network: BitcoinNetwork) => boolean;
11
+ //# sourceMappingURL=doesInputBelongToAddress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doesInputBelongToAddress.d.ts","sourceRoot":"","sources":["../../../src/utils/doesInputBelongToAddress/doesInputBelongToAddress.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,UAC5B,IAAI,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,WAC5B,MAAM,WACN,cAAc,KACtB,OAwCF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { doesInputBelongToAddress } from './doesInputBelongToAddress.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/doesInputBelongToAddress/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"encodeBip322Signature.d.ts","sourceRoot":"","sources":["../../../src/utils/encodeBip322Signature/encodeBip322Signature.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,eACpB,GAAG,UACP,GAAG,aACA,cAAc,GAAG,UAAU,eACzB,kBAAkB,KAC9B,MAgDF,CAAC"}
1
+ {"version":3,"file":"encodeBip322Signature.d.ts","sourceRoot":"","sources":["../../../src/utils/encodeBip322Signature/encodeBip322Signature.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAEnE;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,eACpB,GAAG,UACP,GAAG,aACA,cAAc,GAAG,UAAU,eACzB,kBAAkB,KAC9B,MAgDF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"getAddressTypeFromDerivationPath.d.ts","sourceRoot":"","sources":["../../../src/utils/getAddressTypeFromDerivationPath/getAddressTypeFromDerivationPath.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,sBACxB,MAAM,KACxB,kBAyBF,CAAC"}
1
+ {"version":3,"file":"getAddressTypeFromDerivationPath.d.ts","sourceRoot":"","sources":["../../../src/utils/getAddressTypeFromDerivationPath/getAddressTypeFromDerivationPath.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,sBACxB,MAAM,KACxB,kBAyBF,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { BitcoinAddressType } from '@dynamic-labs-wallet/browser';
2
+ import type { BitcoinNetwork } from '../../types/index.js';
3
+ /**
4
+ * Derives a public key from a private key (WIF format) based on address type
5
+ *
6
+ * - For NATIVE_SEGWIT (ECDSA): Returns compressed public key (33 bytes)
7
+ * - For TAPROOT (BIP340): Returns x-only public key (32 bytes)
8
+ *
9
+ * @param privateKey - Private key in WIF format (Base58 encoded)
10
+ * @param addressType - Bitcoin address type (NATIVE_SEGWIT or TAPROOT)
11
+ * @param network - Bitcoin network (mainnet, testnet)
12
+ * @returns Public key as Buffer (33 bytes for NATIVE_SEGWIT, 32 bytes for TAPROOT)
13
+ * @throws Error if private key is invalid or derivation fails
14
+ */
15
+ export declare const getPublicKeyFromPrivateKey: (privateKey: string, addressType: BitcoinAddressType, network?: BitcoinNetwork) => Promise<Buffer>;
16
+ //# sourceMappingURL=getPublicKeyFromPrivateKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"getPublicKeyFromPrivateKey.d.ts","sourceRoot":"","sources":["../../../src/utils/getPublicKeyFromPrivateKey/getPublicKeyFromPrivateKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAI3D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,0BAA0B,eACzB,MAAM,eACL,kBAAkB,YACtB,cAAc,KACtB,OAAO,CAAC,MAAM,CAsChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { getPublicKeyFromPrivateKey } from './getPublicKeyFromPrivateKey.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/getPublicKeyFromPrivateKey/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC"}
@@ -4,6 +4,8 @@ export { getAddressTypeFromDerivationPath } from './getAddressTypeFromDerivation
4
4
  export { calculateBip322Hash } from './calculateBip322Hash/index.js';
5
5
  export { encodeBip322Signature } from './encodeBip322Signature/index.js';
6
6
  export { privateKeyToWIF } from './privateKeyToWIF/index.js';
7
+ export { wifToPrivateKey } from './wifToPrivateKey/index.js';
8
+ export { getPublicKeyFromPrivateKey } from './getPublicKeyFromPrivateKey/index.js';
7
9
  export { convertSignatureToDER } from './convertSignatureToDER/index.js';
8
10
  export { getUTXOs } from './getUTXOs/index.js';
9
11
  export { selectUTXOs } from './selectUTXOs/index.js';
@@ -12,4 +14,5 @@ export { getDefaultRpcUrl } from './getDefaultRpcUrl/index.js';
12
14
  export { calculateTaprootTweak } from './calculateTaprootTweak/index.js';
13
15
  export { convertSignatureToTaprootBuffer } from './convertSignatureToTaprootBuffer/index.js';
14
16
  export { collectPSBTInputData } from './collectPSBTInputData/index.js';
17
+ export { doesInputBelongToAddress } from './doesInputBelongToAddress/index.js';
15
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,gCAAgC,EAAE,MAAM,6CAA6C,CAAC;AAC/F,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,sCAAsC,CAAC;AACjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAE,gCAAgC,EAAE,MAAM,6CAA6C,CAAC;AAC/F,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,0BAA0B,EAAE,MAAM,uCAAuC,CAAC;AACnF,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,EAAE,+BAA+B,EAAE,MAAM,4CAA4C,CAAC;AAC7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC"}
@@ -1,5 +1,4 @@
1
- import type { EcdsaPublicKey } from '@dynamic-labs-wallet/browser';
2
- import { BitcoinAddressType } from '@dynamic-labs-wallet/browser';
1
+ import { type EcdsaPublicKey, BitcoinAddressType } from '@dynamic-labs-wallet/browser';
3
2
  /**
4
3
  * Normalizes a public key to a standard Buffer format
5
4
  * Handles various input types (Uint8Array, Buffer, object with pubKeyAsHex, etc.)
@@ -1 +1 @@
1
- {"version":3,"file":"normalizePublicKey.d.ts","sourceRoot":"","sources":["../../../src/utils/normalizePublicKey/normalizePublicKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAKlE;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,WACrB,cAAc,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,gBACvC,kBAAkB,KAC/B,MAQF,CAAC"}
1
+ {"version":3,"file":"normalizePublicKey.d.ts","sourceRoot":"","sources":["../../../src/utils/normalizePublicKey/normalizePublicKey.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,cAAc,EACnB,kBAAkB,EACnB,MAAM,8BAA8B,CAAC;AAMtC;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,WACrB,cAAc,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,gBACvC,kBAAkB,KAC/B,MAQF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"publicKeyToBitcoinAddress.d.ts","sourceRoot":"","sources":["../../../src/utils/publicKeyToBitcoinAddress/publicKeyToBitcoinAddress.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAM3D;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,cACzB,MAAM,GAAG,UAAU,gBACjB,kBAAkB,YACtB,cAAc,KACtB,MAeF,CAAC"}
1
+ {"version":3,"file":"publicKeyToBitcoinAddress.d.ts","sourceRoot":"","sources":["../../../src/utils/publicKeyToBitcoinAddress/publicKeyToBitcoinAddress.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAM3D;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,cACzB,MAAM,GAAG,UAAU,gBACjB,kBAAkB,YACtB,cAAc,KACtB,MAeF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { wifToPrivateKey } from './wifToPrivateKey.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/utils/wifToPrivateKey/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { BitcoinNetwork } from '../../types/index.js';
2
+ /**
3
+ * Converts a Bitcoin WIF (Wallet Import Format) private key to hex format
4
+ * This is the reverse operation of `privateKeyToWIF`
5
+ *
6
+ * WIF decoding steps:
7
+ * 1. Base58 decode the WIF string
8
+ * 2. Validate network prefix
9
+ * 3. Validate checksum (double SHA-256, first 4 bytes)
10
+ * 4. Extract private key bytes (skip prefix, compression flag, and checksum)
11
+ * 5. Convert to hex string
12
+ *
13
+ * @param wif - Private key in WIF format (Base58 encoded)
14
+ * @param network - Bitcoin network (mainnet, testnet)
15
+ * @returns Private key as hex string (64 characters, 32 bytes)
16
+ * @throws Error if WIF format is invalid
17
+ */
18
+ export declare const wifToPrivateKey: (wif: string, network?: BitcoinNetwork) => string;
19
+ //# sourceMappingURL=wifToPrivateKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wifToPrivateKey.d.ts","sourceRoot":"","sources":["../../../src/utils/wifToPrivateKey/wifToPrivateKey.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAG3D;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,eAAe,QACrB,MAAM,YACF,cAAc,KACtB,MAkDF,CAAC"}