@btc-vision/transaction 1.1.7 → 1.1.9
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/keypair/MessageSigner.d.ts +11 -0
- package/browser/opnet.d.ts +2 -1
- package/browser/utils/BufferHelper.d.ts +1 -1
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/buffer/BinaryWriter.js +1 -1
- package/build/keypair/EcKeyPair.js +1 -1
- package/build/keypair/MessageSigner.d.ts +11 -0
- package/build/keypair/MessageSigner.js +41 -0
- package/build/opnet.d.ts +2 -1
- package/build/opnet.js +2 -1
- package/build/utils/BufferHelper.d.ts +1 -1
- package/build/utils/BufferHelper.js +5 -5
- package/package.json +1 -1
- package/src/_version.ts +1 -1
- package/src/buffer/BinaryWriter.ts +1 -1
- package/src/keypair/EcKeyPair.ts +1 -1
- package/src/keypair/MessageSigner.ts +99 -0
- package/src/opnet.ts +2 -9
- package/src/utils/BufferHelper.ts +5 -6
- package/src/transaction/builders/UnwrapSegwitTransaction.ts.disabled +0 -371
- package/src/transaction/builders/UnwrapTransaction.ts.disabled +0 -503
- package/src/transaction/builders/WrapTransaction.ts.disabled +0 -338
|
@@ -1,338 +0,0 @@
|
|
|
1
|
-
import { Taptree } from '@btc-vision/bitcoin/src/types.js';
|
|
2
|
-
import { TransactionType } from '../enums/TransactionType.js';
|
|
3
|
-
import { TapLeafScript } from '../interfaces/Tap.js';
|
|
4
|
-
import { IWrapParameters } from '../interfaces/ITransactionParameters.js';
|
|
5
|
-
import { SharedInteractionTransaction } from './SharedInteractionTransaction.js';
|
|
6
|
-
import { wBTC } from '../../metadata/contracts/wBTC.js';
|
|
7
|
-
import { WrappedGeneration } from '../../../wbtc_disabled/WrappedGenerationParameters.js';
|
|
8
|
-
import { BitcoinUtils } from '../../utils/BitcoinUtils.js';
|
|
9
|
-
import { Network, PsbtOutputExtendedAddress } from '@btc-vision/bitcoin';
|
|
10
|
-
import { P2TR_MS } from '../shared/P2TR_MS.js';
|
|
11
|
-
import { currentConsensusConfig } from '../../consensus/ConsensusConfig.js';
|
|
12
|
-
import { Selector } from '../../utils/types.js';
|
|
13
|
-
import { ABICoder } from '../../abi/ABICoder.js';
|
|
14
|
-
import { BinaryWriter } from '../../buffer/BinaryWriter.js';
|
|
15
|
-
import { Address } from '../../keypair/Address.js';
|
|
16
|
-
|
|
17
|
-
const abiCoder: ABICoder = new ABICoder();
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Wrapped Bitcoin transaction wrap interaction
|
|
21
|
-
* @class InteractionTransaction
|
|
22
|
-
*/
|
|
23
|
-
export class WrapTransaction extends SharedInteractionTransaction<TransactionType.WBTC_WRAP> {
|
|
24
|
-
private static readonly WRAP_SELECTOR: Selector = Number(
|
|
25
|
-
'0x' + abiCoder.encodeSelector('mint'),
|
|
26
|
-
);
|
|
27
|
-
|
|
28
|
-
public type: TransactionType.WBTC_WRAP = TransactionType.WBTC_WRAP;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* The vault address
|
|
32
|
-
* @private
|
|
33
|
-
* @readonly
|
|
34
|
-
*/
|
|
35
|
-
public readonly vault: string;
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* The amount to wrap
|
|
39
|
-
* @private
|
|
40
|
-
*/
|
|
41
|
-
public readonly amount: bigint;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The receiver of the wrapped tokens
|
|
45
|
-
* @private
|
|
46
|
-
*/
|
|
47
|
-
public readonly receiver: Address;
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* The compiled target script
|
|
51
|
-
* @protected
|
|
52
|
-
*/
|
|
53
|
-
protected readonly compiledTargetScript: Buffer;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Tap tree for the interaction
|
|
57
|
-
* @protected
|
|
58
|
-
*/
|
|
59
|
-
protected readonly scriptTree: Taptree;
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Tap leaf script
|
|
63
|
-
* @protected
|
|
64
|
-
*/
|
|
65
|
-
protected tapLeafScript: TapLeafScript | null = null;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Contract secret for the interaction
|
|
69
|
-
* @protected
|
|
70
|
-
*/
|
|
71
|
-
protected readonly contractSecret: Buffer;
|
|
72
|
-
/**
|
|
73
|
-
* Public keys specified in the interaction
|
|
74
|
-
* @protected
|
|
75
|
-
*/
|
|
76
|
-
protected readonly interactionPubKeys: Buffer[] = [];
|
|
77
|
-
/**
|
|
78
|
-
* Minimum signatures required for the interaction
|
|
79
|
-
* @protected
|
|
80
|
-
*/
|
|
81
|
-
protected readonly minimumSignatures: number = 0;
|
|
82
|
-
/**
|
|
83
|
-
* The wBTC contract
|
|
84
|
-
* @private
|
|
85
|
-
*/
|
|
86
|
-
private readonly wbtc: wBTC;
|
|
87
|
-
|
|
88
|
-
public constructor(parameters: IWrapParameters) {
|
|
89
|
-
if (parameters.amount < currentConsensusConfig.VAULT_MINIMUM_AMOUNT) {
|
|
90
|
-
throw new Error(
|
|
91
|
-
`Amount is below the minimum required of ${currentConsensusConfig.VAULT_MINIMUM_AMOUNT} sat.`,
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const receiver: Address = parameters.receiver || new Address(parameters.signer.publicKey);
|
|
96
|
-
|
|
97
|
-
parameters.calldata = WrapTransaction.generateMintCalldata(
|
|
98
|
-
parameters.amount,
|
|
99
|
-
receiver,
|
|
100
|
-
parameters.network,
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
super(parameters);
|
|
104
|
-
|
|
105
|
-
this.wbtc = new wBTC(parameters.network, parameters.chainId);
|
|
106
|
-
this.vault = parameters.generationParameters.vault;
|
|
107
|
-
|
|
108
|
-
this.to = this.wbtc.getAddress();
|
|
109
|
-
this.receiver = receiver;
|
|
110
|
-
this.amount = parameters.amount;
|
|
111
|
-
|
|
112
|
-
this.verifyRequiredValue();
|
|
113
|
-
|
|
114
|
-
this.interactionPubKeys = parameters.generationParameters.pubKeys;
|
|
115
|
-
this.minimumSignatures = parameters.generationParameters.constraints.minimum;
|
|
116
|
-
this.contractSecret = this.generateSecret();
|
|
117
|
-
|
|
118
|
-
if (!this.verifyPublicKeysConstraints(parameters.generationParameters)) {
|
|
119
|
-
throw new Error(
|
|
120
|
-
'Oops. Your wrapping request have been decline! It failed security checks!',
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
this.compiledTargetScript = this.calldataGenerator.compile(
|
|
125
|
-
this.calldata,
|
|
126
|
-
this.contractSecret,
|
|
127
|
-
[],
|
|
128
|
-
this.interactionPubKeys,
|
|
129
|
-
this.minimumSignatures,
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
this.scriptTree = this.getScriptTree();
|
|
133
|
-
this.internalInit();
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Generate a valid wBTC calldata
|
|
138
|
-
* @param {bigint} amount - The amount to wrap
|
|
139
|
-
* @param {Address} to - The address to send the wrapped tokens to
|
|
140
|
-
* @param {Network} network - The network to use
|
|
141
|
-
* @private
|
|
142
|
-
* @returns {Buffer} - The calldata
|
|
143
|
-
*/
|
|
144
|
-
private static generateMintCalldata(amount: bigint, to: Address, network: Network): Buffer {
|
|
145
|
-
if (!amount) throw new Error('Amount is required');
|
|
146
|
-
if (!to) throw new Error('To address is required');
|
|
147
|
-
|
|
148
|
-
if (!to.isValid(network)) {
|
|
149
|
-
throw new Error(
|
|
150
|
-
`Oops! The address ${to} is not a valid P2TR address! If you wrap at this address, your funds will be lost!`,
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const bufWriter: BinaryWriter = new BinaryWriter();
|
|
155
|
-
bufWriter.writeSelector(WrapTransaction.WRAP_SELECTOR);
|
|
156
|
-
bufWriter.writeAddress(to);
|
|
157
|
-
bufWriter.writeU256(amount);
|
|
158
|
-
|
|
159
|
-
return Buffer.from(bufWriter.getBuffer());
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Verify the data integrity received by the client.
|
|
164
|
-
* @param {WrappedGeneration} generation - The generation parameters
|
|
165
|
-
* @returns {boolean} - True if the data is valid
|
|
166
|
-
* @throws {Error} - If the data is invalid
|
|
167
|
-
*/
|
|
168
|
-
public verifyPublicKeysConstraints(generation: WrappedGeneration): boolean {
|
|
169
|
-
if (generation.constraints.minimum < 2) {
|
|
170
|
-
throw new Error('Minimum signatures must be at least 2');
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (
|
|
174
|
-
generation.keys.length < generation.constraints.transactionMinimum ||
|
|
175
|
-
generation.keys.length < generation.constraints.minimum
|
|
176
|
-
) {
|
|
177
|
-
throw new Error('Not enough pub keys');
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
if (generation.keys.length > 255) {
|
|
181
|
-
throw new Error('Too many pub keys');
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const generatedVault: string = this.generateVaultAddress(
|
|
185
|
-
generation.pubKeys,
|
|
186
|
-
generation.constraints.minimum,
|
|
187
|
-
);
|
|
188
|
-
if (generatedVault !== generation.vault) {
|
|
189
|
-
throw new Error(
|
|
190
|
-
`Invalid vault address. Expected: ${generatedVault} Got: ${generation.vault}`,
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const passChecksum: Buffer = this.generateChecksumSalt(
|
|
195
|
-
generation,
|
|
196
|
-
this.amount,
|
|
197
|
-
generation.vault,
|
|
198
|
-
);
|
|
199
|
-
|
|
200
|
-
const checksum: string = BitcoinUtils.opnetHash(passChecksum);
|
|
201
|
-
if (checksum !== generation.signature) {
|
|
202
|
-
throw new Error(`Invalid checksum. Expected: ${checksum} Got: ${generation.signature}`);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return true;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Build the transaction
|
|
210
|
-
* @protected
|
|
211
|
-
*
|
|
212
|
-
* @throws {Error} If the leftover funds script redeem is required
|
|
213
|
-
* @throws {Error} If the leftover funds script redeem version is required
|
|
214
|
-
* @throws {Error} If the leftover funds script redeem output is required
|
|
215
|
-
* @throws {Error} If the to address is required
|
|
216
|
-
*/
|
|
217
|
-
protected override async buildTransaction(): Promise<void> {
|
|
218
|
-
if (!this.to) throw new Error('To address is required');
|
|
219
|
-
|
|
220
|
-
const selectedRedeem = this.scriptSigner
|
|
221
|
-
? this.targetScriptRedeem
|
|
222
|
-
: this.leftOverFundsScriptRedeem;
|
|
223
|
-
|
|
224
|
-
if (!selectedRedeem) {
|
|
225
|
-
throw new Error('Left over funds script redeem is required');
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (!selectedRedeem.redeemVersion) {
|
|
229
|
-
throw new Error('Left over funds script redeem version is required');
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (!selectedRedeem.output) {
|
|
233
|
-
throw new Error('Left over funds script redeem output is required');
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
this.tapLeafScript = {
|
|
237
|
-
leafVersion: selectedRedeem.redeemVersion,
|
|
238
|
-
script: selectedRedeem.output,
|
|
239
|
-
controlBlock: this.getWitness(),
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
this.addInputsFromUTXO();
|
|
243
|
-
|
|
244
|
-
const amountSpent: bigint = this.getTransactionOPNetFee();
|
|
245
|
-
this.addOutput({
|
|
246
|
-
value: Number(amountSpent),
|
|
247
|
-
address: this.to,
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
this.addVaultOutput();
|
|
251
|
-
await this.addRefundOutput(
|
|
252
|
-
amountSpent +
|
|
253
|
-
this.amount +
|
|
254
|
-
currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT,
|
|
255
|
-
);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Verify if the required value is available
|
|
260
|
-
* @private
|
|
261
|
-
*/
|
|
262
|
-
private verifyRequiredValue(): void {
|
|
263
|
-
if (this.totalInputAmount < this.amount) {
|
|
264
|
-
throw new Error(
|
|
265
|
-
`Not enough funds to wrap the amount specified. ${this.totalInputAmount} < ${this.amount}`,
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
const valueToVault: bigint =
|
|
270
|
-
this.amount + currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT; //this.priorityFee
|
|
271
|
-
|
|
272
|
-
if (this.totalInputAmount < valueToVault) {
|
|
273
|
-
throw new Error(
|
|
274
|
-
`Not enough funds to wrap the amount specified. ${this.totalInputAmount} < ${valueToVault}. Make sure that your inputs cover the amount to wrap, the priority fee and the unwrap prepaid fees.`,
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Add the vault output
|
|
281
|
-
* @private
|
|
282
|
-
* @throws {Error} If no vault address is provided
|
|
283
|
-
* @throws {Error} If the amount is not a number
|
|
284
|
-
*/
|
|
285
|
-
private addVaultOutput(): void {
|
|
286
|
-
if (!this.vault) {
|
|
287
|
-
throw new Error(`No vault address provided`);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
const valueToSend: bigint =
|
|
291
|
-
this.amount + currentConsensusConfig.UNWRAP_CONSOLIDATION_PREPAID_FEES_SAT;
|
|
292
|
-
|
|
293
|
-
const amountOutput: PsbtOutputExtendedAddress = {
|
|
294
|
-
address: this.vault,
|
|
295
|
-
value: Number(valueToSend),
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
this.addOutput(amountOutput);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Generate a vault address
|
|
303
|
-
* @param {Buffer[]} keys
|
|
304
|
-
* @param {number} minimumSignatureRequired
|
|
305
|
-
* @private
|
|
306
|
-
* @returns {string}
|
|
307
|
-
*/
|
|
308
|
-
private generateVaultAddress(keys: Buffer[], minimumSignatureRequired: number): string {
|
|
309
|
-
return P2TR_MS.generateMultiSigAddress(keys, minimumSignatureRequired, this.network);
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Generate a wrapped checksum hash
|
|
314
|
-
* @param {WrappedGeneration} param
|
|
315
|
-
* @param {bigint} amount
|
|
316
|
-
* @param {string} vault
|
|
317
|
-
* @private
|
|
318
|
-
* @returns {Buffer}
|
|
319
|
-
*/
|
|
320
|
-
private generateChecksumSalt(param: WrappedGeneration, amount: bigint, vault: string): Buffer {
|
|
321
|
-
const version: string = param.constraints.version;
|
|
322
|
-
const timestamp: number = param.constraints.timestamp;
|
|
323
|
-
|
|
324
|
-
const params: Buffer = Buffer.alloc(12 + version.length);
|
|
325
|
-
params.writeBigInt64BE(BigInt(timestamp), 0);
|
|
326
|
-
params.writeInt16BE(param.constraints.minimum, 8);
|
|
327
|
-
params.writeInt16BE(param.constraints.transactionMinimum, 10);
|
|
328
|
-
params.write(version, 12, version.length, 'utf-8');
|
|
329
|
-
|
|
330
|
-
return Buffer.concat([
|
|
331
|
-
...param.pubKeys,
|
|
332
|
-
...param.entities.map((entity: string) => Buffer.from(entity, 'utf-8')),
|
|
333
|
-
params,
|
|
334
|
-
Buffer.from(amount.toString(), 'utf-8'),
|
|
335
|
-
Buffer.from(vault, 'utf-8'),
|
|
336
|
-
]);
|
|
337
|
-
}
|
|
338
|
-
}
|