@btc-vision/transaction 1.1.2 → 1.1.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.
Files changed (30) hide show
  1. package/browser/_version.d.ts +1 -1
  2. package/browser/index.js +1 -1
  3. package/browser/transaction/browser/extensions/UnisatSigner.d.ts +4 -4
  4. package/browser/transaction/browser/types/Unisat.d.ts +1 -1
  5. package/browser/transaction/builders/DeploymentTransaction.d.ts +1 -0
  6. package/browser/transaction/builders/SharedInteractionTransaction.d.ts +2 -0
  7. package/browser/transaction/builders/TransactionBuilder.d.ts +2 -1
  8. package/browser/transaction/shared/TweakedTransaction.d.ts +6 -3
  9. package/build/_version.d.ts +1 -1
  10. package/build/_version.js +1 -1
  11. package/build/buffer/BinaryWriter.js +0 -1
  12. package/build/transaction/browser/extensions/UnisatSigner.d.ts +4 -4
  13. package/build/transaction/browser/extensions/UnisatSigner.js +103 -20
  14. package/build/transaction/browser/types/Unisat.d.ts +1 -1
  15. package/build/transaction/builders/DeploymentTransaction.d.ts +1 -0
  16. package/build/transaction/builders/DeploymentTransaction.js +17 -0
  17. package/build/transaction/builders/SharedInteractionTransaction.d.ts +2 -0
  18. package/build/transaction/builders/SharedInteractionTransaction.js +31 -10
  19. package/build/transaction/builders/TransactionBuilder.d.ts +2 -1
  20. package/build/transaction/shared/TweakedTransaction.d.ts +6 -3
  21. package/build/transaction/shared/TweakedTransaction.js +61 -43
  22. package/package.json +1 -1
  23. package/src/_version.ts +1 -1
  24. package/src/buffer/BinaryWriter.ts +0 -2
  25. package/src/transaction/browser/extensions/UnisatSigner.ts +139 -28
  26. package/src/transaction/browser/types/Unisat.ts +1 -1
  27. package/src/transaction/builders/DeploymentTransaction.ts +25 -0
  28. package/src/transaction/builders/SharedInteractionTransaction.ts +51 -21
  29. package/src/transaction/builders/TransactionBuilder.ts +2 -1
  30. package/src/transaction/shared/TweakedTransaction.ts +90 -49
@@ -1,9 +1,19 @@
1
- import { Network, networks, Psbt, TapScriptSig } from '@btc-vision/bitcoin';
1
+ import {
2
+ crypto as bitCrypto,
3
+ Network,
4
+ networks,
5
+ opcodes,
6
+ Psbt,
7
+ PsbtInput,
8
+ script as bitScript,
9
+ TapScriptSig,
10
+ } from '@btc-vision/bitcoin';
2
11
  import { ECPairInterface } from 'ecpair';
3
12
  import { EcKeyPair } from '../../../keypair/EcKeyPair.js';
4
13
  import { CustomKeypair } from '../BrowserSignerBase.js';
5
14
  import { PsbtSignatureOptions, Unisat, UnisatNetwork } from '../types/Unisat.js';
6
15
  import { PartialSig } from 'bip174/src/lib/interfaces.js';
16
+ import { toXOnly } from '@btc-vision/bitcoin/src/psbt/bip371.js';
7
17
 
8
18
  declare global {
9
19
  interface Window {
@@ -122,15 +132,15 @@ export class UnisatSigner extends CustomKeypair {
122
132
  return this.publicKey;
123
133
  }
124
134
 
125
- public sign(hash: Buffer, lowR?: boolean): Buffer {
135
+ public sign(_hash: Buffer, _lowR?: boolean): Buffer {
126
136
  throw new Error('Not implemented: sign');
127
137
  }
128
138
 
129
- public signSchnorr(hash: Buffer): Buffer {
139
+ public signSchnorr(_hash: Buffer): Buffer {
130
140
  throw new Error('Not implemented: signSchnorr');
131
141
  }
132
142
 
133
- public verify(hash: Buffer, signature: Buffer): boolean {
143
+ public verify(_hash: Buffer, _signature: Buffer): boolean {
134
144
  throw new Error('Not implemented: verify');
135
145
  }
136
146
 
@@ -176,6 +186,80 @@ export class UnisatSigner extends CustomKeypair {
176
186
  this.combine(transaction, firstSignature, i);
177
187
  }
178
188
 
189
+ public async multiSignPsbt(transactions: Psbt[]): Promise<void> {
190
+ const toSignPsbts: string[] = [];
191
+ const options: PsbtSignatureOptions[] = [];
192
+
193
+ for (const psbt of transactions) {
194
+ const hex = psbt.toHex();
195
+ toSignPsbts.push(hex);
196
+
197
+ const toSignInputs = psbt.data.inputs
198
+ .map((input, i) => {
199
+ let needsToSign = false;
200
+ let viaTaproot = false;
201
+
202
+ if (isTaprootInput(input)) {
203
+ if (input.tapLeafScript && input.tapLeafScript.length > 0) {
204
+ for (const tapLeafScript of input.tapLeafScript) {
205
+ if (pubkeyInScript(this.publicKey, tapLeafScript.script)) {
206
+ needsToSign = true;
207
+ viaTaproot = false; // for opnet, we use original keys.
208
+ break;
209
+ }
210
+ }
211
+ }
212
+
213
+ if (!needsToSign && input.tapInternalKey) {
214
+ const tapInternalKey = input.tapInternalKey;
215
+ const xOnlyPubKey = toXOnly(this.publicKey);
216
+
217
+ if (tapInternalKey.equals(xOnlyPubKey)) {
218
+ needsToSign = true;
219
+ viaTaproot = true;
220
+ }
221
+ }
222
+ } else {
223
+ // Non-Taproot input
224
+ const script = getInputRelevantScript(input);
225
+
226
+ if (script && pubkeyInScript(this.publicKey, script)) {
227
+ needsToSign = true;
228
+ viaTaproot = false;
229
+ }
230
+ }
231
+
232
+ if (needsToSign) {
233
+ return {
234
+ index: i,
235
+ publicKey: this.publicKey.toString('hex'),
236
+ disableTweakSigner: !viaTaproot,
237
+ };
238
+ } else {
239
+ return null;
240
+ }
241
+ })
242
+ .filter((v) => v !== null);
243
+
244
+ options.push({
245
+ autoFinalized: false,
246
+ toSignInputs: toSignInputs,
247
+ });
248
+ }
249
+
250
+ const signed = await this.unisat.signPsbt(toSignPsbts[0], options[0]);
251
+ const signedPsbts = Psbt.fromHex(signed); //signed.map((hex) => Psbt.fromHex(hex));
252
+
253
+ /*for (let i = 0; i < signedPsbts.length; i++) {
254
+ const psbtOriginal = transactions[i];
255
+ const psbtSigned = signedPsbts[i];
256
+
257
+ psbtOriginal.combine(psbtSigned);
258
+ }*/
259
+
260
+ transactions[0].combine(signedPsbts);
261
+ }
262
+
179
263
  private hasAlreadySignedTapScriptSig(input: TapScriptSig[]): boolean {
180
264
  for (let i = 0; i < input.length; i++) {
181
265
  const item = input[i];
@@ -257,30 +341,6 @@ export class UnisatSigner extends CustomKeypair {
257
341
  return Psbt.fromHex(signed);
258
342
  }
259
343
 
260
- private async signTweaked(
261
- transaction: Psbt,
262
- i: number,
263
- sighashTypes: number[],
264
- disableTweakSigner: boolean = false,
265
- ): Promise<Psbt> {
266
- const opts: PsbtSignatureOptions = {
267
- autoFinalized: false,
268
- toSignInputs: [
269
- {
270
- index: i,
271
- publicKey: this.publicKey.toString('hex'),
272
- sighashTypes,
273
- disableTweakSigner: disableTweakSigner,
274
- },
275
- ],
276
- };
277
-
278
- const psbt = transaction.toHex();
279
- const signed = await this.unisat.signPsbt(psbt, opts);
280
-
281
- return Psbt.fromHex(signed);
282
- }
283
-
284
344
  private getNonDuplicateScriptSig(
285
345
  scriptSig1: TapScriptSig[],
286
346
  scriptSig2: TapScriptSig[],
@@ -296,3 +356,54 @@ export class UnisatSigner extends CustomKeypair {
296
356
  return nonDuplicate;
297
357
  }
298
358
  }
359
+
360
+ // Helper functions
361
+ function isTaprootInput(input: PsbtInput): boolean {
362
+ if (input.tapInternalKey || input.tapKeySig || input.tapScriptSig || input.tapLeafScript) {
363
+ return true;
364
+ }
365
+
366
+ if (input.witnessUtxo) {
367
+ const script = input.witnessUtxo.script;
368
+ return script.length === 34 && script[0] === opcodes.OP_1 && script[1] === 0x20;
369
+ }
370
+
371
+ return false;
372
+ }
373
+
374
+ function getInputRelevantScript(input: PsbtInput): Buffer | null {
375
+ if (input.redeemScript) {
376
+ return input.redeemScript;
377
+ }
378
+ if (input.witnessScript) {
379
+ return input.witnessScript;
380
+ }
381
+ if (input.witnessUtxo) {
382
+ return input.witnessUtxo.script;
383
+ }
384
+ if (input.nonWitnessUtxo) {
385
+ // Additional logic can be added here if needed
386
+ return null;
387
+ }
388
+ return null;
389
+ }
390
+
391
+ function pubkeyInScript(pubkey: Buffer, script: Buffer): boolean {
392
+ return pubkeyPositionInScript(pubkey, script) !== -1;
393
+ }
394
+
395
+ function pubkeyPositionInScript(pubkey: Buffer, script: Buffer): number {
396
+ const pubkeyHash = bitCrypto.hash160(pubkey);
397
+ const pubkeyXOnly = toXOnly(pubkey);
398
+
399
+ const decompiled = bitScript.decompile(script);
400
+ if (decompiled === null) throw new Error('Unknown script error');
401
+
402
+ return decompiled.findIndex((element) => {
403
+ if (typeof element === 'number') return false;
404
+ return (
405
+ Buffer.isBuffer(element) &&
406
+ (element.equals(pubkey) || element.equals(pubkeyHash) || element.equals(pubkeyXOnly))
407
+ );
408
+ });
409
+ }
@@ -83,7 +83,7 @@ export interface Unisat {
83
83
 
84
84
  signPsbt(psbtHex: string, psbtOptions: PsbtSignatureOptions): Promise<string>;
85
85
 
86
- signPsbts(psbtHex: string[], psbtOptions: PsbtSignatureOptions): Promise<string[]>;
86
+ signPsbts(psbtHex: string[], psbtOptions: PsbtSignatureOptions[]): Promise<string[]>;
87
87
 
88
88
  pushPsbt(psbtHex: string): Promise<string>;
89
89
 
@@ -12,6 +12,7 @@ import { Compressor } from '../../bytecode/Compressor.js';
12
12
  import { SharedInteractionTransaction } from './SharedInteractionTransaction.js';
13
13
  import { ECPairInterface } from 'ecpair';
14
14
  import { Address } from '../../keypair/Address.js';
15
+ import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
15
16
 
16
17
  export class DeploymentTransaction extends TransactionBuilder<TransactionType.DEPLOYMENT> {
17
18
  public static readonly MAXIMUM_CONTRACT_SIZE = 128 * 1024;
@@ -203,6 +204,25 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
203
204
  await this.addRefundOutput(amountSpent);
204
205
  }
205
206
 
207
+ protected override async signInputsWalletBased(transaction: Psbt): Promise<void> {
208
+ const signer: UnisatSigner = this.signer as UnisatSigner;
209
+
210
+ // first, we sign the first input with the script signer.
211
+ await this.signInput(transaction, transaction.data.inputs[0], 0, this.contractSigner);
212
+
213
+ // then, we sign all the remaining inputs with the wallet signer.
214
+ await signer.multiSignPsbt([transaction]);
215
+
216
+ // Then, we finalize every input.
217
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
218
+ if (i === 0) {
219
+ transaction.finalizeInput(i, this.customFinalizer);
220
+ } else {
221
+ transaction.finalizeInput(i);
222
+ }
223
+ }
224
+ }
225
+
206
226
  /**
207
227
  * Sign the inputs
208
228
  * @param {Psbt} transaction The transaction to sign
@@ -215,6 +235,11 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
215
235
  return;
216
236
  }
217
237
 
238
+ if ('multiSignPsbt' in this.signer) {
239
+ await this.signInputsWalletBased(transaction);
240
+ return;
241
+ }
242
+
218
243
  for (let i = 0; i < transaction.data.inputs.length; i++) {
219
244
  if (i === 0) {
220
245
  // multi sig input
@@ -9,6 +9,7 @@ import { Compressor } from '../../bytecode/Compressor.js';
9
9
  import { EcKeyPair } from '../../keypair/EcKeyPair.js';
10
10
  import { BitcoinUtils } from '../../utils/BitcoinUtils.js';
11
11
  import { toXOnly } from '@btc-vision/bitcoin/src/psbt/bip371.js';
12
+ import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
12
13
 
13
14
  /**
14
15
  * Shared interaction transaction
@@ -186,27 +187,10 @@ export abstract class SharedInteractionTransaction<
186
187
  return;
187
188
  }
188
189
 
189
- for (let i = 0; i < transaction.data.inputs.length; i++) {
190
- if (i === 0) {
191
- await this.signInput(transaction, transaction.data.inputs[i], i, this.scriptSigner);
192
- await this.signInput(
193
- transaction,
194
- transaction.data.inputs[i],
195
- i,
196
- this.getSignerKey(),
197
- );
198
-
199
- transaction.finalizeInput(i, this.customFinalizer);
200
- } else {
201
- await this.signInput(
202
- transaction,
203
- transaction.data.inputs[i],
204
- i,
205
- this.getSignerKey(),
206
- );
207
-
208
- transaction.finalizeInput(i);
209
- }
190
+ if ('multiSignPsbt' in this.signer) {
191
+ await this.signInputsWalletBased(transaction);
192
+ } else {
193
+ await this.signInputsNonWalletBased(transaction);
210
194
  }
211
195
  }
212
196
 
@@ -308,6 +292,52 @@ export abstract class SharedInteractionTransaction<
308
292
  };
309
293
  };
310
294
 
295
+ // custom for interactions
296
+ protected override async signInputsWalletBased(transaction: Psbt): Promise<void> {
297
+ const signer: UnisatSigner = this.signer as UnisatSigner;
298
+
299
+ // first, we sign the first input with the script signer.
300
+ await this.signInput(transaction, transaction.data.inputs[0], 0, this.scriptSigner);
301
+
302
+ // then, we sign all the remaining inputs with the wallet signer.
303
+ await signer.multiSignPsbt([transaction]);
304
+
305
+ // Then, we finalize every input.
306
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
307
+ if (i === 0) {
308
+ transaction.finalizeInput(i, this.customFinalizer);
309
+ } else {
310
+ transaction.finalizeInput(i);
311
+ }
312
+ }
313
+ }
314
+
315
+ private async signInputsNonWalletBased(transaction: Psbt): Promise<void> {
316
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
317
+ if (i === 0) {
318
+ await this.signInput(transaction, transaction.data.inputs[i], i, this.scriptSigner);
319
+
320
+ await this.signInput(
321
+ transaction,
322
+ transaction.data.inputs[i],
323
+ i,
324
+ this.getSignerKey(),
325
+ );
326
+
327
+ transaction.finalizeInput(i, this.customFinalizer);
328
+ } else {
329
+ await this.signInput(
330
+ transaction,
331
+ transaction.data.inputs[i],
332
+ i,
333
+ this.getSignerKey(),
334
+ );
335
+
336
+ transaction.finalizeInput(i);
337
+ }
338
+ }
339
+ }
340
+
311
341
  /**
312
342
  * Get the public keys
313
343
  * @private
@@ -22,6 +22,7 @@ import { UTXO } from '../../utxo/interfaces/IUTXO.js';
22
22
  import { ECPairInterface } from 'ecpair';
23
23
  import { AddressVerificator } from '../../keypair/AddressVerificator.js';
24
24
  import { TweakedTransaction } from '../shared/TweakedTransaction.js';
25
+ import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
25
26
 
26
27
  initEccLib(ecc);
27
28
 
@@ -91,7 +92,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
91
92
  /**
92
93
  * @description The signer of the transaction
93
94
  */
94
- protected readonly signer: Signer | ECPairInterface;
95
+ protected readonly signer: Signer | ECPairInterface | UnisatSigner;
95
96
 
96
97
  /**
97
98
  * @description The network where the transaction will be broadcasted
@@ -24,9 +24,10 @@ import { AddressTypes, AddressVerificator } from '../../keypair/AddressVerificat
24
24
  import { ChainId } from '../../network/ChainId.js';
25
25
  import { varuint } from '@btc-vision/bitcoin/src/bufferutils.js';
26
26
  import * as bscript from '@btc-vision/bitcoin/src/script.js';
27
+ import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
27
28
 
28
29
  export interface ITweakedTransactionData {
29
- readonly signer: Signer | ECPairInterface;
30
+ readonly signer: Signer | ECPairInterface | UnisatSigner;
30
31
  readonly network: Network;
31
32
  readonly chainId?: ChainId;
32
33
  readonly nonWitnessUtxo?: Buffer;
@@ -46,22 +47,27 @@ export enum TransactionSequence {
46
47
  export abstract class TweakedTransaction extends Logger {
47
48
  public readonly logColor: string = '#00ffe1';
48
49
  public finalized: boolean = false;
50
+
49
51
  /**
50
52
  * @description Was the transaction signed?
51
53
  */
52
- protected signer: Signer | ECPairInterface;
54
+ protected signer: Signer | ECPairInterface | UnisatSigner;
55
+
53
56
  /**
54
57
  * @description Tweaked signer
55
58
  */
56
59
  protected tweakedSigner?: ECPairInterface;
60
+
57
61
  /**
58
62
  * @description The network of the transaction
59
63
  */
60
64
  protected network: Network;
65
+
61
66
  /**
62
67
  * @description Was the transaction signed?
63
68
  */
64
69
  protected signed: boolean = false;
70
+
65
71
  /**
66
72
  * @description The transaction
67
73
  * @protected
@@ -363,6 +369,7 @@ export abstract class TweakedTransaction extends Logger {
363
369
  * @param {PsbtInput} input - The input to sign
364
370
  * @param {number} i - The index of the input
365
371
  * @param {Signer} signer - The signer to use
372
+ * @param {boolean} [reverse=false] - Should the input be signed in reverse
366
373
  * @protected
367
374
  */
368
375
  protected async signInput(
@@ -370,45 +377,27 @@ export abstract class TweakedTransaction extends Logger {
370
377
  input: PsbtInput,
371
378
  i: number,
372
379
  signer: Signer | ECPairInterface,
380
+ reverse: boolean = false,
373
381
  ): Promise<void> {
374
382
  const publicKey = signer.publicKey;
375
- const isTaproot = this.isTaprootInput(input);
383
+ let isTaproot = this.isTaprootInput(input);
376
384
 
377
- let signed = false;
385
+ if (reverse) {
386
+ isTaproot = !isTaproot;
387
+ }
378
388
 
379
- if (isTaproot) {
380
- const isScriptSpend = this.isTaprootScriptSpend(input, publicKey);
389
+ let signed: boolean = false;
381
390
 
382
- if (isScriptSpend) {
383
- try {
384
- await this.signTaprootInput(signer, transaction, i);
385
- signed = true;
386
- } catch (e) {
387
- this.error(`Failed to sign Taproot script path input ${i}: ${e}`);
388
- }
389
- } else {
390
- let tweakedSigner: ECPairInterface | undefined;
391
- if (signer !== this.signer) {
392
- tweakedSigner = this.getTweakedSigner(true, signer);
393
- } else {
394
- if (!this.tweakedSigner) this.tweakSigner();
395
- tweakedSigner = this.tweakedSigner;
396
- }
397
-
398
- if (tweakedSigner) {
399
- try {
400
- await this.signTaprootInput(tweakedSigner, transaction, i);
401
- signed = true;
402
- } catch (e) {
403
- this.error(`Failed to sign Taproot key path input ${i}: ${e}`);
404
- }
405
- } else {
406
- this.error(`Failed to obtain tweaked signer for input ${i}.`);
407
- }
391
+ if (isTaproot) {
392
+ try {
393
+ await this.attemptSignTaproot(transaction, input, i, signer, publicKey);
394
+ signed = true;
395
+ } catch (e) {
396
+ this.error(`Failed to sign Taproot script path input ${i}: ${e}`);
408
397
  }
409
398
  } else {
410
399
  // Non-Taproot input
411
- if (this.canSignNonTaprootInput(input, publicKey)) {
400
+ if (!reverse ? this.canSignNonTaprootInput(input, publicKey) : true) {
412
401
  try {
413
402
  await this.signNonTaprootInput(signer, transaction, i);
414
403
  signed = true;
@@ -419,7 +408,11 @@ export abstract class TweakedTransaction extends Logger {
419
408
  }
420
409
 
421
410
  if (!signed) {
422
- throw new Error(`Cannot sign input ${i} with the provided signer.`);
411
+ try {
412
+ await this.signInput(transaction, input, i, signer, true);
413
+ } catch {
414
+ throw new Error(`Cannot sign input ${i} with the provided signer.`);
415
+ }
423
416
  }
424
417
  }
425
418
 
@@ -443,6 +436,12 @@ export abstract class TweakedTransaction extends Logger {
443
436
  * @returns {Promise<void>}
444
437
  */
445
438
  protected async signInputs(transaction: Psbt): Promise<void> {
439
+ if ('multiSignPsbt' in this.signer) {
440
+ await this.signInputsWalletBased(transaction);
441
+ return;
442
+ }
443
+
444
+ // non web based signing.
446
445
  const txs: PsbtInput[] = transaction.data.inputs;
447
446
 
448
447
  const batchSize: number = 20;
@@ -467,15 +466,11 @@ export abstract class TweakedTransaction extends Logger {
467
466
  await Promise.all(promises);
468
467
  }
469
468
 
470
- transaction.finalizeInput(0, this.customFinalizerP2SH);
471
-
472
- try {
473
- transaction.finalizeAllInputs();
474
-
475
- this.finalized = true;
476
- } catch (e) {
477
- this.finalized = false;
469
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
470
+ transaction.finalizeInput(i, this.customFinalizerP2SH);
478
471
  }
472
+
473
+ this.finalized = true;
479
474
  }
480
475
 
481
476
  /**
@@ -706,6 +701,48 @@ export abstract class TweakedTransaction extends Logger {
706
701
  return getFinalScripts(inputIndex, input, scriptA, isSegwit, isP2SH, isP2WSH);
707
702
  };
708
703
 
704
+ protected async signInputsWalletBased(transaction: Psbt): Promise<void> {
705
+ const signer: UnisatSigner = this.signer as UnisatSigner;
706
+
707
+ // then, we sign all the remaining inputs with the wallet signer.
708
+ await signer.multiSignPsbt([transaction]);
709
+
710
+ // Then, we finalize every input.
711
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
712
+ transaction.finalizeInput(i, this.customFinalizerP2SH);
713
+ }
714
+
715
+ this.finalized = true;
716
+ }
717
+
718
+ private async attemptSignTaproot(
719
+ transaction: Psbt,
720
+ input: PsbtInput,
721
+ i: number,
722
+ signer: Signer | ECPairInterface,
723
+ publicKey: Buffer,
724
+ ): Promise<void> {
725
+ const isScriptSpend = this.isTaprootScriptSpend(input, publicKey);
726
+
727
+ if (isScriptSpend) {
728
+ await this.signTaprootInput(signer, transaction, i);
729
+ } else {
730
+ let tweakedSigner: ECPairInterface | undefined;
731
+ if (signer !== this.signer) {
732
+ tweakedSigner = this.getTweakedSigner(true, signer);
733
+ } else {
734
+ if (!this.tweakedSigner) this.tweakSigner();
735
+ tweakedSigner = this.tweakedSigner;
736
+ }
737
+
738
+ if (tweakedSigner) {
739
+ await this.signTaprootInput(tweakedSigner, transaction, i);
740
+ } else {
741
+ this.error(`Failed to obtain tweaked signer for input ${i}.`);
742
+ }
743
+ }
744
+ }
745
+
709
746
  private isTaprootScriptSpend(input: PsbtInput, publicKey: Buffer): boolean {
710
747
  if (input.tapLeafScript && input.tapLeafScript.length > 0) {
711
748
  // Check if the signer's public key is involved in any tapLeafScript
@@ -788,13 +825,17 @@ export abstract class TweakedTransaction extends Logger {
788
825
  tapLeafHash?: Buffer,
789
826
  ): Promise<void> {
790
827
  if ('signTaprootInput' in signer) {
791
- await (
792
- signer.signTaprootInput as (
793
- tx: Psbt,
794
- i: number,
795
- tapLeafHash?: Buffer,
796
- ) => Promise<void>
797
- )(transaction, i, tapLeafHash);
828
+ try {
829
+ await (
830
+ signer.signTaprootInput as (
831
+ tx: Psbt,
832
+ i: number,
833
+ tapLeafHash?: Buffer,
834
+ ) => Promise<void>
835
+ )(transaction, i, tapLeafHash);
836
+ } catch {
837
+ throw new Error('Failed to sign Taproot input with provided signer.');
838
+ }
798
839
  } else {
799
840
  transaction.signTaprootInput(i, signer); //tapLeafHash
800
841
  }