@btc-vision/transaction 1.6.10 → 1.6.12

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 (39) hide show
  1. package/browser/_version.d.ts +1 -1
  2. package/browser/index.js +1 -1
  3. package/browser/opnet.d.ts +1 -0
  4. package/browser/transaction/TransactionFactory.d.ts +3 -0
  5. package/browser/transaction/builders/CancelTransaction.d.ts +28 -0
  6. package/browser/transaction/builders/SharedInteractionTransaction.d.ts +1 -0
  7. package/browser/transaction/builders/TransactionBuilder.d.ts +3 -2
  8. package/browser/transaction/enums/TransactionType.d.ts +1 -1
  9. package/browser/transaction/interfaces/ITransactionParameters.d.ts +1 -0
  10. package/build/_version.d.ts +1 -1
  11. package/build/_version.js +1 -1
  12. package/build/opnet.d.ts +1 -0
  13. package/build/opnet.js +1 -0
  14. package/build/transaction/TransactionFactory.d.ts +3 -0
  15. package/build/transaction/TransactionFactory.js +8 -1
  16. package/build/transaction/builders/CancelTransaction.d.ts +28 -0
  17. package/build/transaction/builders/CancelTransaction.js +154 -0
  18. package/build/transaction/builders/CustomScriptTransaction.js +2 -1
  19. package/build/transaction/builders/DeploymentTransaction.js +2 -1
  20. package/build/transaction/builders/SharedInteractionTransaction.d.ts +1 -0
  21. package/build/transaction/builders/SharedInteractionTransaction.js +7 -2
  22. package/build/transaction/builders/TransactionBuilder.d.ts +3 -2
  23. package/build/transaction/builders/TransactionBuilder.js +12 -8
  24. package/build/transaction/enums/TransactionType.d.ts +1 -1
  25. package/build/transaction/enums/TransactionType.js +1 -1
  26. package/build/transaction/interfaces/ITransactionParameters.d.ts +1 -0
  27. package/build/verification/TapscriptVerificator.js +11 -4
  28. package/package.json +1 -1
  29. package/src/_version.ts +1 -1
  30. package/src/opnet.ts +1 -0
  31. package/src/transaction/TransactionFactory.ts +15 -9
  32. package/src/transaction/builders/CancelTransaction.ts +266 -0
  33. package/src/transaction/builders/CustomScriptTransaction.ts +2 -1
  34. package/src/transaction/builders/DeploymentTransaction.ts +2 -1
  35. package/src/transaction/builders/SharedInteractionTransaction.ts +12 -3
  36. package/src/transaction/builders/TransactionBuilder.ts +27 -10
  37. package/src/transaction/enums/TransactionType.ts +1 -1
  38. package/src/transaction/interfaces/ITransactionParameters.ts +1 -0
  39. package/src/verification/TapscriptVerificator.ts +14 -3
@@ -57,7 +57,10 @@ export interface InteractionResponse {
57
57
  readonly interactionTransaction: string;
58
58
  readonly estimatedFees: bigint;
59
59
  readonly nextUTXOs: UTXO[];
60
+ readonly fundingUTXOs: UTXO[];
60
61
  readonly challenge: RawChallenge;
62
+ readonly interactionAddress: string | null;
63
+ readonly compiledTargetScript: string | null;
61
64
  }
62
65
 
63
66
  export interface BitcoinTransferResponse extends BitcoinTransferBase {
@@ -158,10 +161,6 @@ export class TransactionFactory {
158
161
  ];
159
162
  }
160
163
 
161
- /**
162
- * @description Generates the required transactions.
163
- * @returns {Promise<InteractionResponse>} - The signed transaction
164
- */
165
164
  /**
166
165
  * @description Generates the required transactions.
167
166
  * @returns {Promise<InteractionResponse>} - The signed transaction
@@ -239,13 +238,14 @@ export class TransactionFactory {
239
238
  throw new Error('Could not sign funding transaction.');
240
239
  }
241
240
 
241
+ const fundingUTXO = this.getUTXOAsTransaction(
242
+ signedTransaction.tx,
243
+ finalTransaction.getScriptAddress(),
244
+ 0,
245
+ );
242
246
  const newParams: IInteractionParameters = {
243
247
  ...interactionParameters,
244
- utxos: this.getUTXOAsTransaction(
245
- signedTransaction.tx,
246
- finalTransaction.getScriptAddress(),
247
- 0,
248
- ),
248
+ utxos: fundingUTXO,
249
249
  randomBytes: finalTransaction.getRndBytes(),
250
250
  challenge: challenge,
251
251
  nonWitnessUtxo: signedTransaction.tx.toBuffer(),
@@ -257,6 +257,7 @@ export class TransactionFactory {
257
257
  const outTx = await interactionTx.signTransaction();
258
258
 
259
259
  return {
260
+ interactionAddress: finalTransaction.getScriptAddress(),
260
261
  fundingTransaction: signedTransaction.tx.toHex(),
261
262
  interactionTransaction: outTx.toHex(),
262
263
  estimatedFees: interactionTx.transactionFee,
@@ -266,6 +267,8 @@ export class TransactionFactory {
266
267
  1,
267
268
  ),
268
269
  challenge: challenge.toRaw(),
270
+ fundingUTXOs: fundingUTXO,
271
+ compiledTargetScript: interactionTx.exportCompiledTargetScript().toString('hex'),
269
272
  };
270
273
  }
271
274
 
@@ -587,6 +590,7 @@ export class TransactionFactory {
587
590
  const txHex = signedTx.toHex();
588
591
 
589
592
  return {
593
+ interactionAddress: null,
590
594
  fundingTransaction: null,
591
595
  interactionTransaction: txHex,
592
596
  estimatedFees: p2wdaTransaction.estimatedFees,
@@ -595,7 +599,9 @@ export class TransactionFactory {
595
599
  interactionParameters.from,
596
600
  signedTx.outs.length - 1, // Last output is typically the change
597
601
  ),
602
+ fundingUTXOs: [...interactionParameters.utxos, ...inputs],
598
603
  challenge: interactionParameters.challenge.toRaw(),
604
+ compiledTargetScript: null,
599
605
  };
600
606
  }
601
607
 
@@ -0,0 +1,266 @@
1
+ import { TransactionType } from '../enums/TransactionType.js';
2
+ import { P2TRPayment, PaymentType, Psbt, PsbtInput, Taptree } from '@btc-vision/bitcoin';
3
+ import { TransactionBuilder } from './TransactionBuilder.js';
4
+ import { TapLeafScript } from '../interfaces/Tap.js';
5
+ import { ITransactionParameters, SharedInteractionParameters, } from '../interfaces/ITransactionParameters.js';
6
+ import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
7
+
8
+ export interface ICancelTransactionParameters
9
+ extends Omit<ITransactionParameters, 'priorityFee' | 'gasSatFee'> {
10
+ readonly compiledTargetScript: string | Buffer;
11
+ }
12
+
13
+ export class CancelTransaction extends TransactionBuilder<TransactionType.CANCEL> {
14
+ public type: TransactionType.CANCEL = TransactionType.CANCEL;
15
+
16
+ /**
17
+ * The tap leaf script for spending
18
+ */
19
+ protected tapLeafScript: TapLeafScript | null = null;
20
+
21
+ protected readonly compiledTargetScript: Buffer;
22
+ protected readonly scriptTree: Taptree;
23
+
24
+ protected readonly contractSecret: Buffer;
25
+ protected leftOverFundsScriptRedeem: P2TRPayment | null = null;
26
+
27
+ public constructor(parameters: ICancelTransactionParameters) {
28
+ super({
29
+ ...parameters,
30
+ gasSatFee: 1n,
31
+ isCancellation: true,
32
+ priorityFee: 1n,
33
+ calldata: Buffer.alloc(0),
34
+ } as unknown as SharedInteractionParameters);
35
+
36
+ this.contractSecret = Buffer.alloc(0);
37
+
38
+ if (Buffer.isBuffer(parameters.compiledTargetScript)) {
39
+ this.compiledTargetScript = parameters.compiledTargetScript;
40
+ } else {
41
+ this.compiledTargetScript = Buffer.from(parameters.compiledTargetScript, 'hex');
42
+ }
43
+
44
+ // Generate the minimal script tree needed for recovery
45
+ this.scriptTree = this.getMinimalScriptTree();
46
+
47
+ this.internalInit();
48
+ }
49
+
50
+ protected override async buildTransaction(): Promise<void> {
51
+ if (!this.from) {
52
+ throw new Error('From address is required');
53
+ }
54
+
55
+ if (!this.leftOverFundsScriptRedeem) {
56
+ throw new Error('Left over funds script redeem is required');
57
+ }
58
+
59
+ if (!this.leftOverFundsScriptRedeem.redeemVersion) {
60
+ throw new Error('Left over funds script redeem version is required');
61
+ }
62
+
63
+ if (!this.leftOverFundsScriptRedeem.output) {
64
+ throw new Error('Left over funds script redeem output is required');
65
+ }
66
+
67
+ // Set up the tap leaf script for spending
68
+ this.tapLeafScript = {
69
+ leafVersion: this.leftOverFundsScriptRedeem.redeemVersion,
70
+ script: this.leftOverFundsScriptRedeem.output,
71
+ controlBlock: this.getWitness(),
72
+ };
73
+
74
+ this.addInputsFromUTXO();
75
+
76
+ await this.addRefundOutput(0n, true);
77
+
78
+ if (!this.feeOutput) {
79
+ throw new Error('Must add extra UTXOs to cancel this transaction');
80
+ }
81
+ }
82
+
83
+ /*protected override async buildTransaction(): Promise<void> {
84
+ if (!this.from) {
85
+ throw new Error('From address is required');
86
+ }
87
+
88
+ // For key-path spend, we don't need the tap leaf script
89
+ this.tapLeafScript = null;
90
+
91
+ this.addInputsFromUTXO();
92
+ await this.addRefundOutput(0n);
93
+ }*/
94
+
95
+ /**
96
+ * Sign the inputs
97
+ * @param {Psbt} transaction The transaction to sign
98
+ * @protected
99
+ */
100
+ /*protected async signInputs(transaction: Psbt): Promise<void> {
101
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
102
+ if (i === 0) {
103
+ transaction.signInput(0, this.getSignerKey());
104
+
105
+ transaction.finalizeInput(0, this.customFinalizer.bind(this));
106
+ } else {
107
+ await super.signInputs(transaction);
108
+ }
109
+ }
110
+ }*/
111
+
112
+ /**
113
+ * Generate the script address (for verification purposes)
114
+ */
115
+ protected override generateScriptAddress(): P2TRPayment {
116
+ return {
117
+ internalPubkey: this.internalPubKeyToXOnly(),
118
+ network: this.network,
119
+ scriptTree: this.scriptTree,
120
+ name: PaymentType.P2TR,
121
+ };
122
+ }
123
+
124
+ /**
125
+ * Generate the tap data for spending
126
+ */
127
+ /*protected override generateTapData(): P2TRPayment {
128
+ const internalPubkey = this.internalPubKeyToXOnly();
129
+
130
+ return {
131
+ name: PaymentType.P2TR,
132
+ internalPubkey: internalPubkey,
133
+ network: this.network,
134
+ scriptTree: this.scriptTree, // This is crucial for the tweak
135
+ };
136
+ }*/
137
+ protected override generateTapData(): P2TRPayment {
138
+ const selectedRedeem = this.leftOverFundsScriptRedeem;
139
+
140
+ if (!selectedRedeem) {
141
+ throw new Error('Left over funds script redeem is required');
142
+ }
143
+
144
+ if (!this.scriptTree) {
145
+ throw new Error('Script tree is required');
146
+ }
147
+
148
+ return {
149
+ internalPubkey: this.internalPubKeyToXOnly(),
150
+ network: this.network,
151
+ scriptTree: this.scriptTree,
152
+ redeem: selectedRedeem,
153
+ name: PaymentType.P2TR,
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Custom finalizer for the tap script spend
159
+ */
160
+ protected customFinalizer = (_inputIndex: number, input: PsbtInput) => {
161
+ if (!this.tapLeafScript) {
162
+ throw new Error('Tap leaf script is required');
163
+ }
164
+
165
+ if (!input.tapScriptSig || input.tapScriptSig.length === 0) {
166
+ throw new Error('Tap script signature is required');
167
+ }
168
+
169
+ // For the simple lock script, we only need the signature
170
+ const scriptSolution = [input.tapScriptSig[0].signature];
171
+
172
+ const witness = scriptSolution
173
+ .concat(this.tapLeafScript.script)
174
+ .concat(this.tapLeafScript.controlBlock);
175
+
176
+ return {
177
+ finalScriptWitness: TransactionBuilder.witnessStackToScriptWitness(witness),
178
+ };
179
+ };
180
+
181
+ protected override async signInputs(transaction: Psbt): Promise<void> {
182
+ if ('multiSignPsbt' in this.signer) {
183
+ await this.signInputsWalletBased(transaction);
184
+ } else {
185
+ await this.signInputsNonWalletBased(transaction);
186
+ }
187
+ }
188
+
189
+ protected override async signInputsWalletBased(transaction: Psbt): Promise<void> {
190
+ const signer: UnisatSigner = this.signer as UnisatSigner;
191
+
192
+ // then, we sign all the remaining inputs with the wallet signer.
193
+ await signer.multiSignPsbt([transaction]);
194
+
195
+ // Then, we finalize every input.
196
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
197
+ if (i === 0) {
198
+ transaction.finalizeInput(i, this.customFinalizer.bind(this));
199
+ } else {
200
+ try {
201
+ transaction.finalizeInput(i, this.customFinalizerP2SH.bind(this));
202
+ } catch (e) {
203
+ transaction.finalizeInput(i);
204
+ }
205
+ }
206
+ }
207
+ }
208
+
209
+ protected override async signInputsNonWalletBased(transaction: Psbt): Promise<void> {
210
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
211
+ if (i === 0) {
212
+ await this.signInput(
213
+ transaction,
214
+ transaction.data.inputs[i],
215
+ i,
216
+ this.getSignerKey(),
217
+ );
218
+
219
+ transaction.finalizeInput(0, this.customFinalizer.bind(this));
220
+ } else {
221
+ await this.signInput(transaction, transaction.data.inputs[i], i, this.signer);
222
+
223
+ try {
224
+ transaction.finalizeInput(i, this.customFinalizerP2SH.bind(this));
225
+ } catch (e) {
226
+ transaction.finalizeInput(i);
227
+ }
228
+ }
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Generate the minimal script tree needed for recovery
234
+ * This only includes the leftover funds script
235
+ */
236
+ private getMinimalScriptTree(): Taptree {
237
+ this.generateLeftoverFundsRedeem();
238
+
239
+ if (!this.leftOverFundsScriptRedeem || !this.leftOverFundsScriptRedeem.output) {
240
+ throw new Error('Failed to generate leftover funds redeem script');
241
+ }
242
+
243
+ return [
244
+ {
245
+ output: this.compiledTargetScript,
246
+ version: 192,
247
+ },
248
+ {
249
+ output: this.leftOverFundsScriptRedeem.output,
250
+ version: 192,
251
+ },
252
+ ];
253
+ }
254
+
255
+ /**
256
+ * Generate the leftover funds redeem script
257
+ */
258
+ private generateLeftoverFundsRedeem(): void {
259
+ // Use the same LOCK_LEAF_SCRIPT from the parent class
260
+ this.leftOverFundsScriptRedeem = {
261
+ name: PaymentType.P2TR,
262
+ output: this.LOCK_LEAF_SCRIPT,
263
+ redeemVersion: 192,
264
+ };
265
+ }
266
+ }
@@ -107,6 +107,7 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
107
107
 
108
108
  this.witnesses = parameters.witnesses;
109
109
  this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
110
+ this.LOCK_LEAF_SCRIPT = this.defineLockScript();
110
111
 
111
112
  this.scriptSeed = this.getContractSeed();
112
113
  this.contractSigner = EcKeyPair.fromSeedKeyPair(this.scriptSeed, this.network);
@@ -353,7 +354,7 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
353
354
  * @private
354
355
  */
355
356
  private getLeafScript(): Buffer {
356
- return TransactionBuilder.LOCK_LEAF_SCRIPT;
357
+ return this.LOCK_LEAF_SCRIPT;
357
358
  }
358
359
 
359
360
  /**
@@ -127,6 +127,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
127
127
  this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
128
128
  this.challenge = parameters.challenge;
129
129
 
130
+ this.LOCK_LEAF_SCRIPT = this.defineLockScript();
130
131
  this.epochChallenge = TimeLockGenerator.generateTimeLockAddress(
131
132
  this.challenge.publicKey.originalPublicKeyBuffer(),
132
133
  this.network,
@@ -471,7 +472,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
471
472
  * @private
472
473
  */
473
474
  private getLeafScript(): Buffer {
474
- return TransactionBuilder.LOCK_LEAF_SCRIPT;
475
+ return this.LOCK_LEAF_SCRIPT;
475
476
  }
476
477
 
477
478
  /**
@@ -75,6 +75,8 @@ export abstract class SharedInteractionTransaction<
75
75
 
76
76
  this.challenge = parameters.challenge;
77
77
 
78
+ this.LOCK_LEAF_SCRIPT = this.defineLockScript();
79
+
78
80
  this.disableAutoRefund = parameters.disableAutoRefund || false;
79
81
  this.epochChallenge = TimeLockGenerator.generateTimeLockAddress(
80
82
  this.challenge.publicKey.originalPublicKeyBuffer(),
@@ -93,6 +95,10 @@ export abstract class SharedInteractionTransaction<
93
95
  );
94
96
  }
95
97
 
98
+ public exportCompiledTargetScript(): Buffer {
99
+ return this.compiledTargetScript;
100
+ }
101
+
96
102
  /**
97
103
  * Get the contract secret
98
104
  * @returns {Buffer} The contract secret
@@ -215,6 +221,8 @@ export abstract class SharedInteractionTransaction<
215
221
  throw new Error('Script tree is required');
216
222
  }
217
223
 
224
+ console.log('internalPubkey', this.internalPubKeyToXOnly().toString('hex'));
225
+
218
226
  return {
219
227
  internalPubkey: this.internalPubKeyToXOnly(),
220
228
  network: this.network,
@@ -262,7 +270,7 @@ export abstract class SharedInteractionTransaction<
262
270
  version: 192,
263
271
  },
264
272
  {
265
- output: SharedInteractionTransaction.LOCK_LEAF_SCRIPT,
273
+ output: this.LOCK_LEAF_SCRIPT,
266
274
  version: 192,
267
275
  },
268
276
  ];
@@ -350,7 +358,8 @@ export abstract class SharedInteractionTransaction<
350
358
  this.addFeeToOutput(opnetFee, this.to, this.epochChallenge, false);
351
359
 
352
360
  // Get the actual amount added to outputs (might be MINIMUM_AMOUNT_REWARD if opnetFee is too small)
353
- const actualOutputAmount = opnetFee < MINIMUM_AMOUNT_REWARD ? MINIMUM_AMOUNT_REWARD : opnetFee;
361
+ const actualOutputAmount =
362
+ opnetFee < MINIMUM_AMOUNT_REWARD ? MINIMUM_AMOUNT_REWARD : opnetFee;
354
363
 
355
364
  const optionalAmount = this.addOptionalOutputsAndGetAmount();
356
365
 
@@ -395,7 +404,7 @@ export abstract class SharedInteractionTransaction<
395
404
 
396
405
  this.leftOverFundsScriptRedeem = {
397
406
  name: PaymentType.P2TR,
398
- output: SharedInteractionTransaction.LOCK_LEAF_SCRIPT,
407
+ output: this.LOCK_LEAF_SCRIPT,
399
408
  redeemVersion: 192,
400
409
  };
401
410
  }
@@ -8,13 +8,17 @@ import bitcoin, {
8
8
  PsbtOutputExtended,
9
9
  script,
10
10
  Signer,
11
+ toXOnly,
11
12
  Transaction,
12
13
  varuint,
13
14
  } from '@btc-vision/bitcoin';
14
15
  import * as ecc from '@bitcoinerlab/secp256k1';
15
16
  import { UpdateInput } from '../interfaces/Tap.js';
16
17
  import { TransactionType } from '../enums/TransactionType.js';
17
- import { IFundingTransactionParameters, ITransactionParameters, } from '../interfaces/ITransactionParameters.js';
18
+ import {
19
+ IFundingTransactionParameters,
20
+ ITransactionParameters,
21
+ } from '../interfaces/ITransactionParameters.js';
18
22
  import { EcKeyPair } from '../../keypair/EcKeyPair.js';
19
23
  import { UTXO } from '../../utxo/interfaces/IUTXO.js';
20
24
  import { ECPairInterface } from 'ecpair';
@@ -37,18 +41,15 @@ export const ANCHOR_SCRIPT = Buffer.from('51024e73', 'hex');
37
41
  * @class TransactionBuilder
38
42
  */
39
43
  export abstract class TransactionBuilder<T extends TransactionType> extends TweakedTransaction {
40
- // Cancel script
41
- public static readonly LOCK_LEAF_SCRIPT: Buffer = script.compile([
42
- opcodes.OP_FALSE,
43
- opcodes.OP_VERIFY,
44
- ]);
45
-
46
44
  public static readonly MINIMUM_DUST: bigint = 330n;
47
45
 
48
46
  public abstract readonly type: T;
49
47
  public readonly logColor: string = '#785def';
50
48
  public debugFees: boolean = false;
51
49
 
50
+ // Cancel script
51
+ public LOCK_LEAF_SCRIPT: Buffer;
52
+
52
53
  /**
53
54
  * @description The overflow fees of the transaction
54
55
  * @public
@@ -177,6 +178,8 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
177
178
  this.to = parameters.to || undefined;
178
179
  this.debugFees = parameters.debugFees || false;
179
180
 
181
+ this.LOCK_LEAF_SCRIPT = this.defineLockScript();
182
+
180
183
  if (parameters.note) {
181
184
  if (typeof parameters.note === 'string') {
182
185
  this.note = Buffer.from(parameters.note, 'utf8');
@@ -737,7 +740,10 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
737
740
  return total;
738
741
  }
739
742
 
740
- protected async addRefundOutput(amountSpent: bigint): Promise<void> {
743
+ protected async addRefundOutput(
744
+ amountSpent: bigint,
745
+ expectRefund: boolean = false,
746
+ ): Promise<void> {
741
747
  if (this.note) {
742
748
  this.addOPReturn(this.note);
743
749
  }
@@ -752,6 +758,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
752
758
  let iterations = 0;
753
759
  const maxIterations = 5; // Prevent infinite loops
754
760
 
761
+ let sendBackAmount = 0n;
755
762
  // Iterate until fee stabilizes
756
763
  while (iterations < maxIterations && estimatedFee !== previousFee) {
757
764
  previousFee = estimatedFee;
@@ -763,7 +770,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
763
770
  const totalSpent = amountSpent + estimatedFee;
764
771
 
765
772
  // Calculate refund
766
- const sendBackAmount = this.totalInputAmount - totalSpent;
773
+ sendBackAmount = this.totalInputAmount - totalSpent;
767
774
 
768
775
  if (this.debugFees) {
769
776
  this.log(
@@ -804,7 +811,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
804
811
  this.feeOutput = null;
805
812
  this.overflowFees = 0n;
806
813
 
807
- if (sendBackAmount < 0n) {
814
+ if (sendBackAmount < 0n && iterations === maxIterations) {
808
815
  throw new Error(
809
816
  `Insufficient funds: need ${totalSpent} sats but only have ${this.totalInputAmount} sats`,
810
817
  );
@@ -820,6 +827,12 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
820
827
  iterations++;
821
828
  }
822
829
 
830
+ if (expectRefund && sendBackAmount < 0n) {
831
+ throw new Error(
832
+ `Insufficient funds: need at least ${-sendBackAmount} more sats to cover fees.`,
833
+ );
834
+ }
835
+
823
836
  if (iterations >= maxIterations) {
824
837
  this.warn(`Fee calculation did not stabilize after ${maxIterations} iterations`);
825
838
  }
@@ -834,6 +847,10 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
834
847
  }
835
848
  }
836
849
 
850
+ protected defineLockScript(): Buffer {
851
+ return script.compile([toXOnly(Buffer.from(this.signer.publicKey)), opcodes.OP_CHECKSIG]);
852
+ }
853
+
837
854
  /**
838
855
  * @description Adds the value to the output
839
856
  * @param {number | bigint} value - The value to add
@@ -5,5 +5,5 @@ export enum TransactionType {
5
5
  INTERACTION = 3,
6
6
  MULTI_SIG = 4,
7
7
  CUSTOM_CODE = 5,
8
- CHALLENGE_SOLUTION = 6,
8
+ CANCEL = 6,
9
9
  }
@@ -46,6 +46,7 @@ export interface SharedInteractionParameters extends ITransactionParameters {
46
46
  readonly randomBytes?: Buffer;
47
47
 
48
48
  readonly loadedStorage?: LoadedStorage;
49
+ readonly isCancellation?: boolean;
49
50
  }
50
51
 
51
52
  export interface IInteractionParameters extends SharedInteractionParameters {
@@ -2,13 +2,14 @@ import {
2
2
  crypto as bitCrypto,
3
3
  Network,
4
4
  networks,
5
+ opcodes,
5
6
  Payment,
6
7
  payments,
8
+ script,
7
9
  Taptree,
8
10
  toXOnly,
9
11
  } from '@btc-vision/bitcoin';
10
12
  import { DeploymentGenerator } from '../generators/builders/DeploymentGenerator.js';
11
- import { TransactionBuilder } from '../transaction/builders/TransactionBuilder.js';
12
13
  import { ChallengeSolution } from '../epoch/ChallengeSolution.js';
13
14
  import { Feature, Features } from '../generators/Features.js';
14
15
 
@@ -46,13 +47,18 @@ export class TapscriptVerificator {
46
47
  params.features,
47
48
  );
48
49
 
50
+ const lockLeafScript = script.compile([
51
+ toXOnly(params.deployerPubKey),
52
+ opcodes.OP_CHECKSIG,
53
+ ]);
54
+
49
55
  const scriptTree: Taptree = [
50
56
  {
51
57
  output: compiledTargetScript,
52
58
  version: TapscriptVerificator.TAP_SCRIPT_VERSION,
53
59
  },
54
60
  {
55
- output: TransactionBuilder.LOCK_LEAF_SCRIPT,
61
+ output: lockLeafScript,
56
62
  version: TapscriptVerificator.TAP_SCRIPT_VERSION,
57
63
  },
58
64
  ];
@@ -80,13 +86,18 @@ export class TapscriptVerificator {
80
86
  params.features,
81
87
  );
82
88
 
89
+ const lockLeafScript = script.compile([
90
+ toXOnly(params.deployerPubKey),
91
+ opcodes.OP_CHECKSIG,
92
+ ]);
93
+
83
94
  const scriptTree: Taptree = [
84
95
  {
85
96
  output: compiledTargetScript,
86
97
  version: TapscriptVerificator.TAP_SCRIPT_VERSION,
87
98
  },
88
99
  {
89
- output: TransactionBuilder.LOCK_LEAF_SCRIPT,
100
+ output: lockLeafScript,
90
101
  version: TapscriptVerificator.TAP_SCRIPT_VERSION,
91
102
  },
92
103
  ];