@btc-vision/transaction 1.7.16 → 1.7.18
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/generators/Generator.d.ts +2 -1
- package/browser/generators/builders/P2WDAGenerator.d.ts +0 -1
- package/browser/index.js +1 -1
- package/browser/transaction/TransactionFactory.d.ts +6 -1
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/generators/Generator.d.ts +2 -1
- package/build/generators/Generator.js +10 -10
- package/build/generators/builders/CalldataGenerator.js +6 -5
- package/build/generators/builders/DeploymentGenerator.js +5 -4
- package/build/generators/builders/LegacyCalldataGenerator.js +6 -5
- package/build/generators/builders/P2WDAGenerator.d.ts +0 -1
- package/build/generators/builders/P2WDAGenerator.js +1 -18
- package/build/transaction/TransactionFactory.d.ts +6 -1
- package/build/transaction/TransactionFactory.js +20 -7
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/generators/Generator.ts +15 -15
- package/src/generators/builders/CalldataGenerator.ts +10 -7
- package/src/generators/builders/DeploymentGenerator.ts +6 -6
- package/src/generators/builders/LegacyCalldataGenerator.ts +10 -7
- package/src/generators/builders/P2WDAGenerator.ts +1 -57
- package/src/transaction/TransactionFactory.ts +96 -33
|
@@ -32,9 +32,6 @@ export class P2WDAGenerator extends Generator {
|
|
|
32
32
|
maxWitnessFields: number = 10,
|
|
33
33
|
maxBytesPerWitness: number = 80,
|
|
34
34
|
): boolean {
|
|
35
|
-
// Account for Schnorr signature (64 bytes) and compression
|
|
36
|
-
// Assume 30% compression ratio (conservative estimate)
|
|
37
|
-
|
|
38
35
|
const signatureSize = 64;
|
|
39
36
|
const compressionRatio = 0.7;
|
|
40
37
|
|
|
@@ -79,12 +76,10 @@ export class P2WDAGenerator extends Generator {
|
|
|
79
76
|
|
|
80
77
|
const writer = new BinaryWriter();
|
|
81
78
|
|
|
82
|
-
// Version byte
|
|
83
79
|
writer.writeU8(P2WDAGenerator.P2WDA_VERSION);
|
|
84
80
|
|
|
85
81
|
const features: Feature<Features>[] = featuresRaw.sort((a, b) => a.priority - b.priority);
|
|
86
82
|
|
|
87
|
-
// Header
|
|
88
83
|
writer.writeBytes(
|
|
89
84
|
this.getHeader(
|
|
90
85
|
maxPriority,
|
|
@@ -92,33 +87,19 @@ export class P2WDAGenerator extends Generator {
|
|
|
92
87
|
),
|
|
93
88
|
);
|
|
94
89
|
|
|
95
|
-
// Contract secret
|
|
96
90
|
writer.writeBytes(contractSecret);
|
|
97
91
|
|
|
98
|
-
// Challenge components for epoch rewards
|
|
99
92
|
writer.writeBytes(challenge.publicKey.toBuffer());
|
|
100
93
|
writer.writeBytes(challenge.solution);
|
|
101
94
|
|
|
102
|
-
// Calldata with length prefix
|
|
103
95
|
writer.writeU32(calldata.length);
|
|
104
96
|
writer.writeBytes(calldata);
|
|
105
97
|
|
|
106
|
-
// Features
|
|
107
98
|
this.writeFeatures(writer, features);
|
|
108
99
|
|
|
109
100
|
return Buffer.from(writer.getBuffer());
|
|
110
101
|
}
|
|
111
102
|
|
|
112
|
-
/**
|
|
113
|
-
* Create a minimal header for P2WDA operations
|
|
114
|
-
*
|
|
115
|
-
* The header contains essential transaction metadata in a compact format:
|
|
116
|
-
* [sender_pubkey_prefix(1)] [feature_flags(3)] [max_priority(8)]
|
|
117
|
-
*
|
|
118
|
-
* @param maxPriority Maximum priority fee
|
|
119
|
-
* @param features Feature opcodes to set in flags
|
|
120
|
-
* @returns 12-byte header
|
|
121
|
-
*/
|
|
122
103
|
public override getHeader(maxPriority: bigint, features: Features[] = []): Buffer {
|
|
123
104
|
return super.getHeader(maxPriority, features);
|
|
124
105
|
}
|
|
@@ -133,48 +114,11 @@ export class P2WDAGenerator extends Generator {
|
|
|
133
114
|
* @param features Array of features to encode
|
|
134
115
|
*/
|
|
135
116
|
private writeFeatures(writer: BinaryWriter, features: Feature<Features>[]): void {
|
|
136
|
-
// Write feature count
|
|
137
117
|
writer.writeU16(features.length);
|
|
138
118
|
|
|
139
119
|
for (const feature of features) {
|
|
140
|
-
// Write feature opcode
|
|
141
120
|
writer.writeU8(feature.opcode);
|
|
142
|
-
|
|
143
|
-
// Encode feature data
|
|
144
|
-
const encodedData = this.encodeFeatureData(feature);
|
|
145
|
-
|
|
146
|
-
// Write feature data with length prefix
|
|
147
|
-
writer.writeU32(encodedData.length);
|
|
148
|
-
writer.writeBytes(encodedData);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Encode a single feature's data
|
|
154
|
-
*
|
|
155
|
-
* Unlike the base Generator class, we don't split into chunks here
|
|
156
|
-
* since P2WDA handles chunking at the witness level
|
|
157
|
-
*
|
|
158
|
-
* @param feature The feature to encode
|
|
159
|
-
* @returns Encoded feature data
|
|
160
|
-
*/
|
|
161
|
-
private encodeFeatureData(feature: Feature<Features>): Buffer {
|
|
162
|
-
switch (feature.opcode) {
|
|
163
|
-
case Features.ACCESS_LIST: {
|
|
164
|
-
// Access lists are already encoded efficiently by the parent class
|
|
165
|
-
const chunks = this.encodeFeature(feature);
|
|
166
|
-
// Flatten chunks since P2WDA doesn't need script-level chunking
|
|
167
|
-
return Buffer.concat(chunks.flat());
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
case Features.EPOCH_SUBMISSION: {
|
|
171
|
-
// Epoch submissions are also handled by parent
|
|
172
|
-
const chunks = this.encodeFeature(feature);
|
|
173
|
-
return Buffer.concat(chunks.flat());
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
default:
|
|
177
|
-
throw new Error(`Unknown feature type: ${feature.opcode}`);
|
|
121
|
+
this.encodeFeature(feature, writer);
|
|
178
122
|
}
|
|
179
123
|
}
|
|
180
124
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { Transaction, TxOutput } from '@btc-vision/bitcoin';
|
|
2
2
|
import { currentConsensus } from '../consensus/ConsensusConfig.js';
|
|
3
3
|
import { UTXO } from '../utxo/interfaces/IUTXO.js';
|
|
4
|
-
import {
|
|
5
|
-
CustomScriptTransaction,
|
|
6
|
-
ICustomTransactionParameters,
|
|
7
|
-
} from './builders/CustomScriptTransaction.js';
|
|
4
|
+
import { CustomScriptTransaction, ICustomTransactionParameters, } from './builders/CustomScriptTransaction.js';
|
|
8
5
|
import { DeploymentTransaction } from './builders/DeploymentTransaction.js';
|
|
9
6
|
import { FundingTransaction } from './builders/FundingTransaction.js';
|
|
10
7
|
import { InteractionTransaction } from './builders/InteractionTransaction.js';
|
|
@@ -34,12 +31,11 @@ import { CancelTransaction, ICancelTransactionParameters } from './builders/Canc
|
|
|
34
31
|
|
|
35
32
|
export interface DeploymentResult {
|
|
36
33
|
readonly transaction: [string, string];
|
|
37
|
-
|
|
38
34
|
readonly contractAddress: string;
|
|
39
35
|
readonly contractPubKey: string;
|
|
40
36
|
readonly challenge: RawChallenge;
|
|
41
|
-
|
|
42
37
|
readonly utxos: UTXO[];
|
|
38
|
+
readonly inputUtxos: UTXO[];
|
|
43
39
|
}
|
|
44
40
|
|
|
45
41
|
export interface FundingTransactionResponse {
|
|
@@ -47,12 +43,14 @@ export interface FundingTransactionResponse {
|
|
|
47
43
|
readonly original: FundingTransaction;
|
|
48
44
|
readonly estimatedFees: bigint;
|
|
49
45
|
readonly nextUTXOs: UTXO[];
|
|
46
|
+
readonly inputUtxos: UTXO[];
|
|
50
47
|
}
|
|
51
48
|
|
|
52
49
|
export interface BitcoinTransferBase {
|
|
53
50
|
readonly tx: string;
|
|
54
51
|
readonly estimatedFees: bigint;
|
|
55
52
|
readonly nextUTXOs: UTXO[];
|
|
53
|
+
readonly inputUtxos: UTXO[];
|
|
56
54
|
}
|
|
57
55
|
|
|
58
56
|
export interface InteractionResponse {
|
|
@@ -61,6 +59,7 @@ export interface InteractionResponse {
|
|
|
61
59
|
readonly estimatedFees: bigint;
|
|
62
60
|
readonly nextUTXOs: UTXO[];
|
|
63
61
|
readonly fundingUTXOs: UTXO[];
|
|
62
|
+
readonly fundingInputUtxos: UTXO[];
|
|
64
63
|
readonly challenge: RawChallenge;
|
|
65
64
|
readonly interactionAddress: string | null;
|
|
66
65
|
readonly compiledTargetScript: string | null;
|
|
@@ -73,19 +72,22 @@ export interface BitcoinTransferResponse extends BitcoinTransferBase {
|
|
|
73
72
|
export interface CancelledTransaction {
|
|
74
73
|
readonly transaction: string;
|
|
75
74
|
readonly nextUTXOs: UTXO[];
|
|
75
|
+
readonly inputUtxos: UTXO[];
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
export class TransactionFactory {
|
|
79
79
|
public debug: boolean = false;
|
|
80
80
|
|
|
81
81
|
private readonly DUMMY_PUBKEY = Buffer.alloc(32, 1);
|
|
82
|
-
private readonly P2TR_SCRIPT = Buffer.concat([
|
|
83
|
-
Buffer.from([0x51, 0x20]), // OP_1 + 32 bytes
|
|
84
|
-
this.DUMMY_PUBKEY,
|
|
85
|
-
]);
|
|
82
|
+
private readonly P2TR_SCRIPT = Buffer.concat([Buffer.from([0x51, 0x20]), this.DUMMY_PUBKEY]);
|
|
86
83
|
private readonly INITIAL_FUNDING_ESTIMATE = 2000n;
|
|
87
84
|
private readonly MAX_ITERATIONS = 10;
|
|
88
85
|
|
|
86
|
+
/**
|
|
87
|
+
* @description Creates a cancellable transaction.
|
|
88
|
+
* @param {ICancelTransactionParameters | ICancelTransactionParametersWithoutSigner} params - The cancel transaction parameters
|
|
89
|
+
* @returns {Promise<CancelledTransaction>} - The cancelled transaction result
|
|
90
|
+
*/
|
|
89
91
|
public async createCancellableTransaction(
|
|
90
92
|
params: ICancelTransactionParameters | ICancelTransactionParametersWithoutSigner,
|
|
91
93
|
): Promise<CancelledTransaction> {
|
|
@@ -115,16 +117,18 @@ export class TransactionFactory {
|
|
|
115
117
|
return {
|
|
116
118
|
transaction: rawTx,
|
|
117
119
|
nextUTXOs: this.getUTXOAsTransaction(signed, params.from, 0),
|
|
120
|
+
inputUtxos: params.utxos,
|
|
118
121
|
};
|
|
119
122
|
}
|
|
120
123
|
|
|
121
124
|
/**
|
|
122
125
|
* @description Generate a transaction with a custom script.
|
|
123
|
-
* @
|
|
126
|
+
* @param {ICustomTransactionParameters | ICustomTransactionWithoutSigner} interactionParameters - The custom transaction parameters
|
|
127
|
+
* @returns {Promise<[string, string, UTXO[], UTXO[]]>} - The signed transaction tuple [fundingTx, customTx, nextUTXOs, inputUtxos]
|
|
124
128
|
*/
|
|
125
129
|
public async createCustomScriptTransaction(
|
|
126
130
|
interactionParameters: ICustomTransactionParameters | ICustomTransactionWithoutSigner,
|
|
127
|
-
): Promise<[string, string, UTXO[]]> {
|
|
131
|
+
): Promise<[string, string, UTXO[], UTXO[]]> {
|
|
128
132
|
if (!interactionParameters.to) {
|
|
129
133
|
throw new Error('Field "to" not provided.');
|
|
130
134
|
}
|
|
@@ -140,7 +144,6 @@ export class TransactionFactory {
|
|
|
140
144
|
|
|
141
145
|
const inputs = this.parseOptionalInputs(interactionParameters.optionalInputs);
|
|
142
146
|
|
|
143
|
-
// Use common iteration logic
|
|
144
147
|
const { finalTransaction, estimatedAmount, challenge } = await this.iterateFundingAmount(
|
|
145
148
|
{ ...interactionParameters, optionalInputs: inputs },
|
|
146
149
|
CustomScriptTransaction,
|
|
@@ -159,7 +162,6 @@ export class TransactionFactory {
|
|
|
159
162
|
parameters.utxos = interactionParameters.utxos;
|
|
160
163
|
parameters.amount = estimatedAmount;
|
|
161
164
|
|
|
162
|
-
// Create funding transaction
|
|
163
165
|
const feeEstimationFunding = await this.createFundTransaction({
|
|
164
166
|
...parameters,
|
|
165
167
|
optionalOutputs: [],
|
|
@@ -199,11 +201,13 @@ export class TransactionFactory {
|
|
|
199
201
|
signedTransaction.tx.toHex(),
|
|
200
202
|
outTx.toHex(),
|
|
201
203
|
this.getUTXOAsTransaction(signedTransaction.tx, interactionParameters.from, 1),
|
|
204
|
+
interactionParameters.utxos,
|
|
202
205
|
];
|
|
203
206
|
}
|
|
204
207
|
|
|
205
208
|
/**
|
|
206
209
|
* @description Generates the required transactions.
|
|
210
|
+
* @param {IInteractionParameters | InteractionParametersWithoutSigner} interactionParameters - The interaction parameters
|
|
207
211
|
* @returns {Promise<InteractionResponse>} - The signed transaction
|
|
208
212
|
*/
|
|
209
213
|
public async signInteraction(
|
|
@@ -235,7 +239,6 @@ export class TransactionFactory {
|
|
|
235
239
|
|
|
236
240
|
const inputs = this.parseOptionalInputs(interactionParameters.optionalInputs);
|
|
237
241
|
|
|
238
|
-
// Use common iteration logic
|
|
239
242
|
const { finalTransaction, estimatedAmount, challenge } = await this.iterateFundingAmount(
|
|
240
243
|
{ ...interactionParameters, optionalInputs: inputs },
|
|
241
244
|
InteractionTransaction,
|
|
@@ -310,6 +313,7 @@ export class TransactionFactory {
|
|
|
310
313
|
),
|
|
311
314
|
challenge: challenge.toRaw(),
|
|
312
315
|
fundingUTXOs: fundingUTXO,
|
|
316
|
+
fundingInputUtxos: interactionParameters.utxos,
|
|
313
317
|
compiledTargetScript: interactionTx.exportCompiledTargetScript().toString('hex'),
|
|
314
318
|
};
|
|
315
319
|
}
|
|
@@ -333,7 +337,6 @@ export class TransactionFactory {
|
|
|
333
337
|
|
|
334
338
|
const inputs = this.parseOptionalInputs(deploymentParameters.optionalInputs);
|
|
335
339
|
|
|
336
|
-
// Use common iteration logic
|
|
337
340
|
const { finalTransaction, estimatedAmount, challenge } = await this.iterateFundingAmount(
|
|
338
341
|
{ ...deploymentParameters, optionalInputs: inputs },
|
|
339
342
|
DeploymentTransaction,
|
|
@@ -421,13 +424,14 @@ export class TransactionFactory {
|
|
|
421
424
|
contractPubKey: deploymentTx.contractPubKey,
|
|
422
425
|
utxos: [refundUTXO],
|
|
423
426
|
challenge: challenge.toRaw(),
|
|
427
|
+
inputUtxos: deploymentParameters.utxos,
|
|
424
428
|
};
|
|
425
429
|
}
|
|
426
430
|
|
|
427
431
|
/**
|
|
428
432
|
* @description Creates a funding transaction.
|
|
429
433
|
* @param {IFundingTransactionParameters} parameters - The funding transaction parameters
|
|
430
|
-
* @returns {Promise<
|
|
434
|
+
* @returns {Promise<BitcoinTransferResponse>} - The signed transaction
|
|
431
435
|
*/
|
|
432
436
|
public async createBTCTransfer(
|
|
433
437
|
parameters: IFundingTransactionParameters,
|
|
@@ -442,6 +446,7 @@ export class TransactionFactory {
|
|
|
442
446
|
original: resp.original,
|
|
443
447
|
tx: resp.tx.toHex(),
|
|
444
448
|
nextUTXOs: this.getAllNewUTXOs(resp.original, resp.tx, parameters.from),
|
|
449
|
+
inputUtxos: parameters.utxos,
|
|
445
450
|
};
|
|
446
451
|
}
|
|
447
452
|
|
|
@@ -450,6 +455,7 @@ export class TransactionFactory {
|
|
|
450
455
|
* @param {TransactionBuilder<TransactionType>} original - The original transaction
|
|
451
456
|
* @param {Transaction} tx - The transaction
|
|
452
457
|
* @param {string} to - The address to filter
|
|
458
|
+
* @returns {UTXO[]} - The new UTXOs belonging to the specified address
|
|
453
459
|
*/
|
|
454
460
|
public getAllNewUTXOs(
|
|
455
461
|
original: TransactionBuilder<TransactionType>,
|
|
@@ -473,6 +479,11 @@ export class TransactionFactory {
|
|
|
473
479
|
return utxos;
|
|
474
480
|
}
|
|
475
481
|
|
|
482
|
+
/**
|
|
483
|
+
* Parse optional inputs and normalize nonWitnessUtxo format.
|
|
484
|
+
* @param {UTXO[]} optionalInputs - The optional inputs to parse
|
|
485
|
+
* @returns {UTXO[]} - The parsed inputs with normalized nonWitnessUtxo
|
|
486
|
+
*/
|
|
476
487
|
private parseOptionalInputs(optionalInputs?: UTXO[]): UTXO[] {
|
|
477
488
|
return (optionalInputs || []).map((input) => {
|
|
478
489
|
let nonWitness = input.nonWitnessUtxo;
|
|
@@ -495,6 +506,11 @@ export class TransactionFactory {
|
|
|
495
506
|
});
|
|
496
507
|
}
|
|
497
508
|
|
|
509
|
+
/**
|
|
510
|
+
* Detect and use OP_WALLET for cancel transactions if available.
|
|
511
|
+
* @param {ICancelTransactionParameters | ICancelTransactionParametersWithoutSigner} interactionParameters - The cancel parameters
|
|
512
|
+
* @returns {Promise<CancelledTransaction | null>} - The cancelled transaction or null if OP_WALLET not available
|
|
513
|
+
*/
|
|
498
514
|
private async detectCancelOPWallet(
|
|
499
515
|
interactionParameters:
|
|
500
516
|
| ICancelTransactionParameters
|
|
@@ -512,7 +528,6 @@ export class TransactionFactory {
|
|
|
512
528
|
const opnet = _window.opnet.web3;
|
|
513
529
|
const interaction = await opnet.cancelTransaction({
|
|
514
530
|
...interactionParameters,
|
|
515
|
-
|
|
516
531
|
// @ts-expect-error no, this is ok
|
|
517
532
|
signer: undefined,
|
|
518
533
|
});
|
|
@@ -521,9 +536,17 @@ export class TransactionFactory {
|
|
|
521
536
|
throw new Error('Could not sign interaction transaction.');
|
|
522
537
|
}
|
|
523
538
|
|
|
524
|
-
return
|
|
539
|
+
return {
|
|
540
|
+
...interaction,
|
|
541
|
+
inputUtxos: interaction.inputUtxos ?? interactionParameters.utxos,
|
|
542
|
+
};
|
|
525
543
|
}
|
|
526
544
|
|
|
545
|
+
/**
|
|
546
|
+
* Detect and use OP_WALLET for interaction transactions if available.
|
|
547
|
+
* @param {IInteractionParameters | InteractionParametersWithoutSigner} interactionParameters - The interaction parameters
|
|
548
|
+
* @returns {Promise<InteractionResponse | null>} - The interaction response or null if OP_WALLET not available
|
|
549
|
+
*/
|
|
527
550
|
private async detectInteractionOPWallet(
|
|
528
551
|
interactionParameters: IInteractionParameters | InteractionParametersWithoutSigner,
|
|
529
552
|
): Promise<InteractionResponse | null> {
|
|
@@ -539,7 +562,6 @@ export class TransactionFactory {
|
|
|
539
562
|
const opnet = _window.opnet.web3;
|
|
540
563
|
const interaction = await opnet.signInteraction({
|
|
541
564
|
...interactionParameters,
|
|
542
|
-
|
|
543
565
|
// @ts-expect-error no, this is ok
|
|
544
566
|
signer: undefined,
|
|
545
567
|
});
|
|
@@ -548,9 +570,17 @@ export class TransactionFactory {
|
|
|
548
570
|
throw new Error('Could not sign interaction transaction.');
|
|
549
571
|
}
|
|
550
572
|
|
|
551
|
-
return
|
|
573
|
+
return {
|
|
574
|
+
...interaction,
|
|
575
|
+
fundingInputUtxos: interaction.fundingInputUtxos ?? interactionParameters.utxos,
|
|
576
|
+
};
|
|
552
577
|
}
|
|
553
578
|
|
|
579
|
+
/**
|
|
580
|
+
* Detect and use OP_WALLET for deployment transactions if available.
|
|
581
|
+
* @param {IDeploymentParameters | IDeploymentParametersWithoutSigner} deploymentParameters - The deployment parameters
|
|
582
|
+
* @returns {Promise<DeploymentResult | null>} - The deployment result or null if OP_WALLET not available
|
|
583
|
+
*/
|
|
554
584
|
private async detectDeploymentOPWallet(
|
|
555
585
|
deploymentParameters: IDeploymentParameters | IDeploymentParametersWithoutSigner,
|
|
556
586
|
): Promise<DeploymentResult | null> {
|
|
@@ -566,7 +596,6 @@ export class TransactionFactory {
|
|
|
566
596
|
const opnet = _window.opnet.web3;
|
|
567
597
|
const deployment = await opnet.deployContract({
|
|
568
598
|
...deploymentParameters,
|
|
569
|
-
|
|
570
599
|
// @ts-expect-error no, this is ok
|
|
571
600
|
signer: undefined,
|
|
572
601
|
});
|
|
@@ -575,9 +604,17 @@ export class TransactionFactory {
|
|
|
575
604
|
throw new Error('Could not sign interaction transaction.');
|
|
576
605
|
}
|
|
577
606
|
|
|
578
|
-
return
|
|
607
|
+
return {
|
|
608
|
+
...deployment,
|
|
609
|
+
inputUtxos: deployment.inputUtxos ?? deploymentParameters.utxos,
|
|
610
|
+
};
|
|
579
611
|
}
|
|
580
612
|
|
|
613
|
+
/**
|
|
614
|
+
* Create and sign a funding transaction.
|
|
615
|
+
* @param {IFundingTransactionParameters} parameters - The funding transaction parameters
|
|
616
|
+
* @returns {Promise<FundingTransactionResponse>} - The funding transaction response
|
|
617
|
+
*/
|
|
581
618
|
private async createFundTransaction(
|
|
582
619
|
parameters: IFundingTransactionParameters,
|
|
583
620
|
): Promise<FundingTransactionResponse> {
|
|
@@ -594,6 +631,7 @@ export class TransactionFactory {
|
|
|
594
631
|
original: fundingTransaction,
|
|
595
632
|
estimatedFees: fundingTransaction.estimatedFees,
|
|
596
633
|
nextUTXOs: this.getUTXOAsTransaction(signedTransaction, parameters.to, 0),
|
|
634
|
+
inputUtxos: parameters.utxos,
|
|
597
635
|
};
|
|
598
636
|
}
|
|
599
637
|
|
|
@@ -604,13 +642,19 @@ export class TransactionFactory {
|
|
|
604
642
|
* if any of them are P2WDA addresses. P2WDA detection is based on the
|
|
605
643
|
* witness script pattern: (OP_2DROP * 5) <pubkey> OP_CHECKSIG
|
|
606
644
|
*
|
|
607
|
-
* @param utxos The main UTXOs to check
|
|
608
|
-
* @returns true if any UTXO is P2WDA, false otherwise
|
|
645
|
+
* @param {UTXO[]} utxos - The main UTXOs to check
|
|
646
|
+
* @returns {boolean} - true if any UTXO is P2WDA, false otherwise
|
|
609
647
|
*/
|
|
610
648
|
private hasP2WDAInputs(utxos: UTXO[]): boolean {
|
|
611
649
|
return utxos.some((utxo) => P2WDADetector.isP2WDAUTXO(utxo));
|
|
612
650
|
}
|
|
613
651
|
|
|
652
|
+
/**
|
|
653
|
+
* Write PSBT header with type and consensus version.
|
|
654
|
+
* @param {PSBTTypes} type - The PSBT type
|
|
655
|
+
* @param {string} psbt - The base64 encoded PSBT
|
|
656
|
+
* @returns {string} - The hex encoded PSBT with header
|
|
657
|
+
*/
|
|
614
658
|
private writePSBTHeader(type: PSBTTypes, psbt: string): string {
|
|
615
659
|
const buf = Buffer.from(psbt, 'base64');
|
|
616
660
|
|
|
@@ -635,8 +679,8 @@ export class TransactionFactory {
|
|
|
635
679
|
* - 75% cost reduction for data storage
|
|
636
680
|
* - No separate funding transaction needed
|
|
637
681
|
*
|
|
638
|
-
* @param interactionParameters The interaction parameters
|
|
639
|
-
* @returns The signed P2WDA interaction response
|
|
682
|
+
* @param {IInteractionParameters | InteractionParametersWithoutSigner} interactionParameters - The interaction parameters
|
|
683
|
+
* @returns {Promise<InteractionResponse>} - The signed P2WDA interaction response
|
|
640
684
|
*/
|
|
641
685
|
private async signP2WDAInteraction(
|
|
642
686
|
interactionParameters: IInteractionParameters | InteractionParametersWithoutSigner,
|
|
@@ -645,7 +689,6 @@ export class TransactionFactory {
|
|
|
645
689
|
throw new Error('Field "from" not provided.');
|
|
646
690
|
}
|
|
647
691
|
|
|
648
|
-
// Ensure we have a signer for P2WDA
|
|
649
692
|
if (!('signer' in interactionParameters)) {
|
|
650
693
|
throw new Error(
|
|
651
694
|
'P2WDA interactions require a signer. OP_WALLET is not supported for P2WDA.',
|
|
@@ -669,14 +712,20 @@ export class TransactionFactory {
|
|
|
669
712
|
nextUTXOs: this.getUTXOAsTransaction(
|
|
670
713
|
signedTx,
|
|
671
714
|
interactionParameters.from,
|
|
672
|
-
signedTx.outs.length - 1,
|
|
715
|
+
signedTx.outs.length - 1,
|
|
673
716
|
),
|
|
674
717
|
fundingUTXOs: [...interactionParameters.utxos, ...inputs],
|
|
718
|
+
fundingInputUtxos: interactionParameters.utxos,
|
|
675
719
|
challenge: interactionParameters.challenge.toRaw(),
|
|
676
720
|
compiledTargetScript: null,
|
|
677
721
|
};
|
|
678
722
|
}
|
|
679
723
|
|
|
724
|
+
/**
|
|
725
|
+
* Get the priority fee from transaction parameters.
|
|
726
|
+
* @param {ITransactionParameters} params - The transaction parameters
|
|
727
|
+
* @returns {bigint} - The priority fee, minimum dust if below threshold
|
|
728
|
+
*/
|
|
680
729
|
private getPriorityFee(params: ITransactionParameters): bigint {
|
|
681
730
|
const totalFee = params.priorityFee + params.gasSatFee;
|
|
682
731
|
if (totalFee < TransactionBuilder.MINIMUM_DUST) {
|
|
@@ -687,7 +736,16 @@ export class TransactionFactory {
|
|
|
687
736
|
}
|
|
688
737
|
|
|
689
738
|
/**
|
|
690
|
-
* Common iteration logic for finding the correct funding amount
|
|
739
|
+
* Common iteration logic for finding the correct funding amount.
|
|
740
|
+
*
|
|
741
|
+
* This method iteratively estimates the required funding amount by simulating
|
|
742
|
+
* transactions until the amount converges or max iterations is reached.
|
|
743
|
+
*
|
|
744
|
+
* @param {P} params - The transaction parameters
|
|
745
|
+
* @param {new (params: P) => T} TransactionClass - The transaction class constructor
|
|
746
|
+
* @param {(tx: T) => Promise<bigint>} calculateAmount - Function to calculate required amount
|
|
747
|
+
* @param {string} debugPrefix - Prefix for debug logging
|
|
748
|
+
* @returns {Promise<{finalTransaction: T, estimatedAmount: bigint, challenge: ChallengeSolution | null}>} - The final transaction and estimated amount
|
|
691
749
|
*/
|
|
692
750
|
private async iterateFundingAmount<
|
|
693
751
|
T extends InteractionTransaction | DeploymentTransaction | CustomScriptTransaction,
|
|
@@ -732,14 +790,13 @@ export class TransactionFactory {
|
|
|
732
790
|
nonWitnessUtxo: dummyTx.toBuffer(),
|
|
733
791
|
};
|
|
734
792
|
|
|
735
|
-
// Build transaction params - TypeScript needs explicit typing here
|
|
736
793
|
let txParams: P;
|
|
737
794
|
if ('challenge' in params && params.challenge) {
|
|
738
795
|
const withChallenge = {
|
|
739
796
|
...params,
|
|
740
797
|
utxos: [simulatedFundedUtxo],
|
|
741
798
|
randomBytes: randomBytes,
|
|
742
|
-
challenge: challenge ?? params.challenge,
|
|
799
|
+
challenge: challenge ?? params.challenge,
|
|
743
800
|
};
|
|
744
801
|
txParams = withChallenge as P;
|
|
745
802
|
} else {
|
|
@@ -776,7 +833,6 @@ export class TransactionFactory {
|
|
|
776
833
|
|
|
777
834
|
finalPreTransaction = preTransaction;
|
|
778
835
|
|
|
779
|
-
// Extract challenge with explicit typing
|
|
780
836
|
if (
|
|
781
837
|
'getChallenge' in preTransaction &&
|
|
782
838
|
typeof preTransaction.getChallenge === 'function'
|
|
@@ -804,6 +860,13 @@ export class TransactionFactory {
|
|
|
804
860
|
};
|
|
805
861
|
}
|
|
806
862
|
|
|
863
|
+
/**
|
|
864
|
+
* Convert a transaction output to a UTXO.
|
|
865
|
+
* @param {Transaction} tx - The transaction
|
|
866
|
+
* @param {string} to - The address
|
|
867
|
+
* @param {number} index - The output index
|
|
868
|
+
* @returns {UTXO[]} - The UTXO array (empty if output doesn't exist)
|
|
869
|
+
*/
|
|
807
870
|
private getUTXOAsTransaction(tx: Transaction, to: string, index: number): UTXO[] {
|
|
808
871
|
if (!tx.outs[index]) return [];
|
|
809
872
|
|