@btc-vision/transaction 1.6.11 → 1.6.13

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 -2
  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 -2
  15. package/build/transaction/TransactionFactory.js +8 -4
  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 +6 -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 -10
  32. package/src/transaction/builders/CancelTransaction.ts +269 -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 +10 -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
package/src/opnet.ts CHANGED
@@ -52,6 +52,7 @@ export * from './transaction/builders/InteractionTransactionP2WDA.js';
52
52
  export * from './transaction/builders/MultiSignTransaction.js';
53
53
  export * from './transaction/builders/SharedInteractionTransaction.js';
54
54
  export * from './transaction/builders/TransactionBuilder.js';
55
+ export * from './transaction/builders/CancelTransaction.js';
55
56
 
56
57
  /** Epoch */
57
58
  export * from './epoch/interfaces/IChallengeSolution.js';
@@ -36,7 +36,6 @@ export interface DeploymentResult {
36
36
  readonly contractPubKey: string;
37
37
  readonly challenge: RawChallenge;
38
38
 
39
- readonly rawTransaction: Transaction;
40
39
  readonly utxos: UTXO[];
41
40
  }
42
41
 
@@ -58,8 +57,10 @@ export interface InteractionResponse {
58
57
  readonly interactionTransaction: string;
59
58
  readonly estimatedFees: bigint;
60
59
  readonly nextUTXOs: UTXO[];
60
+ readonly fundingUTXOs: UTXO[];
61
61
  readonly challenge: RawChallenge;
62
- readonly rawTransaction: Transaction;
62
+ readonly interactionAddress: string | null;
63
+ readonly compiledTargetScript: string | null;
63
64
  }
64
65
 
65
66
  export interface BitcoinTransferResponse extends BitcoinTransferBase {
@@ -237,13 +238,14 @@ export class TransactionFactory {
237
238
  throw new Error('Could not sign funding transaction.');
238
239
  }
239
240
 
241
+ const fundingUTXO = this.getUTXOAsTransaction(
242
+ signedTransaction.tx,
243
+ finalTransaction.getScriptAddress(),
244
+ 0,
245
+ );
240
246
  const newParams: IInteractionParameters = {
241
247
  ...interactionParameters,
242
- utxos: this.getUTXOAsTransaction(
243
- signedTransaction.tx,
244
- finalTransaction.getScriptAddress(),
245
- 0,
246
- ),
248
+ utxos: fundingUTXO,
247
249
  randomBytes: finalTransaction.getRndBytes(),
248
250
  challenge: challenge,
249
251
  nonWitnessUtxo: signedTransaction.tx.toBuffer(),
@@ -255,7 +257,7 @@ export class TransactionFactory {
255
257
  const outTx = await interactionTx.signTransaction();
256
258
 
257
259
  return {
258
- rawTransaction: signedTransaction.tx,
260
+ interactionAddress: finalTransaction.getScriptAddress(),
259
261
  fundingTransaction: signedTransaction.tx.toHex(),
260
262
  interactionTransaction: outTx.toHex(),
261
263
  estimatedFees: interactionTx.transactionFee,
@@ -265,6 +267,8 @@ export class TransactionFactory {
265
267
  1,
266
268
  ),
267
269
  challenge: challenge.toRaw(),
270
+ fundingUTXOs: fundingUTXO,
271
+ compiledTargetScript: interactionTx.exportCompiledTargetScript().toString('hex'),
268
272
  };
269
273
  }
270
274
 
@@ -369,7 +373,6 @@ export class TransactionFactory {
369
373
  };
370
374
 
371
375
  return {
372
- rawTransaction: outTx,
373
376
  transaction: [signedTransaction.toHex(), outTx.toHex()],
374
377
  contractAddress: deploymentTx.getContractAddress(),
375
378
  contractPubKey: deploymentTx.contractPubKey,
@@ -587,7 +590,7 @@ export class TransactionFactory {
587
590
  const txHex = signedTx.toHex();
588
591
 
589
592
  return {
590
- rawTransaction: signedTx,
593
+ interactionAddress: null,
591
594
  fundingTransaction: null,
592
595
  interactionTransaction: txHex,
593
596
  estimatedFees: p2wdaTransaction.estimatedFees,
@@ -596,7 +599,9 @@ export class TransactionFactory {
596
599
  interactionParameters.from,
597
600
  signedTx.outs.length - 1, // Last output is typically the change
598
601
  ),
602
+ fundingUTXOs: [...interactionParameters.utxos, ...inputs],
599
603
  challenge: interactionParameters.challenge.toRaw(),
604
+ compiledTargetScript: null,
600
605
  };
601
606
  }
602
607
 
@@ -0,0 +1,269 @@
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 {
6
+ ITransactionParameters,
7
+ SharedInteractionParameters,
8
+ } from '../interfaces/ITransactionParameters.js';
9
+ import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
10
+
11
+ export interface ICancelTransactionParameters
12
+ extends Omit<ITransactionParameters, 'priorityFee' | 'gasSatFee'> {
13
+ readonly compiledTargetScript: string | Buffer;
14
+ }
15
+
16
+ export class CancelTransaction extends TransactionBuilder<TransactionType.CANCEL> {
17
+ public type: TransactionType.CANCEL = TransactionType.CANCEL;
18
+
19
+ /**
20
+ * The tap leaf script for spending
21
+ */
22
+ protected tapLeafScript: TapLeafScript | null = null;
23
+
24
+ protected readonly compiledTargetScript: Buffer;
25
+ protected readonly scriptTree: Taptree;
26
+
27
+ protected readonly contractSecret: Buffer;
28
+ protected leftOverFundsScriptRedeem: P2TRPayment | null = null;
29
+
30
+ public constructor(parameters: ICancelTransactionParameters) {
31
+ super({
32
+ ...parameters,
33
+ gasSatFee: 1n,
34
+ isCancellation: true,
35
+ priorityFee: 1n,
36
+ calldata: Buffer.alloc(0),
37
+ } as unknown as SharedInteractionParameters);
38
+
39
+ this.contractSecret = Buffer.alloc(0);
40
+
41
+ if (Buffer.isBuffer(parameters.compiledTargetScript)) {
42
+ this.compiledTargetScript = parameters.compiledTargetScript;
43
+ } else {
44
+ this.compiledTargetScript = Buffer.from(parameters.compiledTargetScript, 'hex');
45
+ }
46
+
47
+ // Generate the minimal script tree needed for recovery
48
+ this.scriptTree = this.getMinimalScriptTree();
49
+
50
+ this.internalInit();
51
+ }
52
+
53
+ protected override async buildTransaction(): Promise<void> {
54
+ if (!this.from) {
55
+ throw new Error('From address is required');
56
+ }
57
+
58
+ if (!this.leftOverFundsScriptRedeem) {
59
+ throw new Error('Left over funds script redeem is required');
60
+ }
61
+
62
+ if (!this.leftOverFundsScriptRedeem.redeemVersion) {
63
+ throw new Error('Left over funds script redeem version is required');
64
+ }
65
+
66
+ if (!this.leftOverFundsScriptRedeem.output) {
67
+ throw new Error('Left over funds script redeem output is required');
68
+ }
69
+
70
+ // Set up the tap leaf script for spending
71
+ this.tapLeafScript = {
72
+ leafVersion: this.leftOverFundsScriptRedeem.redeemVersion,
73
+ script: this.leftOverFundsScriptRedeem.output,
74
+ controlBlock: this.getWitness(),
75
+ };
76
+
77
+ this.addInputsFromUTXO();
78
+
79
+ await this.addRefundOutput(0n, true);
80
+
81
+ if (!this.feeOutput) {
82
+ throw new Error('Must add extra UTXOs to cancel this transaction');
83
+ }
84
+ }
85
+
86
+ /*protected override async buildTransaction(): Promise<void> {
87
+ if (!this.from) {
88
+ throw new Error('From address is required');
89
+ }
90
+
91
+ // For key-path spend, we don't need the tap leaf script
92
+ this.tapLeafScript = null;
93
+
94
+ this.addInputsFromUTXO();
95
+ await this.addRefundOutput(0n);
96
+ }*/
97
+
98
+ /**
99
+ * Sign the inputs
100
+ * @param {Psbt} transaction The transaction to sign
101
+ * @protected
102
+ */
103
+ /*protected async signInputs(transaction: Psbt): Promise<void> {
104
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
105
+ if (i === 0) {
106
+ transaction.signInput(0, this.getSignerKey());
107
+
108
+ transaction.finalizeInput(0, this.customFinalizer.bind(this));
109
+ } else {
110
+ await super.signInputs(transaction);
111
+ }
112
+ }
113
+ }*/
114
+
115
+ /**
116
+ * Generate the script address (for verification purposes)
117
+ */
118
+ protected override generateScriptAddress(): P2TRPayment {
119
+ return {
120
+ internalPubkey: this.internalPubKeyToXOnly(),
121
+ network: this.network,
122
+ scriptTree: this.scriptTree,
123
+ name: PaymentType.P2TR,
124
+ };
125
+ }
126
+
127
+ /**
128
+ * Generate the tap data for spending
129
+ */
130
+ /*protected override generateTapData(): P2TRPayment {
131
+ const internalPubkey = this.internalPubKeyToXOnly();
132
+
133
+ return {
134
+ name: PaymentType.P2TR,
135
+ internalPubkey: internalPubkey,
136
+ network: this.network,
137
+ scriptTree: this.scriptTree, // This is crucial for the tweak
138
+ };
139
+ }*/
140
+ protected override generateTapData(): P2TRPayment {
141
+ const selectedRedeem = this.leftOverFundsScriptRedeem;
142
+
143
+ if (!selectedRedeem) {
144
+ throw new Error('Left over funds script redeem is required');
145
+ }
146
+
147
+ if (!this.scriptTree) {
148
+ throw new Error('Script tree is required');
149
+ }
150
+
151
+ return {
152
+ internalPubkey: this.internalPubKeyToXOnly(),
153
+ network: this.network,
154
+ scriptTree: this.scriptTree,
155
+ redeem: selectedRedeem,
156
+ name: PaymentType.P2TR,
157
+ };
158
+ }
159
+
160
+ /**
161
+ * Custom finalizer for the tap script spend
162
+ */
163
+ protected customFinalizer = (_inputIndex: number, input: PsbtInput) => {
164
+ if (!this.tapLeafScript) {
165
+ throw new Error('Tap leaf script is required');
166
+ }
167
+
168
+ if (!input.tapScriptSig || input.tapScriptSig.length === 0) {
169
+ throw new Error('Tap script signature is required');
170
+ }
171
+
172
+ // For the simple lock script, we only need the signature
173
+ const scriptSolution = [input.tapScriptSig[0].signature];
174
+
175
+ const witness = scriptSolution
176
+ .concat(this.tapLeafScript.script)
177
+ .concat(this.tapLeafScript.controlBlock);
178
+
179
+ return {
180
+ finalScriptWitness: TransactionBuilder.witnessStackToScriptWitness(witness),
181
+ };
182
+ };
183
+
184
+ protected override async signInputs(transaction: Psbt): Promise<void> {
185
+ if ('multiSignPsbt' in this.signer) {
186
+ await this.signInputsWalletBased(transaction);
187
+ } else {
188
+ await this.signInputsNonWalletBased(transaction);
189
+ }
190
+ }
191
+
192
+ protected override async signInputsWalletBased(transaction: Psbt): Promise<void> {
193
+ const signer: UnisatSigner = this.signer as UnisatSigner;
194
+
195
+ // then, we sign all the remaining inputs with the wallet signer.
196
+ await signer.multiSignPsbt([transaction]);
197
+
198
+ // Then, we finalize every input.
199
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
200
+ if (i === 0) {
201
+ transaction.finalizeInput(i, this.customFinalizer.bind(this));
202
+ } else {
203
+ try {
204
+ transaction.finalizeInput(i, this.customFinalizerP2SH.bind(this));
205
+ } catch (e) {
206
+ transaction.finalizeInput(i);
207
+ }
208
+ }
209
+ }
210
+ }
211
+
212
+ protected override async signInputsNonWalletBased(transaction: Psbt): Promise<void> {
213
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
214
+ if (i === 0) {
215
+ await this.signInput(
216
+ transaction,
217
+ transaction.data.inputs[i],
218
+ i,
219
+ this.getSignerKey(),
220
+ );
221
+
222
+ transaction.finalizeInput(0, this.customFinalizer.bind(this));
223
+ } else {
224
+ await this.signInput(transaction, transaction.data.inputs[i], i, this.signer);
225
+
226
+ try {
227
+ transaction.finalizeInput(i, this.customFinalizerP2SH.bind(this));
228
+ } catch (e) {
229
+ transaction.finalizeInput(i);
230
+ }
231
+ }
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Generate the minimal script tree needed for recovery
237
+ * This only includes the leftover funds script
238
+ */
239
+ private getMinimalScriptTree(): Taptree {
240
+ this.generateLeftoverFundsRedeem();
241
+
242
+ if (!this.leftOverFundsScriptRedeem || !this.leftOverFundsScriptRedeem.output) {
243
+ throw new Error('Failed to generate leftover funds redeem script');
244
+ }
245
+
246
+ return [
247
+ {
248
+ output: this.compiledTargetScript,
249
+ version: 192,
250
+ },
251
+ {
252
+ output: this.leftOverFundsScriptRedeem.output,
253
+ version: 192,
254
+ },
255
+ ];
256
+ }
257
+
258
+ /**
259
+ * Generate the leftover funds redeem script
260
+ */
261
+ private generateLeftoverFundsRedeem(): void {
262
+ // Use the same LOCK_LEAF_SCRIPT from the parent class
263
+ this.leftOverFundsScriptRedeem = {
264
+ name: PaymentType.P2TR,
265
+ output: this.LOCK_LEAF_SCRIPT,
266
+ redeemVersion: 192,
267
+ };
268
+ }
269
+ }
@@ -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
@@ -262,7 +268,7 @@ export abstract class SharedInteractionTransaction<
262
268
  version: 192,
263
269
  },
264
270
  {
265
- output: SharedInteractionTransaction.LOCK_LEAF_SCRIPT,
271
+ output: this.LOCK_LEAF_SCRIPT,
266
272
  version: 192,
267
273
  },
268
274
  ];
@@ -350,7 +356,8 @@ export abstract class SharedInteractionTransaction<
350
356
  this.addFeeToOutput(opnetFee, this.to, this.epochChallenge, false);
351
357
 
352
358
  // 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;
359
+ const actualOutputAmount =
360
+ opnetFee < MINIMUM_AMOUNT_REWARD ? MINIMUM_AMOUNT_REWARD : opnetFee;
354
361
 
355
362
  const optionalAmount = this.addOptionalOutputsAndGetAmount();
356
363
 
@@ -395,7 +402,7 @@ export abstract class SharedInteractionTransaction<
395
402
 
396
403
  this.leftOverFundsScriptRedeem = {
397
404
  name: PaymentType.P2TR,
398
- output: SharedInteractionTransaction.LOCK_LEAF_SCRIPT,
405
+ output: this.LOCK_LEAF_SCRIPT,
399
406
  redeemVersion: 192,
400
407
  };
401
408
  }
@@ -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
  ];