@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.
- package/browser/_version.d.ts +1 -1
- package/browser/index.js +1 -1
- package/browser/opnet.d.ts +1 -0
- package/browser/transaction/TransactionFactory.d.ts +3 -0
- package/browser/transaction/builders/CancelTransaction.d.ts +28 -0
- package/browser/transaction/builders/SharedInteractionTransaction.d.ts +1 -0
- package/browser/transaction/builders/TransactionBuilder.d.ts +3 -2
- package/browser/transaction/enums/TransactionType.d.ts +1 -1
- package/browser/transaction/interfaces/ITransactionParameters.d.ts +1 -0
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/opnet.d.ts +1 -0
- package/build/opnet.js +1 -0
- package/build/transaction/TransactionFactory.d.ts +3 -0
- package/build/transaction/TransactionFactory.js +8 -1
- package/build/transaction/builders/CancelTransaction.d.ts +28 -0
- package/build/transaction/builders/CancelTransaction.js +154 -0
- package/build/transaction/builders/CustomScriptTransaction.js +2 -1
- package/build/transaction/builders/DeploymentTransaction.js +2 -1
- package/build/transaction/builders/SharedInteractionTransaction.d.ts +1 -0
- package/build/transaction/builders/SharedInteractionTransaction.js +7 -2
- package/build/transaction/builders/TransactionBuilder.d.ts +3 -2
- package/build/transaction/builders/TransactionBuilder.js +12 -8
- package/build/transaction/enums/TransactionType.d.ts +1 -1
- package/build/transaction/enums/TransactionType.js +1 -1
- package/build/transaction/interfaces/ITransactionParameters.d.ts +1 -0
- package/build/verification/TapscriptVerificator.js +11 -4
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/opnet.ts +1 -0
- package/src/transaction/TransactionFactory.ts +15 -9
- package/src/transaction/builders/CancelTransaction.ts +266 -0
- package/src/transaction/builders/CustomScriptTransaction.ts +2 -1
- package/src/transaction/builders/DeploymentTransaction.ts +2 -1
- package/src/transaction/builders/SharedInteractionTransaction.ts +12 -3
- package/src/transaction/builders/TransactionBuilder.ts +27 -10
- package/src/transaction/enums/TransactionType.ts +1 -1
- package/src/transaction/interfaces/ITransactionParameters.ts +1 -0
- package/src/verification/TapscriptVerificator.ts +14 -3
package/browser/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';
|
|
@@ -30,7 +30,10 @@ export interface InteractionResponse {
|
|
|
30
30
|
readonly interactionTransaction: string;
|
|
31
31
|
readonly estimatedFees: bigint;
|
|
32
32
|
readonly nextUTXOs: UTXO[];
|
|
33
|
+
readonly fundingUTXOs: UTXO[];
|
|
33
34
|
readonly challenge: RawChallenge;
|
|
35
|
+
readonly interactionAddress: string | null;
|
|
36
|
+
readonly compiledTargetScript: string | null;
|
|
34
37
|
}
|
|
35
38
|
export interface BitcoinTransferResponse extends BitcoinTransferBase {
|
|
36
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;
|
|
@@ -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;
|
package/build/_version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "1.6.
|
|
1
|
+
export declare const version = "1.6.12";
|
package/build/_version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.6.
|
|
1
|
+
export const version = '1.6.12';
|
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';
|
|
@@ -30,7 +30,10 @@ export interface InteractionResponse {
|
|
|
30
30
|
readonly interactionTransaction: string;
|
|
31
31
|
readonly estimatedFees: bigint;
|
|
32
32
|
readonly nextUTXOs: UTXO[];
|
|
33
|
+
readonly fundingUTXOs: UTXO[];
|
|
33
34
|
readonly challenge: RawChallenge;
|
|
35
|
+
readonly interactionAddress: string | null;
|
|
36
|
+
readonly compiledTargetScript: string | null;
|
|
34
37
|
}
|
|
35
38
|
export interface BitcoinTransferResponse extends BitcoinTransferBase {
|
|
36
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:
|
|
132
|
+
utxos: fundingUTXO,
|
|
132
133
|
randomBytes: finalTransaction.getRndBytes(),
|
|
133
134
|
challenge: challenge,
|
|
134
135
|
nonWitnessUtxo: signedTransaction.tx.toBuffer(),
|
|
@@ -138,11 +139,14 @@ export class TransactionFactory {
|
|
|
138
139
|
const interactionTx = new InteractionTransaction(newParams);
|
|
139
140
|
const outTx = await interactionTx.signTransaction();
|
|
140
141
|
return {
|
|
142
|
+
interactionAddress: finalTransaction.getScriptAddress(),
|
|
141
143
|
fundingTransaction: signedTransaction.tx.toHex(),
|
|
142
144
|
interactionTransaction: outTx.toHex(),
|
|
143
145
|
estimatedFees: interactionTx.transactionFee,
|
|
144
146
|
nextUTXOs: this.getUTXOAsTransaction(signedTransaction.tx, interactionParameters.from, 1),
|
|
145
147
|
challenge: challenge.toRaw(),
|
|
148
|
+
fundingUTXOs: fundingUTXO,
|
|
149
|
+
compiledTargetScript: interactionTx.exportCompiledTargetScript().toString('hex'),
|
|
146
150
|
};
|
|
147
151
|
}
|
|
148
152
|
async signDeployment(deploymentParameters) {
|
|
@@ -341,11 +345,14 @@ export class TransactionFactory {
|
|
|
341
345
|
const signedTx = await p2wdaTransaction.signTransaction();
|
|
342
346
|
const txHex = signedTx.toHex();
|
|
343
347
|
return {
|
|
348
|
+
interactionAddress: null,
|
|
344
349
|
fundingTransaction: null,
|
|
345
350
|
interactionTransaction: txHex,
|
|
346
351
|
estimatedFees: p2wdaTransaction.estimatedFees,
|
|
347
352
|
nextUTXOs: this.getUTXOAsTransaction(signedTx, interactionParameters.from, signedTx.outs.length - 1),
|
|
353
|
+
fundingUTXOs: [...interactionParameters.utxos, ...inputs],
|
|
348
354
|
challenge: interactionParameters.challenge.toRaw(),
|
|
355
|
+
compiledTargetScript: null,
|
|
349
356
|
};
|
|
350
357
|
}
|
|
351
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
|
|
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
|
|
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
|
}
|
|
@@ -107,6 +111,7 @@ export class SharedInteractionTransaction extends TransactionBuilder {
|
|
|
107
111
|
if (!this.scriptTree) {
|
|
108
112
|
throw new Error('Script tree is required');
|
|
109
113
|
}
|
|
114
|
+
console.log('internalPubkey', this.internalPubKeyToXOnly().toString('hex'));
|
|
110
115
|
return {
|
|
111
116
|
internalPubkey: this.internalPubKeyToXOnly(),
|
|
112
117
|
network: this.network,
|
|
@@ -136,7 +141,7 @@ export class SharedInteractionTransaction extends TransactionBuilder {
|
|
|
136
141
|
version: 192,
|
|
137
142
|
},
|
|
138
143
|
{
|
|
139
|
-
output:
|
|
144
|
+
output: this.LOCK_LEAF_SCRIPT,
|
|
140
145
|
version: 192,
|
|
141
146
|
},
|
|
142
147
|
];
|
|
@@ -203,7 +208,7 @@ export class SharedInteractionTransaction extends TransactionBuilder {
|
|
|
203
208
|
};
|
|
204
209
|
this.leftOverFundsScriptRedeem = {
|
|
205
210
|
name: PaymentType.P2TR,
|
|
206
|
-
output:
|
|
211
|
+
output: this.LOCK_LEAF_SCRIPT,
|
|
207
212
|
redeemVersion: 192,
|
|
208
213
|
};
|
|
209
214
|
}
|
|
@@ -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
|
-
|
|
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;
|
|
@@ -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["
|
|
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:
|
|
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:
|
|
38
|
+
output: lockLeafScript,
|
|
32
39
|
version: TapscriptVerificator.TAP_SCRIPT_VERSION,
|
|
33
40
|
},
|
|
34
41
|
];
|
package/package.json
CHANGED
package/src/_version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.6.
|
|
1
|
+
export const version = '1.6.12';
|
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';
|