@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
@@ -34,6 +34,7 @@ export * from './transaction/builders/InteractionTransactionP2WDA.js';
34
34
  export * from './transaction/builders/MultiSignTransaction.js';
35
35
  export * from './transaction/builders/SharedInteractionTransaction.js';
36
36
  export * from './transaction/builders/TransactionBuilder.js';
37
+ export * from './transaction/builders/CancelTransaction.js';
37
38
  export * from './epoch/interfaces/IChallengeSolution.js';
38
39
  export * from './epoch/validator/EpochValidator.js';
39
40
  export * from './epoch/ChallengeSolution.js';
@@ -12,7 +12,6 @@ export interface DeploymentResult {
12
12
  readonly contractAddress: string;
13
13
  readonly contractPubKey: string;
14
14
  readonly challenge: RawChallenge;
15
- readonly rawTransaction: Transaction;
16
15
  readonly utxos: UTXO[];
17
16
  }
18
17
  export interface FundingTransactionResponse {
@@ -31,8 +30,10 @@ export interface InteractionResponse {
31
30
  readonly interactionTransaction: string;
32
31
  readonly estimatedFees: bigint;
33
32
  readonly nextUTXOs: UTXO[];
33
+ readonly fundingUTXOs: UTXO[];
34
34
  readonly challenge: RawChallenge;
35
- readonly rawTransaction: Transaction;
35
+ readonly interactionAddress: string | null;
36
+ readonly compiledTargetScript: string | null;
36
37
  }
37
38
  export interface BitcoinTransferResponse extends BitcoinTransferBase {
38
39
  readonly original: FundingTransaction;
@@ -0,0 +1,28 @@
1
+ import { TransactionType } from '../enums/TransactionType.js';
2
+ import { P2TRPayment, Psbt, PsbtInput, Taptree } from '@btc-vision/bitcoin';
3
+ import { TransactionBuilder } from './TransactionBuilder.js';
4
+ import { TapLeafScript } from '../interfaces/Tap.js';
5
+ import { ITransactionParameters } from '../interfaces/ITransactionParameters.js';
6
+ export interface ICancelTransactionParameters extends Omit<ITransactionParameters, 'priorityFee' | 'gasSatFee'> {
7
+ readonly compiledTargetScript: string | Buffer;
8
+ }
9
+ export declare class CancelTransaction extends TransactionBuilder<TransactionType.CANCEL> {
10
+ type: TransactionType.CANCEL;
11
+ protected tapLeafScript: TapLeafScript | null;
12
+ protected readonly compiledTargetScript: Buffer;
13
+ protected readonly scriptTree: Taptree;
14
+ protected readonly contractSecret: Buffer;
15
+ protected leftOverFundsScriptRedeem: P2TRPayment | null;
16
+ constructor(parameters: ICancelTransactionParameters);
17
+ protected buildTransaction(): Promise<void>;
18
+ protected generateScriptAddress(): P2TRPayment;
19
+ protected generateTapData(): P2TRPayment;
20
+ protected customFinalizer: (_inputIndex: number, input: PsbtInput) => {
21
+ finalScriptWitness: Buffer<ArrayBufferLike>;
22
+ };
23
+ protected signInputs(transaction: Psbt): Promise<void>;
24
+ protected signInputsWalletBased(transaction: Psbt): Promise<void>;
25
+ protected signInputsNonWalletBased(transaction: Psbt): Promise<void>;
26
+ private getMinimalScriptTree;
27
+ private generateLeftoverFundsRedeem;
28
+ }
@@ -21,6 +21,7 @@ export declare abstract class SharedInteractionTransaction<T extends Transaction
21
21
  protected readonly scriptSigner: Signer | ECPairInterface;
22
22
  protected readonly disableAutoRefund: boolean;
23
23
  protected constructor(parameters: SharedInteractionParameters);
24
+ exportCompiledTargetScript(): Buffer;
24
25
  getContractSecret(): Buffer;
25
26
  getRndBytes(): Buffer;
26
27
  getChallenge(): ChallengeSolution;
@@ -11,11 +11,11 @@ export declare const MINIMUM_AMOUNT_REWARD: bigint;
11
11
  export declare const MINIMUM_AMOUNT_CA: bigint;
12
12
  export declare const ANCHOR_SCRIPT: Buffer<ArrayBuffer>;
13
13
  export declare abstract class TransactionBuilder<T extends TransactionType> extends TweakedTransaction {
14
- static readonly LOCK_LEAF_SCRIPT: Buffer;
15
14
  static readonly MINIMUM_DUST: bigint;
16
15
  abstract readonly type: T;
17
16
  readonly logColor: string;
18
17
  debugFees: boolean;
18
+ LOCK_LEAF_SCRIPT: Buffer;
19
19
  overflowFees: bigint;
20
20
  transactionFee: bigint;
21
21
  estimatedFees: bigint;
@@ -61,7 +61,8 @@ export declare abstract class TransactionBuilder<T extends TransactionType> exte
61
61
  getInputs(): PsbtInputExtended[];
62
62
  getOutputs(): PsbtOutputExtended[];
63
63
  getOptionalOutputValue(): bigint;
64
- protected addRefundOutput(amountSpent: bigint): Promise<void>;
64
+ protected addRefundOutput(amountSpent: bigint, expectRefund?: boolean): Promise<void>;
65
+ protected defineLockScript(): Buffer;
65
66
  protected addValueToToOutput(value: number | bigint): void;
66
67
  protected getTransactionOPNetFee(): bigint;
67
68
  protected calculateTotalUTXOAmount(): bigint;
@@ -5,5 +5,5 @@ export declare 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
  }
@@ -33,6 +33,7 @@ export interface SharedInteractionParameters extends ITransactionParameters {
33
33
  readonly challenge: ChallengeSolution;
34
34
  readonly randomBytes?: Buffer;
35
35
  readonly loadedStorage?: LoadedStorage;
36
+ readonly isCancellation?: boolean;
36
37
  }
37
38
  export interface IInteractionParameters extends SharedInteractionParameters {
38
39
  readonly calldata: Buffer;
@@ -1 +1 @@
1
- export declare const version = "1.6.11";
1
+ export declare const version = "1.6.13";
package/build/_version.js CHANGED
@@ -1 +1 @@
1
- export const version = '1.6.11';
1
+ export const version = '1.6.13';
package/build/opnet.d.ts CHANGED
@@ -34,6 +34,7 @@ export * from './transaction/builders/InteractionTransactionP2WDA.js';
34
34
  export * from './transaction/builders/MultiSignTransaction.js';
35
35
  export * from './transaction/builders/SharedInteractionTransaction.js';
36
36
  export * from './transaction/builders/TransactionBuilder.js';
37
+ export * from './transaction/builders/CancelTransaction.js';
37
38
  export * from './epoch/interfaces/IChallengeSolution.js';
38
39
  export * from './epoch/validator/EpochValidator.js';
39
40
  export * from './epoch/ChallengeSolution.js';
package/build/opnet.js CHANGED
@@ -33,6 +33,7 @@ export * from './transaction/builders/InteractionTransactionP2WDA.js';
33
33
  export * from './transaction/builders/MultiSignTransaction.js';
34
34
  export * from './transaction/builders/SharedInteractionTransaction.js';
35
35
  export * from './transaction/builders/TransactionBuilder.js';
36
+ export * from './transaction/builders/CancelTransaction.js';
36
37
  export * from './epoch/interfaces/IChallengeSolution.js';
37
38
  export * from './epoch/validator/EpochValidator.js';
38
39
  export * from './epoch/ChallengeSolution.js';
@@ -12,7 +12,6 @@ export interface DeploymentResult {
12
12
  readonly contractAddress: string;
13
13
  readonly contractPubKey: string;
14
14
  readonly challenge: RawChallenge;
15
- readonly rawTransaction: Transaction;
16
15
  readonly utxos: UTXO[];
17
16
  }
18
17
  export interface FundingTransactionResponse {
@@ -31,8 +30,10 @@ export interface InteractionResponse {
31
30
  readonly interactionTransaction: string;
32
31
  readonly estimatedFees: bigint;
33
32
  readonly nextUTXOs: UTXO[];
33
+ readonly fundingUTXOs: UTXO[];
34
34
  readonly challenge: RawChallenge;
35
- readonly rawTransaction: Transaction;
35
+ readonly interactionAddress: string | null;
36
+ readonly compiledTargetScript: string | null;
36
37
  }
37
38
  export interface BitcoinTransferResponse extends BitcoinTransferBase {
38
39
  readonly original: FundingTransaction;
@@ -126,9 +126,10 @@ export class TransactionFactory {
126
126
  if (!signedTransaction) {
127
127
  throw new Error('Could not sign funding transaction.');
128
128
  }
129
+ const fundingUTXO = this.getUTXOAsTransaction(signedTransaction.tx, finalTransaction.getScriptAddress(), 0);
129
130
  const newParams = {
130
131
  ...interactionParameters,
131
- utxos: this.getUTXOAsTransaction(signedTransaction.tx, finalTransaction.getScriptAddress(), 0),
132
+ utxos: fundingUTXO,
132
133
  randomBytes: finalTransaction.getRndBytes(),
133
134
  challenge: challenge,
134
135
  nonWitnessUtxo: signedTransaction.tx.toBuffer(),
@@ -138,12 +139,14 @@ export class TransactionFactory {
138
139
  const interactionTx = new InteractionTransaction(newParams);
139
140
  const outTx = await interactionTx.signTransaction();
140
141
  return {
141
- rawTransaction: signedTransaction.tx,
142
+ interactionAddress: finalTransaction.getScriptAddress(),
142
143
  fundingTransaction: signedTransaction.tx.toHex(),
143
144
  interactionTransaction: outTx.toHex(),
144
145
  estimatedFees: interactionTx.transactionFee,
145
146
  nextUTXOs: this.getUTXOAsTransaction(signedTransaction.tx, interactionParameters.from, 1),
146
147
  challenge: challenge.toRaw(),
148
+ fundingUTXOs: fundingUTXO,
149
+ compiledTargetScript: interactionTx.exportCompiledTargetScript().toString('hex'),
147
150
  };
148
151
  }
149
152
  async signDeployment(deploymentParameters) {
@@ -217,7 +220,6 @@ export class TransactionFactory {
217
220
  value: BigInt(out2.value),
218
221
  };
219
222
  return {
220
- rawTransaction: outTx,
221
223
  transaction: [signedTransaction.toHex(), outTx.toHex()],
222
224
  contractAddress: deploymentTx.getContractAddress(),
223
225
  contractPubKey: deploymentTx.contractPubKey,
@@ -343,12 +345,14 @@ export class TransactionFactory {
343
345
  const signedTx = await p2wdaTransaction.signTransaction();
344
346
  const txHex = signedTx.toHex();
345
347
  return {
346
- rawTransaction: signedTx,
348
+ interactionAddress: null,
347
349
  fundingTransaction: null,
348
350
  interactionTransaction: txHex,
349
351
  estimatedFees: p2wdaTransaction.estimatedFees,
350
352
  nextUTXOs: this.getUTXOAsTransaction(signedTx, interactionParameters.from, signedTx.outs.length - 1),
353
+ fundingUTXOs: [...interactionParameters.utxos, ...inputs],
351
354
  challenge: interactionParameters.challenge.toRaw(),
355
+ compiledTargetScript: null,
352
356
  };
353
357
  }
354
358
  getPriorityFee(params) {
@@ -0,0 +1,28 @@
1
+ import { TransactionType } from '../enums/TransactionType.js';
2
+ import { P2TRPayment, Psbt, PsbtInput, Taptree } from '@btc-vision/bitcoin';
3
+ import { TransactionBuilder } from './TransactionBuilder.js';
4
+ import { TapLeafScript } from '../interfaces/Tap.js';
5
+ import { ITransactionParameters } from '../interfaces/ITransactionParameters.js';
6
+ export interface ICancelTransactionParameters extends Omit<ITransactionParameters, 'priorityFee' | 'gasSatFee'> {
7
+ readonly compiledTargetScript: string | Buffer;
8
+ }
9
+ export declare class CancelTransaction extends TransactionBuilder<TransactionType.CANCEL> {
10
+ type: TransactionType.CANCEL;
11
+ protected tapLeafScript: TapLeafScript | null;
12
+ protected readonly compiledTargetScript: Buffer;
13
+ protected readonly scriptTree: Taptree;
14
+ protected readonly contractSecret: Buffer;
15
+ protected leftOverFundsScriptRedeem: P2TRPayment | null;
16
+ constructor(parameters: ICancelTransactionParameters);
17
+ protected buildTransaction(): Promise<void>;
18
+ protected generateScriptAddress(): P2TRPayment;
19
+ protected generateTapData(): P2TRPayment;
20
+ protected customFinalizer: (_inputIndex: number, input: PsbtInput) => {
21
+ finalScriptWitness: Buffer<ArrayBufferLike>;
22
+ };
23
+ protected signInputs(transaction: Psbt): Promise<void>;
24
+ protected signInputsWalletBased(transaction: Psbt): Promise<void>;
25
+ protected signInputsNonWalletBased(transaction: Psbt): Promise<void>;
26
+ private getMinimalScriptTree;
27
+ private generateLeftoverFundsRedeem;
28
+ }
@@ -0,0 +1,154 @@
1
+ import { TransactionType } from '../enums/TransactionType.js';
2
+ import { PaymentType } from '@btc-vision/bitcoin';
3
+ import { TransactionBuilder } from './TransactionBuilder.js';
4
+ export class CancelTransaction extends TransactionBuilder {
5
+ constructor(parameters) {
6
+ super({
7
+ ...parameters,
8
+ gasSatFee: 1n,
9
+ isCancellation: true,
10
+ priorityFee: 1n,
11
+ calldata: Buffer.alloc(0),
12
+ });
13
+ this.type = TransactionType.CANCEL;
14
+ this.tapLeafScript = null;
15
+ this.leftOverFundsScriptRedeem = null;
16
+ this.customFinalizer = (_inputIndex, input) => {
17
+ if (!this.tapLeafScript) {
18
+ throw new Error('Tap leaf script is required');
19
+ }
20
+ if (!input.tapScriptSig || input.tapScriptSig.length === 0) {
21
+ throw new Error('Tap script signature is required');
22
+ }
23
+ const scriptSolution = [input.tapScriptSig[0].signature];
24
+ const witness = scriptSolution
25
+ .concat(this.tapLeafScript.script)
26
+ .concat(this.tapLeafScript.controlBlock);
27
+ return {
28
+ finalScriptWitness: TransactionBuilder.witnessStackToScriptWitness(witness),
29
+ };
30
+ };
31
+ this.contractSecret = Buffer.alloc(0);
32
+ if (Buffer.isBuffer(parameters.compiledTargetScript)) {
33
+ this.compiledTargetScript = parameters.compiledTargetScript;
34
+ }
35
+ else {
36
+ this.compiledTargetScript = Buffer.from(parameters.compiledTargetScript, 'hex');
37
+ }
38
+ this.scriptTree = this.getMinimalScriptTree();
39
+ this.internalInit();
40
+ }
41
+ async buildTransaction() {
42
+ if (!this.from) {
43
+ throw new Error('From address is required');
44
+ }
45
+ if (!this.leftOverFundsScriptRedeem) {
46
+ throw new Error('Left over funds script redeem is required');
47
+ }
48
+ if (!this.leftOverFundsScriptRedeem.redeemVersion) {
49
+ throw new Error('Left over funds script redeem version is required');
50
+ }
51
+ if (!this.leftOverFundsScriptRedeem.output) {
52
+ throw new Error('Left over funds script redeem output is required');
53
+ }
54
+ this.tapLeafScript = {
55
+ leafVersion: this.leftOverFundsScriptRedeem.redeemVersion,
56
+ script: this.leftOverFundsScriptRedeem.output,
57
+ controlBlock: this.getWitness(),
58
+ };
59
+ this.addInputsFromUTXO();
60
+ await this.addRefundOutput(0n, true);
61
+ if (!this.feeOutput) {
62
+ throw new Error('Must add extra UTXOs to cancel this transaction');
63
+ }
64
+ }
65
+ generateScriptAddress() {
66
+ return {
67
+ internalPubkey: this.internalPubKeyToXOnly(),
68
+ network: this.network,
69
+ scriptTree: this.scriptTree,
70
+ name: PaymentType.P2TR,
71
+ };
72
+ }
73
+ generateTapData() {
74
+ const selectedRedeem = this.leftOverFundsScriptRedeem;
75
+ if (!selectedRedeem) {
76
+ throw new Error('Left over funds script redeem is required');
77
+ }
78
+ if (!this.scriptTree) {
79
+ throw new Error('Script tree is required');
80
+ }
81
+ return {
82
+ internalPubkey: this.internalPubKeyToXOnly(),
83
+ network: this.network,
84
+ scriptTree: this.scriptTree,
85
+ redeem: selectedRedeem,
86
+ name: PaymentType.P2TR,
87
+ };
88
+ }
89
+ async signInputs(transaction) {
90
+ if ('multiSignPsbt' in this.signer) {
91
+ await this.signInputsWalletBased(transaction);
92
+ }
93
+ else {
94
+ await this.signInputsNonWalletBased(transaction);
95
+ }
96
+ }
97
+ async signInputsWalletBased(transaction) {
98
+ const signer = this.signer;
99
+ await signer.multiSignPsbt([transaction]);
100
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
101
+ if (i === 0) {
102
+ transaction.finalizeInput(i, this.customFinalizer.bind(this));
103
+ }
104
+ else {
105
+ try {
106
+ transaction.finalizeInput(i, this.customFinalizerP2SH.bind(this));
107
+ }
108
+ catch (e) {
109
+ transaction.finalizeInput(i);
110
+ }
111
+ }
112
+ }
113
+ }
114
+ async signInputsNonWalletBased(transaction) {
115
+ for (let i = 0; i < transaction.data.inputs.length; i++) {
116
+ if (i === 0) {
117
+ await this.signInput(transaction, transaction.data.inputs[i], i, this.getSignerKey());
118
+ transaction.finalizeInput(0, this.customFinalizer.bind(this));
119
+ }
120
+ else {
121
+ await this.signInput(transaction, transaction.data.inputs[i], i, this.signer);
122
+ try {
123
+ transaction.finalizeInput(i, this.customFinalizerP2SH.bind(this));
124
+ }
125
+ catch (e) {
126
+ transaction.finalizeInput(i);
127
+ }
128
+ }
129
+ }
130
+ }
131
+ getMinimalScriptTree() {
132
+ this.generateLeftoverFundsRedeem();
133
+ if (!this.leftOverFundsScriptRedeem || !this.leftOverFundsScriptRedeem.output) {
134
+ throw new Error('Failed to generate leftover funds redeem script');
135
+ }
136
+ return [
137
+ {
138
+ output: this.compiledTargetScript,
139
+ version: 192,
140
+ },
141
+ {
142
+ output: this.leftOverFundsScriptRedeem.output,
143
+ version: 192,
144
+ },
145
+ ];
146
+ }
147
+ generateLeftoverFundsRedeem() {
148
+ this.leftOverFundsScriptRedeem = {
149
+ name: PaymentType.P2TR,
150
+ output: this.LOCK_LEAF_SCRIPT,
151
+ redeemVersion: 192,
152
+ };
153
+ }
154
+ }
@@ -36,6 +36,7 @@ export class CustomScriptTransaction extends TransactionBuilder {
36
36
  throw new Error('Witness(es) are required');
37
37
  this.witnesses = parameters.witnesses;
38
38
  this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
39
+ this.LOCK_LEAF_SCRIPT = this.defineLockScript();
39
40
  this.scriptSeed = this.getContractSeed();
40
41
  this.contractSigner = EcKeyPair.fromSeedKeyPair(this.scriptSeed, this.network);
41
42
  this.generator = new CustomGenerator(this.internalPubKeyToXOnly(), this.network);
@@ -166,7 +167,7 @@ export class CustomScriptTransaction extends TransactionBuilder {
166
167
  };
167
168
  }
168
169
  getLeafScript() {
169
- return TransactionBuilder.LOCK_LEAF_SCRIPT;
170
+ return this.LOCK_LEAF_SCRIPT;
170
171
  }
171
172
  getScriptTree() {
172
173
  this.generateRedeemScripts();
@@ -46,6 +46,7 @@ export class DeploymentTransaction extends TransactionBuilder {
46
46
  throw new Error('Challenge solution is required');
47
47
  this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
48
48
  this.challenge = parameters.challenge;
49
+ this.LOCK_LEAF_SCRIPT = this.defineLockScript();
49
50
  this.epochChallenge = TimeLockGenerator.generateTimeLockAddress(this.challenge.publicKey.originalPublicKeyBuffer(), this.network);
50
51
  this.contractSeed = this.getContractSeed();
51
52
  this.contractSigner = EcKeyPair.fromSeedKeyPair(this.contractSeed, this.network);
@@ -231,7 +232,7 @@ export class DeploymentTransaction extends TransactionBuilder {
231
232
  };
232
233
  }
233
234
  getLeafScript() {
234
- return TransactionBuilder.LOCK_LEAF_SCRIPT;
235
+ return this.LOCK_LEAF_SCRIPT;
235
236
  }
236
237
  getScriptTree() {
237
238
  if (!this.bytecode) {
@@ -21,6 +21,7 @@ export declare abstract class SharedInteractionTransaction<T extends Transaction
21
21
  protected readonly scriptSigner: Signer | ECPairInterface;
22
22
  protected readonly disableAutoRefund: boolean;
23
23
  protected constructor(parameters: SharedInteractionParameters);
24
+ exportCompiledTargetScript(): Buffer;
24
25
  getContractSecret(): Buffer;
25
26
  getRndBytes(): Buffer;
26
27
  getChallenge(): ChallengeSolution;
@@ -32,6 +32,7 @@ export class SharedInteractionTransaction extends TransactionBuilder {
32
32
  throw new Error('Challenge solution is required');
33
33
  }
34
34
  this.challenge = parameters.challenge;
35
+ this.LOCK_LEAF_SCRIPT = this.defineLockScript();
35
36
  this.disableAutoRefund = parameters.disableAutoRefund || false;
36
37
  this.epochChallenge = TimeLockGenerator.generateTimeLockAddress(this.challenge.publicKey.originalPublicKeyBuffer(), this.network);
37
38
  this.calldata = Compressor.compress(parameters.calldata);
@@ -39,6 +40,9 @@ export class SharedInteractionTransaction extends TransactionBuilder {
39
40
  this.scriptSigner = this.generateKeyPairFromSeed();
40
41
  this.calldataGenerator = new CalldataGenerator(Buffer.from(this.signer.publicKey), this.scriptSignerXOnlyPubKey(), this.network);
41
42
  }
43
+ exportCompiledTargetScript() {
44
+ return this.compiledTargetScript;
45
+ }
42
46
  getContractSecret() {
43
47
  return this.contractSecret;
44
48
  }
@@ -136,7 +140,7 @@ export class SharedInteractionTransaction extends TransactionBuilder {
136
140
  version: 192,
137
141
  },
138
142
  {
139
- output: SharedInteractionTransaction.LOCK_LEAF_SCRIPT,
143
+ output: this.LOCK_LEAF_SCRIPT,
140
144
  version: 192,
141
145
  },
142
146
  ];
@@ -203,7 +207,7 @@ export class SharedInteractionTransaction extends TransactionBuilder {
203
207
  };
204
208
  this.leftOverFundsScriptRedeem = {
205
209
  name: PaymentType.P2TR,
206
- output: SharedInteractionTransaction.LOCK_LEAF_SCRIPT,
210
+ output: this.LOCK_LEAF_SCRIPT,
207
211
  redeemVersion: 192,
208
212
  };
209
213
  }
@@ -11,11 +11,11 @@ export declare const MINIMUM_AMOUNT_REWARD: bigint;
11
11
  export declare const MINIMUM_AMOUNT_CA: bigint;
12
12
  export declare const ANCHOR_SCRIPT: Buffer<ArrayBuffer>;
13
13
  export declare abstract class TransactionBuilder<T extends TransactionType> extends TweakedTransaction {
14
- static readonly LOCK_LEAF_SCRIPT: Buffer;
15
14
  static readonly MINIMUM_DUST: bigint;
16
15
  abstract readonly type: T;
17
16
  readonly logColor: string;
18
17
  debugFees: boolean;
18
+ LOCK_LEAF_SCRIPT: Buffer;
19
19
  overflowFees: bigint;
20
20
  transactionFee: bigint;
21
21
  estimatedFees: bigint;
@@ -61,7 +61,8 @@ export declare abstract class TransactionBuilder<T extends TransactionType> exte
61
61
  getInputs(): PsbtInputExtended[];
62
62
  getOutputs(): PsbtOutputExtended[];
63
63
  getOptionalOutputValue(): bigint;
64
- protected addRefundOutput(amountSpent: bigint): Promise<void>;
64
+ protected addRefundOutput(amountSpent: bigint, expectRefund?: boolean): Promise<void>;
65
+ protected defineLockScript(): Buffer;
65
66
  protected addValueToToOutput(value: number | bigint): void;
66
67
  protected getTransactionOPNetFee(): bigint;
67
68
  protected calculateTotalUTXOAmount(): bigint;
@@ -1,4 +1,4 @@
1
- import bitcoin, { getFinalScripts, initEccLib, opcodes, Psbt, script, Transaction, varuint, } from '@btc-vision/bitcoin';
1
+ import bitcoin, { getFinalScripts, initEccLib, opcodes, Psbt, script, toXOnly, Transaction, varuint, } from '@btc-vision/bitcoin';
2
2
  import * as ecc from '@bitcoinerlab/secp256k1';
3
3
  import { EcKeyPair } from '../../keypair/EcKeyPair.js';
4
4
  import { AddressVerificator } from '../../keypair/AddressVerificator.js';
@@ -33,6 +33,7 @@ export class TransactionBuilder extends TweakedTransaction {
33
33
  this.optionalInputs = parameters.optionalInputs || [];
34
34
  this.to = parameters.to || undefined;
35
35
  this.debugFees = parameters.debugFees || false;
36
+ this.LOCK_LEAF_SCRIPT = this.defineLockScript();
36
37
  if (parameters.note) {
37
38
  if (typeof parameters.note === 'string') {
38
39
  this.note = Buffer.from(parameters.note, 'utf8');
@@ -402,7 +403,7 @@ export class TransactionBuilder extends TweakedTransaction {
402
403
  }
403
404
  return total;
404
405
  }
405
- async addRefundOutput(amountSpent) {
406
+ async addRefundOutput(amountSpent, expectRefund = false) {
406
407
  if (this.note) {
407
408
  this.addOPReturn(this.note);
408
409
  }
@@ -413,11 +414,12 @@ export class TransactionBuilder extends TweakedTransaction {
413
414
  let estimatedFee = 0n;
414
415
  let iterations = 0;
415
416
  const maxIterations = 5;
417
+ let sendBackAmount = 0n;
416
418
  while (iterations < maxIterations && estimatedFee !== previousFee) {
417
419
  previousFee = estimatedFee;
418
420
  estimatedFee = await this.estimateTransactionFees();
419
421
  const totalSpent = amountSpent + estimatedFee;
420
- const sendBackAmount = this.totalInputAmount - totalSpent;
422
+ sendBackAmount = this.totalInputAmount - totalSpent;
421
423
  if (this.debugFees) {
422
424
  this.log(`Iteration ${iterations + 1}: inputAmount=${this.totalInputAmount}, totalSpent=${totalSpent}, sendBackAmount=${sendBackAmount}`);
423
425
  }
@@ -450,7 +452,7 @@ export class TransactionBuilder extends TweakedTransaction {
450
452
  else {
451
453
  this.feeOutput = null;
452
454
  this.overflowFees = 0n;
453
- if (sendBackAmount < 0n) {
455
+ if (sendBackAmount < 0n && iterations === maxIterations) {
454
456
  throw new Error(`Insufficient funds: need ${totalSpent} sats but only have ${this.totalInputAmount} sats`);
455
457
  }
456
458
  if (this.debugFees) {
@@ -459,6 +461,9 @@ export class TransactionBuilder extends TweakedTransaction {
459
461
  }
460
462
  iterations++;
461
463
  }
464
+ if (expectRefund && sendBackAmount < 0n) {
465
+ throw new Error(`Insufficient funds: need at least ${-sendBackAmount} more sats to cover fees.`);
466
+ }
462
467
  if (iterations >= maxIterations) {
463
468
  this.warn(`Fee calculation did not stabilize after ${maxIterations} iterations`);
464
469
  }
@@ -467,6 +472,9 @@ export class TransactionBuilder extends TweakedTransaction {
467
472
  this.log(`Final fee: ${estimatedFee} sats, Change output: ${this.feeOutput ? `${this.feeOutput.value} sats` : 'none'}`);
468
473
  }
469
474
  }
475
+ defineLockScript() {
476
+ return script.compile([toXOnly(Buffer.from(this.signer.publicKey)), opcodes.OP_CHECKSIG]);
477
+ }
470
478
  addValueToToOutput(value) {
471
479
  if (value < TransactionBuilder.MINIMUM_DUST) {
472
480
  throw new Error(`Value to send is less than the minimum dust ${value} < ${TransactionBuilder.MINIMUM_DUST}`);
@@ -667,8 +675,4 @@ export class TransactionBuilder extends TweakedTransaction {
667
675
  return false;
668
676
  }
669
677
  }
670
- TransactionBuilder.LOCK_LEAF_SCRIPT = script.compile([
671
- opcodes.OP_FALSE,
672
- opcodes.OP_VERIFY,
673
- ]);
674
678
  TransactionBuilder.MINIMUM_DUST = 330n;
@@ -5,5 +5,5 @@ export declare 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
  }
@@ -6,5 +6,5 @@ export var TransactionType;
6
6
  TransactionType[TransactionType["INTERACTION"] = 3] = "INTERACTION";
7
7
  TransactionType[TransactionType["MULTI_SIG"] = 4] = "MULTI_SIG";
8
8
  TransactionType[TransactionType["CUSTOM_CODE"] = 5] = "CUSTOM_CODE";
9
- TransactionType[TransactionType["CHALLENGE_SOLUTION"] = 6] = "CHALLENGE_SOLUTION";
9
+ TransactionType[TransactionType["CANCEL"] = 6] = "CANCEL";
10
10
  })(TransactionType || (TransactionType = {}));
@@ -33,6 +33,7 @@ export interface SharedInteractionParameters extends ITransactionParameters {
33
33
  readonly challenge: ChallengeSolution;
34
34
  readonly randomBytes?: Buffer;
35
35
  readonly loadedStorage?: LoadedStorage;
36
+ readonly isCancellation?: boolean;
36
37
  }
37
38
  export interface IInteractionParameters extends SharedInteractionParameters {
38
39
  readonly calldata: Buffer;
@@ -1,18 +1,21 @@
1
- import { crypto as bitCrypto, networks, payments, toXOnly, } from '@btc-vision/bitcoin';
1
+ import { crypto as bitCrypto, networks, opcodes, payments, script, toXOnly, } from '@btc-vision/bitcoin';
2
2
  import { DeploymentGenerator } from '../generators/builders/DeploymentGenerator.js';
3
- import { TransactionBuilder } from '../transaction/builders/TransactionBuilder.js';
4
3
  export class TapscriptVerificator {
5
4
  static getContractAddress(params) {
6
5
  const network = params.network || networks.bitcoin;
7
6
  const scriptBuilder = new DeploymentGenerator(params.deployerPubKey, toXOnly(params.contractSaltPubKey), network);
8
7
  const compiledTargetScript = scriptBuilder.compile(params.bytecode, params.originalSalt, params.challenge, params.priorityFee, params.calldata, params.features);
8
+ const lockLeafScript = script.compile([
9
+ toXOnly(params.deployerPubKey),
10
+ opcodes.OP_CHECKSIG,
11
+ ]);
9
12
  const scriptTree = [
10
13
  {
11
14
  output: compiledTargetScript,
12
15
  version: TapscriptVerificator.TAP_SCRIPT_VERSION,
13
16
  },
14
17
  {
15
- output: TransactionBuilder.LOCK_LEAF_SCRIPT,
18
+ output: lockLeafScript,
16
19
  version: TapscriptVerificator.TAP_SCRIPT_VERSION,
17
20
  },
18
21
  ];
@@ -22,13 +25,17 @@ export class TapscriptVerificator {
22
25
  const network = params.network || networks.bitcoin;
23
26
  const scriptBuilder = new DeploymentGenerator(params.deployerPubKey, toXOnly(params.contractSaltPubKey), network);
24
27
  const compiledTargetScript = scriptBuilder.compile(params.bytecode, params.originalSalt, params.challenge, params.priorityFee, params.calldata, params.features);
28
+ const lockLeafScript = script.compile([
29
+ toXOnly(params.deployerPubKey),
30
+ opcodes.OP_CHECKSIG,
31
+ ]);
25
32
  const scriptTree = [
26
33
  {
27
34
  output: compiledTargetScript,
28
35
  version: TapscriptVerificator.TAP_SCRIPT_VERSION,
29
36
  },
30
37
  {
31
- output: TransactionBuilder.LOCK_LEAF_SCRIPT,
38
+ output: lockLeafScript,
32
39
  version: TapscriptVerificator.TAP_SCRIPT_VERSION,
33
40
  },
34
41
  ];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@btc-vision/transaction",
3
3
  "type": "module",
4
- "version": "1.6.11",
4
+ "version": "1.6.13",
5
5
  "author": "BlobMaster41",
6
6
  "description": "OPNet transaction library allows you to create and sign transactions for the OPNet network.",
7
7
  "engines": {
package/src/_version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '1.6.11';
1
+ export const version = '1.6.13';