@argonprotocol/bitcoin 1.3.2 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.js CHANGED
@@ -5,17 +5,22 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // ts/index.ts
8
- import { Transaction as Transaction2, Psbt as Psbt2, networks as networks3, Network, address as address2 } from "bitcoinjs-lib";
8
+ import { Transaction as Transaction2, Address as Address2, p2wsh as p2wsh2, p2wpkh as p2wpkh2, p2sh as p2sh2, p2pk, p2pkh as p2pkh2 } from "@scure/btc-signer";
9
9
 
10
10
  // ts/CosignScript.ts
11
- import { networks as networks2, payments, Psbt, Transaction } from "bitcoinjs-lib";
11
+ import { p2pkh, p2sh, p2wpkh, p2wsh, Transaction } from "@scure/btc-signer";
12
+ import {
13
+ hexToU8a as hexToU8a2,
14
+ u8aEq,
15
+ u8aToHex as u8aToHex2
16
+ } from "@argonprotocol/mainchain";
12
17
 
13
18
  // ts/wasm/bitcoin_bindings_bg.wasm
14
19
  var bitcoin_bindings_bg_exports = {};
15
20
  __export(bitcoin_bindings_bg_exports, {
16
21
  default: () => bitcoin_bindings_bg_default
17
22
  });
18
- var bitcoin_bindings_bg_default = "./bitcoin_bindings_bg-NTNPUTAE.wasm";
23
+ var bitcoin_bindings_bg_default = "./bitcoin_bindings_bg-WMK2AQRE.wasm";
19
24
 
20
25
  // ts/wasm/bitcoin_bindings_bg.js
21
26
  var wasm;
@@ -226,77 +231,108 @@ var BitcoinNetwork = Object.freeze({
226
231
 
227
232
  // ts/wasm/bitcoin_bindings.js
228
233
  __wbg_set_wasm(bitcoin_bindings_bg_exports);
229
- (void 0)();
230
234
 
231
235
  // ts/KeysHelper.ts
232
- import { address } from "bitcoinjs-lib";
233
- import BIP32Factory from "bip32";
234
- import * as ecc from "tiny-secp256k1";
235
- import * as bip39 from "bip39";
236
- function getBip32Factory() {
237
- return BIP32Factory(ecc);
236
+ import { Address, NETWORK, OutScript, TEST_NETWORK } from "@scure/btc-signer";
237
+ import { bech32 } from "@scure/base";
238
+ import { HDKey } from "@scure/bip32";
239
+ import { hexToU8a, u8aToHex } from "@argonprotocol/mainchain";
240
+ import * as secp256k1 from "@noble/secp256k1";
241
+ function getBip32Version(network) {
242
+ if (!network) {
243
+ return void 0;
244
+ }
245
+ if (network === BitcoinNetwork.Testnet || network === BitcoinNetwork.Signet) {
246
+ return {
247
+ private: 70615956,
248
+ // tprv
249
+ public: 70617039
250
+ // tpub
251
+ };
252
+ }
253
+ if (network === BitcoinNetwork.Regtest) {
254
+ return {
255
+ private: 70615956,
256
+ // rprv
257
+ public: 70617039
258
+ // rpub
259
+ };
260
+ }
261
+ return void 0;
238
262
  }
239
263
  function getChildXpriv(bip39Seed, hdPath, network) {
240
- const root = BIP32Factory(ecc).fromSeed(bip39Seed, network);
241
- return root.derivePath(hdPath);
242
- }
243
- function getBip39Seed(mnemonic, passphrase) {
244
- return bip39.mnemonicToSeedSync(mnemonic, passphrase);
264
+ const root = HDKey.fromMasterSeed(bip39Seed, getBip32Version(network));
265
+ return root.derive(hdPath);
245
266
  }
246
267
  function getXpubFromXpriv(xpriv) {
247
- return xpriv.neutered().toBase58();
268
+ return xpriv.publicExtendedKey;
248
269
  }
249
270
  function getCompressedPubkey(pubkey) {
250
- const pubkeyBuffer = keyToBuffer(pubkey);
251
- if (ecc.isPointCompressed(pubkeyBuffer)) {
252
- return pubkeyBuffer;
271
+ const pubkeyUint8Array = keyToU8a(pubkey);
272
+ if (pubkeyUint8Array.length === 33) {
273
+ return pubkeyUint8Array;
253
274
  }
254
- return Buffer.from(ecc.pointCompress(pubkeyBuffer, true));
275
+ const point = secp256k1.Point.fromHex(pubkeyUint8Array);
276
+ return point.toRawBytes(true);
255
277
  }
256
- function stripLeadingHexPrefix(hex) {
257
- if (hex.startsWith("0x")) {
258
- return hex.slice(2);
278
+ function getBech32Prefix(network) {
279
+ return getScureNetwork(network).bech32;
280
+ }
281
+ function p2wshScriptHexToAddress(scriptPubKeyHex, network) {
282
+ const script = hexToU8a(scriptPubKeyHex);
283
+ if (Buffer.byteLength(script) !== 34 || script[0] !== 0 || script[1] !== 32) {
284
+ throw new Error("Invalid P2WSH scriptPubKey");
259
285
  }
260
- return hex;
286
+ const witnessProgram = script.slice(2);
287
+ const version = 0;
288
+ const prefix = getBech32Prefix(network);
289
+ return bech32.encode(prefix, [version, ...bech32.toWords(witnessProgram)]);
261
290
  }
262
- function addressBytesHex(addressString, network) {
263
- if (addressString.startsWith("0x")) {
264
- return addressString;
291
+ function addressBytesHex(address, network) {
292
+ if (address.startsWith("0x")) {
293
+ return address;
265
294
  }
266
- console.log("Converting address to bytes:", addressString, network);
267
- if (/^[0-9a-fA-F]+$/.test(addressString) && !addressString.startsWith("bc")) {
268
- return `0x${addressString}`;
295
+ const bech32Prefix = getBech32Prefix(network);
296
+ if (/^[0-9a-fA-F]+$/.test(address) && !address.startsWith("bc") && !address.startsWith(bech32Prefix)) {
297
+ return `0x${address}`;
269
298
  }
270
- const scriptbuf = address.toOutputScript(addressString, network);
271
- return `0x${scriptbuf.toString("hex")}`;
299
+ const btcNetwork = getScureNetwork(network);
300
+ const decoded = Address(btcNetwork).decode(address);
301
+ const out = OutScript.encode(decoded);
302
+ return u8aToHex(out);
303
+ }
304
+ function keyToU8a(pubkey) {
305
+ return typeof pubkey === "string" ? hexToU8a(pubkey) : pubkey;
272
306
  }
273
- function keyToBuffer(key) {
274
- if (typeof key === "string") {
275
- key = stripLeadingHexPrefix(key);
276
- return Buffer.from(key, "hex");
307
+ function getScureNetwork(network) {
308
+ if (network === BitcoinNetwork.Bitcoin) {
309
+ return NETWORK;
310
+ } else if (network === BitcoinNetwork.Testnet || network === BitcoinNetwork.Signet) {
311
+ return TEST_NETWORK;
312
+ } else {
313
+ return {
314
+ bech32: "bcrt",
315
+ pubKeyHash: 111,
316
+ scriptHash: 196,
317
+ wif: 239
318
+ };
277
319
  }
278
- return Buffer.from(key);
279
320
  }
280
321
 
281
322
  // ts/CosignScript.ts
282
- var CosignScript = class _CosignScript {
323
+ var CosignScript = class {
283
324
  constructor(lock, network) {
284
325
  this.lock = lock;
285
- if (network === networks2.bitcoin || network === networks2.testnet || network === networks2.regtest) {
286
- this.network = network;
287
- } else {
288
- this.network = _CosignScript.getBitcoinJsNetwork(
289
- network
290
- );
291
- }
326
+ this.network = network;
292
327
  }
293
- network;
294
328
  getFundingPsbt() {
295
329
  const { lock, network } = this;
296
- return new Psbt({ network }).addOutput({
297
- script: keyToBuffer(lock.p2wshScriptHashHex),
298
- value: Number(lock.satoshis)
330
+ const tx = new Transaction();
331
+ tx.addOutput({
332
+ script: keyToU8a(lock.p2wshScriptHashHex),
333
+ amount: lock.satoshis
299
334
  });
335
+ return tx.toPSBT(0);
300
336
  }
301
337
  calculateFee(feeRatePerSatVb, toScriptPubkey) {
302
338
  toScriptPubkey = addressBytesHex(toScriptPubkey, this.network);
@@ -308,7 +344,7 @@ var CosignScript = class _CosignScript {
308
344
  BigInt(lock.vaultClaimHeight),
309
345
  BigInt(lock.openClaimHeight),
310
346
  BigInt(lock.createdAtHeight),
311
- toBitcoinNetwork(network),
347
+ network,
312
348
  feeRatePerSatVb,
313
349
  toScriptPubkey
314
350
  );
@@ -322,7 +358,7 @@ var CosignScript = class _CosignScript {
322
358
  BigInt(lock.vaultClaimHeight),
323
359
  BigInt(lock.openClaimHeight),
324
360
  BigInt(lock.createdAtHeight),
325
- toBitcoinNetwork(network)
361
+ network
326
362
  );
327
363
  }
328
364
  getCosignPsbt(args) {
@@ -339,21 +375,22 @@ var CosignScript = class _CosignScript {
339
375
  BigInt(lock.vaultClaimHeight),
340
376
  BigInt(lock.openClaimHeight),
341
377
  BigInt(lock.createdAtHeight),
342
- toBitcoinNetwork(network),
378
+ network,
343
379
  releaseRequest.toScriptPubkey,
344
380
  releaseRequest.bitcoinNetworkFee
345
381
  );
346
382
  return this.psbtFromHex(psbtStr);
347
383
  }
348
384
  psbtFromHex(psbtHex) {
349
- const psbt = Psbt.fromHex(psbtHex.replace(/^0x(.+)/, "$1"), { network: this.network });
350
- if (psbt.data.inputs.length === 0) {
385
+ const psbtBytes = hexToU8a2(psbtHex);
386
+ const tx = Transaction.fromPSBT(psbtBytes);
387
+ if (tx.inputsLength === 0) {
351
388
  throw new Error("PSBT has no inputs");
352
389
  }
353
- if (psbt.data.outputs.length === 0) {
390
+ if (tx.outputsLength === 0) {
354
391
  throw new Error("PSBT has no outputs");
355
392
  }
356
- return psbt;
393
+ return tx;
357
394
  }
358
395
  /**
359
396
  * Cosigns the PSBT with the vault xpub.
@@ -362,21 +399,33 @@ var CosignScript = class _CosignScript {
362
399
  * @param vaultXpriv - The vault's extended private key of which the xpub was used to create the vault.
363
400
  */
364
401
  vaultCosignPsbt(psbt, lock, vaultXpriv) {
365
- const parentFingerprint = Buffer.from(lock.vaultXpubSources.parentFingerprint);
366
- if (!parentFingerprint.equals(vaultXpriv.fingerprint)) {
402
+ const parentFingerprint = lock.vaultXpubSources.parentFingerprint;
403
+ const vaultFingerprint = vaultXpriv.identifier?.slice(0, 4);
404
+ if (!vaultFingerprint) {
405
+ throw new Error("Could not get vault fingerprint from HDKey");
406
+ }
407
+ if (!u8aEq(parentFingerprint, vaultFingerprint)) {
367
408
  throw new Error(
368
- `Vault xpub fingerprint ${parentFingerprint.toString("hex")} does not match the vault xpriv fingerprint ${vaultXpriv.fingerprint.toString("hex")}`
409
+ `Vault xpub fingerprint ${u8aToHex2(parentFingerprint)} does not match the vault xpriv fingerprint ${u8aToHex2(vaultFingerprint)}`
369
410
  );
370
411
  }
371
412
  const childPath = `${lock.vaultXpubSources.cosignHdIndex}`;
372
- const pubkey = vaultXpriv.derivePath(childPath).publicKey;
373
- const vaultPubkey = keyToBuffer(lock.vaultPubkey);
374
- if (!vaultPubkey.equals(pubkey)) {
413
+ const pubkey = vaultXpriv.deriveChild(lock.vaultXpubSources.cosignHdIndex).publicKey;
414
+ if (!pubkey) {
415
+ throw new Error(`Failed to derive public key for path ${childPath}`);
416
+ }
417
+ const vaultPubkey = keyToU8a(lock.vaultPubkey);
418
+ if (!u8aEq(vaultPubkey, pubkey)) {
375
419
  throw new Error(
376
- `Vault pubkey ${vaultPubkey.toString("hex")} does not match the derived pubkey ${pubkey.toString("hex")} using path ${childPath}`
420
+ `Vault pubkey ${u8aToHex2(vaultPubkey)} does not match the derived pubkey ${u8aToHex2(pubkey)} using path ${childPath}`
377
421
  );
378
422
  }
379
- const signedPsbt = signPsbtDerived(psbt.toHex(), vaultXpriv.toBase58(), childPath, false);
423
+ const signedPsbt = signPsbtDerived(
424
+ u8aToHex2(psbt.toPSBT()),
425
+ vaultXpriv.privateExtendedKey,
426
+ childPath,
427
+ false
428
+ );
380
429
  psbt = this.psbtFromHex(signedPsbt);
381
430
  return psbt;
382
431
  }
@@ -388,84 +437,80 @@ var CosignScript = class _CosignScript {
388
437
  const psbt = this.getCosignPsbt(args);
389
438
  const { addTx, vaultCosignature, ownerXpriv, ownerXprivChildHdPath } = args;
390
439
  psbt.updateInput(0, {
391
- partialSig: [
392
- {
393
- pubkey: keyToBuffer(lock.vaultPubkey),
394
- signature: Buffer.from(vaultCosignature)
395
- }
396
- ]
440
+ partialSig: [[keyToU8a(lock.vaultPubkey), vaultCosignature]]
397
441
  });
398
442
  const derivePubkey = ownerXpriv.publicKey;
399
- const ownerPubkey = keyToBuffer(lock.ownerPubkey);
400
- if (!ownerPubkey.equals(derivePubkey)) {
443
+ if (!derivePubkey) {
444
+ throw new Error("Failed to derive owner public key");
445
+ }
446
+ const ownerPubkey = keyToU8a(lock.ownerPubkey);
447
+ if (!u8aEq(ownerPubkey, derivePubkey)) {
401
448
  throw new Error(
402
- `Owner pubkey ${ownerPubkey.toString("hex")} does not match the derived pubkey ${derivePubkey.toString("hex")}`
449
+ `Owner pubkey ${u8aToHex2(ownerPubkey)} does not match the derived pubkey ${u8aToHex2(derivePubkey)}`
403
450
  );
404
451
  }
405
452
  if (addTx) {
406
- const tx = Transaction.fromHex(addTx.replace(/^0x(.+)/, "$1"));
407
- for (let i = 0; i < tx.outs.length; i++) {
408
- const output = tx.outs[i];
453
+ const addTxBytes = hexToU8a2(addTx);
454
+ const tx = Transaction.fromPSBT(addTxBytes);
455
+ for (let i = 0; i < tx.outputsLength; i++) {
456
+ const output = tx.getOutput(i);
457
+ const network = getScureNetwork(this.network);
409
458
  const scripts = [
410
- payments.p2wpkh({ pubkey: ownerPubkey }).output,
411
- payments.p2sh({ redeem: payments.p2wpkh({ pubkey: ownerPubkey }) }).output,
412
- payments.p2pkh({ pubkey: ownerPubkey }).output
459
+ p2wpkh(ownerPubkey, network).script,
460
+ p2wsh(p2wpkh(ownerPubkey, network), network).script,
461
+ p2sh(p2pkh(ownerPubkey, network), network).script,
462
+ p2pkh(ownerPubkey, network).script
413
463
  ];
414
- if (scripts.some((x) => x && output.script.equals(x))) {
464
+ if (scripts.some((x) => x && output.script && u8aEq(output.script, x))) {
415
465
  psbt.addInput({
416
- hash: tx.getId(),
466
+ txid: tx.id,
417
467
  index: i,
418
468
  witnessUtxo: {
419
469
  script: output.script,
420
- value: output.value
470
+ amount: output.amount
421
471
  }
422
472
  });
423
473
  }
424
474
  }
425
475
  }
426
- const signedPsbt = ownerXprivChildHdPath ? signPsbtDerived(psbt.toHex(), ownerXpriv.toBase58(), ownerXprivChildHdPath, true) : signPsbt(
427
- psbt.toHex(),
428
- toBitcoinNetwork(this.network),
429
- ownerXpriv.privateKey.toString("hex"),
430
- true
431
- );
432
- const finalPsbt = this.psbtFromHex(signedPsbt);
433
- return finalPsbt.extractTransaction();
434
- }
435
- static getBitcoinJsNetwork(network) {
436
- if (network.isBitcoin) return networks2.bitcoin;
437
- if (network.isTestnet || network.isSignet) return networks2.testnet;
438
- if (network.isRegtest) return networks2.regtest;
439
- throw new Error("Unsupported network: " + network);
476
+ const psbtBytes = u8aToHex2(psbt.toPSBT());
477
+ const signedPsbt = ownerXprivChildHdPath ? signPsbtDerived(psbtBytes, ownerXpriv.privateExtendedKey, ownerXprivChildHdPath, true) : signPsbt(psbtBytes, this.network, u8aToHex2(ownerXpriv.privateKey, void 0, false), true);
478
+ return this.psbtFromHex(signedPsbt);
440
479
  }
441
480
  };
442
- function toBitcoinNetwork(network) {
443
- if (network === networks2.bitcoin) {
481
+ function getBitcoinNetworkFromApi(network) {
482
+ if (network.isBitcoin) {
444
483
  return BitcoinNetwork.Bitcoin;
445
- } else if (network === networks2.testnet) {
484
+ } else if (network.isTestnet) {
446
485
  return BitcoinNetwork.Testnet;
447
- } else if (network === networks2.regtest) {
486
+ } else if (network.isRegtest) {
448
487
  return BitcoinNetwork.Regtest;
449
488
  }
450
489
  throw new Error("Unsupported network: " + network);
451
490
  }
452
491
 
453
492
  // ts/index.ts
454
- import * as bip392 from "bip39";
493
+ import * as bip39 from "@scure/bip39";
455
494
  export {
495
+ Address2 as Address,
496
+ BitcoinNetwork,
456
497
  CosignScript,
457
- Network,
458
- Psbt2 as Psbt,
498
+ HDKey,
459
499
  Transaction2 as Transaction,
460
- address2 as address,
461
500
  addressBytesHex,
462
- bip392 as bip39,
463
- getBip32Factory,
464
- getBip39Seed,
501
+ bip39,
502
+ getBech32Prefix,
503
+ getBip32Version,
504
+ getBitcoinNetworkFromApi,
465
505
  getChildXpriv,
466
506
  getCompressedPubkey,
507
+ getScureNetwork,
467
508
  getXpubFromXpriv,
468
- keyToBuffer,
469
- networks3 as networks,
470
- stripLeadingHexPrefix
509
+ keyToU8a,
510
+ p2pk,
511
+ p2pkh2 as p2pkh,
512
+ p2sh2 as p2sh,
513
+ p2wpkh2 as p2wpkh,
514
+ p2wsh2 as p2wsh,
515
+ p2wshScriptHexToAddress
471
516
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@argonprotocol/bitcoin",
3
- "version": "1.3.2",
3
+ "version": "1.3.3",
4
4
  "description": "A client for interop with bitcoin in nodejs.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "homepage": "https://github.com/argonprotocol/mainchain#readme",
15
15
  "scripts": {
16
- "wasm-pack": "wasm-pack build --target bundler --release --out-dir ts/wasm --out-name bitcoin_bindings --no-pack --no-opt",
16
+ "wasm-pack": "wasm-pack build --target bundler --release --out-dir ts/wasm --out-name bitcoin_bindings --no-pack --no-opt && node clean-wasm.js",
17
17
  "prebuild": "yarn workspace @argonprotocol/mainchain run build",
18
18
  "build": "yarn wasm-pack && yarn tsc",
19
19
  "pretsc": "yarn workspace @argonprotocol/mainchain run tsc",
@@ -23,22 +23,33 @@
23
23
  "tsup": "yarn tsc"
24
24
  },
25
25
  "files": [
26
- "lib/"
26
+ "lib/",
27
+ "browser/"
27
28
  ],
28
29
  "type": "module",
29
- "bin": "./lib/cli.js",
30
30
  "module": "./lib/index.js",
31
31
  "types": "./lib/index.d.ts",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./lib/index.d.ts",
35
+ "import": "./lib/index.js",
36
+ "browser": {
37
+ "types": "./browser/index.d.ts",
38
+ "default": "./browser/index.js"
39
+ }
40
+ }
41
+ },
32
42
  "dependencies": {
33
- "@argonprotocol/mainchain": "1.3.2",
34
- "bignumber.js": "^9.1.2",
35
- "bip32": "^4.0.0",
36
- "bip39": "^3.1.0",
37
- "bitcoinjs-lib": "^6.1.7",
38
- "tiny-secp256k1": "^2.2.3"
43
+ "@argonprotocol/mainchain": "1.3.3",
44
+ "@noble/secp256k1": "^2.3.0",
45
+ "@scure/bip32": "^1.7.0",
46
+ "@scure/bip39": "^1.6.0",
47
+ "@scure/btc-signer": "^1.8.1",
48
+ "bignumber.js": "^9.1.2"
39
49
  },
40
50
  "devDependencies": {
41
- "@argonprotocol/testing": "1.3.2",
51
+ "@argonprotocol/testing": "1.3.3",
52
+ "@types/node": "22.16.3",
42
53
  "tsup": "^8.4.0",
43
54
  "tsx": "^4.19.2",
44
55
  "typescript": "^5.8.3",