@dynamic-labs/bitcoin 5.3.0 → 5.3.2

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/CHANGELOG.md CHANGED
@@ -1,4 +1,23 @@
1
1
 
2
+ ### [5.3.2](https://github.com/dynamic-labs/dynamic-auth/compare/v5.3.1...v5.3.2) (2026-08-19)
3
+
4
+
5
+ ### Features
6
+
7
+ * **bitcoin:** add allowedSighash to embedded wallet signPsbt ([#12233](https://github.com/dynamic-labs/dynamic-auth/issues/12233)) ([d0ff829](https://github.com/dynamic-labs/dynamic-auth/commit/d0ff8291a3d1771d5ca356172acc10af94349b15))
8
+ * **bitcoin:** forward signingIndexes to embedded PSBT signing ([#12211](https://github.com/dynamic-labs/dynamic-auth/issues/12211)) ([733da3d](https://github.com/dynamic-labs/dynamic-auth/commit/733da3d32f39a9ae6d813df84fcff6350ba12eb5))
9
+ * expose createOfflineRecoveryShares SDK function in webview and legacy client ([#12239](https://github.com/dynamic-labs/dynamic-auth/issues/12239)) ([c8056e8](https://github.com/dynamic-labs/dynamic-auth/commit/c8056e8d5a1c66ac0146b046bc7cc198de118f0b))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * **bitcoin:** parse PSBTs with the active network's address encoding ([#12219](https://github.com/dynamic-labs/dynamic-auth/issues/12219)) ([8b151e2](https://github.com/dynamic-labs/dynamic-auth/commit/8b151e23440094cfa0d48728e1d0f19de567ca05))
15
+ * **bitcoin:** stop ensureActiveAccount from resetting a switched network ([#12215](https://github.com/dynamic-labs/dynamic-auth/issues/12215)) ([86668b7](https://github.com/dynamic-labs/dynamic-auth/commit/86668b79d23cd89b7e96518551cdaecab7dd5ce3))
16
+ * remediate high-severity dependency vulnerabilities ([#12238](https://github.com/dynamic-labs/dynamic-auth/issues/12238)) ([a4fc78c](https://github.com/dynamic-labs/dynamic-auth/commit/a4fc78ca27ee44ce6a1038c4e0d07f55528b4994))
17
+ * **waas-svm:** retry SVM gas sponsorship before falling back, then throw ([#12240](https://github.com/dynamic-labs/dynamic-auth/issues/12240)) ([f599a7a](https://github.com/dynamic-labs/dynamic-auth/commit/f599a7af55727e06373772acf574ee7c43e56bbb))
18
+
19
+ ### [5.3.1](https://github.com/dynamic-labs/dynamic-auth/compare/v5.3.0...v5.3.1) (2026-08-14)
20
+
2
21
  ## [5.3.0](https://github.com/dynamic-labs/dynamic-auth/compare/v5.2.0...v5.3.0) (2026-08-12)
3
22
 
4
23
 
package/package.cjs CHANGED
@@ -3,6 +3,6 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
- var version = "5.3.0";
6
+ var version = "5.3.2";
7
7
 
8
8
  exports.version = version;
package/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  'use client'
2
- var version = "5.3.0";
2
+ var version = "5.3.2";
3
3
 
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/bitcoin",
3
- "version": "5.3.0",
3
+ "version": "5.3.2",
4
4
  "description": "A React SDK for implementing wallet web3 authentication and authorization to your website.",
5
5
  "author": "Dynamic Labs, Inc.",
6
6
  "license": "MIT",
@@ -18,24 +18,24 @@
18
18
  },
19
19
  "homepage": "https://www.dynamic.xyz/",
20
20
  "dependencies": {
21
- "@dynamic-labs-wallet/browser-wallet-client": "1.0.92",
21
+ "@dynamic-labs-wallet/browser-wallet-client": "1.0.106",
22
22
  "@dynamic-labs-wallet/forward-mpc-client": "1.0.1",
23
23
  "@bitcoinerlab/secp256k1": "1.1.1",
24
24
  "@btckit/types": "0.0.19",
25
- "@dynamic-labs/sdk-api-core": "0.0.1118",
25
+ "@dynamic-labs/sdk-api-core": "0.12.0",
26
26
  "@wallet-standard/app": "1.0.1",
27
27
  "@wallet-standard/base": "1.0.1",
28
28
  "bitcoinjs-lib": "6.1.5",
29
29
  "ecpair": "2.1.0",
30
30
  "sats-connect": "4.2.1",
31
31
  "jsontokens": "4.0.1",
32
- "@dynamic-labs/assert-package-version": "5.3.0",
33
- "@dynamic-labs/logger": "5.3.0",
34
- "@dynamic-labs/types": "5.3.0",
35
- "@dynamic-labs/utils": "5.3.0",
36
- "@dynamic-labs/waas": "5.3.0",
37
- "@dynamic-labs/wallet-book": "5.3.0",
38
- "@dynamic-labs/wallet-connector-core": "5.3.0",
32
+ "@dynamic-labs/assert-package-version": "5.3.2",
33
+ "@dynamic-labs/logger": "5.3.2",
34
+ "@dynamic-labs/types": "5.3.2",
35
+ "@dynamic-labs/utils": "5.3.2",
36
+ "@dynamic-labs/waas": "5.3.2",
37
+ "@dynamic-labs/wallet-book": "5.3.2",
38
+ "@dynamic-labs/wallet-connector-core": "5.3.2",
39
39
  "eventemitter3": "5.0.1"
40
40
  },
41
41
  "peerDependencies": {}
@@ -17,6 +17,7 @@ var BitcoinWalletConnector = require('../BitcoinWalletConnector.cjs');
17
17
  require('@wallet-standard/app');
18
18
  require('jsontokens');
19
19
  var btcToSatoshis = require('../../utils/btcToSatoshis/btcToSatoshis.cjs');
20
+ var getBitcoinNetwork = require('../../utils/getBitcoinNetwork/getBitcoinNetwork.cjs');
20
21
  var PsbtParser = require('../../utils/psbtParser/PsbtParser.cjs');
21
22
  var BitcoinUiTransaction = require('../../utils/BitcoinUiTransaction/BitcoinUiTransaction.cjs');
22
23
 
@@ -161,26 +162,65 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
161
162
  });
162
163
  }
163
164
  /**
164
- * Finds the credential that owns the active address, either as its primary
165
- * (mainnet) address or as one of its network-tagged additional addresses.
165
+ * Finds the credential that owns `address`, either as its primary (mainnet)
166
+ * address or as one of its network-tagged additional addresses.
166
167
  *
167
168
  * This connector is shared across every Bitcoin wallet of the user —
168
169
  * `verifiedCredentials` holds them all — so the owning credential must be
169
- * looked up by the active address. Reading `verifiedCredential` instead
170
- * would always answer with the user's *first* wallet.
170
+ * looked up by address. Reading `verifiedCredential` instead would always
171
+ * answer with the user's *first* wallet.
171
172
  */
172
- findCredentialForActiveAddress() {
173
+ findCredentialForAddress(address) {
173
174
  var _a;
174
- const { activeAccountAddress } = this;
175
- if (!activeAccountAddress) {
175
+ if (!address) {
176
176
  return undefined;
177
177
  }
178
178
  return ((_a = this.verifiedCredentials) !== null && _a !== void 0 ? _a : []).find((credential) => {
179
179
  var _a;
180
- return (credential === null || credential === void 0 ? void 0 : credential.address) === activeAccountAddress ||
181
- ((_a = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []).some((additionalAddress) => additionalAddress.address === activeAccountAddress);
180
+ return (credential === null || credential === void 0 ? void 0 : credential.address) === address ||
181
+ ((_a = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []).some((additionalAddress) => additionalAddress.address === address);
182
182
  });
183
183
  }
184
+ /** @see findCredentialForAddress */
185
+ findCredentialForActiveAddress() {
186
+ return this.findCredentialForAddress(this.activeAccountAddress);
187
+ }
188
+ /**
189
+ * True when `accountAddress` belongs to the same wallet as the currently
190
+ * active address — including when the active address is a *different*
191
+ * network-tagged encoding of that same wallet (e.g. the testnet address
192
+ * set by switchNetwork, compared against the wallet's primary mainnet
193
+ * address).
194
+ *
195
+ * Used by getWalletClientByAddress to avoid clobbering an explicit
196
+ * switchNetwork: callers like ensureActiveAccount re-assert the wallet's
197
+ * primary address before every send/sign, and setting activeAccountAddress
198
+ * back to that primary address would silently undo the network switch —
199
+ * UTXO/PSBT/broadcast calls would then run against the wrong (likely
200
+ * unfunded) encoding while getNetwork still reports the switched network.
201
+ *
202
+ * Compares the two resolved credential *objects* by reference rather than
203
+ * by id: both lookups run against the same verifiedCredentials array in
204
+ * the same synchronous call, so `.find()` returns the identical element
205
+ * for both addresses whenever they belong to the same wallet. Comparing
206
+ * `.id` instead would be wrong whenever accountAddress doesn't resolve to
207
+ * any known credential yet (e.g. a brand-new wallet not yet synced) —
208
+ * `undefined === undefined` would falsely read as "same wallet".
209
+ */
210
+ isSameWalletAddress(accountAddress) {
211
+ if (!this.activeAccountAddress) {
212
+ return false;
213
+ }
214
+ if (accountAddress === this.activeAccountAddress) {
215
+ return true;
216
+ }
217
+ const activeCredential = this.findCredentialForActiveAddress();
218
+ if (!activeCredential) {
219
+ return false;
220
+ }
221
+ const candidateCredential = this.findCredentialForAddress(accountAddress);
222
+ return (Boolean(candidateCredential) && candidateCredential === activeCredential);
223
+ }
184
224
  /**
185
225
  * Wallet identity: keyshares/wallet records are keyed by the wallet's
186
226
  * primary (mainnet) address. On testnet the active address is the same
@@ -302,7 +342,11 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
302
342
  * Signs a Partially Signed Bitcoin Transaction (PSBT) for embedded wallets
303
343
  *
304
344
  * Embedded wallets only support PSBT format and automatically sign all inputs
305
- * that belong to the wallet address. Always uses SIGHASH_ALL (0x01).
345
+ * that belong to the wallet address, unless `signingIndexes` narrows that set.
346
+ *
347
+ * The sighash type is read from the PSBT itself, falling back to
348
+ * SIGHASH_DEFAULT (0x00) for Taproot and SIGHASH_ALL (0x01) otherwise.
349
+ * `allowedSighash` restricts which declared types are accepted.
306
350
  *
307
351
  * @param request - The PSBT signing request. Only unsignedPsbtBase64 is required.
308
352
  * @returns The signed (but not finalized) PSBT response
@@ -331,12 +375,14 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
331
375
  accountAddress: walletIdentityAddress,
332
376
  });
333
377
  const signedTransaction = yield walletClient.signTransaction({
378
+ allowedSighash: request.allowedSighash,
334
379
  authToken: (_d = this.getAuthToken) === null || _d === void 0 ? void 0 : _d.call(this),
335
380
  elevatedAccessToken,
336
381
  mfaToken,
337
382
  password,
338
383
  senderAddress: walletIdentityAddress,
339
384
  signedSessionId,
385
+ signingIndexes: request.signingIndexes,
340
386
  transaction: request.unsignedPsbtBase64,
341
387
  });
342
388
  return {
@@ -472,12 +518,18 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
472
518
  });
473
519
  }
474
520
  /**
475
- * Gets the wallet client for a specific account address and sets it as active
521
+ * Gets the wallet client for a specific account address and sets it as
522
+ * active — unless `accountAddress` is just a different network-tagged
523
+ * encoding of the wallet that's already active (see isSameWalletAddress),
524
+ * in which case the current (possibly switchNetwork'd) active address is
525
+ * left untouched.
476
526
  * @param accountAddress - The Bitcoin account address
477
527
  * @returns The WaaS wallet client instance
478
528
  */
479
529
  getWalletClientByAddress({ accountAddress }) {
480
- this.setActiveAccountAddress(accountAddress);
530
+ if (!this.isSameWalletAddress(accountAddress)) {
531
+ this.setActiveAccountAddress(accountAddress);
532
+ }
481
533
  return this.getWaasWalletClient();
482
534
  }
483
535
  /**
@@ -497,7 +549,7 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
497
549
  */
498
550
  validateActiveWallet(expectedAddress) {
499
551
  return _tslib.__awaiter(this, void 0, void 0, function* () {
500
- var _a, _b, _c, _d;
552
+ var _a;
501
553
  const walletClient = yield this.getWaasWalletClient();
502
554
  const targetWallet = yield walletClient.getWallet({
503
555
  accountAddress: expectedAddress,
@@ -511,8 +563,12 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
511
563
  const isWalletActive = walletConnectorCore.isSameAddress(targetWallet.accountAddress, this.activeAccountAddress || '', this.connectedChain);
512
564
  // The active address may be a per-network encoding of this same wallet
513
565
  // (one key, network-tagged additional addresses). Resetting it here would
514
- // silently un-switch the selected network.
515
- const isPerNetworkVariantOfWallet = (_d = (_c = (_b = this.verifiedCredential) === null || _b === void 0 ? void 0 : _b.walletAdditionalAddresses) === null || _c === void 0 ? void 0 : _c.some((addr) => addr.address === this.activeAccountAddress)) !== null && _d !== void 0 ? _d : false;
566
+ // silently un-switch the selected network. Resolved via isSameWalletAddress
567
+ // (which looks up the credential that actually owns the active address)
568
+ // rather than `verifiedCredential`, which is always the user's *first*
569
+ // wallet — using it here would wrongly reset the address for any other
570
+ // wallet the user validates.
571
+ const isPerNetworkVariantOfWallet = this.isSameWalletAddress(targetWallet.accountAddress);
516
572
  if (!isWalletActive && !isPerNetworkVariantOfWallet) {
517
573
  this.activeAccountAddress = targetWallet.accountAddress;
518
574
  }
@@ -665,7 +721,7 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
665
721
  * @returns Parsed transaction data with inputs and outputs, or null if parsing fails
666
722
  */
667
723
  parsePsbt(psbtInput) {
668
- return PsbtParser.PsbtParser.parsePsbt(psbtInput);
724
+ return PsbtParser.PsbtParser.parsePsbt(psbtInput, this.getPsbtNetwork());
669
725
  }
670
726
  /**
671
727
  * Parse a PSBT or finalized transaction from hex format
@@ -673,7 +729,7 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
673
729
  * @returns Parsed transaction data with inputs and outputs, or null if parsing fails
674
730
  */
675
731
  parseHexPsbt(psbtHex) {
676
- return PsbtParser.PsbtParser.parseHexPsbt(psbtHex);
732
+ return PsbtParser.PsbtParser.parseHexPsbt(psbtHex, this.getPsbtNetwork());
677
733
  }
678
734
  /**
679
735
  * Parse a PSBT or finalized transaction from base64 format
@@ -681,7 +737,17 @@ class DynamicWaasBitcoinConnector extends waas.withDynamicWaas(BitcoinWalletConn
681
737
  * @returns Parsed transaction data with inputs and outputs, or null if parsing fails
682
738
  */
683
739
  parseBase64Psbt(psbtBase64) {
684
- return PsbtParser.PsbtParser.parseBase64Psbt(psbtBase64);
740
+ return PsbtParser.PsbtParser.parseBase64Psbt(psbtBase64, this.getPsbtNetwork());
741
+ }
742
+ /**
743
+ * bitcoinjs network for the address encoding the parsers should emit.
744
+ * Derived from the active address rather than activeNetworkId, which is
745
+ * in-memory only and can report mainnet while a testnet address is active.
746
+ */
747
+ getPsbtNetwork() {
748
+ return this.activeAccountAddress
749
+ ? getBitcoinNetwork.getBitcoinNetwork(this.activeAccountAddress)
750
+ : bitcoinjsLib.networks.bitcoin;
685
751
  }
686
752
  /**
687
753
  * Gets the public key for the active account
@@ -104,7 +104,9 @@ declare const DynamicWaasBitcoinConnector_base: (abstract new (...args: any[]) =
104
104
  deviceId: string;
105
105
  jwt: string;
106
106
  walletPassword: string;
107
- ncwStorage: Record<string, string>;
107
+ ncwStorage: Record<string, string>; /**
108
+ * Gets the current Bitcoin network id (1 mainnet, 2 testnet)
109
+ */
108
110
  expectedAddresses: Record<string, string>;
109
111
  coinTypes?: Record<string, number> | undefined;
110
112
  password?: string | undefined;
@@ -189,6 +191,12 @@ declare const DynamicWaasBitcoinConnector_base: (abstract new (...args: any[]) =
189
191
  getWalletRecoveryState({ accountAddress, }: {
190
192
  accountAddress: string;
191
193
  }): Promise<import("@dynamic-labs-wallet/browser-wallet-client").WalletRecoveryState>;
194
+ createOfflineRecoveryShares({ accountAddress, password, cloudProviderAccessToken, mfaToken, }: {
195
+ accountAddress: string;
196
+ password?: string | undefined;
197
+ cloudProviderAccessToken?: string | undefined;
198
+ mfaToken?: string | undefined;
199
+ }): Promise<void>;
192
200
  endSession(reason?: import("@dynamic-labs-sdk/client").LogoutReason | undefined): Promise<void>;
193
201
  getActiveAccountAddress(): Promise<string | undefined>;
194
202
  getConnectedAccounts(): Promise<string[]>;
@@ -295,15 +303,40 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
295
303
  */
296
304
  getBalance(address: string): Promise<string | undefined>;
297
305
  /**
298
- * Finds the credential that owns the active address, either as its primary
299
- * (mainnet) address or as one of its network-tagged additional addresses.
306
+ * Finds the credential that owns `address`, either as its primary (mainnet)
307
+ * address or as one of its network-tagged additional addresses.
300
308
  *
301
309
  * This connector is shared across every Bitcoin wallet of the user —
302
310
  * `verifiedCredentials` holds them all — so the owning credential must be
303
- * looked up by the active address. Reading `verifiedCredential` instead
304
- * would always answer with the user's *first* wallet.
311
+ * looked up by address. Reading `verifiedCredential` instead would always
312
+ * answer with the user's *first* wallet.
305
313
  */
314
+ private findCredentialForAddress;
315
+ /** @see findCredentialForAddress */
306
316
  private findCredentialForActiveAddress;
317
+ /**
318
+ * True when `accountAddress` belongs to the same wallet as the currently
319
+ * active address — including when the active address is a *different*
320
+ * network-tagged encoding of that same wallet (e.g. the testnet address
321
+ * set by switchNetwork, compared against the wallet's primary mainnet
322
+ * address).
323
+ *
324
+ * Used by getWalletClientByAddress to avoid clobbering an explicit
325
+ * switchNetwork: callers like ensureActiveAccount re-assert the wallet's
326
+ * primary address before every send/sign, and setting activeAccountAddress
327
+ * back to that primary address would silently undo the network switch —
328
+ * UTXO/PSBT/broadcast calls would then run against the wrong (likely
329
+ * unfunded) encoding while getNetwork still reports the switched network.
330
+ *
331
+ * Compares the two resolved credential *objects* by reference rather than
332
+ * by id: both lookups run against the same verifiedCredentials array in
333
+ * the same synchronous call, so `.find()` returns the identical element
334
+ * for both addresses whenever they belong to the same wallet. Comparing
335
+ * `.id` instead would be wrong whenever accountAddress doesn't resolve to
336
+ * any known credential yet (e.g. a brand-new wallet not yet synced) —
337
+ * `undefined === undefined` would falsely read as "same wallet".
338
+ */
339
+ private isSameWalletAddress;
307
340
  /**
308
341
  * Wallet identity: keyshares/wallet records are keyed by the wallet's
309
342
  * primary (mainnet) address. On testnet the active address is the same
@@ -354,7 +387,11 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
354
387
  * Signs a Partially Signed Bitcoin Transaction (PSBT) for embedded wallets
355
388
  *
356
389
  * Embedded wallets only support PSBT format and automatically sign all inputs
357
- * that belong to the wallet address. Always uses SIGHASH_ALL (0x01).
390
+ * that belong to the wallet address, unless `signingIndexes` narrows that set.
391
+ *
392
+ * The sighash type is read from the PSBT itself, falling back to
393
+ * SIGHASH_DEFAULT (0x00) for Taproot and SIGHASH_ALL (0x01) otherwise.
394
+ * `allowedSighash` restricts which declared types are accepted.
358
395
  *
359
396
  * @param request - The PSBT signing request. Only unsignedPsbtBase64 is required.
360
397
  * @returns The signed (but not finalized) PSBT response
@@ -414,7 +451,11 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
414
451
  legacyWalletId?: string;
415
452
  }): Promise<void>;
416
453
  /**
417
- * Gets the wallet client for a specific account address and sets it as active
454
+ * Gets the wallet client for a specific account address and sets it as
455
+ * active — unless `accountAddress` is just a different network-tagged
456
+ * encoding of the wallet that's already active (see isSameWalletAddress),
457
+ * in which case the current (possibly switchNetwork'd) active address is
458
+ * left untouched.
418
459
  * @param accountAddress - The Bitcoin account address
419
460
  * @returns The WaaS wallet client instance
420
461
  */
@@ -480,6 +521,12 @@ export declare class DynamicWaasBitcoinConnector extends DynamicWaasBitcoinConne
480
521
  * @returns Parsed transaction data with inputs and outputs, or null if parsing fails
481
522
  */
482
523
  parseBase64Psbt(psbtBase64: string): ParsedTransaction | null;
524
+ /**
525
+ * bitcoinjs network for the address encoding the parsers should emit.
526
+ * Derived from the active address rather than activeNetworkId, which is
527
+ * in-memory only and can report mainnet while a testnet address is active.
528
+ */
529
+ private getPsbtNetwork;
483
530
  /**
484
531
  * Gets the public key for the active account
485
532
  * Falls back to the account address if public key retrieval fails
@@ -13,6 +13,7 @@ import { BitcoinWalletConnector } from '../BitcoinWalletConnector.js';
13
13
  import '@wallet-standard/app';
14
14
  import 'jsontokens';
15
15
  import { btcToSatoshis } from '../../utils/btcToSatoshis/btcToSatoshis.js';
16
+ import { getBitcoinNetwork } from '../../utils/getBitcoinNetwork/getBitcoinNetwork.js';
16
17
  import { PsbtParser } from '../../utils/psbtParser/PsbtParser.js';
17
18
  import { BitcoinUiTransaction } from '../../utils/BitcoinUiTransaction/BitcoinUiTransaction.js';
18
19
 
@@ -157,26 +158,65 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
157
158
  });
158
159
  }
159
160
  /**
160
- * Finds the credential that owns the active address, either as its primary
161
- * (mainnet) address or as one of its network-tagged additional addresses.
161
+ * Finds the credential that owns `address`, either as its primary (mainnet)
162
+ * address or as one of its network-tagged additional addresses.
162
163
  *
163
164
  * This connector is shared across every Bitcoin wallet of the user —
164
165
  * `verifiedCredentials` holds them all — so the owning credential must be
165
- * looked up by the active address. Reading `verifiedCredential` instead
166
- * would always answer with the user's *first* wallet.
166
+ * looked up by address. Reading `verifiedCredential` instead would always
167
+ * answer with the user's *first* wallet.
167
168
  */
168
- findCredentialForActiveAddress() {
169
+ findCredentialForAddress(address) {
169
170
  var _a;
170
- const { activeAccountAddress } = this;
171
- if (!activeAccountAddress) {
171
+ if (!address) {
172
172
  return undefined;
173
173
  }
174
174
  return ((_a = this.verifiedCredentials) !== null && _a !== void 0 ? _a : []).find((credential) => {
175
175
  var _a;
176
- return (credential === null || credential === void 0 ? void 0 : credential.address) === activeAccountAddress ||
177
- ((_a = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []).some((additionalAddress) => additionalAddress.address === activeAccountAddress);
176
+ return (credential === null || credential === void 0 ? void 0 : credential.address) === address ||
177
+ ((_a = credential === null || credential === void 0 ? void 0 : credential.walletAdditionalAddresses) !== null && _a !== void 0 ? _a : []).some((additionalAddress) => additionalAddress.address === address);
178
178
  });
179
179
  }
180
+ /** @see findCredentialForAddress */
181
+ findCredentialForActiveAddress() {
182
+ return this.findCredentialForAddress(this.activeAccountAddress);
183
+ }
184
+ /**
185
+ * True when `accountAddress` belongs to the same wallet as the currently
186
+ * active address — including when the active address is a *different*
187
+ * network-tagged encoding of that same wallet (e.g. the testnet address
188
+ * set by switchNetwork, compared against the wallet's primary mainnet
189
+ * address).
190
+ *
191
+ * Used by getWalletClientByAddress to avoid clobbering an explicit
192
+ * switchNetwork: callers like ensureActiveAccount re-assert the wallet's
193
+ * primary address before every send/sign, and setting activeAccountAddress
194
+ * back to that primary address would silently undo the network switch —
195
+ * UTXO/PSBT/broadcast calls would then run against the wrong (likely
196
+ * unfunded) encoding while getNetwork still reports the switched network.
197
+ *
198
+ * Compares the two resolved credential *objects* by reference rather than
199
+ * by id: both lookups run against the same verifiedCredentials array in
200
+ * the same synchronous call, so `.find()` returns the identical element
201
+ * for both addresses whenever they belong to the same wallet. Comparing
202
+ * `.id` instead would be wrong whenever accountAddress doesn't resolve to
203
+ * any known credential yet (e.g. a brand-new wallet not yet synced) —
204
+ * `undefined === undefined` would falsely read as "same wallet".
205
+ */
206
+ isSameWalletAddress(accountAddress) {
207
+ if (!this.activeAccountAddress) {
208
+ return false;
209
+ }
210
+ if (accountAddress === this.activeAccountAddress) {
211
+ return true;
212
+ }
213
+ const activeCredential = this.findCredentialForActiveAddress();
214
+ if (!activeCredential) {
215
+ return false;
216
+ }
217
+ const candidateCredential = this.findCredentialForAddress(accountAddress);
218
+ return (Boolean(candidateCredential) && candidateCredential === activeCredential);
219
+ }
180
220
  /**
181
221
  * Wallet identity: keyshares/wallet records are keyed by the wallet's
182
222
  * primary (mainnet) address. On testnet the active address is the same
@@ -298,7 +338,11 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
298
338
  * Signs a Partially Signed Bitcoin Transaction (PSBT) for embedded wallets
299
339
  *
300
340
  * Embedded wallets only support PSBT format and automatically sign all inputs
301
- * that belong to the wallet address. Always uses SIGHASH_ALL (0x01).
341
+ * that belong to the wallet address, unless `signingIndexes` narrows that set.
342
+ *
343
+ * The sighash type is read from the PSBT itself, falling back to
344
+ * SIGHASH_DEFAULT (0x00) for Taproot and SIGHASH_ALL (0x01) otherwise.
345
+ * `allowedSighash` restricts which declared types are accepted.
302
346
  *
303
347
  * @param request - The PSBT signing request. Only unsignedPsbtBase64 is required.
304
348
  * @returns The signed (but not finalized) PSBT response
@@ -327,12 +371,14 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
327
371
  accountAddress: walletIdentityAddress,
328
372
  });
329
373
  const signedTransaction = yield walletClient.signTransaction({
374
+ allowedSighash: request.allowedSighash,
330
375
  authToken: (_d = this.getAuthToken) === null || _d === void 0 ? void 0 : _d.call(this),
331
376
  elevatedAccessToken,
332
377
  mfaToken,
333
378
  password,
334
379
  senderAddress: walletIdentityAddress,
335
380
  signedSessionId,
381
+ signingIndexes: request.signingIndexes,
336
382
  transaction: request.unsignedPsbtBase64,
337
383
  });
338
384
  return {
@@ -468,12 +514,18 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
468
514
  });
469
515
  }
470
516
  /**
471
- * Gets the wallet client for a specific account address and sets it as active
517
+ * Gets the wallet client for a specific account address and sets it as
518
+ * active — unless `accountAddress` is just a different network-tagged
519
+ * encoding of the wallet that's already active (see isSameWalletAddress),
520
+ * in which case the current (possibly switchNetwork'd) active address is
521
+ * left untouched.
472
522
  * @param accountAddress - The Bitcoin account address
473
523
  * @returns The WaaS wallet client instance
474
524
  */
475
525
  getWalletClientByAddress({ accountAddress }) {
476
- this.setActiveAccountAddress(accountAddress);
526
+ if (!this.isSameWalletAddress(accountAddress)) {
527
+ this.setActiveAccountAddress(accountAddress);
528
+ }
477
529
  return this.getWaasWalletClient();
478
530
  }
479
531
  /**
@@ -493,7 +545,7 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
493
545
  */
494
546
  validateActiveWallet(expectedAddress) {
495
547
  return __awaiter(this, void 0, void 0, function* () {
496
- var _a, _b, _c, _d;
548
+ var _a;
497
549
  const walletClient = yield this.getWaasWalletClient();
498
550
  const targetWallet = yield walletClient.getWallet({
499
551
  accountAddress: expectedAddress,
@@ -507,8 +559,12 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
507
559
  const isWalletActive = isSameAddress(targetWallet.accountAddress, this.activeAccountAddress || '', this.connectedChain);
508
560
  // The active address may be a per-network encoding of this same wallet
509
561
  // (one key, network-tagged additional addresses). Resetting it here would
510
- // silently un-switch the selected network.
511
- const isPerNetworkVariantOfWallet = (_d = (_c = (_b = this.verifiedCredential) === null || _b === void 0 ? void 0 : _b.walletAdditionalAddresses) === null || _c === void 0 ? void 0 : _c.some((addr) => addr.address === this.activeAccountAddress)) !== null && _d !== void 0 ? _d : false;
562
+ // silently un-switch the selected network. Resolved via isSameWalletAddress
563
+ // (which looks up the credential that actually owns the active address)
564
+ // rather than `verifiedCredential`, which is always the user's *first*
565
+ // wallet — using it here would wrongly reset the address for any other
566
+ // wallet the user validates.
567
+ const isPerNetworkVariantOfWallet = this.isSameWalletAddress(targetWallet.accountAddress);
512
568
  if (!isWalletActive && !isPerNetworkVariantOfWallet) {
513
569
  this.activeAccountAddress = targetWallet.accountAddress;
514
570
  }
@@ -661,7 +717,7 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
661
717
  * @returns Parsed transaction data with inputs and outputs, or null if parsing fails
662
718
  */
663
719
  parsePsbt(psbtInput) {
664
- return PsbtParser.parsePsbt(psbtInput);
720
+ return PsbtParser.parsePsbt(psbtInput, this.getPsbtNetwork());
665
721
  }
666
722
  /**
667
723
  * Parse a PSBT or finalized transaction from hex format
@@ -669,7 +725,7 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
669
725
  * @returns Parsed transaction data with inputs and outputs, or null if parsing fails
670
726
  */
671
727
  parseHexPsbt(psbtHex) {
672
- return PsbtParser.parseHexPsbt(psbtHex);
728
+ return PsbtParser.parseHexPsbt(psbtHex, this.getPsbtNetwork());
673
729
  }
674
730
  /**
675
731
  * Parse a PSBT or finalized transaction from base64 format
@@ -677,7 +733,17 @@ class DynamicWaasBitcoinConnector extends withDynamicWaas(BitcoinWalletConnector
677
733
  * @returns Parsed transaction data with inputs and outputs, or null if parsing fails
678
734
  */
679
735
  parseBase64Psbt(psbtBase64) {
680
- return PsbtParser.parseBase64Psbt(psbtBase64);
736
+ return PsbtParser.parseBase64Psbt(psbtBase64, this.getPsbtNetwork());
737
+ }
738
+ /**
739
+ * bitcoinjs network for the address encoding the parsers should emit.
740
+ * Derived from the active address rather than activeNetworkId, which is
741
+ * in-memory only and can report mainnet while a testnet address is active.
742
+ */
743
+ getPsbtNetwork() {
744
+ return this.activeAccountAddress
745
+ ? getBitcoinNetwork(this.activeAccountAddress)
746
+ : networks.bitcoin;
681
747
  }
682
748
  /**
683
749
  * Gets the public key for the active account
package/src/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { OkxConnector } from './connectors';
1
+ import { OkxConnector, DynamicWaasBitcoinConnector } from './connectors';
2
2
  export { BitcoinWalletConnector, type BitcoinWalletConnectorOpts, } from './connectors';
3
3
  export type { BitcoinTransaction, BitcoinSignProtocol, BitcoinSignPsbtRequest, BitcoinSignPsbtResponse, BitcoinWalletStandardMethods, SignPsbtOptions, EmbeddedWalletSignPsbtRequest, } from './types';
4
4
  export * from './utils';
5
5
  export * from './wallet';
6
6
  export { UnisatConnector, BitcoinSatsConnectConnector, DynamicWaasBitcoinConnector, } from './connectors';
7
- export declare const BitcoinWalletConnectors: (props: any) => (import("dist/packages/wallet-connector-core/src").WalletConnectorConstructor | typeof OkxConnector)[];
7
+ export declare const BitcoinWalletConnectors: (props: any) => (import("dist/packages/wallet-connector-core/src").WalletConnectorConstructor | typeof OkxConnector | typeof DynamicWaasBitcoinConnector)[];
8
8
  export { BitcoinProviderHelper } from './bitcoinProviderHelper';
9
9
  export { DUST_LIMIT, HTTP_STATUS_NOT_FOUND, HTTP_STATUS_TOO_MANY_REQUESTS, } from './const';
package/src/types.d.ts CHANGED
@@ -67,6 +67,19 @@ export type EmbeddedWalletSignPsbtRequest = {
67
67
  * Embedded wallets only support PSBT format, not raw transaction hex.
68
68
  */
69
69
  unsignedPsbtBase64: string;
70
+ /**
71
+ * Optional subset of PSBT input indexes to sign. When provided, only these
72
+ * indexes are signed (they must still belong to the wallet's own address).
73
+ * When omitted, behavior is unchanged: all wallet-owned inputs are signed.
74
+ */
75
+ signingIndexes?: number[];
76
+ /**
77
+ * Optional allow-list of sighash types. The sighash type itself is read from
78
+ * the PSBT (BIP-174 `PSBT_IN_SIGHASH_TYPE`) — this only restricts which
79
+ * declared types are accepted, and signing throws if an input declares one
80
+ * outside the list. When omitted, any declared type is signed.
81
+ */
82
+ allowedSighash?: number[];
70
83
  };
71
84
  export type SatsConnectSignTransactionInput = {
72
85
  message?: string;
@@ -13,16 +13,19 @@ class PsbtParser {
13
13
  * Parse a PSBT or finalized transaction and extract transaction information
14
14
  * Auto-detects format (hex/base64) and type (PSBT/finalized transaction)
15
15
  * @param psbtInput - The PSBT or finalized transaction in Base64 or hex format
16
+ * @param network - Network used to encode the extracted addresses. Scripts are
17
+ * network-agnostic, so passing the wrong one silently renders a valid address
18
+ * under the wrong prefix (a testnet output shown as `bc1…`).
16
19
  * @returns Parsed transaction data with inputs and outputs
17
20
  * @throws Error if parsing fails
18
21
  */
19
- static parsePsbt(psbtInput) {
22
+ static parsePsbt(psbtInput, network = bitcoinjsLib.networks.bitcoin) {
20
23
  const isHex = /^[0-9a-fA-F]+$/.test(psbtInput) && psbtInput.length > 100;
21
24
  if (isHex) {
22
- return PsbtParser.parseHexPsbt(psbtInput);
25
+ return PsbtParser.parseHexPsbt(psbtInput, network);
23
26
  }
24
27
  else {
25
- return PsbtParser.parseBase64Psbt(psbtInput);
28
+ return PsbtParser.parseBase64Psbt(psbtInput, network);
26
29
  }
27
30
  }
28
31
  /**
@@ -31,14 +34,14 @@ class PsbtParser {
31
34
  * @returns Parsed transaction data with inputs and outputs
32
35
  * @throws Error if parsing fails
33
36
  */
34
- static parseHexPsbt(psbtHex) {
37
+ static parseHexPsbt(psbtHex, network = bitcoinjsLib.networks.bitcoin) {
35
38
  try {
36
39
  try {
37
- const psbt = bitcoinjsLib.Psbt.fromHex(psbtHex, { network: bitcoinjsLib.networks.bitcoin });
38
- return PsbtParser.extractPsbtData(psbt);
40
+ const psbt = bitcoinjsLib.Psbt.fromHex(psbtHex, { network });
41
+ return PsbtParser.extractPsbtData(psbt, network);
39
42
  }
40
43
  catch (psbtError) {
41
- return PsbtParser.parseFinalizedTransactionHex(psbtHex);
44
+ return PsbtParser.parseFinalizedTransactionHex(psbtHex, network);
42
45
  }
43
46
  }
44
47
  catch (error) {
@@ -51,14 +54,14 @@ class PsbtParser {
51
54
  * @returns Parsed transaction data with inputs and outputs
52
55
  * @throws Error if parsing fails
53
56
  */
54
- static parseBase64Psbt(psbtBase64) {
57
+ static parseBase64Psbt(psbtBase64, network = bitcoinjsLib.networks.bitcoin) {
55
58
  try {
56
59
  try {
57
- const psbt = bitcoinjsLib.Psbt.fromBase64(psbtBase64, { network: bitcoinjsLib.networks.bitcoin });
58
- return PsbtParser.extractPsbtData(psbt);
60
+ const psbt = bitcoinjsLib.Psbt.fromBase64(psbtBase64, { network });
61
+ return PsbtParser.extractPsbtData(psbt, network);
59
62
  }
60
63
  catch (psbtError) {
61
- return PsbtParser.parseFinalizedTransactionBase64(psbtBase64);
64
+ return PsbtParser.parseFinalizedTransactionBase64(psbtBase64, network);
62
65
  }
63
66
  }
64
67
  catch (error) {
@@ -71,7 +74,7 @@ class PsbtParser {
71
74
  * @param psbt - The parsed PSBT object
72
75
  * @returns Parsed transaction data with inputs and outputs
73
76
  */
74
- static extractPsbtData(psbt) {
77
+ static extractPsbtData(psbt, network) {
75
78
  const inputs = [];
76
79
  const outputs = [];
77
80
  psbt.txInputs.forEach((txInput, index) => {
@@ -83,7 +86,7 @@ class PsbtParser {
83
86
  if (input.witnessUtxo) {
84
87
  inputData.value = input.witnessUtxo.value;
85
88
  try {
86
- inputData.address = bitcoinjsLib.address.fromOutputScript(input.witnessUtxo.script, bitcoinjsLib.networks.bitcoin);
89
+ inputData.address = bitcoinjsLib.address.fromOutputScript(input.witnessUtxo.script, network);
87
90
  }
88
91
  catch (e) {
89
92
  // Address extraction failed
@@ -95,7 +98,7 @@ class PsbtParser {
95
98
  const prevOut = prevTx.outs[txInput.index];
96
99
  inputData.value = prevOut.value;
97
100
  try {
98
- inputData.address = bitcoinjsLib.address.fromOutputScript(prevOut.script, bitcoinjsLib.networks.bitcoin);
101
+ inputData.address = bitcoinjsLib.address.fromOutputScript(prevOut.script, network);
99
102
  }
100
103
  catch (e) {
101
104
  // Address extraction failed
@@ -107,7 +110,7 @@ class PsbtParser {
107
110
  }
108
111
  inputs.push(inputData);
109
112
  });
110
- PsbtParser.extractOutputs(psbt.txOutputs, outputs);
113
+ PsbtParser.extractOutputs(psbt.txOutputs, outputs, network);
111
114
  return { inputs, outputs };
112
115
  }
113
116
  /**
@@ -116,13 +119,13 @@ class PsbtParser {
116
119
  * @param txOutputs - Array of transaction outputs (from PSBT or Transaction)
117
120
  * @param outputs - Array to populate with parsed output data
118
121
  */
119
- static extractOutputs(txOutputs, outputs) {
122
+ static extractOutputs(txOutputs, outputs, network) {
120
123
  txOutputs.forEach((txOutput) => {
121
124
  const outputData = {
122
125
  value: txOutput.value,
123
126
  };
124
127
  try {
125
- outputData.address = bitcoinjsLib.address.fromOutputScript(txOutput.script, bitcoinjsLib.networks.bitcoin);
128
+ outputData.address = bitcoinjsLib.address.fromOutputScript(txOutput.script, network);
126
129
  }
127
130
  catch (e) {
128
131
  // Address extraction failed - continue without address
@@ -136,10 +139,10 @@ class PsbtParser {
136
139
  * @returns Parsed transaction data with inputs and outputs
137
140
  * @throws Error if parsing fails
138
141
  */
139
- static parseFinalizedTransactionHex(txHex) {
142
+ static parseFinalizedTransactionHex(txHex, network) {
140
143
  try {
141
144
  const tx = bitcoinjsLib.Transaction.fromHex(txHex);
142
- return PsbtParser.extractTransactionData(tx);
145
+ return PsbtParser.extractTransactionData(tx, network);
143
146
  }
144
147
  catch (error) {
145
148
  throw new Error(`Failed to parse finalized transaction hex: ${error instanceof Error ? error.message : String(error)}`);
@@ -151,11 +154,11 @@ class PsbtParser {
151
154
  * @returns Parsed transaction data with inputs and outputs
152
155
  * @throws Error if parsing fails
153
156
  */
154
- static parseFinalizedTransactionBase64(txBase64) {
157
+ static parseFinalizedTransactionBase64(txBase64, network) {
155
158
  try {
156
159
  const buffer = Buffer.from(txBase64, 'base64');
157
160
  const tx = bitcoinjsLib.Transaction.fromBuffer(buffer);
158
- return PsbtParser.extractTransactionData(tx);
161
+ return PsbtParser.extractTransactionData(tx, network);
159
162
  }
160
163
  catch (error) {
161
164
  throw new Error(`Failed to parse finalized transaction base64: ${error instanceof Error ? error.message : String(error)}`);
@@ -167,7 +170,7 @@ class PsbtParser {
167
170
  * @param tx - The parsed Transaction object
168
171
  * @returns Parsed transaction data with inputs and outputs
169
172
  */
170
- static extractTransactionData(tx) {
173
+ static extractTransactionData(tx, network) {
171
174
  const inputs = [];
172
175
  const outputs = [];
173
176
  tx.ins.forEach((input) => {
@@ -177,7 +180,7 @@ class PsbtParser {
177
180
  };
178
181
  inputs.push(inputData);
179
182
  });
180
- PsbtParser.extractOutputs(tx.outs, outputs);
183
+ PsbtParser.extractOutputs(tx.outs, outputs, network);
181
184
  return { inputs, outputs };
182
185
  }
183
186
  }
@@ -1,3 +1,4 @@
1
+ import { type Network } from 'bitcoinjs-lib';
1
2
  import type { ParsedTransaction } from '../../types';
2
3
  /**
3
4
  * Utility class for parsing PSBTs and finalized Bitcoin transactions
@@ -7,24 +8,27 @@ export declare class PsbtParser {
7
8
  * Parse a PSBT or finalized transaction and extract transaction information
8
9
  * Auto-detects format (hex/base64) and type (PSBT/finalized transaction)
9
10
  * @param psbtInput - The PSBT or finalized transaction in Base64 or hex format
11
+ * @param network - Network used to encode the extracted addresses. Scripts are
12
+ * network-agnostic, so passing the wrong one silently renders a valid address
13
+ * under the wrong prefix (a testnet output shown as `bc1…`).
10
14
  * @returns Parsed transaction data with inputs and outputs
11
15
  * @throws Error if parsing fails
12
16
  */
13
- static parsePsbt(psbtInput: string): ParsedTransaction;
17
+ static parsePsbt(psbtInput: string, network?: Network): ParsedTransaction;
14
18
  /**
15
19
  * Parse a PSBT or finalized transaction from hex format
16
20
  * @param psbtHex - The PSBT or finalized transaction in hex format
17
21
  * @returns Parsed transaction data with inputs and outputs
18
22
  * @throws Error if parsing fails
19
23
  */
20
- static parseHexPsbt(psbtHex: string): ParsedTransaction;
24
+ static parseHexPsbt(psbtHex: string, network?: Network): ParsedTransaction;
21
25
  /**
22
26
  * Parse a PSBT or finalized transaction from base64 format
23
27
  * @param psbtBase64 - The PSBT or finalized transaction in base64 format
24
28
  * @returns Parsed transaction data with inputs and outputs
25
29
  * @throws Error if parsing fails
26
30
  */
27
- static parseBase64Psbt(psbtBase64: string): ParsedTransaction;
31
+ static parseBase64Psbt(psbtBase64: string, network?: Network): ParsedTransaction;
28
32
  /**
29
33
  * Extract transaction data from a PSBT
30
34
  * Shared logic used by both parseHexPsbt and parseBase64Psbt
@@ -1,5 +1,5 @@
1
1
  'use client'
2
- import { Psbt, networks, address, Transaction } from 'bitcoinjs-lib';
2
+ import { networks, Psbt, address, Transaction } from 'bitcoinjs-lib';
3
3
 
4
4
  /**
5
5
  * Utility class for parsing PSBTs and finalized Bitcoin transactions
@@ -9,16 +9,19 @@ class PsbtParser {
9
9
  * Parse a PSBT or finalized transaction and extract transaction information
10
10
  * Auto-detects format (hex/base64) and type (PSBT/finalized transaction)
11
11
  * @param psbtInput - The PSBT or finalized transaction in Base64 or hex format
12
+ * @param network - Network used to encode the extracted addresses. Scripts are
13
+ * network-agnostic, so passing the wrong one silently renders a valid address
14
+ * under the wrong prefix (a testnet output shown as `bc1…`).
12
15
  * @returns Parsed transaction data with inputs and outputs
13
16
  * @throws Error if parsing fails
14
17
  */
15
- static parsePsbt(psbtInput) {
18
+ static parsePsbt(psbtInput, network = networks.bitcoin) {
16
19
  const isHex = /^[0-9a-fA-F]+$/.test(psbtInput) && psbtInput.length > 100;
17
20
  if (isHex) {
18
- return PsbtParser.parseHexPsbt(psbtInput);
21
+ return PsbtParser.parseHexPsbt(psbtInput, network);
19
22
  }
20
23
  else {
21
- return PsbtParser.parseBase64Psbt(psbtInput);
24
+ return PsbtParser.parseBase64Psbt(psbtInput, network);
22
25
  }
23
26
  }
24
27
  /**
@@ -27,14 +30,14 @@ class PsbtParser {
27
30
  * @returns Parsed transaction data with inputs and outputs
28
31
  * @throws Error if parsing fails
29
32
  */
30
- static parseHexPsbt(psbtHex) {
33
+ static parseHexPsbt(psbtHex, network = networks.bitcoin) {
31
34
  try {
32
35
  try {
33
- const psbt = Psbt.fromHex(psbtHex, { network: networks.bitcoin });
34
- return PsbtParser.extractPsbtData(psbt);
36
+ const psbt = Psbt.fromHex(psbtHex, { network });
37
+ return PsbtParser.extractPsbtData(psbt, network);
35
38
  }
36
39
  catch (psbtError) {
37
- return PsbtParser.parseFinalizedTransactionHex(psbtHex);
40
+ return PsbtParser.parseFinalizedTransactionHex(psbtHex, network);
38
41
  }
39
42
  }
40
43
  catch (error) {
@@ -47,14 +50,14 @@ class PsbtParser {
47
50
  * @returns Parsed transaction data with inputs and outputs
48
51
  * @throws Error if parsing fails
49
52
  */
50
- static parseBase64Psbt(psbtBase64) {
53
+ static parseBase64Psbt(psbtBase64, network = networks.bitcoin) {
51
54
  try {
52
55
  try {
53
- const psbt = Psbt.fromBase64(psbtBase64, { network: networks.bitcoin });
54
- return PsbtParser.extractPsbtData(psbt);
56
+ const psbt = Psbt.fromBase64(psbtBase64, { network });
57
+ return PsbtParser.extractPsbtData(psbt, network);
55
58
  }
56
59
  catch (psbtError) {
57
- return PsbtParser.parseFinalizedTransactionBase64(psbtBase64);
60
+ return PsbtParser.parseFinalizedTransactionBase64(psbtBase64, network);
58
61
  }
59
62
  }
60
63
  catch (error) {
@@ -67,7 +70,7 @@ class PsbtParser {
67
70
  * @param psbt - The parsed PSBT object
68
71
  * @returns Parsed transaction data with inputs and outputs
69
72
  */
70
- static extractPsbtData(psbt) {
73
+ static extractPsbtData(psbt, network) {
71
74
  const inputs = [];
72
75
  const outputs = [];
73
76
  psbt.txInputs.forEach((txInput, index) => {
@@ -79,7 +82,7 @@ class PsbtParser {
79
82
  if (input.witnessUtxo) {
80
83
  inputData.value = input.witnessUtxo.value;
81
84
  try {
82
- inputData.address = address.fromOutputScript(input.witnessUtxo.script, networks.bitcoin);
85
+ inputData.address = address.fromOutputScript(input.witnessUtxo.script, network);
83
86
  }
84
87
  catch (e) {
85
88
  // Address extraction failed
@@ -91,7 +94,7 @@ class PsbtParser {
91
94
  const prevOut = prevTx.outs[txInput.index];
92
95
  inputData.value = prevOut.value;
93
96
  try {
94
- inputData.address = address.fromOutputScript(prevOut.script, networks.bitcoin);
97
+ inputData.address = address.fromOutputScript(prevOut.script, network);
95
98
  }
96
99
  catch (e) {
97
100
  // Address extraction failed
@@ -103,7 +106,7 @@ class PsbtParser {
103
106
  }
104
107
  inputs.push(inputData);
105
108
  });
106
- PsbtParser.extractOutputs(psbt.txOutputs, outputs);
109
+ PsbtParser.extractOutputs(psbt.txOutputs, outputs, network);
107
110
  return { inputs, outputs };
108
111
  }
109
112
  /**
@@ -112,13 +115,13 @@ class PsbtParser {
112
115
  * @param txOutputs - Array of transaction outputs (from PSBT or Transaction)
113
116
  * @param outputs - Array to populate with parsed output data
114
117
  */
115
- static extractOutputs(txOutputs, outputs) {
118
+ static extractOutputs(txOutputs, outputs, network) {
116
119
  txOutputs.forEach((txOutput) => {
117
120
  const outputData = {
118
121
  value: txOutput.value,
119
122
  };
120
123
  try {
121
- outputData.address = address.fromOutputScript(txOutput.script, networks.bitcoin);
124
+ outputData.address = address.fromOutputScript(txOutput.script, network);
122
125
  }
123
126
  catch (e) {
124
127
  // Address extraction failed - continue without address
@@ -132,10 +135,10 @@ class PsbtParser {
132
135
  * @returns Parsed transaction data with inputs and outputs
133
136
  * @throws Error if parsing fails
134
137
  */
135
- static parseFinalizedTransactionHex(txHex) {
138
+ static parseFinalizedTransactionHex(txHex, network) {
136
139
  try {
137
140
  const tx = Transaction.fromHex(txHex);
138
- return PsbtParser.extractTransactionData(tx);
141
+ return PsbtParser.extractTransactionData(tx, network);
139
142
  }
140
143
  catch (error) {
141
144
  throw new Error(`Failed to parse finalized transaction hex: ${error instanceof Error ? error.message : String(error)}`);
@@ -147,11 +150,11 @@ class PsbtParser {
147
150
  * @returns Parsed transaction data with inputs and outputs
148
151
  * @throws Error if parsing fails
149
152
  */
150
- static parseFinalizedTransactionBase64(txBase64) {
153
+ static parseFinalizedTransactionBase64(txBase64, network) {
151
154
  try {
152
155
  const buffer = Buffer.from(txBase64, 'base64');
153
156
  const tx = Transaction.fromBuffer(buffer);
154
- return PsbtParser.extractTransactionData(tx);
157
+ return PsbtParser.extractTransactionData(tx, network);
155
158
  }
156
159
  catch (error) {
157
160
  throw new Error(`Failed to parse finalized transaction base64: ${error instanceof Error ? error.message : String(error)}`);
@@ -163,7 +166,7 @@ class PsbtParser {
163
166
  * @param tx - The parsed Transaction object
164
167
  * @returns Parsed transaction data with inputs and outputs
165
168
  */
166
- static extractTransactionData(tx) {
169
+ static extractTransactionData(tx, network) {
167
170
  const inputs = [];
168
171
  const outputs = [];
169
172
  tx.ins.forEach((input) => {
@@ -173,7 +176,7 @@ class PsbtParser {
173
176
  };
174
177
  inputs.push(inputData);
175
178
  });
176
- PsbtParser.extractOutputs(tx.outs, outputs);
179
+ PsbtParser.extractOutputs(tx.outs, outputs, network);
177
180
  return { inputs, outputs };
178
181
  }
179
182
  }