@btc-vision/transaction 1.0.6 → 1.0.8
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/Deploy.md +186 -0
- package/README.md +5 -0
- package/Wrap.md +192 -0
- package/browser/_version.d.ts +1 -1
- package/browser/index.js +1 -1
- package/browser/index.js.LICENSE.txt +9 -0
- package/browser/opnet.d.ts +6 -1
- package/browser/tests/deploy.d.ts +1 -0
- package/browser/tests/wrap.d.ts +1 -0
- package/browser/tests/wrapTest.d.ts +1 -0
- package/browser/transaction/TransactionFactory.d.ts +15 -1
- package/browser/transaction/builders/DeploymentTransaction.d.ts +40 -0
- package/browser/transaction/builders/InteractionTransaction.d.ts +2 -35
- package/browser/transaction/builders/SharedInteractionTransaction.d.ts +46 -0
- package/browser/transaction/builders/TransactionBuilder.d.ts +8 -1
- package/browser/transaction/builders/WrapTransaction.d.ts +27 -0
- package/browser/transaction/interfaces/ITransactionParameters.d.ts +16 -12
- package/browser/utils/BitcoinUtils.d.ts +1 -0
- package/browser/utxo/OPNetLimitedProvider.d.ts +10 -0
- package/browser/wbtc/Generate.d.ts +13 -0
- package/browser/wbtc/WrappedGenerationParameters.d.ts +11 -0
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/bytecode/Compressor.js +4 -3
- package/build/generators/AddressGenerator.js +1 -1
- package/build/keypair/EcKeyPair.js +1 -1
- package/build/opnet.d.ts +6 -1
- package/build/opnet.js +6 -1
- package/build/signer/TweakedSigner.js +1 -1
- package/build/tests/deploy.d.ts +1 -0
- package/build/tests/deploy.js +60 -0
- package/build/tests/test.js +3 -3
- package/build/tests/transfer.js +2 -2
- package/build/tests/wrap.d.ts +1 -0
- package/build/tests/wrap.js +64 -0
- package/build/tests/wrapTest.d.ts +1 -0
- package/build/tests/wrapTest.js +64 -0
- package/build/tests/wrapTestg.d.ts +1 -0
- package/build/tests/wrapTestg.js +66 -0
- package/build/transaction/TransactionFactory.d.ts +15 -1
- package/build/transaction/TransactionFactory.js +68 -0
- package/build/transaction/builders/DeploymentTransaction.d.ts +40 -0
- package/build/transaction/builders/DeploymentTransaction.js +216 -0
- package/build/transaction/builders/FundingTransaction.js +4 -1
- package/build/transaction/builders/InteractionTransaction.d.ts +2 -35
- package/build/transaction/builders/InteractionTransaction.js +4 -207
- package/build/transaction/builders/SharedInteractionTransaction.d.ts +46 -0
- package/build/transaction/builders/SharedInteractionTransaction.js +213 -0
- package/build/transaction/builders/TransactionBuilder.d.ts +8 -1
- package/build/transaction/builders/TransactionBuilder.js +20 -12
- package/build/transaction/builders/WrapTransaction.d.ts +27 -0
- package/build/transaction/builders/WrapTransaction.js +132 -0
- package/build/transaction/interfaces/ITransactionParameters.d.ts +16 -12
- package/build/utils/BitcoinUtils.d.ts +1 -0
- package/build/utils/BitcoinUtils.js +7 -0
- package/build/utxo/OPNetLimitedProvider.d.ts +10 -0
- package/build/utxo/OPNetLimitedProvider.js +85 -0
- package/build/utxo/OPNetUtils.d.ts +7 -0
- package/build/utxo/OPNetUtils.js +47 -0
- package/build/verification/TapscriptVerificator.js +3 -3
- package/build/wbtc/Generate.d.ts +13 -0
- package/build/wbtc/Generate.js +1 -0
- package/build/wbtc/WrappedGenerationParameters.d.ts +11 -0
- package/build/wbtc/WrappedGenerationParameters.js +16 -0
- package/bytecode/contract.wasm +0 -0
- package/cjs/_version.d.ts +1 -1
- package/cjs/_version.js +1 -1
- package/cjs/bytecode/Compressor.js +1 -1
- package/cjs/generators/AddressGenerator.d.ts +7 -0
- package/cjs/generators/AddressGenerator.js +48 -0
- package/cjs/generators/Generator.d.ts +1 -2
- package/cjs/generators/Generator.js +1 -3
- package/cjs/generators/builders/DeploymentGenerator.d.ts +1 -0
- package/cjs/generators/builders/DeploymentGenerator.js +10 -7
- package/cjs/keypair/Wallet.d.ts +1 -0
- package/cjs/keypair/Wallet.js +6 -0
- package/cjs/opnet.d.ts +23 -0
- package/cjs/opnet.js +37 -0
- package/cjs/tests/Regtest.d.ts +3 -0
- package/cjs/tests/Regtest.js +32 -0
- package/cjs/tests/gen.d.ts +1 -0
- package/cjs/tests/gen.js +17 -0
- package/cjs/tests/test.d.ts +1 -0
- package/cjs/tests/test.js +53 -0
- package/cjs/tests/transfer.d.ts +1 -0
- package/cjs/tests/transfer.js +76 -0
- package/cjs/transaction/TransactionFactory.js +7 -4
- package/cjs/transaction/builders/FundingTransaction.js +1 -1
- package/cjs/transaction/builders/InteractionTransaction.d.ts +2 -0
- package/cjs/transaction/builders/InteractionTransaction.js +11 -2
- package/cjs/transaction/builders/TransactionBuilder.d.ts +3 -2
- package/cjs/transaction/builders/TransactionBuilder.js +22 -7
- package/cjs/transaction/interfaces/ITransactionParameters.d.ts +1 -0
- package/cjs/verification/TapscriptVerificator.d.ts +17 -0
- package/cjs/verification/TapscriptVerificator.js +70 -0
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/classes/AddressGenerator.html +2 -2
- package/docs/classes/BitcoinUtils.html +7 -3
- package/docs/classes/CalldataGenerator.html +10 -10
- package/docs/classes/Compressor.html +4 -4
- package/docs/classes/ContractBaseMetadata.html +4 -4
- package/docs/classes/DeploymentGenerator.html +9 -9
- package/docs/classes/DeploymentTransaction.html +368 -0
- package/docs/classes/EcKeyPair.html +16 -16
- package/docs/classes/FundingTransaction.html +50 -47
- package/docs/classes/Generator.html +9 -9
- package/docs/classes/InteractionTransaction.html +89 -109
- package/docs/classes/OPNetLimitedProvider.html +197 -0
- package/docs/classes/SharedInteractionTransaction.html +392 -0
- package/docs/classes/TapscriptVerificator.html +2 -2
- package/docs/classes/TransactionBuilder.html +53 -50
- package/docs/classes/TransactionFactory.html +11 -4
- package/docs/classes/TweakedSigner.html +2 -2
- package/docs/classes/Wallet.html +10 -10
- package/docs/classes/WrapTransaction.html +404 -0
- package/docs/classes/WrappedGeneration.html +187 -0
- package/docs/classes/wBTC.html +7 -7
- package/docs/enums/TransactionSequence.html +177 -0
- package/docs/enums/TransactionType.html +2 -2
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +3 -1
- package/docs/interfaces/ContractAddressVerificationParams.html +2 -2
- package/docs/interfaces/DeploymentResult.html +177 -0
- package/docs/interfaces/FetchUTXOParams.html +2 -2
- package/docs/interfaces/GenerationConstraints.html +182 -0
- package/docs/interfaces/IDeploymentParameters.html +183 -0
- package/docs/interfaces/IFundingTransactionParameters.html +3 -3
- package/docs/interfaces/IInteractionParameters.html +4 -6
- package/docs/interfaces/ITransactionParameters.html +3 -3
- package/docs/interfaces/IWallet.html +4 -4
- package/docs/interfaces/IWrapParameters.html +186 -0
- package/docs/interfaces/NetworkInformation.html +2 -2
- package/docs/interfaces/PsbtInputExtended.html +1 -1
- package/docs/interfaces/PsbtOutputExtendedAddress.html +2 -2
- package/docs/interfaces/PsbtOutputExtendedScript.html +2 -2
- package/docs/interfaces/RawUTXOResponse.html +2 -2
- package/docs/interfaces/SharedInteractionParameters.html +183 -0
- package/docs/interfaces/TapLeafScript.html +2 -2
- package/docs/interfaces/TweakSettings.html +3 -3
- package/docs/interfaces/UTXO.html +2 -2
- package/docs/interfaces/UpdateInput.html +2 -2
- package/docs/interfaces/WrapResult.html +178 -0
- package/docs/interfaces/WrappedGenerationParameters.html +184 -0
- package/docs/modules.html +14 -4
- package/docs/types/PsbtOutputExtended.html +1 -1
- package/docs/variables/version.html +1 -1
- package/package.json +4 -5
- package/src/_version.ts +1 -1
- package/src/bytecode/Compressor.ts +27 -26
- package/src/generators/AddressGenerator.ts +1 -1
- package/src/keypair/EcKeyPair.ts +1 -1
- package/src/opnet.ts +8 -1
- package/src/signer/TweakedSigner.ts +1 -1
- package/src/tests/deploy.ts +81 -0
- package/src/tests/test.ts +3 -3
- package/src/tests/transfer.ts +2 -2
- package/src/tests/wrap.ts +89 -0
- package/src/tests/wrapTest.ts +88 -0
- package/src/transaction/TransactionFactory.ts +119 -1
- package/src/transaction/builders/DeploymentTransaction.ts +418 -0
- package/src/transaction/builders/FundingTransaction.ts +5 -1
- package/src/transaction/builders/InteractionTransaction.ts +5 -404
- package/src/transaction/builders/SharedInteractionTransaction.ts +432 -0
- package/src/transaction/builders/TransactionBuilder.ts +41 -16
- package/src/transaction/builders/WrapTransaction.ts +286 -0
- package/src/transaction/interfaces/ITransactionParameters.ts +20 -13
- package/src/utils/BitcoinUtils.ts +16 -0
- package/src/utxo/{UTXOManager.ts → OPNetLimitedProvider.ts} +53 -2
- package/src/verification/TapscriptVerificator.ts +3 -3
- package/src/wbtc/Generate.ts +30 -0
- package/src/wbtc/WrappedGenerationParameters.ts +33 -0
- package/tests/TransactionBuilder.test.ts +58 -58
- package/tsconfig.webpack.json +7 -1
- package/webpack.config.js +3 -1
- package/browser/873e754d6c7c6e9361f1.module.wasm +0 -0
- package/docs/classes/UTXOManager.html +0 -187
- package/docs/interfaces/ITransactionDataContractDeployment.html +0 -184
- package/docs/interfaces/ITransactionDataContractInteractionWrap.html +0 -186
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import { PsbtInput } from 'bip174/src/lib/interfaces.js';
|
|
2
|
+
import { address, Payment, Psbt, Signer } from 'bitcoinjs-lib';
|
|
3
|
+
import { Taptree } from 'bitcoinjs-lib/src/types.js';
|
|
4
|
+
import { ECPairInterface } from 'ecpair';
|
|
5
|
+
import { TransactionBuilder } from './TransactionBuilder.js';
|
|
6
|
+
import { TransactionType } from '../enums/TransactionType.js';
|
|
7
|
+
import { PsbtInputExtended, TapLeafScript } from '../interfaces/Tap.js';
|
|
8
|
+
import { CalldataGenerator } from '../../generators/builders/CalldataGenerator.js';
|
|
9
|
+
import { SharedInteractionParameters } from '../interfaces/ITransactionParameters.js';
|
|
10
|
+
import { Compressor } from '../../bytecode/Compressor.js';
|
|
11
|
+
import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
12
|
+
import { BitcoinUtils } from '../../utils/BitcoinUtils.js';
|
|
13
|
+
import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371.js';
|
|
14
|
+
import { TweakedSigner, TweakSettings } from '../../signer/TweakedSigner.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Shared interaction transaction
|
|
18
|
+
* @class SharedInteractionTransaction
|
|
19
|
+
*/
|
|
20
|
+
export abstract class SharedInteractionTransaction<
|
|
21
|
+
T extends TransactionType,
|
|
22
|
+
> extends TransactionBuilder<T> {
|
|
23
|
+
/**
|
|
24
|
+
* Random salt for the interaction
|
|
25
|
+
* @type {Buffer}
|
|
26
|
+
*/
|
|
27
|
+
public readonly randomBytes: Buffer;
|
|
28
|
+
|
|
29
|
+
protected targetScriptRedeem: Payment | null = null;
|
|
30
|
+
protected leftOverFundsScriptRedeem: Payment | null = null;
|
|
31
|
+
|
|
32
|
+
protected abstract readonly compiledTargetScript: Buffer;
|
|
33
|
+
protected abstract readonly scriptTree: Taptree;
|
|
34
|
+
|
|
35
|
+
protected tapLeafScript: TapLeafScript | null = null;
|
|
36
|
+
protected readonly calldataGenerator: CalldataGenerator;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Calldata for the interaction
|
|
40
|
+
* @protected
|
|
41
|
+
*/
|
|
42
|
+
protected readonly calldata: Buffer;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Contract secret for the interaction
|
|
46
|
+
* @protected
|
|
47
|
+
*/
|
|
48
|
+
protected abstract readonly contractSecret: Buffer;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The tweaked signer for the interaction (if any)
|
|
52
|
+
* @protected
|
|
53
|
+
*/
|
|
54
|
+
protected tweakedSigner?: Signer;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Script signer for the interaction
|
|
58
|
+
* @protected
|
|
59
|
+
*/
|
|
60
|
+
protected readonly scriptSigner: Signer;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Public keys specified in the interaction
|
|
64
|
+
* @protected
|
|
65
|
+
*/
|
|
66
|
+
protected readonly interactionPubKeys: Buffer[] = [];
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Minimum signatures required for the interaction
|
|
70
|
+
* @protected
|
|
71
|
+
*/
|
|
72
|
+
protected readonly minimumSignatures: number = 0;
|
|
73
|
+
|
|
74
|
+
protected constructor(parameters: SharedInteractionParameters) {
|
|
75
|
+
super(parameters);
|
|
76
|
+
|
|
77
|
+
if (!parameters.calldata) {
|
|
78
|
+
throw new Error('Calldata is required');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.calldata = Compressor.compress(parameters.calldata);
|
|
82
|
+
|
|
83
|
+
this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
|
|
84
|
+
this.scriptSigner = this.generateKeyPairFromSeed();
|
|
85
|
+
|
|
86
|
+
this.calldataGenerator = new CalldataGenerator(
|
|
87
|
+
this.internalPubKeyToXOnly(),
|
|
88
|
+
this.scriptSignerXOnlyPubKey(),
|
|
89
|
+
this.network,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Get the contract secret
|
|
95
|
+
* @returns {Buffer} The contract secret
|
|
96
|
+
*/
|
|
97
|
+
public getContractSecret(): Buffer {
|
|
98
|
+
return this.contractSecret;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Get the random bytes used for the interaction
|
|
103
|
+
* @returns {Buffer} The random bytes
|
|
104
|
+
*/
|
|
105
|
+
public getRndBytes(): Buffer {
|
|
106
|
+
return this.randomBytes;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Generate the secret for the interaction
|
|
111
|
+
* @protected
|
|
112
|
+
* @returns {Buffer} The secret
|
|
113
|
+
* @throws {Error} If the to address is invalid
|
|
114
|
+
*/
|
|
115
|
+
protected generateSecret(): Buffer {
|
|
116
|
+
if (!this.to) throw new Error('To address is required');
|
|
117
|
+
|
|
118
|
+
return address.fromBech32(this.to).data;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Tweak the signer for the interaction
|
|
123
|
+
* @protected
|
|
124
|
+
*/
|
|
125
|
+
protected tweakSigner(): void {
|
|
126
|
+
this.tweakedSigner = this.getTweakedSigner();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get the internal pubkey as an x-only key
|
|
131
|
+
* @protected
|
|
132
|
+
* @returns {Buffer} The internal pubkey as an x-only key
|
|
133
|
+
*/
|
|
134
|
+
protected scriptSignerXOnlyPubKey(): Buffer {
|
|
135
|
+
return toXOnly(this.scriptSigner.publicKey);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Generate a key pair from the seed
|
|
140
|
+
* @protected
|
|
141
|
+
*
|
|
142
|
+
* @returns {ECPairInterface} The key pair
|
|
143
|
+
*/
|
|
144
|
+
protected generateKeyPairFromSeed(): ECPairInterface {
|
|
145
|
+
return EcKeyPair.fromSeedKeyPair(this.randomBytes, this.network);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Add inputs from the UTXO
|
|
150
|
+
* @protected
|
|
151
|
+
*
|
|
152
|
+
* @throws {Error} If the tap leaf script is required
|
|
153
|
+
*/
|
|
154
|
+
protected override addInputsFromUTXO(): void {
|
|
155
|
+
if (!this.tapLeafScript) throw new Error('Tap leaf script is required');
|
|
156
|
+
|
|
157
|
+
for (let utxo of this.utxos) {
|
|
158
|
+
const input: PsbtInputExtended = {
|
|
159
|
+
hash: utxo.transactionId,
|
|
160
|
+
index: utxo.outputIndex,
|
|
161
|
+
witnessUtxo: {
|
|
162
|
+
value: Number(utxo.value),
|
|
163
|
+
script: this.getTapOutput(),
|
|
164
|
+
},
|
|
165
|
+
tapLeafScript: [this.tapLeafScript],
|
|
166
|
+
sequence: this.sequence,
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
this.addInput(input);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Build the transaction
|
|
175
|
+
* @protected
|
|
176
|
+
*
|
|
177
|
+
* @throws {Error} If the left over funds script redeem is required
|
|
178
|
+
* @throws {Error} If the left over funds script redeem version is required
|
|
179
|
+
* @throws {Error} If the left over funds script redeem output is required
|
|
180
|
+
* @throws {Error} If the to address is required
|
|
181
|
+
*/
|
|
182
|
+
protected override buildTransaction(): void {
|
|
183
|
+
if (!this.to) throw new Error('To address is required');
|
|
184
|
+
|
|
185
|
+
const selectedRedeem = !!this.scriptSigner
|
|
186
|
+
? this.targetScriptRedeem
|
|
187
|
+
: this.leftOverFundsScriptRedeem;
|
|
188
|
+
|
|
189
|
+
if (!selectedRedeem) {
|
|
190
|
+
throw new Error('Left over funds script redeem is required');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (!selectedRedeem.redeemVersion) {
|
|
194
|
+
throw new Error('Left over funds script redeem version is required');
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (!selectedRedeem.output) {
|
|
198
|
+
throw new Error('Left over funds script redeem output is required');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
this.tapLeafScript = {
|
|
202
|
+
leafVersion: selectedRedeem.redeemVersion,
|
|
203
|
+
script: selectedRedeem.output,
|
|
204
|
+
controlBlock: this.getWitness(),
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
this.addInputsFromUTXO();
|
|
208
|
+
|
|
209
|
+
const amountSpent: bigint = this.getTransactionOPNetFee();
|
|
210
|
+
this.addOutput({
|
|
211
|
+
value: Number(amountSpent),
|
|
212
|
+
address: this.to,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
this.addRefundOutput(amountSpent);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Sign the inputs
|
|
220
|
+
* @param {Psbt} transaction The transaction to sign
|
|
221
|
+
* @protected
|
|
222
|
+
*/
|
|
223
|
+
protected signInputs(transaction: Psbt): void {
|
|
224
|
+
if (!this.scriptSigner) {
|
|
225
|
+
super.signInputs(transaction);
|
|
226
|
+
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
transaction.signInput(0, this.scriptSigner);
|
|
231
|
+
transaction.signInput(0, this.getSignerKey());
|
|
232
|
+
|
|
233
|
+
transaction.finalizeInput(0, this.customFinalizer);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Get the signer
|
|
238
|
+
* @protected
|
|
239
|
+
*
|
|
240
|
+
* @returns {Signer} The signer
|
|
241
|
+
*/
|
|
242
|
+
protected getSignerKey(): Signer {
|
|
243
|
+
if (this.tweakedSigner) {
|
|
244
|
+
return this.tweakedSigner;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return this.signer;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
protected override generateScriptAddress(): Payment {
|
|
251
|
+
return {
|
|
252
|
+
internalPubkey: this.internalPubKeyToXOnly(),
|
|
253
|
+
network: this.network,
|
|
254
|
+
scriptTree: this.scriptTree,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
protected override generateTapData(): Payment {
|
|
259
|
+
const selectedRedeem = !!this.scriptSigner
|
|
260
|
+
? this.targetScriptRedeem
|
|
261
|
+
: this.leftOverFundsScriptRedeem;
|
|
262
|
+
|
|
263
|
+
if (!selectedRedeem) {
|
|
264
|
+
throw new Error('Left over funds script redeem is required');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (!this.scriptTree) {
|
|
268
|
+
throw new Error('Script tree is required');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
internalPubkey: this.internalPubKeyToXOnly(),
|
|
273
|
+
network: this.network,
|
|
274
|
+
scriptTree: this.scriptTree,
|
|
275
|
+
redeem: selectedRedeem,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Generate the script solution
|
|
281
|
+
* @param {PsbtInput} input The input
|
|
282
|
+
* @protected
|
|
283
|
+
*
|
|
284
|
+
* @returns {Buffer[]} The script solution
|
|
285
|
+
*/
|
|
286
|
+
protected getScriptSolution(input: PsbtInput): Buffer[] {
|
|
287
|
+
if (!input.tapScriptSig) {
|
|
288
|
+
throw new Error('Tap script signature is required');
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return [
|
|
292
|
+
this.contractSecret,
|
|
293
|
+
this.internalPubKeyToXOnly(),
|
|
294
|
+
input.tapScriptSig[0].signature,
|
|
295
|
+
input.tapScriptSig[1].signature,
|
|
296
|
+
];
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Get the script tree
|
|
301
|
+
* @private
|
|
302
|
+
*
|
|
303
|
+
* @returns {Taptree} The script tree
|
|
304
|
+
*/
|
|
305
|
+
protected getScriptTree(): Taptree {
|
|
306
|
+
if (!this.calldata) {
|
|
307
|
+
throw new Error('Calldata is required');
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
this.generateRedeemScripts();
|
|
311
|
+
|
|
312
|
+
return [
|
|
313
|
+
{
|
|
314
|
+
output: this.compiledTargetScript,
|
|
315
|
+
version: 192,
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
output: this.getLeafScript(),
|
|
319
|
+
version: 192,
|
|
320
|
+
},
|
|
321
|
+
];
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Get the public keys
|
|
326
|
+
* @private
|
|
327
|
+
*
|
|
328
|
+
* @returns {Buffer[]} The public keys
|
|
329
|
+
*/
|
|
330
|
+
private getPubKeys(): Buffer[] {
|
|
331
|
+
const pubkeys = [this.signer.publicKey];
|
|
332
|
+
|
|
333
|
+
if (this.scriptSigner) {
|
|
334
|
+
pubkeys.push(this.scriptSigner.publicKey);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
return pubkeys;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Transaction finalizer
|
|
342
|
+
* @param {number} _inputIndex The input index
|
|
343
|
+
* @param {PsbtInput} input The input
|
|
344
|
+
*/
|
|
345
|
+
private customFinalizer = (_inputIndex: number, input: PsbtInput) => {
|
|
346
|
+
if (!this.tapLeafScript) {
|
|
347
|
+
throw new Error('Tap leaf script is required');
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (!input.tapScriptSig) {
|
|
351
|
+
throw new Error('Tap script signature is required');
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (!this.contractSecret) {
|
|
355
|
+
throw new Error('Contract secret is required');
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const scriptSolution = this.getScriptSolution(input);
|
|
359
|
+
|
|
360
|
+
const witness = scriptSolution
|
|
361
|
+
.concat(this.tapLeafScript.script)
|
|
362
|
+
.concat(this.tapLeafScript.controlBlock);
|
|
363
|
+
|
|
364
|
+
return {
|
|
365
|
+
finalScriptWitness: this.witnessStackToScriptWitness(witness),
|
|
366
|
+
};
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Get the tweaked hash
|
|
371
|
+
* @private
|
|
372
|
+
*
|
|
373
|
+
* @returns {Buffer | undefined} The tweaked hash
|
|
374
|
+
*/
|
|
375
|
+
private getTweakerHash(): Buffer | undefined {
|
|
376
|
+
return this.tapData?.hash;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Get the tweaked signer
|
|
381
|
+
* @param {boolean} useTweakedHash Whether to use the tweaked hash
|
|
382
|
+
* @private
|
|
383
|
+
*
|
|
384
|
+
* @returns {Signer} The tweaked signer
|
|
385
|
+
*/
|
|
386
|
+
private getTweakedSigner(useTweakedHash: boolean = false): Signer {
|
|
387
|
+
const settings: TweakSettings = {
|
|
388
|
+
network: this.network,
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
if (useTweakedHash) {
|
|
392
|
+
settings.tweakHash = this.getTweakerHash();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return TweakedSigner.tweakSigner(this.signer, settings);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Generate the redeem scripts
|
|
400
|
+
* @private
|
|
401
|
+
*
|
|
402
|
+
* @throws {Error} If the public keys are required
|
|
403
|
+
* @throws {Error} If the leaf script is required
|
|
404
|
+
* @throws {Error} If the leaf script version is required
|
|
405
|
+
* @throws {Error} If the leaf script output is required
|
|
406
|
+
* @throws {Error} If the target script redeem is required
|
|
407
|
+
*/
|
|
408
|
+
private generateRedeemScripts(): void {
|
|
409
|
+
this.targetScriptRedeem = {
|
|
410
|
+
pubkeys: this.getPubKeys(),
|
|
411
|
+
output: this.compiledTargetScript,
|
|
412
|
+
redeemVersion: 192,
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
this.leftOverFundsScriptRedeem = {
|
|
416
|
+
pubkeys: this.getPubKeys(),
|
|
417
|
+
output: this.getLeafScript(),
|
|
418
|
+
redeemVersion: 192,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/**
|
|
423
|
+
* Get the second leaf script
|
|
424
|
+
* @private
|
|
425
|
+
*
|
|
426
|
+
* @returns {Buffer} The leaf script
|
|
427
|
+
*/
|
|
428
|
+
private getLeafScript(): Buffer {
|
|
429
|
+
// For now, we disable this.
|
|
430
|
+
return SharedInteractionTransaction.LOCK_LEAF_SCRIPT;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { initEccLib, Network, opcodes, Payment, payments, Psbt, script, Signer, Transaction } from 'bitcoinjs-lib';
|
|
2
2
|
import { varuint } from 'bitcoinjs-lib/src/bufferutils.js';
|
|
3
3
|
import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371.js';
|
|
4
|
-
import * as ecc from '
|
|
4
|
+
import * as ecc from '@bitcoinerlab/secp256k1';
|
|
5
5
|
import { PsbtInputExtended, PsbtOutputExtended, UpdateInput } from '../interfaces/Tap.js';
|
|
6
6
|
import { TransactionType } from '../enums/TransactionType.js';
|
|
7
7
|
import { IFundingTransactionParameters, ITransactionParameters } from '../interfaces/ITransactionParameters.js';
|
|
@@ -11,6 +11,14 @@ import { UTXO } from '../../utxo/interfaces/IUTXO.js';
|
|
|
11
11
|
import { ECPairInterface } from 'ecpair';
|
|
12
12
|
import { Logger } from '@btc-vision/logger';
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* The transaction sequence
|
|
16
|
+
*/
|
|
17
|
+
export enum TransactionSequence {
|
|
18
|
+
REPLACE_BY_FEE = 0xfffffffd,
|
|
19
|
+
FINAL = 0xffffffff,
|
|
20
|
+
}
|
|
21
|
+
|
|
14
22
|
/**
|
|
15
23
|
* Allows to build a transaction like you would on Ethereum.
|
|
16
24
|
* @description The transaction builder class
|
|
@@ -27,11 +35,15 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Logg
|
|
|
27
35
|
|
|
28
36
|
public abstract readonly type: T;
|
|
29
37
|
public readonly logColor: string = '#785def';
|
|
30
|
-
|
|
31
38
|
/**
|
|
32
39
|
* @description Cost in satoshis of the transaction fee
|
|
33
40
|
*/
|
|
34
41
|
public transactionFee: bigint = 0n;
|
|
42
|
+
/**
|
|
43
|
+
* @description The sequence of the transaction
|
|
44
|
+
* @protected
|
|
45
|
+
*/
|
|
46
|
+
protected sequence: number = TransactionSequence.REPLACE_BY_FEE;
|
|
35
47
|
/**
|
|
36
48
|
* @description The transaction itself.
|
|
37
49
|
*/
|
|
@@ -93,7 +105,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Logg
|
|
|
93
105
|
* @description The address where the transaction is sent to
|
|
94
106
|
* @protected
|
|
95
107
|
*/
|
|
96
|
-
protected to: Address;
|
|
108
|
+
protected to: Address | undefined;
|
|
97
109
|
|
|
98
110
|
/**
|
|
99
111
|
* @description The address where the transaction is sent from
|
|
@@ -117,10 +129,13 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Logg
|
|
|
117
129
|
this.feeRate = parameters.feeRate;
|
|
118
130
|
this.priorityFee = parameters.priorityFee;
|
|
119
131
|
this.utxos = parameters.utxos;
|
|
120
|
-
this.to = parameters.to;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
132
|
+
this.to = parameters.to || undefined;
|
|
133
|
+
|
|
134
|
+
this.from = TransactionBuilder.getFrom(
|
|
135
|
+
parameters.from,
|
|
136
|
+
this.signer as ECPairInterface,
|
|
137
|
+
this.network,
|
|
138
|
+
);
|
|
124
139
|
|
|
125
140
|
this.totalInputAmount = this.calculateTotalUTXOAmount();
|
|
126
141
|
const totalVOut: bigint = this.calculateTotalVOutAmount();
|
|
@@ -138,6 +153,14 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Logg
|
|
|
138
153
|
});
|
|
139
154
|
}
|
|
140
155
|
|
|
156
|
+
public static getFrom(
|
|
157
|
+
from: string | undefined,
|
|
158
|
+
keypair: ECPairInterface,
|
|
159
|
+
network: Network,
|
|
160
|
+
): Address {
|
|
161
|
+
return from || EcKeyPair.getTaprootAddress(keypair, network);
|
|
162
|
+
}
|
|
163
|
+
|
|
141
164
|
public getFundingTransactionParameters(): IFundingTransactionParameters {
|
|
142
165
|
return {
|
|
143
166
|
utxos: this.utxos,
|
|
@@ -147,7 +170,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Logg
|
|
|
147
170
|
feeRate: this.feeRate,
|
|
148
171
|
priorityFee: this.priorityFee,
|
|
149
172
|
from: this.from,
|
|
150
|
-
|
|
173
|
+
childTransactionRequiredValue: this.transactionFee,
|
|
151
174
|
};
|
|
152
175
|
}
|
|
153
176
|
|
|
@@ -175,12 +198,12 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Logg
|
|
|
175
198
|
* @throws {Error} - If something went wrong
|
|
176
199
|
*/
|
|
177
200
|
public signTransaction(): Transaction {
|
|
178
|
-
if (
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
201
|
+
if (this.to) {
|
|
202
|
+
if (!EcKeyPair.verifyContractAddress(this.to, this.network)) {
|
|
203
|
+
throw new Error(
|
|
204
|
+
'Invalid contract address. The contract address must be a taproot address.',
|
|
205
|
+
);
|
|
206
|
+
}
|
|
184
207
|
}
|
|
185
208
|
|
|
186
209
|
if (this.signed) throw new Error('Transaction is already signed');
|
|
@@ -222,8 +245,10 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Logg
|
|
|
222
245
|
public disableRBF(): void {
|
|
223
246
|
if (this.signed) throw new Error('Transaction is already signed');
|
|
224
247
|
|
|
248
|
+
this.sequence = TransactionSequence.FINAL;
|
|
249
|
+
|
|
225
250
|
for (let input of this.inputs) {
|
|
226
|
-
input.sequence =
|
|
251
|
+
input.sequence = TransactionSequence.FINAL;
|
|
227
252
|
}
|
|
228
253
|
}
|
|
229
254
|
|
|
@@ -344,7 +369,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Logg
|
|
|
344
369
|
value: Number(utxo.value),
|
|
345
370
|
script: Buffer.from(utxo.scriptPubKey.hex, 'hex'),
|
|
346
371
|
},
|
|
347
|
-
sequence:
|
|
372
|
+
sequence: this.sequence,
|
|
348
373
|
};
|
|
349
374
|
|
|
350
375
|
this.addInput(input);
|