@btc-vision/transaction 1.0.106 → 1.0.107
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/browser/_version.d.ts +1 -1
- package/browser/index.js +1 -1
- package/browser/keypair/EcKeyPair.d.ts +4 -4
- package/browser/transaction/builders/MultiSignTransaction.d.ts +1 -1
- package/browser/transaction/builders/SharedInteractionTransaction.d.ts +1 -0
- package/browser/transaction/builders/TransactionBuilder.d.ts +3 -3
- package/browser/transaction/builders/UnwrapSegwitTransaction.d.ts +1 -1
- package/browser/transaction/builders/UnwrapTransaction.d.ts +1 -1
- package/browser/transaction/processor/PsbtTransaction.d.ts +1 -1
- package/browser/transaction/shared/TweakedTransaction.d.ts +2 -1
- package/browser/utxo/interfaces/IUTXO.d.ts +1 -0
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/keypair/EcKeyPair.d.ts +4 -4
- package/build/transaction/builders/CustomScriptTransaction.js +1 -4
- package/build/transaction/builders/MultiSignTransaction.d.ts +1 -1
- package/build/transaction/builders/MultiSignTransaction.js +2 -2
- package/build/transaction/builders/SharedInteractionTransaction.d.ts +1 -0
- package/build/transaction/builders/SharedInteractionTransaction.js +43 -31
- package/build/transaction/builders/TransactionBuilder.d.ts +3 -3
- package/build/transaction/builders/TransactionBuilder.js +4 -4
- package/build/transaction/builders/UnwrapSegwitTransaction.d.ts +1 -1
- package/build/transaction/builders/UnwrapSegwitTransaction.js +2 -3
- package/build/transaction/builders/UnwrapTransaction.d.ts +1 -1
- package/build/transaction/builders/UnwrapTransaction.js +2 -2
- package/build/transaction/processor/PsbtTransaction.d.ts +1 -1
- package/build/transaction/processor/PsbtTransaction.js +2 -2
- package/build/transaction/shared/TweakedTransaction.d.ts +2 -1
- package/build/transaction/shared/TweakedTransaction.js +30 -10
- package/build/utxo/OPNetLimitedProvider.js +1 -1
- package/build/utxo/interfaces/IUTXO.d.ts +1 -0
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/keypair/EcKeyPair.ts +4 -4
- package/src/transaction/builders/CustomScriptTransaction.ts +3 -7
- package/src/transaction/builders/MultiSignTransaction.ts +3 -2
- package/src/transaction/builders/SharedInteractionTransaction.ts +61 -34
- package/src/transaction/builders/TransactionBuilder.ts +17 -11
- package/src/transaction/builders/UnwrapSegwitTransaction.ts +5 -5
- package/src/transaction/builders/UnwrapTransaction.ts +6 -2
- package/src/transaction/processor/PsbtTransaction.ts +2 -2
- package/src/transaction/shared/TweakedTransaction.ts +38 -10
- package/src/utxo/OPNetLimitedProvider.ts +1 -1
- package/src/utxo/interfaces/IUTXO.ts +1 -0
|
@@ -185,44 +185,37 @@ export abstract class SharedInteractionTransaction<
|
|
|
185
185
|
return;
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
try {
|
|
199
|
-
await this.signInput(transaction, input, i);
|
|
200
|
-
signed = true;
|
|
201
|
-
} 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];
|
|
202
196
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
finalized = true;
|
|
206
|
-
} catch (e) {}
|
|
197
|
+
promises.push(this.signIndividualInputs(transaction, input, offset));
|
|
198
|
+
}
|
|
207
199
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
200
|
+
await Promise.all(promises).catch((e: unknown) => {
|
|
201
|
+
throw e;
|
|
202
|
+
});
|
|
203
|
+
}
|
|
212
204
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
`Signed input or finalized input #${i} out of ${transaction.data.inputs.length}! {Signed: ${signed}, Finalized: ${finalized}}`,
|
|
216
|
-
);
|
|
205
|
+
try {
|
|
206
|
+
transaction.finalizeInput(0, this.customFinalizer);
|
|
217
207
|
|
|
218
|
-
|
|
219
|
-
|
|
208
|
+
this.log(`Finalized input 0!`);
|
|
209
|
+
} catch (e) {
|
|
210
|
+
console.log(`Failed to finalize input 0: ${(e as Error).stack}`);
|
|
211
|
+
}
|
|
220
212
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
213
|
+
for (let i = 0; i < txs.length; i++) {
|
|
214
|
+
try {
|
|
215
|
+
transaction.finalizeInput(i);
|
|
224
216
|
|
|
225
|
-
|
|
217
|
+
this.log(`Finalized input ${i}!`);
|
|
218
|
+
} catch {}
|
|
226
219
|
}
|
|
227
220
|
}
|
|
228
221
|
|
|
@@ -310,9 +303,11 @@ export abstract class SharedInteractionTransaction<
|
|
|
310
303
|
throw new Error('Tap leaf script is required');
|
|
311
304
|
}
|
|
312
305
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
306
|
+
//console.log('finalizing input', input);
|
|
307
|
+
|
|
308
|
+
//if (!input.tapLeafScript) {
|
|
309
|
+
// throw new Error('Tap script signature is required');
|
|
310
|
+
//}
|
|
316
311
|
|
|
317
312
|
if (!this.contractSecret) {
|
|
318
313
|
throw new Error('Contract secret is required');
|
|
@@ -328,6 +323,38 @@ export abstract class SharedInteractionTransaction<
|
|
|
328
323
|
};
|
|
329
324
|
};
|
|
330
325
|
|
|
326
|
+
private async signIndividualInputs(
|
|
327
|
+
transaction: Psbt,
|
|
328
|
+
input: PsbtInput,
|
|
329
|
+
i: number,
|
|
330
|
+
): Promise<void> {
|
|
331
|
+
let signed: boolean = false;
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
await this.signInput(transaction, input, i, this.scriptSigner);
|
|
335
|
+
signed = true;
|
|
336
|
+
} catch {}
|
|
337
|
+
|
|
338
|
+
try {
|
|
339
|
+
await this.signInput(transaction, input, i);
|
|
340
|
+
signed = true;
|
|
341
|
+
} catch {}
|
|
342
|
+
|
|
343
|
+
if (signed) {
|
|
344
|
+
this.log(
|
|
345
|
+
`Signed input #${i} out of ${transaction.data.inputs.length}! {Signed: ${signed}}`,
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (this.regenerated || this.ignoreSignatureErrors) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
throw new Error('Failed to sign input');
|
|
356
|
+
}
|
|
357
|
+
|
|
331
358
|
/**
|
|
332
359
|
* Get the public keys
|
|
333
360
|
* @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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
112
|
+
public static readScriptWitnessToWitnessStack(Buffer: Buffer): Buffer[] {
|
|
113
113
|
let offset = 0;
|
|
114
114
|
|
|
115
115
|
function readSlice(n: number): Buffer {
|
|
116
|
-
const slice =
|
|
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(
|
|
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
|
-
|
|
432
|
-
|
|
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
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
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:
|
|
135
|
+
usePendingUTXO: settings.usePendingUTXO,
|
|
136
136
|
};
|
|
137
137
|
|
|
138
138
|
const promise = this.fetchUTXO(params).catch(() => {
|