@btc-vision/transaction 1.0.106 → 1.0.108

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 (46) hide show
  1. package/browser/_version.d.ts +1 -1
  2. package/browser/index.js +1 -1
  3. package/browser/keypair/EcKeyPair.d.ts +4 -4
  4. package/browser/transaction/builders/MultiSignTransaction.d.ts +1 -1
  5. package/browser/transaction/builders/SharedInteractionTransaction.d.ts +1 -0
  6. package/browser/transaction/builders/TransactionBuilder.d.ts +3 -3
  7. package/browser/transaction/builders/UnwrapSegwitTransaction.d.ts +1 -1
  8. package/browser/transaction/builders/UnwrapTransaction.d.ts +1 -1
  9. package/browser/transaction/processor/PsbtTransaction.d.ts +1 -1
  10. package/browser/transaction/shared/TweakedTransaction.d.ts +2 -1
  11. package/browser/utxo/interfaces/IUTXO.d.ts +1 -0
  12. package/build/_version.d.ts +1 -1
  13. package/build/_version.js +1 -1
  14. package/build/keypair/EcKeyPair.d.ts +4 -4
  15. package/build/transaction/browser/extensions/UnisatSigner.js +4 -3
  16. package/build/transaction/builders/CustomScriptTransaction.js +1 -4
  17. package/build/transaction/builders/MultiSignTransaction.d.ts +1 -1
  18. package/build/transaction/builders/MultiSignTransaction.js +2 -2
  19. package/build/transaction/builders/SharedInteractionTransaction.d.ts +1 -0
  20. package/build/transaction/builders/SharedInteractionTransaction.js +42 -31
  21. package/build/transaction/builders/TransactionBuilder.d.ts +3 -3
  22. package/build/transaction/builders/TransactionBuilder.js +4 -4
  23. package/build/transaction/builders/UnwrapSegwitTransaction.d.ts +1 -1
  24. package/build/transaction/builders/UnwrapSegwitTransaction.js +2 -3
  25. package/build/transaction/builders/UnwrapTransaction.d.ts +1 -1
  26. package/build/transaction/builders/UnwrapTransaction.js +2 -2
  27. package/build/transaction/processor/PsbtTransaction.d.ts +1 -1
  28. package/build/transaction/processor/PsbtTransaction.js +2 -2
  29. package/build/transaction/shared/TweakedTransaction.d.ts +2 -1
  30. package/build/transaction/shared/TweakedTransaction.js +30 -10
  31. package/build/utxo/OPNetLimitedProvider.js +1 -1
  32. package/build/utxo/interfaces/IUTXO.d.ts +1 -0
  33. package/package.json +1 -1
  34. package/src/_version.ts +1 -1
  35. package/src/keypair/EcKeyPair.ts +4 -4
  36. package/src/transaction/browser/extensions/UnisatSigner.ts +4 -3
  37. package/src/transaction/builders/CustomScriptTransaction.ts +3 -7
  38. package/src/transaction/builders/MultiSignTransaction.ts +3 -2
  39. package/src/transaction/builders/SharedInteractionTransaction.ts +59 -34
  40. package/src/transaction/builders/TransactionBuilder.ts +17 -11
  41. package/src/transaction/builders/UnwrapSegwitTransaction.ts +5 -5
  42. package/src/transaction/builders/UnwrapTransaction.ts +6 -2
  43. package/src/transaction/processor/PsbtTransaction.ts +2 -2
  44. package/src/transaction/shared/TweakedTransaction.ts +38 -10
  45. package/src/utxo/OPNetLimitedProvider.ts +1 -1
  46. package/src/utxo/interfaces/IUTXO.ts +1 -0
@@ -255,17 +255,13 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
255
255
  /**
256
256
  * Finalize the transaction
257
257
  * @param _inputIndex
258
- * @param input
258
+ * @param _input
259
259
  */
260
- private customFinalizer = (_inputIndex: number, input: PsbtInput) => {
260
+ private customFinalizer = (_inputIndex: number, _input: PsbtInput) => {
261
261
  if (!this.tapLeafScript) {
262
262
  throw new Error('Tap leaf script is required');
263
263
  }
264
-
265
- if (!input.tapScriptSig) {
266
- throw new Error('Tap script signature is required');
267
- }
268
-
264
+
269
265
  const scriptSolution = this.witnesses;
270
266
  const witness = scriptSolution
271
267
  .concat(this.tapLeafScript.script)
@@ -493,16 +493,17 @@ export class MultiSignTransaction extends TransactionBuilder<TransactionType.MUL
493
493
  /**
494
494
  * Builds the transaction.
495
495
  * @param {Psbt} transaction - The transaction to build
496
+ * @param checkPartialSigs
496
497
  * @protected
497
498
  * @returns {Promise<boolean>}
498
499
  * @throws {Error} - If something went wrong while building the transaction
499
500
  */
500
- protected override async internalBuildTransaction(transaction: Psbt): Promise<boolean> {
501
+ protected override async internalBuildTransaction(transaction: Psbt, checkPartialSigs: boolean = false): Promise<boolean> {
501
502
  const inputs: PsbtInputExtended[] = this.getInputs();
502
503
  const outputs: PsbtOutputExtended[] = this.getOutputs();
503
504
 
504
505
  transaction.setMaximumFeeRate(this._maximumFeeRate);
505
- transaction.addInputs(inputs);
506
+ transaction.addInputs(inputs, checkPartialSigs);
506
507
 
507
508
  for (let i = 0; i < this.updateInputs.length; i++) {
508
509
  transaction.updateInput(i, this.updateInputs[i]);
@@ -185,44 +185,35 @@ export abstract class SharedInteractionTransaction<
185
185
  return;
186
186
  }
187
187
 
188
- for (let i = 0; i < transaction.data.inputs.length; i++) {
189
- const input: PsbtInput = transaction.data.inputs[i];
190
- let finalized: boolean = false;
191
- let signed: boolean = false;
188
+ const txs: PsbtInput[] = transaction.data.inputs;
189
+ for (let i = 0; i < txs.length; i += 20) {
190
+ const batch = txs.slice(i, i + 20);
192
191
 
193
- try {
194
- await this.signInput(transaction, input, i, this.scriptSigner);
195
- signed = true;
196
- } catch (e) {}
192
+ const promises: Promise<void>[] = [];
193
+ for (let y = 0; y < batch.length; y++) {
194
+ const offset = i * 20 + y;
195
+ const input = batch[y];
197
196
 
198
- try {
199
- await this.signInput(transaction, input, i);
200
- signed = true;
201
- } catch (e) {}
197
+ promises.push(this.signIndividualInputs(transaction, input, offset));
198
+ }
202
199
 
203
- try {
204
- transaction.finalizeInput(0, this.customFinalizer);
205
- finalized = true;
206
- } catch (e) {}
200
+ await Promise.all(promises).catch((e: unknown) => {
201
+ throw e;
202
+ });
203
+ }
204
+
205
+ try {
206
+ transaction.finalizeInput(0, this.customFinalizer);
207
+ } catch (e) {
208
+ this.error(`Failed to finalize input 0: ${(e as Error).stack}`);
209
+ }
207
210
 
211
+ for (let i = 0; i < txs.length; i++) {
208
212
  try {
209
213
  transaction.finalizeInput(i);
210
- finalized = true;
211
- } catch (e) {}
212
214
 
213
- if (signed || finalized) {
214
- this.log(
215
- `Signed input or finalized input #${i} out of ${transaction.data.inputs.length}! {Signed: ${signed}, Finalized: ${finalized}}`,
216
- );
217
-
218
- continue;
219
- }
220
-
221
- if (this.regenerated || this.ignoreSignatureErrors) {
222
- continue;
223
- }
224
-
225
- throw new Error('Failed to sign input');
215
+ this.log(`Finalized input ${i}!`);
216
+ } catch {}
226
217
  }
227
218
  }
228
219
 
@@ -310,9 +301,11 @@ export abstract class SharedInteractionTransaction<
310
301
  throw new Error('Tap leaf script is required');
311
302
  }
312
303
 
313
- if (!input.tapScriptSig) {
314
- throw new Error('Tap script signature is required');
315
- }
304
+ //console.log('finalizing input', input);
305
+
306
+ //if (!input.tapLeafScript) {
307
+ // throw new Error('Tap script signature is required');
308
+ //}
316
309
 
317
310
  if (!this.contractSecret) {
318
311
  throw new Error('Contract secret is required');
@@ -328,6 +321,38 @@ export abstract class SharedInteractionTransaction<
328
321
  };
329
322
  };
330
323
 
324
+ private async signIndividualInputs(
325
+ transaction: Psbt,
326
+ input: PsbtInput,
327
+ i: number,
328
+ ): Promise<void> {
329
+ let signed: boolean = false;
330
+
331
+ try {
332
+ await this.signInput(transaction, input, i, this.scriptSigner);
333
+ signed = true;
334
+ } catch {}
335
+
336
+ try {
337
+ await this.signInput(transaction, input, i);
338
+ signed = true;
339
+ } catch {}
340
+
341
+ if (signed) {
342
+ this.log(
343
+ `Signed input #${i} out of ${transaction.data.inputs.length}! {Signed: ${signed}}`,
344
+ );
345
+
346
+ return;
347
+ }
348
+
349
+ if (this.regenerated || this.ignoreSignatureErrors) {
350
+ return;
351
+ }
352
+
353
+ throw new Error('Failed to sign input');
354
+ }
355
+
331
356
  /**
332
357
  * Get the public keys
333
358
  * @private
@@ -47,6 +47,11 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
47
47
  * @description The estimated fees of the transaction
48
48
  */
49
49
  public estimatedFees: bigint = 0n;
50
+ /**
51
+ * @param {ITransactionParameters} parameters - The transaction parameters
52
+ */
53
+
54
+ public optionalOutputs: PsbtOutputExtended[] | undefined;
50
55
  /**
51
56
  * @description The transaction itself.
52
57
  */
@@ -102,12 +107,6 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
102
107
  */
103
108
  protected _maximumFeeRate: number = 100000000;
104
109
 
105
- /**
106
- * @param {ITransactionParameters} parameters - The transaction parameters
107
- */
108
-
109
- public optionalOutputs: PsbtOutputExtended[] | undefined;
110
-
111
110
  protected constructor(parameters: ITransactionParameters) {
112
111
  super(parameters);
113
112
 
@@ -259,7 +258,9 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
259
258
  * @description Generates the transaction minimal signatures
260
259
  * @public
261
260
  */
262
- public async generateTransactionMinimalSignatures(): Promise<void> {
261
+ public async generateTransactionMinimalSignatures(
262
+ checkPartialSigs: boolean = false,
263
+ ): Promise<void> {
263
264
  if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
264
265
  throw new Error(
265
266
  'Invalid contract address. The contract address must be a taproot address.',
@@ -273,7 +274,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
273
274
  const outputs: PsbtOutputExtended[] = this.getOutputs();
274
275
 
275
276
  this.transaction.setMaximumFeeRate(this._maximumFeeRate);
276
- this.transaction.addInputs(inputs);
277
+ this.transaction.addInputs(inputs, checkPartialSigs);
277
278
 
278
279
  for (let i = 0; i < this.updateInputs.length; i++) {
279
280
  this.transaction.updateInput(i, this.updateInputs[i]);
@@ -364,7 +365,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
364
365
  const fee: number = this.feeRate * size;
365
366
 
366
367
  this.estimatedFees = BigInt(Math.ceil(fee) + 1);
367
-
368
+
368
369
  return this.estimatedFees;
369
370
  } else {
370
371
  throw new Error(
@@ -501,6 +502,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
501
502
 
502
503
  return total;
503
504
  }
505
+
504
506
  /**
505
507
  * @description Adds optional outputs to transaction and returns their total value in satoshi to calculate refund transaction
506
508
  * @protected
@@ -655,17 +657,21 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
655
657
  /**
656
658
  * Builds the transaction.
657
659
  * @param {Psbt} transaction - The transaction to build
660
+ * @param checkPartialSigs
658
661
  * @protected
659
662
  * @returns {Promise<boolean>}
660
663
  * @throws {Error} - If something went wrong while building the transaction
661
664
  */
662
- protected async internalBuildTransaction(transaction: Psbt): Promise<boolean> {
665
+ protected async internalBuildTransaction(
666
+ transaction: Psbt,
667
+ checkPartialSigs: boolean = false,
668
+ ): Promise<boolean> {
663
669
  if (transaction.data.inputs.length === 0) {
664
670
  const inputs: PsbtInputExtended[] = this.getInputs();
665
671
  const outputs: PsbtOutputExtended[] = this.getOutputs();
666
672
 
667
673
  transaction.setMaximumFeeRate(this._maximumFeeRate);
668
- transaction.addInputs(inputs);
674
+ transaction.addInputs(inputs, checkPartialSigs);
669
675
 
670
676
  for (let i = 0; i < this.updateInputs.length; i++) {
671
677
  transaction.updateInput(i, this.updateInputs[i]);
@@ -196,13 +196,13 @@ export class UnwrapSegwitTransaction extends SharedInteractionTransaction<Transa
196
196
  * @returns {Promise<boolean>}
197
197
  * @throws {Error} - If something went wrong while building the transaction
198
198
  */
199
- protected async internalBuildTransaction(transaction: Psbt): Promise<boolean> {
199
+ protected async internalBuildTransaction(transaction: Psbt, checkPartialSigs: boolean = false): Promise<boolean> {
200
200
  if (transaction.data.inputs.length === 0) {
201
201
  const inputs: PsbtInputExtended[] = this.getInputs();
202
202
  const outputs: PsbtOutputExtended[] = this.getOutputs();
203
203
 
204
204
  transaction.setMaximumFeeRate(this._maximumFeeRate);
205
- transaction.addInputs(inputs);
205
+ transaction.addInputs(inputs, checkPartialSigs);
206
206
 
207
207
  for (let i = 0; i < this.updateInputs.length; i++) {
208
208
  transaction.updateInput(i, this.updateInputs[i]);
@@ -313,9 +313,9 @@ export class UnwrapSegwitTransaction extends SharedInteractionTransaction<Transa
313
313
  this.addVaultUTXO(utxo, p2wshOutput);
314
314
 
315
315
  if (firstSigner) {
316
- this.log(
317
- `Signing input ${inputIndex} with ${firstSigner.publicKey.toString('hex')}`,
318
- );
316
+ //this.log(
317
+ // `Signing input ${inputIndex} with ${firstSigner.publicKey.toString('hex')}`,
318
+ //);
319
319
 
320
320
  // we don't care if we fail to sign the input
321
321
  try {
@@ -381,17 +381,21 @@ export class UnwrapTransaction extends SharedInteractionTransaction<TransactionT
381
381
  /**
382
382
  * Builds the transaction.
383
383
  * @param {Psbt} transaction - The transaction to build
384
+ * @param checkPartialSigs
384
385
  * @protected
385
386
  * @returns {Promise<boolean>}
386
387
  * @throws {Error} - If something went wrong while building the transaction
387
388
  */
388
- protected async internalBuildTransaction(transaction: Psbt): Promise<boolean> {
389
+ protected async internalBuildTransaction(
390
+ transaction: Psbt,
391
+ checkPartialSigs: boolean = false,
392
+ ): Promise<boolean> {
389
393
  if (transaction.data.inputs.length === 0) {
390
394
  const inputs: PsbtInputExtended[] = this.getInputs();
391
395
  const outputs: PsbtOutputExtended[] = this.getOutputs();
392
396
 
393
397
  transaction.setMaximumFeeRate(this._maximumFeeRate);
394
- transaction.addInputs(inputs);
398
+ transaction.addInputs(inputs, checkPartialSigs);
395
399
 
396
400
  for (let i = 0; i < this.updateInputs.length; i++) {
397
401
  transaction.updateInput(i, this.updateInputs[i]);
@@ -119,8 +119,8 @@ export class PsbtTransaction extends TweakedTransaction {
119
119
  * @description Add an input to the transaction
120
120
  * @param input
121
121
  */
122
- public addInput(input: PsbtInputExtended): void {
123
- this.transaction.addInput(input);
122
+ public addInput(input: PsbtInputExtended, checkPartialSigs: boolean = false): void {
123
+ this.transaction.addInput(input, checkPartialSigs);
124
124
  }
125
125
 
126
126
  /**
@@ -7,8 +7,8 @@ import { PsbtInput } from 'bip174/src/lib/interfaces.js';
7
7
  import { UTXO } from '../../utxo/interfaces/IUTXO.js';
8
8
  import { PsbtInputExtended, TapLeafScript } from '../interfaces/Tap.js';
9
9
  import { AddressVerificator } from '../../keypair/AddressVerificator.js';
10
- import { varuint } from 'bitcoinjs-lib/src/bufferutils.js';
11
10
  import { ChainId } from '../../network/ChainId.js';
11
+ import { varuint } from 'bitcoinjs-lib/src/bufferutils.js';
12
12
 
13
13
  export interface ITweakedTransactionData {
14
14
  readonly signer: Signer;
@@ -109,17 +109,17 @@ export abstract class TweakedTransaction extends Logger {
109
109
  * Read witnesses
110
110
  * @protected
111
111
  */
112
- public static readScriptWitnessToWitnessStack(buffer: Buffer): Buffer[] {
112
+ public static readScriptWitnessToWitnessStack(Buffer: Buffer): Buffer[] {
113
113
  let offset = 0;
114
114
 
115
115
  function readSlice(n: number): Buffer {
116
- const slice = buffer.subarray(offset, offset + n);
116
+ const slice = Buffer.subarray(offset, offset + n);
117
117
  offset += n;
118
118
  return slice;
119
119
  }
120
120
 
121
121
  function readVarInt(): number {
122
- const varint = varuint.decode(buffer, offset);
122
+ const varint = varuint.decode(Buffer, offset);
123
123
  offset += varuint.decode.bytes;
124
124
  return varint;
125
125
  }
@@ -421,6 +421,20 @@ export abstract class TweakedTransaction extends Logger {
421
421
  }
422
422
  }
423
423
 
424
+ protected splitArray<T>(arr: T[], chunkSize: number): T[][] {
425
+ if (chunkSize <= 0) {
426
+ throw new Error('Chunk size must be greater than 0.');
427
+ }
428
+
429
+ const result: T[][] = [];
430
+
431
+ for (let i = 0; i < arr.length; i += chunkSize) {
432
+ result.push(arr.slice(i, i + chunkSize));
433
+ }
434
+
435
+ return result;
436
+ }
437
+
424
438
  /**
425
439
  * Signs all the inputs of the transaction.
426
440
  * @param {Psbt} transaction - The transaction to sign
@@ -428,14 +442,28 @@ export abstract class TweakedTransaction extends Logger {
428
442
  * @returns {Promise<void>}
429
443
  */
430
444
  protected async signInputs(transaction: Psbt): Promise<void> {
431
- for (let i = 0; i < transaction.data.inputs.length; i++) {
432
- const input: PsbtInput = transaction.data.inputs[i];
445
+ const txs: PsbtInput[] = transaction.data.inputs;
446
+
447
+ const batchSize: number = 20;
448
+ const batches = this.splitArray(txs, batchSize);
449
+
450
+ for (let i = 0; i < batches.length; i++) {
451
+ const batch = batches[i];
452
+ const promises: Promise<void>[] = [];
453
+ const offset = i * batchSize;
454
+
455
+ for (let j = 0; j < batch.length; j++) {
456
+ const index = offset + j;
457
+ const input = batch[j];
433
458
 
434
- try {
435
- await this.signInput(transaction, input, i);
436
- } catch (e) {
437
- this.log(`Failed to sign input ${i}: ${(e as Error).stack}`);
459
+ try {
460
+ promises.push(this.signInput(transaction, input, index));
461
+ } catch (e) {
462
+ this.log(`Failed to sign input ${index}: ${(e as Error).stack}`);
463
+ }
438
464
  }
465
+
466
+ await Promise.all(promises);
439
467
  }
440
468
 
441
469
  try {
@@ -132,7 +132,7 @@ export class OPNetLimitedProvider {
132
132
  minAmount: settings.minAmount,
133
133
  requestedAmount: settings.requestedAmount,
134
134
  optimized: settings.optimized,
135
- usePendingUTXO: false,
135
+ usePendingUTXO: settings.usePendingUTXO,
136
136
  };
137
137
 
138
138
  const promise = this.fetchUTXO(params).catch(() => {
@@ -20,6 +20,7 @@ export interface FetchUTXOParamsMultiAddress {
20
20
  readonly minAmount: bigint;
21
21
  readonly requestedAmount: bigint;
22
22
  readonly optimized?: boolean;
23
+ readonly usePendingUTXO?: boolean;
23
24
  }
24
25
 
25
26
  export interface RawUTXOResponse {