@dynamic-labs-wallet/btc 0.0.253 → 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.
Files changed (115) hide show
  1. package/index.cjs.js +31 -763
  2. package/index.esm.js +10 -743
  3. package/package.json +4 -6
  4. package/src/client/client.d.ts +0 -6
  5. package/src/client/client.d.ts.map +1 -1
  6. package/src/utils/index.d.ts +0 -17
  7. package/src/utils/index.d.ts.map +1 -1
  8. package/src/utils/calculateBip322Hash/calculateBip322Hash.d.ts +0 -16
  9. package/src/utils/calculateBip322Hash/calculateBip322Hash.d.ts.map +0 -1
  10. package/src/utils/calculateBip322Hash/index.d.ts +0 -2
  11. package/src/utils/calculateBip322Hash/index.d.ts.map +0 -1
  12. package/src/utils/calculateTaprootTweak/calculateTaprootTweak.d.ts +0 -7
  13. package/src/utils/calculateTaprootTweak/calculateTaprootTweak.d.ts.map +0 -1
  14. package/src/utils/calculateTaprootTweak/index.d.ts +0 -2
  15. package/src/utils/calculateTaprootTweak/index.d.ts.map +0 -1
  16. package/src/utils/collectPSBTInputData/collectPSBTInputData.d.ts +0 -13
  17. package/src/utils/collectPSBTInputData/collectPSBTInputData.d.ts.map +0 -1
  18. package/src/utils/collectPSBTInputData/index.d.ts +0 -2
  19. package/src/utils/collectPSBTInputData/index.d.ts.map +0 -1
  20. package/src/utils/convertPublicKeyToBuffer/convertPublicKeyToBuffer.d.ts +0 -10
  21. package/src/utils/convertPublicKeyToBuffer/convertPublicKeyToBuffer.d.ts.map +0 -1
  22. package/src/utils/convertPublicKeyToBuffer/index.d.ts +0 -2
  23. package/src/utils/convertPublicKeyToBuffer/index.d.ts.map +0 -1
  24. package/src/utils/convertSignatureToDER/convertSignatureToDER.d.ts +0 -9
  25. package/src/utils/convertSignatureToDER/convertSignatureToDER.d.ts.map +0 -1
  26. package/src/utils/convertSignatureToDER/index.d.ts +0 -2
  27. package/src/utils/convertSignatureToDER/index.d.ts.map +0 -1
  28. package/src/utils/convertSignatureToTaprootBuffer/convertSignatureToTaprootBuffer.d.ts +0 -9
  29. package/src/utils/convertSignatureToTaprootBuffer/convertSignatureToTaprootBuffer.d.ts.map +0 -1
  30. package/src/utils/convertSignatureToTaprootBuffer/index.d.ts +0 -2
  31. package/src/utils/convertSignatureToTaprootBuffer/index.d.ts.map +0 -1
  32. package/src/utils/createLegacyAddress/createLegacyAddress.d.ts +0 -10
  33. package/src/utils/createLegacyAddress/createLegacyAddress.d.ts.map +0 -1
  34. package/src/utils/createLegacyAddress/index.d.ts +0 -2
  35. package/src/utils/createLegacyAddress/index.d.ts.map +0 -1
  36. package/src/utils/createNativeSegWitAddress/createNativeSegWitAddress.d.ts +0 -10
  37. package/src/utils/createNativeSegWitAddress/createNativeSegWitAddress.d.ts.map +0 -1
  38. package/src/utils/createNativeSegWitAddress/index.d.ts +0 -2
  39. package/src/utils/createNativeSegWitAddress/index.d.ts.map +0 -1
  40. package/src/utils/createSegWitAddress/createSegWitAddress.d.ts +0 -10
  41. package/src/utils/createSegWitAddress/createSegWitAddress.d.ts.map +0 -1
  42. package/src/utils/createSegWitAddress/index.d.ts +0 -2
  43. package/src/utils/createSegWitAddress/index.d.ts.map +0 -1
  44. package/src/utils/createTaprootAddress/createTaprootAddress.d.ts +0 -10
  45. package/src/utils/createTaprootAddress/createTaprootAddress.d.ts.map +0 -1
  46. package/src/utils/createTaprootAddress/index.d.ts +0 -2
  47. package/src/utils/createTaprootAddress/index.d.ts.map +0 -1
  48. package/src/utils/doesInputBelongToAddress/doesInputBelongToAddress.d.ts +0 -11
  49. package/src/utils/doesInputBelongToAddress/doesInputBelongToAddress.d.ts.map +0 -1
  50. package/src/utils/doesInputBelongToAddress/index.d.ts +0 -2
  51. package/src/utils/doesInputBelongToAddress/index.d.ts.map +0 -1
  52. package/src/utils/encodeBip322Signature/encodeBip322Signature.d.ts +0 -13
  53. package/src/utils/encodeBip322Signature/encodeBip322Signature.d.ts.map +0 -1
  54. package/src/utils/encodeBip322Signature/index.d.ts +0 -2
  55. package/src/utils/encodeBip322Signature/index.d.ts.map +0 -1
  56. package/src/utils/getAddressTypeFromDerivationPath/getAddressTypeFromDerivationPath.d.ts +0 -9
  57. package/src/utils/getAddressTypeFromDerivationPath/getAddressTypeFromDerivationPath.d.ts.map +0 -1
  58. package/src/utils/getAddressTypeFromDerivationPath/index.d.ts +0 -2
  59. package/src/utils/getAddressTypeFromDerivationPath/index.d.ts.map +0 -1
  60. package/src/utils/getBitcoinNetwork/getBitcoinNetwork.d.ts +0 -10
  61. package/src/utils/getBitcoinNetwork/getBitcoinNetwork.d.ts.map +0 -1
  62. package/src/utils/getBitcoinNetwork/index.d.ts +0 -2
  63. package/src/utils/getBitcoinNetwork/index.d.ts.map +0 -1
  64. package/src/utils/getDefaultRpcUrl/getDefaultRpcUrl.d.ts +0 -9
  65. package/src/utils/getDefaultRpcUrl/getDefaultRpcUrl.d.ts.map +0 -1
  66. package/src/utils/getDefaultRpcUrl/index.d.ts +0 -2
  67. package/src/utils/getDefaultRpcUrl/index.d.ts.map +0 -1
  68. package/src/utils/getFeeRates/getFeeRates.d.ts +0 -18
  69. package/src/utils/getFeeRates/getFeeRates.d.ts.map +0 -1
  70. package/src/utils/getFeeRates/index.d.ts +0 -2
  71. package/src/utils/getFeeRates/index.d.ts.map +0 -1
  72. package/src/utils/getPublicKeyFromPrivateKey/getPublicKeyFromPrivateKey.d.ts +0 -16
  73. package/src/utils/getPublicKeyFromPrivateKey/getPublicKeyFromPrivateKey.d.ts.map +0 -1
  74. package/src/utils/getPublicKeyFromPrivateKey/index.d.ts +0 -2
  75. package/src/utils/getPublicKeyFromPrivateKey/index.d.ts.map +0 -1
  76. package/src/utils/getUTXOs/getUTXOs.d.ts +0 -15
  77. package/src/utils/getUTXOs/getUTXOs.d.ts.map +0 -1
  78. package/src/utils/getUTXOs/index.d.ts +0 -2
  79. package/src/utils/getUTXOs/index.d.ts.map +0 -1
  80. package/src/utils/initEccLib/index.d.ts +0 -2
  81. package/src/utils/initEccLib/index.d.ts.map +0 -1
  82. package/src/utils/initEccLib/initEccLib.d.ts +0 -5
  83. package/src/utils/initEccLib/initEccLib.d.ts.map +0 -1
  84. package/src/utils/normalizeForCompressed/index.d.ts +0 -2
  85. package/src/utils/normalizeForCompressed/index.d.ts.map +0 -1
  86. package/src/utils/normalizeForCompressed/normalizeForCompressed.d.ts +0 -9
  87. package/src/utils/normalizeForCompressed/normalizeForCompressed.d.ts.map +0 -1
  88. package/src/utils/normalizeForTaproot/index.d.ts +0 -2
  89. package/src/utils/normalizeForTaproot/index.d.ts.map +0 -1
  90. package/src/utils/normalizeForTaproot/normalizeForTaproot.d.ts +0 -9
  91. package/src/utils/normalizeForTaproot/normalizeForTaproot.d.ts.map +0 -1
  92. package/src/utils/normalizePublicKey/index.d.ts +0 -2
  93. package/src/utils/normalizePublicKey/index.d.ts.map +0 -1
  94. package/src/utils/normalizePublicKey/normalizePublicKey.d.ts +0 -13
  95. package/src/utils/normalizePublicKey/normalizePublicKey.d.ts.map +0 -1
  96. package/src/utils/privateKeyToWIF/index.d.ts +0 -2
  97. package/src/utils/privateKeyToWIF/index.d.ts.map +0 -1
  98. package/src/utils/privateKeyToWIF/privateKeyToWIF.d.ts +0 -24
  99. package/src/utils/privateKeyToWIF/privateKeyToWIF.d.ts.map +0 -1
  100. package/src/utils/publicKeyToBitcoinAddress/index.d.ts +0 -2
  101. package/src/utils/publicKeyToBitcoinAddress/index.d.ts.map +0 -1
  102. package/src/utils/publicKeyToBitcoinAddress/publicKeyToBitcoinAddress.d.ts +0 -12
  103. package/src/utils/publicKeyToBitcoinAddress/publicKeyToBitcoinAddress.d.ts.map +0 -1
  104. package/src/utils/selectUTXOs/index.d.ts +0 -2
  105. package/src/utils/selectUTXOs/index.d.ts.map +0 -1
  106. package/src/utils/selectUTXOs/selectUTXOs.d.ts +0 -19
  107. package/src/utils/selectUTXOs/selectUTXOs.d.ts.map +0 -1
  108. package/src/utils/toBuffer/index.d.ts +0 -2
  109. package/src/utils/toBuffer/index.d.ts.map +0 -1
  110. package/src/utils/toBuffer/toBuffer.d.ts +0 -8
  111. package/src/utils/toBuffer/toBuffer.d.ts.map +0 -1
  112. package/src/utils/wifToPrivateKey/index.d.ts +0 -2
  113. package/src/utils/wifToPrivateKey/index.d.ts.map +0 -1
  114. package/src/utils/wifToPrivateKey/wifToPrivateKey.d.ts +0 -19
  115. package/src/utils/wifToPrivateKey/wifToPrivateKey.d.ts.map +0 -1
package/index.cjs.js CHANGED
@@ -3,9 +3,7 @@
3
3
  var browser = require('@dynamic-labs-wallet/browser');
4
4
  var bitcoin = require('bitcoinjs-lib');
5
5
  var ecc = require('@bitcoinerlab/secp256k1');
6
- var bip322Js = require('bip322-js');
7
- var bs58 = require('bs58');
8
- var sha256 = require('@noble/hashes/sha256');
6
+ var btcUtils = require('@dynamic-labs-wallet/btc-utils');
9
7
 
10
8
  function _interopNamespaceDefault(e) {
11
9
  var n = Object.create(null);
@@ -37,722 +35,6 @@ function _extends() {
37
35
  return _extends.apply(this, arguments);
38
36
  }
39
37
 
40
- /**
41
- * Maps a BitcoinNetwork string to a bitcoinjs-lib Network object.
42
- *
43
- * @param network - The network identifier ('mainnet' or 'testnet').
44
- * @returns The corresponding bitcoinjs-lib Network object. Defaults to bitcoin mainnet if the network is not recognized.
45
- */ function getBitcoinNetwork(network) {
46
- switch(network){
47
- case 'mainnet':
48
- return bitcoin__namespace.networks.bitcoin;
49
- case 'testnet':
50
- return bitcoin__namespace.networks.testnet;
51
- default:
52
- return bitcoin__namespace.networks.bitcoin;
53
- }
54
- }
55
-
56
- /**
57
- * Helper to handle Buffer/Uint8Array compatibility issues
58
- *
59
- * @param data - The data to convert to a Buffer
60
- * @returns The Buffer representation of the data
61
- */ const toBuffer = (data)=>{
62
- if (Buffer.isBuffer(data)) return data;
63
- return Buffer.from(data);
64
- };
65
-
66
- /**
67
- * Creates a native SegWit P2WPKH address
68
- *
69
- * @param pubKey - The public key
70
- * @param networkName - The network name
71
- * @returns The native SegWit address
72
- */ const createNativeSegWitAddress = (pubKey, networkName)=>{
73
- const network = getBitcoinNetwork(networkName);
74
- // Convert to Uint8Array
75
- let pubKeyArray = Uint8Array.from(pubKey);
76
- // If it's an uncompressed key (65 bytes), compress it (33 bytes)
77
- if (pubKeyArray.length === 65) {
78
- // Uncompressed format: 0x04 || x (32 bytes) || y (32 bytes)
79
- // Compressed format: 0x02 or 0x03 || x (32 bytes)
80
- const y = pubKeyArray[64];
81
- const compressedX = pubKeyArray.slice(1, 33); // Skip the 0x04 prefix, take x (32 bytes)
82
- const compressed = new Uint8Array(33);
83
- compressed[0] = y % 2 === 0 ? 0x02 : 0x03; // Even y -> 0x02, Odd y -> 0x03
84
- compressed.set(compressedX, 1);
85
- pubKeyArray = compressed;
86
- }
87
- const { address } = bitcoin.payments.p2wpkh({
88
- pubkey: toBuffer(pubKeyArray),
89
- network
90
- });
91
- return address || '';
92
- };
93
-
94
- let isInitialized = false;
95
- /**
96
- * Initializes the ECC library if not already initialized
97
- */ const initEccLib = ()=>{
98
- if (isInitialized) return;
99
- bitcoin.initEccLib(ecc);
100
- isInitialized = true;
101
- };
102
-
103
- /**
104
- * Creates a Taproot P2TR address
105
- *
106
- * @param pubKey - The public key
107
- * @param networkName - The network name
108
- * @returns The Taproot address
109
- */ const createTaprootAddress = (pubKey, networkName)=>{
110
- initEccLib();
111
- const network = getBitcoinNetwork(networkName);
112
- // For Taproot, we need the 32-byte x-only public key
113
- const xOnlyPubKey = pubKey.subarray(-32);
114
- const xOnlyPubKeyArray = Uint8Array.from(xOnlyPubKey);
115
- const { address } = bitcoin.payments.p2tr({
116
- internalPubkey: toBuffer(xOnlyPubKeyArray),
117
- network
118
- });
119
- if (!address) {
120
- throw new Error('Failed to create Taproot address');
121
- }
122
- return address;
123
- };
124
-
125
- // eslint-disable-next-line @nx/enforce-module-boundaries
126
- /**
127
- * Converts a public key to a Bitcoin address
128
- *
129
- * @param publicKey - The public key
130
- * @param addressType - The address type (default: TAPROOT)
131
- * @param network - The Bitcoin network (default: 'mainnet')
132
- * @returns The Bitcoin address
133
- */ const publicKeyToBitcoinAddress = (publicKey, addressType = browser.BitcoinAddressType.TAPROOT, network = 'mainnet')=>{
134
- initEccLib();
135
- // Convert to Uint8Array to Buffer if needed
136
- const pubKeyBuffer = toBuffer(publicKey);
137
- switch(addressType){
138
- case browser.BitcoinAddressType.NATIVE_SEGWIT:
139
- return createNativeSegWitAddress(pubKeyBuffer, network);
140
- case browser.BitcoinAddressType.TAPROOT:
141
- return createTaprootAddress(pubKeyBuffer, network);
142
- default:
143
- throw new Error(`Unsupported address type: ${addressType}`);
144
- }
145
- };
146
-
147
- /**
148
- * Converts a public key input (various formats) to a Buffer.
149
- * Handles objects with `pubkey` property, numeric key maps, `serializeUncompressed` methods, etc.
150
- *
151
- * @param pubkey - The raw public key input
152
- * @returns The public key as a Buffer
153
- */ const convertPublicKeyToBuffer = (pubkey)=>{
154
- const actualPubkey = pubkey;
155
- if (Buffer.isBuffer(actualPubkey)) {
156
- return actualPubkey;
157
- }
158
- if (actualPubkey instanceof Uint8Array) {
159
- return Buffer.from(actualPubkey);
160
- }
161
- if (typeof actualPubkey === 'string') {
162
- const result = Buffer.from(actualPubkey, 'hex');
163
- if (result.length === 0) {
164
- throw new Error('Invalid public key format');
165
- }
166
- return result;
167
- }
168
- if (typeof actualPubkey === 'object' && actualPubkey !== null) {
169
- return convertObjectToBuffer(actualPubkey);
170
- }
171
- throw new Error('Invalid public key format');
172
- };
173
- const convertObjectToBuffer = (actualPubkey)=>{
174
- if ('pubkey' in actualPubkey) {
175
- return convertPublicKeyToBuffer(actualPubkey.pubkey);
176
- }
177
- if ('serializeUncompressed' in actualPubkey && typeof actualPubkey.serializeUncompressed === 'function') {
178
- return Buffer.from(actualPubkey.serializeUncompressed());
179
- }
180
- const keys = Object.keys(actualPubkey).map(Number).filter((k)=>!Number.isNaN(k)).sort((a, b)=>a - b);
181
- if (keys.length > 0) {
182
- return Buffer.from(keys.map((k)=>actualPubkey[k]));
183
- }
184
- throw new Error('Invalid public key object');
185
- };
186
-
187
- /**
188
- * Normalizes a public key buffer for Taproot (P2TR).
189
- * Ensures the result is a 32-byte x-only key.
190
- *
191
- * @param buffer - The public key buffer
192
- * @returns The 32-byte x-only public key buffer
193
- */ const normalizeForTaproot = (buffer)=>{
194
- if (buffer.length === 32) return buffer;
195
- if (buffer.length === 33) return buffer.subarray(1, 33);
196
- if (buffer.length === 65) return buffer.subarray(1, 33);
197
- if (buffer.length === 64) return buffer.subarray(0, 32);
198
- throw new Error(`Unexpected public key length for Taproot: ${buffer.length}`);
199
- };
200
-
201
- /**
202
- * Normalizes a public key buffer for Compressed formats (Legacy, SegWit, Native SegWit).
203
- * Ensures the result is a 33-byte compressed key.
204
- *
205
- * @param buffer - The public key buffer
206
- * @returns The 33-byte compressed public key buffer
207
- */ const normalizeForCompressed = (buffer)=>{
208
- if (buffer.length === 33) {
209
- return buffer;
210
- }
211
- if (buffer.length === 65 && buffer[0] === 0x04) {
212
- // Uncompressed standard (04 + X + Y)
213
- const x = buffer.subarray(1, 33);
214
- const yLastByte = buffer[64];
215
- return compressPublicKey(x, yLastByte);
216
- }
217
- if (buffer.length === 64) {
218
- // Raw X + Y (missing 04 prefix)
219
- const x = buffer.subarray(0, 32);
220
- const yLastByte = buffer[63];
221
- return compressPublicKey(x, yLastByte);
222
- }
223
- throw new Error(`Unexpected public key length: ${buffer.length}`);
224
- };
225
- const compressPublicKey = (x, yLastByte)=>{
226
- const prefix = yLastByte % 2 === 0 ? 0x02 : 0x03;
227
- return Buffer.concat([
228
- Buffer.from([
229
- prefix
230
- ]),
231
- x
232
- ]);
233
- };
234
-
235
- // eslint-disable @nx/enforce-module-boundaries
236
- /**
237
- * Normalizes a public key to a standard Buffer format
238
- * Handles various input types (Uint8Array, Buffer, object with pubKeyAsHex, etc.)
239
- * and formats (32-byte x-only, 33-byte compressed, 65-byte uncompressed)
240
- * based on the target address type.
241
- *
242
- * @param pubkey - The raw public key input
243
- * @param addressType - The target Bitcoin address type
244
- * @returns The normalized public key as a Buffer
245
- */ const normalizePublicKey = (pubkey, addressType)=>{
246
- const buffer = convertPublicKeyToBuffer(pubkey);
247
- if (addressType === browser.BitcoinAddressType.TAPROOT) {
248
- return normalizeForTaproot(buffer);
249
- }
250
- return normalizeForCompressed(buffer);
251
- };
252
-
253
- // eslint-disable-next-line @nx/enforce-module-boundaries
254
- /**
255
- * Infers the Bitcoin address type from a BIP-44 derivation path
256
- *
257
- * @param derivationPathStr - The derivation path string (e.g. "m/44'/0'/0'/0/0" as JSON or string)
258
- * @returns The inferred BitcoinAddressType
259
- */ const getAddressTypeFromDerivationPath = (derivationPathStr)=>{
260
- const derivationPathObj = JSON.parse(derivationPathStr);
261
- const path = Object.values(derivationPathObj).map(Number);
262
- if (path.length < 2) throw new Error('Invalid derivation path length');
263
- const purpose = path[0];
264
- // Handle both raw and hardened just in case, or just raw if strictly non-hardened
265
- // 44 = 0x2C (Legacy), 49 = 0x31 (SegWit P2SH), 84 = 0x54 (Native SegWit), 86 = 0x56 (Taproot)
266
- const purposeIndex = purpose >= 0x80000000 ? purpose - 0x80000000 : purpose;
267
- let addressType;
268
- switch(purposeIndex){
269
- case 84:
270
- addressType = browser.BitcoinAddressType.NATIVE_SEGWIT;
271
- break;
272
- case 86:
273
- addressType = browser.BitcoinAddressType.TAPROOT;
274
- break;
275
- default:
276
- throw new Error(`Unknown derivation path purpose: ${purposeIndex}`);
277
- }
278
- return addressType;
279
- };
280
-
281
- /**
282
- * Calculates the hash to be signed for a BIP-322 message verification
283
- *
284
- * @param message - The message to sign
285
- * @param pubKey - The public key of the signer
286
- * @param addressType - The address type (e.g. TAPROOT, SEGWIT)
287
- * @param network - The Bitcoin network
288
- * @returns The formatted message hash and the PSBT to be signed
289
- */ const calculateBip322Hash = (message, pubKey, addressType, network)=>{
290
- // Normalize key and derive address
291
- const normalizedKey = normalizePublicKey(pubKey, addressType);
292
- const address = publicKeyToBitcoinAddress(normalizedKey, addressType, network);
293
- if (!address) {
294
- throw new Error('Failed to generate address for BIP-322');
295
- }
296
- const scriptPubKey = bip322Js.Address.convertAdressToScriptPubkey(address);
297
- const toSpendTx = bip322Js.BIP322.buildToSpendTx(message, scriptPubKey);
298
- const toSignPsbt = bip322Js.BIP322.buildToSignTx(toSpendTx.getId(), scriptPubKey);
299
- // Calculate Hash to Sign
300
- const txToSign = toSignPsbt.__CACHE.__TX; // Access underlying TX like prototype
301
- let hashToSign;
302
- if (addressType === browser.BitcoinAddressType.TAPROOT) {
303
- // Taproot (BIP-341) Signing
304
- const prevOutScripts = [
305
- scriptPubKey
306
- ];
307
- const values = [
308
- 0
309
- ]; // BIP-322 value
310
- // Cast to any to avoid type issues if definition is missing
311
- hashToSign = Buffer.from(txToSign.hashForWitnessV1(0, prevOutScripts, values, bitcoin__namespace.Transaction.SIGHASH_DEFAULT // Default sighash for Taproot
312
- ));
313
- } else {
314
- // SegWit (BIP-143) Signing (P2WPKH)
315
- const txToSignSegwit = new bitcoin__namespace.Transaction();
316
- txToSignSegwit.version = 0;
317
- txToSignSegwit.locktime = 0;
318
- const prevTxId = toSpendTx.getId();
319
- const prevHash = Buffer.from(prevTxId, 'hex').reverse();
320
- txToSignSegwit.addInput(prevHash, 0, 0);
321
- txToSignSegwit.addOutput(Buffer.from([
322
- 0x6a
323
- ]), BigInt(0));
324
- const p2pkh = bitcoin__namespace.payments.p2pkh({
325
- pubkey: normalizedKey,
326
- network: network === 'testnet' ? bitcoin__namespace.networks.testnet : bitcoin__namespace.networks.bitcoin
327
- });
328
- const scriptCode = p2pkh.output;
329
- if (!scriptCode) throw new Error('Failed to generate scriptCode');
330
- hashToSign = txToSignSegwit.hashForWitnessV0(0, scriptCode, BigInt(0), bitcoin__namespace.Transaction.SIGHASH_ALL);
331
- }
332
- return {
333
- formattedMessage: new Uint8Array(hashToSign),
334
- toSignPsbt
335
- };
336
- };
337
-
338
- /**
339
- * Encodes the signature into the BIP-322 witness format
340
- *
341
- * @param toSignPsbt - The PSBT that was signed
342
- * @param pubKey - The public key of the signer
343
- * @param signature - The signature produced by the signer
344
- * @param addressType - The address type
345
- * @returns The base64 encoded BIP-322 signature
346
- */ const encodeBip322Signature = (toSignPsbt, pubKey, signature, addressType)=>{
347
- const normalizedKey = normalizePublicKey(pubKey, addressType);
348
- if (addressType === browser.BitcoinAddressType.TAPROOT) {
349
- // Prototype logic: direct update
350
- // Signature from MPC should be 64 bytes (r|s)
351
- let sigBuffer;
352
- if (signature instanceof Uint8Array || Buffer.isBuffer(signature)) {
353
- sigBuffer = Buffer.from(signature);
354
- } else {
355
- // ECDSA signature object? Should be raw bytes for Schnorr/BIP340
356
- // If it's EcdsaSignature (r,s), concat them.
357
- const r = signature.r;
358
- const s = signature.s;
359
- const rBuf = Buffer.isBuffer(r) ? r : Buffer.from(r);
360
- const sBuf = Buffer.isBuffer(s) ? s : Buffer.from(s);
361
- sigBuffer = Buffer.concat([
362
- rBuf,
363
- sBuf
364
- ]);
365
- }
366
- toSignPsbt.updateInput(0, {
367
- tapKeySig: sigBuffer
368
- });
369
- } else {
370
- // Serialize the signature (COMPACT SIGNATURE)
371
- const r = signature.r;
372
- const s = signature.s;
373
- const compactSignature = Buffer.concat([
374
- Buffer.from(r),
375
- Buffer.from(s)
376
- ]);
377
- // Apply Signature
378
- const mpcSignerForPsbt = {
379
- publicKey: normalizedKey,
380
- sign: (_hash)=>{
381
- return compactSignature;
382
- }
383
- };
384
- // Sign the input
385
- toSignPsbt.signInput(0, mpcSignerForPsbt);
386
- }
387
- // Finalize the inputs
388
- toSignPsbt.finalizeAllInputs();
389
- // Encode Final Result
390
- return bip322Js.BIP322.encodeWitness(toSignPsbt);
391
- };
392
-
393
- initEccLib();
394
- /**
395
- * Converts a private key (hex string) to Bitcoin WIF (Wallet Import Format)
396
- * WIF is the standard format that Bitcoin wallets expect for importing private keys
397
- *
398
- * WIF encoding steps:
399
- * 1. Add network prefix (0x80 for mainnet, 0xef for testnet/regtest)
400
- * 2. Add compression flag (0x01) for compressed public keys (used for SegWit)
401
- * 3. Calculate checksum (double SHA-256, take first 4 bytes)
402
- * 4. Base58 encode the result
403
- *
404
- * @param privateKey - Private key as hex string (with or without 0x prefix)
405
- * @param network - Bitcoin network (mainnet, testnet)
406
- * @param options - Optional configuration
407
- * @param options.compressed - Whether to use compressed format (default: true for SegWit compatibility)
408
- * @param options.onWarning - Optional callback for warnings (e.g., unexpected key length)
409
- * @returns WIF-encoded private key string
410
- * @throws Error if conversion fails
411
- */ const privateKeyToWIF = (privateKey, network = 'mainnet', options)=>{
412
- const { compressed = true, onWarning } = options || {};
413
- try {
414
- // Remove 0x prefix if present
415
- const cleanPrivateKey = privateKey.startsWith('0x') ? privateKey.slice(2) : privateKey;
416
- // Validate hex string length (should be 64 characters = 32 bytes)
417
- if (cleanPrivateKey.length !== 64) {
418
- onWarning == null ? void 0 : onWarning('Unexpected private key length', {
419
- length: cleanPrivateKey.length,
420
- expected: 64
421
- });
422
- }
423
- // Convert hex to Uint8Array
424
- const privateKeyBytes = new Uint8Array(cleanPrivateKey.match(/.{1,2}/g).map((byte)=>Number.parseInt(byte, 16)));
425
- // Step 1: Get network prefix from bitcoinjs-lib network
426
- const networkConfig = getBitcoinNetwork(network);
427
- const networkPrefix = networkConfig.wif;
428
- // Step 2: Build extended key with network prefix and optional compression flag
429
- // For Native SegWit and SegWit, we use compressed format (0x01 flag)
430
- const extendedKeyLength = compressed ? 34 : 33; // 1 byte prefix + 32 bytes key + (optional) 1 byte compression
431
- const extendedKey = new Uint8Array(extendedKeyLength);
432
- extendedKey[0] = networkPrefix;
433
- extendedKey.set(privateKeyBytes, 1);
434
- if (compressed) {
435
- extendedKey[33] = 0x01; // Compression flag for SegWit addresses
436
- }
437
- // Step 3: Calculate checksum (double SHA-256, take first 4 bytes)
438
- const firstHash = sha256.sha256(extendedKey);
439
- const secondHash = sha256.sha256(firstHash);
440
- const checksum = secondHash.slice(0, 4);
441
- // Step 4: Append checksum and Base58 encode
442
- const wifBytes = new Uint8Array(extendedKey.length + checksum.length);
443
- wifBytes.set(extendedKey, 0);
444
- wifBytes.set(checksum, extendedKey.length);
445
- const wif = bs58.encode(wifBytes);
446
- return wif;
447
- } catch (error) {
448
- // Re-throw with more context
449
- throw new Error(`Failed to convert private key to WIF: ${error instanceof Error ? error.message : String(error)}`);
450
- }
451
- };
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
-
548
- /**
549
- * Converts an ECDSA signature to DER format
550
- *
551
- * @param signature - The ECDSA signature
552
- * @returns The DER encoded signature
553
- */ const convertSignatureToDER = (signature)=>{
554
- // Construct raw 64-byte signature (r + s) using Uint8Array to ensure compatibility
555
- const r = signature.r instanceof Uint8Array ? signature.r : new Uint8Array(signature.r);
556
- const s = signature.s instanceof Uint8Array ? signature.s : new Uint8Array(signature.s);
557
- // Enforce 32-byte length (padding or slicing if needed)
558
- const r32 = new Uint8Array(32);
559
- const rSource = r.length > 32 ? r.slice(-32) : r;
560
- r32.set(rSource, 32 - rSource.length);
561
- const s32 = new Uint8Array(32);
562
- const sSource = s.length > 32 ? s.slice(-32) : s;
563
- s32.set(sSource, 32 - sSource.length);
564
- const rawSignature = new Uint8Array(64);
565
- rawSignature.set(r32, 0);
566
- rawSignature.set(s32, 32);
567
- const derSignature = bitcoin__namespace.script.signature.encode(rawSignature, bitcoin__namespace.Transaction.SIGHASH_ALL);
568
- return derSignature;
569
- };
570
-
571
- /**
572
- * Helper to get the default RPC URL
573
- *
574
- * @param network - The Bitcoin network
575
- * @returns The default RPC URL
576
- */ const getDefaultRpcUrl = (network)=>{
577
- return network === 'mainnet' ? 'https://mempool.space/api' : 'https://mempool.space/testnet/api';
578
- };
579
-
580
- /**
581
- * Fetches UTXOs for a given address using mempool.space API
582
- *
583
- * @param address - The address to fetch UTXOs for
584
- * @param network - The Bitcoin network (default: 'mainnet')
585
- * @param rpcUrl - Optional custom RPC URL
586
- * @returns The list of UTXOs
587
- */ const getUTXOs = async ({ address, network = 'mainnet', rpcUrl })=>{
588
- const baseUrl = rpcUrl || getDefaultRpcUrl(network);
589
- try {
590
- const response = await fetch(`${baseUrl}/address/${address}/utxo`);
591
- if (!response.ok) {
592
- throw new Error(`Failed to fetch UTXOs: ${response.statusText}`);
593
- }
594
- const utxos = await response.json();
595
- return utxos.map((utxo)=>({
596
- txid: utxo.txid,
597
- vout: utxo.vout,
598
- value: BigInt(utxo.value)
599
- }));
600
- } catch (error) {
601
- throw new Error(`Error fetching UTXOs: ${error}`);
602
- }
603
- };
604
-
605
- /**
606
- * Simple greedy coin selection
607
- *
608
- * @param utxos - The list of UTXOs to select from
609
- * @param amount - The amount to spend
610
- * @param feeRate - The fee rate in sat/vByte
611
- * @returns The selected inputs, change amount, and fee
612
- */ const selectUTXOs = ({ utxos, amount, feeRate })=>{
613
- // Sort by value descending
614
- const sorted = [
615
- ...utxos
616
- ].sort((a, b)=>Number(b.value - a.value));
617
- const inputs = [];
618
- let totalInput = 0n;
619
- // Basic fee estimation constants
620
- // Optimized for Native SegWit (P2WPKH) only
621
- // P2WPKH: ~68 vbytes per input, ~31 vbytes per output
622
- // Overhead: ~10 vbytes
623
- const INPUT_SIZE = 68;
624
- const OUTPUT_SIZE = 31;
625
- const OVERHEAD = 10;
626
- for (const utxo of sorted){
627
- inputs.push(utxo);
628
- totalInput += utxo.value;
629
- // Calculate fee for current set + 2 outputs (recipient + change)
630
- const vbytes = OVERHEAD + inputs.length * INPUT_SIZE + 2 * OUTPUT_SIZE;
631
- const fee = BigInt(Math.ceil(vbytes * feeRate));
632
- if (totalInput >= amount + fee) {
633
- return {
634
- inputs,
635
- change: totalInput - amount - fee,
636
- fee
637
- };
638
- }
639
- }
640
- throw new Error('Insufficient funds');
641
- };
642
-
643
- /**
644
- * Fetches current fee rates from mempool.space
645
- * Returns fees in sat/vByte
646
- *
647
- * @param network - The Bitcoin network (default: 'mainnet')
648
- * @param rpcUrl - Optional custom RPC URL
649
- * @returns The fee rates for fast, medium, and slow transactions
650
- */ const getFeeRates = async ({ network = 'mainnet', rpcUrl })=>{
651
- const baseUrl = rpcUrl || getDefaultRpcUrl(network);
652
- const response = await fetch(`${baseUrl}/v1/fees/recommended`);
653
- if (!response.ok) {
654
- throw new Error(`Failed to fetch fee rates: ${response.statusText}`);
655
- }
656
- const fees = await response.json();
657
- return {
658
- fast: fees.fastestFee,
659
- medium: fees.halfHourFee,
660
- slow: fees.hourFee
661
- };
662
- };
663
-
664
- /**
665
- * Calculates the Taproot tweak hash for BIP340 signing
666
- * @param pubKey - The normalized public key (32-byte x-only for Taproot)
667
- * @returns The tweak hash as a hex string (64 hex chars = 32 bytes)
668
- */ const calculateTaprootTweak = (pubKey)=>{
669
- const tweakHash = bitcoin__namespace.crypto.taggedHash('TapTweak', pubKey);
670
- return Buffer.from(tweakHash).toString('hex');
671
- };
672
-
673
- /**
674
- * Converts a signature to a Buffer format suitable for Taproot (BIP340/Schnorr)
675
- * Taproot signatures are 64 bytes (r|s concatenated)
676
- * @param signature - The signature from MPC (can be Uint8Array, Buffer, or EcdsaSignature object)
677
- * @returns A Buffer containing the 64-byte Schnorr signature
678
- */ const convertSignatureToTaprootBuffer = (signature)=>{
679
- if (signature instanceof Uint8Array || Buffer.isBuffer(signature)) {
680
- return Buffer.from(signature);
681
- }
682
- // ECDSA signature object - concat r and s for Schnorr
683
- const r = signature.r;
684
- const s = signature.s;
685
- const rBuf = Buffer.isBuffer(r) ? r : Buffer.from(r);
686
- const sBuf = Buffer.isBuffer(s) ? s : Buffer.from(s);
687
- return Buffer.concat([
688
- rBuf,
689
- sBuf
690
- ]);
691
- };
692
-
693
- /**
694
- * Collects prevOutScripts and values from all PSBT inputs
695
- * Required for Taproot (BIP-341) hashForWitnessV1 calculation
696
- * @param psbt - The PSBT to collect input data from
697
- * @returns An object containing arrays of prevOutScripts and values
698
- * @throws Error if any input is missing witnessUtxo
699
- */ const collectPSBTInputData = (psbt)=>{
700
- const prevOutScripts = [];
701
- const values = [];
702
- psbt.data.inputs.forEach((input, index)=>{
703
- if (!input.witnessUtxo) {
704
- throw new Error(`Input ${index} missing witnessUtxo`);
705
- }
706
- prevOutScripts.push(Buffer.isBuffer(input.witnessUtxo.script) ? input.witnessUtxo.script : Buffer.from(input.witnessUtxo.script));
707
- values.push(input.witnessUtxo.value);
708
- });
709
- return {
710
- prevOutScripts,
711
- values
712
- };
713
- };
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
38
  /**
757
39
  * Parses the derivation path string into a Uint32Array
758
40
  * Handles empty strings and empty array strings by returning an empty Uint32Array
@@ -853,7 +135,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
853
135
  password,
854
136
  signedSessionId
855
137
  });
856
- const publicKeyHex = this.extractPublicKeyHex(rawPublicKey);
138
+ const publicKeyHex = btcUtils.extractPublicKeyHex(rawPublicKey);
857
139
  return {
858
140
  accountAddress,
859
141
  publicKeyHex,
@@ -867,22 +149,6 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
867
149
  }
868
150
  }
869
151
  /**
870
- * Automatically determines the chain config based on address type
871
- * @param rawPublicKey - The raw public key from the server
872
- * @returns The public key hex
873
- */ extractPublicKeyHex(rawPublicKey) {
874
- if (rawPublicKey instanceof Uint8Array) {
875
- return Buffer.from(rawPublicKey).toString('hex');
876
- }
877
- if (rawPublicKey && typeof rawPublicKey === 'object' && typeof rawPublicKey.pubKeyAsHex === 'function') {
878
- return rawPublicKey.pubKeyAsHex();
879
- }
880
- if (typeof rawPublicKey === 'string') {
881
- return rawPublicKey;
882
- }
883
- throw new Error('Invalid public key format');
884
- }
885
- /**
886
152
  * Derives the Bitcoin account address
887
153
  * - BIP340 keys (32 bytes x-only): Only for Taproot addresses
888
154
  * - ECDSA keys (33/65 bytes): For all other address types (Legacy, SegWit, Native SegWit)
@@ -893,8 +159,8 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
893
159
  * @returns The account address
894
160
  */ deriveAccountAddress({ rawPublicKey, addressType, network }) {
895
161
  // Derive address based on the chosen address type and network
896
- const normalizedKey = normalizePublicKey(rawPublicKey, addressType);
897
- const accountAddress = publicKeyToBitcoinAddress(normalizedKey, addressType, network);
162
+ const normalizedKey = btcUtils.normalizePublicKey(rawPublicKey, addressType);
163
+ const accountAddress = btcUtils.publicKeyToBitcoinAddress(normalizedKey, addressType, network, ecc);
898
164
  return {
899
165
  accountAddress
900
166
  };
@@ -931,7 +197,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
931
197
  }
932
198
  let addressType = walletProperties.addressType;
933
199
  if (!addressType) {
934
- addressType = getAddressTypeFromDerivationPath(derivationPath);
200
+ addressType = btcUtils.getAddressTypeFromDerivationPath(derivationPath);
935
201
  }
936
202
  const clientKeyShares = await this.getClientKeySharesFromStorage({
937
203
  accountAddress
@@ -953,14 +219,14 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
953
219
  if (!derivedPublicKey) {
954
220
  throw new Error('Failed to derive public key');
955
221
  }
956
- const pubKey = normalizePublicKey(derivedPublicKey, addressType);
222
+ const pubKey = btcUtils.normalizePublicKey(derivedPublicKey, addressType);
957
223
  this.verifyWalletAddress(derivedPublicKey, addressType, network, accountAddress);
958
224
  // Prepare BIP-322 Transactions and calculate hash
959
- const { formattedMessage, toSignPsbt } = calculateBip322Hash(message, pubKey, addressType, network);
225
+ const { formattedMessage, toSignPsbt } = btcUtils.calculateBip322Hash(message, pubKey, addressType, network, ecc);
960
226
  // Prepare tweak for Taproot in case of BIP340
961
227
  let tweak;
962
228
  if (addressType === browser.BitcoinAddressType.TAPROOT) {
963
- tweak = calculateTaprootTweak(pubKey);
229
+ tweak = btcUtils.calculateTaprootTweak(pubKey);
964
230
  }
965
231
  // Build complete bitcoinConfig with addressType and tweak
966
232
  const completeBitcoinConfig = _extends({}, bitcoinConfig, {
@@ -983,7 +249,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
983
249
  onError
984
250
  });
985
251
  // Encode Final Result
986
- const bip322Signature = encodeBip322Signature(toSignPsbt, pubKey, signature, addressType);
252
+ const bip322Signature = btcUtils.encodeBip322Signature(toSignPsbt, pubKey, signature, addressType);
987
253
  this.logger.debug('[BTC Client] signMessage - bip322Signature', {
988
254
  bip322Signature
989
255
  });
@@ -1002,8 +268,8 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1002
268
  * @param network - The network
1003
269
  * @param expectedAddress - The expected address
1004
270
  */ verifyWalletAddress(rawPublicKey, addressType, network, expectedAddress) {
1005
- const normalizedKey = normalizePublicKey(rawPublicKey, addressType);
1006
- const derivedAddress = publicKeyToBitcoinAddress(normalizedKey, addressType, network);
271
+ const normalizedKey = btcUtils.normalizePublicKey(rawPublicKey, addressType);
272
+ const derivedAddress = btcUtils.publicKeyToBitcoinAddress(normalizedKey, addressType, network, ecc);
1007
273
  if (derivedAddress !== expectedAddress) {
1008
274
  throw new Error(`Address verification failed: expected ${expectedAddress}, got ${derivedAddress}`);
1009
275
  }
@@ -1035,7 +301,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1035
301
  let addressType = walletProperties.addressType;
1036
302
  if (!addressType && walletProperties.derivationPath) {
1037
303
  try {
1038
- addressType = getAddressTypeFromDerivationPath(walletProperties.derivationPath);
304
+ addressType = btcUtils.getAddressTypeFromDerivationPath(walletProperties.derivationPath);
1039
305
  } catch (e) {
1040
306
  this.logger.warn('Failed to infer address type from derivation path', e);
1041
307
  }
@@ -1086,9 +352,9 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1086
352
  const ceremonyCompletePromise = new Promise((resolve)=>{
1087
353
  ceremonyCeremonyCompleteResolver = resolve;
1088
354
  });
1089
- const formattedPrivateKey = wifToPrivateKey(privateKey, network);
355
+ const formattedPrivateKey = btcUtils.wifToPrivateKey(privateKey, network);
1090
356
  if (publicAddressCheck) {
1091
- const derivedPublicKey = await getPublicKeyFromPrivateKey(privateKey, addressTypeEnum, network);
357
+ const derivedPublicKey = await btcUtils.getPublicKeyFromPrivateKey(privateKey, addressTypeEnum, ecc, network);
1092
358
  const { accountAddress } = this.deriveAccountAddress({
1093
359
  rawPublicKey: derivedPublicKey,
1094
360
  addressType: addressTypeEnum,
@@ -1155,7 +421,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1155
421
  password,
1156
422
  signedSessionId
1157
423
  });
1158
- const publicKeyHex = this.extractPublicKeyHex(rawPublicKey);
424
+ const publicKeyHex = btcUtils.extractPublicKeyHex(rawPublicKey);
1159
425
  return {
1160
426
  accountAddress,
1161
427
  publicKeyHex,
@@ -1175,7 +441,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1175
441
  * @returns The Bitcoin WIF format
1176
442
  */ convertPrivateKeyToBitcoinFormat(privateKey, network) {
1177
443
  try {
1178
- const wif = privateKeyToWIF(privateKey, network, {
444
+ const wif = btcUtils.privateKeyToWIF(privateKey, network, {
1179
445
  compressed: true,
1180
446
  onWarning: (message, data)=>{
1181
447
  this.logger.warn(`[BTC Client] convertPrivateKeyToBitcoinFormat - ${message}`, data);
@@ -1230,7 +496,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1230
496
  }
1231
497
  let addressType = walletProperties.addressType;
1232
498
  if (!addressType) {
1233
- addressType = getAddressTypeFromDerivationPath(derivationPath);
499
+ addressType = btcUtils.getAddressTypeFromDerivationPath(derivationPath);
1234
500
  }
1235
501
  const bitcoinConfig = {
1236
502
  addressType,
@@ -1253,13 +519,13 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1253
519
  if (!derivedPublicKey) {
1254
520
  throw new Error('Failed to derive public key');
1255
521
  }
1256
- const pubKey = normalizePublicKey(derivedPublicKey, addressType);
522
+ const pubKey = btcUtils.normalizePublicKey(derivedPublicKey, addressType);
1257
523
  const tx = psbt.__CACHE.__TX;
1258
524
  // Filter inputs to only sign those that belong to the current address
1259
525
  const inputsToSign = psbt.data.inputs.map((input, i)=>({
1260
526
  input,
1261
527
  index: i
1262
- })).filter(({ input })=>doesInputBelongToAddress(input, senderAddress, network));
528
+ })).filter(({ input })=>btcUtils.doesInputBelongToAddress(input, senderAddress, network));
1263
529
  this.logger.debug('[BTC Client] signTransaction - Filtering inputs', {
1264
530
  totalInputs: psbt.data.inputs.length,
1265
531
  inputsToSign: inputsToSign.length,
@@ -1272,12 +538,12 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1272
538
  });
1273
539
  }
1274
540
  if (addressType === browser.BitcoinAddressType.TAPROOT) {
1275
- const tweak = calculateTaprootTweak(pubKey);
541
+ const tweak = btcUtils.calculateTaprootTweak(pubKey);
1276
542
  const completeBitcoinConfig = _extends({}, bitcoinConfig, {
1277
543
  addressType: addressType,
1278
544
  tweak
1279
545
  });
1280
- const { prevOutScripts, values } = collectPSBTInputData(psbt);
546
+ const { prevOutScripts, values } = btcUtils.collectPSBTInputData(psbt);
1281
547
  await Promise.all(inputsToSign.map(async ({ input, index: i })=>{
1282
548
  if (!input.witnessUtxo) {
1283
549
  throw new Error(`Input ${i} missing witnessUtxo`);
@@ -1295,7 +561,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1295
561
  bitcoinConfig: completeBitcoinConfig,
1296
562
  onError
1297
563
  });
1298
- const sigBuffer = convertSignatureToTaprootBuffer(signature);
564
+ const sigBuffer = btcUtils.convertSignatureToTaprootBuffer(signature);
1299
565
  psbt.updateInput(i, {
1300
566
  tapKeySig: sigBuffer
1301
567
  });
@@ -1314,7 +580,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1314
580
  const { script, value } = input.witnessUtxo;
1315
581
  const p2pkh = bitcoin__namespace.payments.p2pkh({
1316
582
  hash: script.slice(2),
1317
- network: getBitcoinNetwork(network)
583
+ network: btcUtils.getBitcoinNetwork(network)
1318
584
  });
1319
585
  const scriptCode = p2pkh.output;
1320
586
  if (!scriptCode) throw new Error('Failed to generate scriptCode');
@@ -1331,7 +597,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1331
597
  bitcoinConfig: completeBitcoinConfig,
1332
598
  onError
1333
599
  });
1334
- const derSignature = convertSignatureToDER(signature);
600
+ const derSignature = btcUtils.convertSignatureToDER(signature);
1335
601
  psbt.updateInput(i, {
1336
602
  partialSig: [
1337
603
  {
@@ -1381,7 +647,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1381
647
  }
1382
648
  let addressType = walletProperties.addressType;
1383
649
  if (!addressType && walletProperties.derivationPath) {
1384
- addressType = getAddressTypeFromDerivationPath(walletProperties.derivationPath);
650
+ addressType = btcUtils.getAddressTypeFromDerivationPath(walletProperties.derivationPath);
1385
651
  }
1386
652
  if (!addressType) {
1387
653
  throw new Error('Address type not determined');
@@ -1391,17 +657,17 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1391
657
  }
1392
658
  const bitcoinNetwork = network === 'testnet' ? bitcoin__namespace.networks.testnet : bitcoin__namespace.networks.bitcoin;
1393
659
  // Fetch fee rates
1394
- const feeRates = await getFeeRates({
660
+ const feeRates = await btcUtils.getFeeRates({
1395
661
  network
1396
662
  });
1397
663
  const feeRate = feeRates[feeRateLevel];
1398
664
  // Fetch UTXOs
1399
- const utxos = await getUTXOs({
665
+ const utxos = await btcUtils.getUTXOs({
1400
666
  address: senderAddress,
1401
667
  network
1402
668
  });
1403
669
  // Select UTXOs
1404
- const { inputs, change, fee } = selectUTXOs({
670
+ const { inputs, change, fee } = btcUtils.selectUTXOs({
1405
671
  utxos,
1406
672
  amount: BigInt(amount),
1407
673
  feeRate
@@ -1459,7 +725,7 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1459
725
  * @param network - The network
1460
726
  * @returns The transaction hex
1461
727
  */ async getTxHex(txid, network) {
1462
- const baseUrl = getDefaultRpcUrl(network);
728
+ const baseUrl = btcUtils.getDefaultRpcUrl(network);
1463
729
  const response = await fetch(`${baseUrl}/tx/${txid}/hex`);
1464
730
  if (!response.ok) {
1465
731
  throw new Error(`Failed to fetch TX hex: ${response.statusText}`);
@@ -1490,6 +756,8 @@ class DynamicBtcWalletClient extends browser.DynamicWalletClient {
1490
756
  sdkVersion,
1491
757
  forwardMPCClient
1492
758
  }, internalOptions), this.chainName = 'BTC';
759
+ // Initialize ECC library for bitcoinjs-lib
760
+ btcUtils.initEccLib(ecc);
1493
761
  }
1494
762
  }
1495
763