@argonprotocol/bitcoin 1.3.1 → 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
@@ -4,15 +4,23 @@ var __export = (target, all) => {
4
4
  __defProp(target, name, { get: all[name], enumerable: true });
5
5
  };
6
6
 
7
+ // ts/index.ts
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
+
7
10
  // ts/CosignScript.ts
8
- 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";
9
17
 
10
18
  // ts/wasm/bitcoin_bindings_bg.wasm
11
19
  var bitcoin_bindings_bg_exports = {};
12
20
  __export(bitcoin_bindings_bg_exports, {
13
21
  default: () => bitcoin_bindings_bg_default
14
22
  });
15
- var bitcoin_bindings_bg_default = "./bitcoin_bindings_bg-T4SJEBFE.wasm";
23
+ var bitcoin_bindings_bg_default = "./bitcoin_bindings_bg-WMK2AQRE.wasm";
16
24
 
17
25
  // ts/wasm/bitcoin_bindings_bg.js
18
26
  var wasm;
@@ -223,74 +231,108 @@ var BitcoinNetwork = Object.freeze({
223
231
 
224
232
  // ts/wasm/bitcoin_bindings.js
225
233
  __wbg_set_wasm(bitcoin_bindings_bg_exports);
226
- (void 0)();
227
234
 
228
235
  // ts/KeysHelper.ts
229
- import { address } from "bitcoinjs-lib";
230
- import BIP32Factory from "bip32";
231
- import * as ecc from "tiny-secp256k1";
232
- import * as bip39 from "bip39";
233
- function getChildXpriv(bip39Seed, hdPath, network) {
234
- const root = BIP32Factory(ecc).fromSeed(bip39Seed, network);
235
- return root.derivePath(hdPath);
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;
236
262
  }
237
- function getBip39Seed(mnemonic, passphrase) {
238
- return bip39.mnemonicToSeedSync(mnemonic, passphrase);
263
+ function getChildXpriv(bip39Seed, hdPath, network) {
264
+ const root = HDKey.fromMasterSeed(bip39Seed, getBip32Version(network));
265
+ return root.derive(hdPath);
239
266
  }
240
267
  function getXpubFromXpriv(xpriv) {
241
- return xpriv.neutered().toBase58();
268
+ return xpriv.publicExtendedKey;
242
269
  }
243
270
  function getCompressedPubkey(pubkey) {
244
- const pubkeyBuffer = keyToBuffer(pubkey);
245
- if (ecc.isPointCompressed(pubkeyBuffer)) {
246
- return pubkeyBuffer;
271
+ const pubkeyUint8Array = keyToU8a(pubkey);
272
+ if (pubkeyUint8Array.length === 33) {
273
+ return pubkeyUint8Array;
247
274
  }
248
- return Buffer.from(ecc.pointCompress(pubkeyBuffer, true));
275
+ const point = secp256k1.Point.fromHex(pubkeyUint8Array);
276
+ return point.toRawBytes(true);
277
+ }
278
+ function getBech32Prefix(network) {
279
+ return getScureNetwork(network).bech32;
249
280
  }
250
- function stripLeadingHexPrefix(hex) {
251
- if (hex.startsWith("0x")) {
252
- return hex.slice(2);
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");
253
285
  }
254
- 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)]);
255
290
  }
256
- function addressBytesHex(addressString, network) {
257
- if (addressString.startsWith("0x")) {
258
- return addressString;
291
+ function addressBytesHex(address, network) {
292
+ if (address.startsWith("0x")) {
293
+ return address;
259
294
  }
260
- console.log("Converting address to bytes:", addressString, network);
261
- if (/^[0-9a-fA-F]+$/.test(addressString) && !addressString.startsWith("bc")) {
262
- 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}`;
263
298
  }
264
- const scriptbuf = address.toOutputScript(addressString, network);
265
- 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;
266
306
  }
267
- function keyToBuffer(key) {
268
- if (typeof key === "string") {
269
- key = stripLeadingHexPrefix(key);
270
- 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
+ };
271
319
  }
272
- return Buffer.from(key);
273
320
  }
274
321
 
275
322
  // ts/CosignScript.ts
276
- var CosignScript = class _CosignScript {
323
+ var CosignScript = class {
277
324
  constructor(lock, network) {
278
325
  this.lock = lock;
279
- if (network === networks2.bitcoin || network === networks2.testnet || network === networks2.regtest) {
280
- this.network = network;
281
- } else {
282
- this.network = _CosignScript.getBitcoinJsNetwork(
283
- network
284
- );
285
- }
326
+ this.network = network;
286
327
  }
287
- network;
288
328
  getFundingPsbt() {
289
329
  const { lock, network } = this;
290
- return new Psbt({ network }).addOutput({
291
- script: keyToBuffer(lock.p2wshScriptHashHex),
292
- value: Number(lock.satoshis)
330
+ const tx = new Transaction();
331
+ tx.addOutput({
332
+ script: keyToU8a(lock.p2wshScriptHashHex),
333
+ amount: lock.satoshis
293
334
  });
335
+ return tx.toPSBT(0);
294
336
  }
295
337
  calculateFee(feeRatePerSatVb, toScriptPubkey) {
296
338
  toScriptPubkey = addressBytesHex(toScriptPubkey, this.network);
@@ -302,7 +344,7 @@ var CosignScript = class _CosignScript {
302
344
  BigInt(lock.vaultClaimHeight),
303
345
  BigInt(lock.openClaimHeight),
304
346
  BigInt(lock.createdAtHeight),
305
- toBitcoinNetwork(network),
347
+ network,
306
348
  feeRatePerSatVb,
307
349
  toScriptPubkey
308
350
  );
@@ -316,7 +358,7 @@ var CosignScript = class _CosignScript {
316
358
  BigInt(lock.vaultClaimHeight),
317
359
  BigInt(lock.openClaimHeight),
318
360
  BigInt(lock.createdAtHeight),
319
- toBitcoinNetwork(network)
361
+ network
320
362
  );
321
363
  }
322
364
  getCosignPsbt(args) {
@@ -333,21 +375,22 @@ var CosignScript = class _CosignScript {
333
375
  BigInt(lock.vaultClaimHeight),
334
376
  BigInt(lock.openClaimHeight),
335
377
  BigInt(lock.createdAtHeight),
336
- toBitcoinNetwork(network),
378
+ network,
337
379
  releaseRequest.toScriptPubkey,
338
380
  releaseRequest.bitcoinNetworkFee
339
381
  );
340
382
  return this.psbtFromHex(psbtStr);
341
383
  }
342
384
  psbtFromHex(psbtHex) {
343
- const psbt = Psbt.fromHex(psbtHex.replace(/^0x(.+)/, "$1"), { network: this.network });
344
- if (psbt.data.inputs.length === 0) {
385
+ const psbtBytes = hexToU8a2(psbtHex);
386
+ const tx = Transaction.fromPSBT(psbtBytes);
387
+ if (tx.inputsLength === 0) {
345
388
  throw new Error("PSBT has no inputs");
346
389
  }
347
- if (psbt.data.outputs.length === 0) {
390
+ if (tx.outputsLength === 0) {
348
391
  throw new Error("PSBT has no outputs");
349
392
  }
350
- return psbt;
393
+ return tx;
351
394
  }
352
395
  /**
353
396
  * Cosigns the PSBT with the vault xpub.
@@ -356,21 +399,33 @@ var CosignScript = class _CosignScript {
356
399
  * @param vaultXpriv - The vault's extended private key of which the xpub was used to create the vault.
357
400
  */
358
401
  vaultCosignPsbt(psbt, lock, vaultXpriv) {
359
- const parentFingerprint = Buffer.from(lock.vaultXpubSources.parentFingerprint);
360
- 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)) {
361
408
  throw new Error(
362
- `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)}`
363
410
  );
364
411
  }
365
412
  const childPath = `${lock.vaultXpubSources.cosignHdIndex}`;
366
- const pubkey = vaultXpriv.derivePath(childPath).publicKey;
367
- const vaultPubkey = keyToBuffer(lock.vaultPubkey);
368
- 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)) {
369
419
  throw new Error(
370
- `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}`
371
421
  );
372
422
  }
373
- 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
+ );
374
429
  psbt = this.psbtFromHex(signedPsbt);
375
430
  return psbt;
376
431
  }
@@ -382,74 +437,80 @@ var CosignScript = class _CosignScript {
382
437
  const psbt = this.getCosignPsbt(args);
383
438
  const { addTx, vaultCosignature, ownerXpriv, ownerXprivChildHdPath } = args;
384
439
  psbt.updateInput(0, {
385
- partialSig: [
386
- {
387
- pubkey: keyToBuffer(lock.vaultPubkey),
388
- signature: Buffer.from(vaultCosignature)
389
- }
390
- ]
440
+ partialSig: [[keyToU8a(lock.vaultPubkey), vaultCosignature]]
391
441
  });
392
442
  const derivePubkey = ownerXpriv.publicKey;
393
- const ownerPubkey = keyToBuffer(lock.ownerPubkey);
394
- 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)) {
395
448
  throw new Error(
396
- `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)}`
397
450
  );
398
451
  }
399
452
  if (addTx) {
400
- const tx = Transaction.fromHex(addTx.replace(/^0x(.+)/, "$1"));
401
- for (let i = 0; i < tx.outs.length; i++) {
402
- 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);
403
458
  const scripts = [
404
- payments.p2wpkh({ pubkey: ownerPubkey }).output,
405
- payments.p2sh({ redeem: payments.p2wpkh({ pubkey: ownerPubkey }) }).output,
406
- 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
407
463
  ];
408
- if (scripts.some((x) => x && output.script.equals(x))) {
464
+ if (scripts.some((x) => x && output.script && u8aEq(output.script, x))) {
409
465
  psbt.addInput({
410
- hash: tx.getId(),
466
+ txid: tx.id,
411
467
  index: i,
412
468
  witnessUtxo: {
413
469
  script: output.script,
414
- value: output.value
470
+ amount: output.amount
415
471
  }
416
472
  });
417
473
  }
418
474
  }
419
475
  }
420
- const signedPsbt = ownerXprivChildHdPath ? signPsbtDerived(psbt.toHex(), ownerXpriv.toBase58(), ownerXprivChildHdPath, true) : signPsbt(
421
- psbt.toHex(),
422
- toBitcoinNetwork(this.network),
423
- ownerXpriv.privateKey.toString("hex"),
424
- true
425
- );
426
- const finalPsbt = this.psbtFromHex(signedPsbt);
427
- return finalPsbt.extractTransaction();
428
- }
429
- static getBitcoinJsNetwork(network) {
430
- if (network.isBitcoin) return networks2.bitcoin;
431
- if (network.isTestnet || network.isSignet) return networks2.testnet;
432
- if (network.isRegtest) return networks2.regtest;
433
- 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);
434
479
  }
435
480
  };
436
- function toBitcoinNetwork(network) {
437
- if (network === networks2.bitcoin) {
481
+ function getBitcoinNetworkFromApi(network) {
482
+ if (network.isBitcoin) {
438
483
  return BitcoinNetwork.Bitcoin;
439
- } else if (network === networks2.testnet) {
484
+ } else if (network.isTestnet) {
440
485
  return BitcoinNetwork.Testnet;
441
- } else if (network === networks2.regtest) {
486
+ } else if (network.isRegtest) {
442
487
  return BitcoinNetwork.Regtest;
443
488
  }
444
489
  throw new Error("Unsupported network: " + network);
445
490
  }
491
+
492
+ // ts/index.ts
493
+ import * as bip39 from "@scure/bip39";
446
494
  export {
495
+ Address2 as Address,
496
+ BitcoinNetwork,
447
497
  CosignScript,
498
+ HDKey,
499
+ Transaction2 as Transaction,
448
500
  addressBytesHex,
449
- getBip39Seed,
501
+ bip39,
502
+ getBech32Prefix,
503
+ getBip32Version,
504
+ getBitcoinNetworkFromApi,
450
505
  getChildXpriv,
451
506
  getCompressedPubkey,
507
+ getScureNetwork,
452
508
  getXpubFromXpriv,
453
- keyToBuffer,
454
- stripLeadingHexPrefix
509
+ keyToU8a,
510
+ p2pk,
511
+ p2pkh2 as p2pkh,
512
+ p2sh2 as p2sh,
513
+ p2wpkh2 as p2wpkh,
514
+ p2wsh2 as p2wsh,
515
+ p2wshScriptHexToAddress
455
516
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@argonprotocol/bitcoin",
3
- "version": "1.3.1",
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.1",
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.1",
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",