@btc-vision/transaction 1.5.3 → 1.6.0
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/abi/ABICoder.d.ts +1 -0
- package/browser/buffer/BinaryWriter.d.ts +1 -1
- package/browser/epoch/ChallengeSolution.d.ts +45 -0
- package/browser/epoch/interfaces/IChallengeSolution.d.ts +50 -0
- package/browser/epoch/validator/EpochValidator.d.ts +19 -0
- package/browser/generators/Features.d.ts +6 -1
- package/browser/generators/Generator.d.ts +1 -0
- package/browser/generators/builders/CalldataGenerator.d.ts +2 -1
- package/browser/generators/builders/DeploymentGenerator.d.ts +3 -1
- package/browser/index.js +1 -1
- package/browser/keypair/Address.d.ts +2 -0
- package/browser/opnet.d.ts +4 -3
- package/browser/transaction/TransactionFactory.d.ts +4 -15
- package/browser/transaction/browser/Web3Provider.d.ts +3 -3
- package/browser/transaction/browser/types/Unisat.d.ts +1 -1
- package/browser/transaction/builders/ChallengeSolutionTransaction.d.ts +1 -18
- package/browser/transaction/builders/CustomScriptTransaction.d.ts +1 -1
- package/browser/transaction/builders/DeploymentTransaction.d.ts +6 -4
- package/browser/transaction/builders/SharedInteractionTransaction.d.ts +5 -4
- package/browser/transaction/builders/TransactionBuilder.d.ts +2 -0
- package/browser/transaction/interfaces/ITransactionParameters.d.ts +4 -6
- package/browser/transaction/mineable/TimelockGenerator.d.ts +9 -0
- package/browser/utils/StringToBuffer.d.ts +1 -0
- package/browser/verification/TapscriptVerificator.d.ts +4 -1
- package/build/_version.d.ts +1 -1
- package/build/_version.js +1 -1
- package/build/abi/ABICoder.d.ts +1 -0
- package/build/abi/ABICoder.js +4 -0
- package/build/buffer/BinaryWriter.d.ts +1 -1
- package/build/buffer/BinaryWriter.js +11 -9
- package/build/epoch/ChallengeSolution.d.ts +45 -0
- package/build/epoch/ChallengeSolution.js +105 -0
- package/build/epoch/interfaces/IChallengeSolution.d.ts +50 -0
- package/build/epoch/interfaces/IChallengeSolution.js +1 -0
- package/build/epoch/validator/EpochValidator.d.ts +19 -0
- package/build/epoch/validator/EpochValidator.js +99 -0
- package/build/generators/Features.d.ts +6 -1
- package/build/generators/Features.js +1 -0
- package/build/generators/Generator.d.ts +1 -0
- package/build/generators/Generator.js +17 -1
- package/build/generators/builders/CalldataGenerator.d.ts +2 -1
- package/build/generators/builders/CalldataGenerator.js +4 -2
- package/build/generators/builders/DeploymentGenerator.d.ts +3 -1
- package/build/generators/builders/DeploymentGenerator.js +5 -3
- package/build/keypair/Address.d.ts +2 -0
- package/build/keypair/Address.js +12 -0
- package/build/keypair/EcKeyPair.js +10 -7
- package/build/opnet.d.ts +4 -3
- package/build/opnet.js +4 -3
- package/build/transaction/TransactionFactory.d.ts +4 -15
- package/build/transaction/TransactionFactory.js +4 -32
- package/build/transaction/browser/Web3Provider.d.ts +3 -3
- package/build/transaction/browser/types/Unisat.d.ts +1 -1
- package/build/transaction/builders/ChallengeSolutionTransaction.d.ts +0 -18
- package/build/transaction/builders/ChallengeSolutionTransaction.js +1 -51
- package/build/transaction/builders/CustomScriptTransaction.d.ts +1 -1
- package/build/transaction/builders/DeploymentTransaction.d.ts +6 -4
- package/build/transaction/builders/DeploymentTransaction.js +19 -7
- package/build/transaction/builders/InteractionTransaction.js +8 -1
- package/build/transaction/builders/SharedInteractionTransaction.d.ts +5 -4
- package/build/transaction/builders/SharedInteractionTransaction.js +7 -7
- package/build/transaction/builders/TransactionBuilder.d.ts +2 -0
- package/build/transaction/builders/TransactionBuilder.js +31 -3
- package/build/transaction/interfaces/ITransactionParameters.d.ts +4 -6
- package/build/transaction/mineable/TimelockGenerator.d.ts +9 -0
- package/build/transaction/mineable/TimelockGenerator.js +24 -0
- package/build/utils/StringToBuffer.d.ts +1 -0
- package/build/utils/StringToBuffer.js +3 -0
- package/build/verification/TapscriptVerificator.d.ts +4 -1
- package/build/verification/TapscriptVerificator.js +2 -2
- package/package.json +16 -16
- package/src/_version.ts +1 -1
- package/src/abi/ABICoder.ts +4 -0
- package/src/buffer/BinaryWriter.ts +13 -11
- package/src/epoch/ChallengeSolution.ts +196 -0
- package/src/epoch/interfaces/IChallengeSolution.ts +56 -0
- package/src/epoch/validator/EpochValidator.ts +180 -0
- package/src/generators/Features.ts +6 -0
- package/src/generators/Generator.ts +24 -2
- package/src/generators/builders/CalldataGenerator.ts +7 -3
- package/src/generators/builders/DeploymentGenerator.ts +18 -6
- package/src/keypair/Address.ts +34 -0
- package/src/keypair/EcKeyPair.ts +13 -8
- package/src/opnet.ts +6 -3
- package/src/transaction/TransactionFactory.ts +7 -62
- package/src/transaction/browser/Web3Provider.ts +3 -3
- package/src/transaction/browser/types/Unisat.ts +1 -1
- package/src/transaction/builders/ChallengeSolutionTransaction.ts +3 -4
- package/src/transaction/builders/CustomScriptTransaction.ts +2 -1
- package/src/transaction/builders/DeploymentTransaction.ts +27 -9
- package/src/transaction/builders/InteractionTransaction.ts +10 -2
- package/src/transaction/builders/SharedInteractionTransaction.ts +12 -28
- package/src/transaction/builders/TransactionBuilder.ts +40 -2
- package/src/transaction/interfaces/ITransactionParameters.ts +5 -8
- package/src/transaction/mineable/TimelockGenerator.ts +42 -0
- package/src/utils/StringToBuffer.ts +3 -0
- package/src/verification/TapscriptVerificator.ts +8 -4
- package/browser/generators/builders/MineableReward.d.ts +0 -7
- package/browser/transaction/mineable/ChallengeGenerator.d.ts +0 -9
- package/build/generators/builders/MineableReward.d.ts +0 -7
- package/build/generators/builders/MineableReward.js +0 -48
- package/build/transaction/mineable/ChallengeGenerator.d.ts +0 -9
- package/build/transaction/mineable/ChallengeGenerator.js +0 -28
- package/src/generators/builders/MineableReward.ts +0 -66
- package/src/transaction/mineable/ChallengeGenerator.ts +0 -39
package/src/keypair/EcKeyPair.ts
CHANGED
|
@@ -26,9 +26,8 @@ if (!BIP32factory) {
|
|
|
26
26
|
throw new Error('Failed to load BIP32 library');
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
secp256k1.
|
|
30
|
-
|
|
31
|
-
const { ProjectivePoint: Point, CURVE } = secp256k1;
|
|
29
|
+
const Point = secp256k1.Point;
|
|
30
|
+
const CURVE_N = Point.Fn.ORDER;
|
|
32
31
|
|
|
33
32
|
const TAP_TAG = utf8ToBytes('TapTweak');
|
|
34
33
|
const TAP_TAG_HASH = sha256(TAP_TAG);
|
|
@@ -48,6 +47,12 @@ export class EcKeyPair {
|
|
|
48
47
|
public static BIP32: BIP32API = BIP32factory(ecc);
|
|
49
48
|
public static ECPair: ECPairAPI = ECPairFactory(ecc);
|
|
50
49
|
|
|
50
|
+
// Initialize precomputation for better performance
|
|
51
|
+
static {
|
|
52
|
+
// Precompute tables for the base point for better performance
|
|
53
|
+
Point.BASE.precompute(8);
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
/**
|
|
52
57
|
* Generate a keypair from a WIF
|
|
53
58
|
* @param {string} wif - The WIF to use
|
|
@@ -272,12 +277,12 @@ export class EcKeyPair {
|
|
|
272
277
|
const P = Point.fromHex(pub);
|
|
273
278
|
const Peven = (P.y & 1n) === 0n ? P : P.negate();
|
|
274
279
|
|
|
275
|
-
const xBytes = Peven.
|
|
280
|
+
const xBytes = Peven.toBytes(true).subarray(1);
|
|
276
281
|
const tBytes = tapTweakHash(xBytes);
|
|
277
|
-
const t = mod(bytesToNumberBE(tBytes),
|
|
282
|
+
const t = mod(bytesToNumberBE(tBytes), CURVE_N);
|
|
278
283
|
|
|
279
284
|
const Q = Peven.add(Point.BASE.multiply(t));
|
|
280
|
-
return Buffer.from(Q.
|
|
285
|
+
return Buffer.from(Q.toBytes(true));
|
|
281
286
|
}
|
|
282
287
|
|
|
283
288
|
/**
|
|
@@ -294,9 +299,9 @@ export class EcKeyPair {
|
|
|
294
299
|
|
|
295
300
|
return pubkeys.map((bytes) => {
|
|
296
301
|
const P = Point.fromHex(bytes);
|
|
297
|
-
const P_even = P.
|
|
302
|
+
const P_even = P.y % 2n === 0n ? P : P.negate();
|
|
298
303
|
const Q = P_even.add(T);
|
|
299
|
-
return Q.
|
|
304
|
+
return Q.toBytes(true);
|
|
300
305
|
});
|
|
301
306
|
}
|
|
302
307
|
|
package/src/opnet.ts
CHANGED
|
@@ -10,12 +10,11 @@ export * from './generators/builders/CalldataGenerator.js';
|
|
|
10
10
|
export * from './generators/builders/CustomGenerator.js';
|
|
11
11
|
export * from './generators/builders/DeploymentGenerator.js';
|
|
12
12
|
export * from './generators/builders/LegacyCalldataGenerator.js';
|
|
13
|
-
export * from './generators/builders/MineableReward.js';
|
|
14
13
|
export * from './generators/builders/MultiSignGenerator.js';
|
|
15
14
|
export * from './generators/Features.js';
|
|
16
15
|
export * from './generators/Generator.js';
|
|
17
16
|
|
|
18
|
-
export * from './transaction/mineable/
|
|
17
|
+
export * from './transaction/mineable/TimelockGenerator.js';
|
|
19
18
|
|
|
20
19
|
/** Address */
|
|
21
20
|
export * from './generators/AddressGenerator.js';
|
|
@@ -42,7 +41,6 @@ export * from './transaction/interfaces/Tap.js';
|
|
|
42
41
|
export * from './transaction/TransactionFactory.js';
|
|
43
42
|
|
|
44
43
|
/** Builders */
|
|
45
|
-
export * from './transaction/builders/ChallengeSolutionTransaction.js';
|
|
46
44
|
export * from './transaction/builders/CustomScriptTransaction.js';
|
|
47
45
|
export * from './transaction/builders/DeploymentTransaction.js';
|
|
48
46
|
export * from './transaction/builders/FundingTransaction.js';
|
|
@@ -51,6 +49,11 @@ export * from './transaction/builders/MultiSignTransaction.js';
|
|
|
51
49
|
export * from './transaction/builders/SharedInteractionTransaction.js';
|
|
52
50
|
export * from './transaction/builders/TransactionBuilder.js';
|
|
53
51
|
|
|
52
|
+
/** Epoch */
|
|
53
|
+
export * from './epoch/interfaces/IChallengeSolution.js';
|
|
54
|
+
export * from './epoch/validator/EpochValidator.js';
|
|
55
|
+
export * from './epoch/ChallengeSolution.js';
|
|
56
|
+
|
|
54
57
|
/** Utils */
|
|
55
58
|
export * from './utils/BitcoinUtils.js';
|
|
56
59
|
export * from './utils/lengths.js';
|
|
@@ -11,26 +11,25 @@ import { InteractionTransaction } from './builders/InteractionTransaction.js';
|
|
|
11
11
|
import { TransactionBuilder } from './builders/TransactionBuilder.js';
|
|
12
12
|
import { TransactionType } from './enums/TransactionType.js';
|
|
13
13
|
import {
|
|
14
|
-
IChallengeSolutionTransactionParameters,
|
|
15
14
|
IDeploymentParameters,
|
|
16
15
|
IFundingTransactionParameters,
|
|
17
16
|
IInteractionParameters,
|
|
18
17
|
ITransactionParameters,
|
|
19
18
|
} from './interfaces/ITransactionParameters.js';
|
|
20
19
|
import { PSBTTypes } from './psbt/PSBTTypes.js';
|
|
21
|
-
import { ChallengeSolutionTransaction } from './builders/ChallengeSolutionTransaction.js';
|
|
22
20
|
import {
|
|
23
21
|
IDeploymentParametersWithoutSigner,
|
|
24
22
|
InteractionParametersWithoutSigner,
|
|
25
23
|
} from './browser/Web3Provider.js';
|
|
26
24
|
import { WindowWithWallets } from './browser/extensions/UnisatSigner.js';
|
|
25
|
+
import { RawChallenge } from '../epoch/interfaces/IChallengeSolution.js';
|
|
27
26
|
|
|
28
27
|
export interface DeploymentResult {
|
|
29
28
|
readonly transaction: [string, string];
|
|
30
29
|
|
|
31
30
|
readonly contractAddress: string;
|
|
32
31
|
readonly contractPubKey: string;
|
|
33
|
-
readonly preimage:
|
|
32
|
+
readonly preimage: RawChallenge;
|
|
34
33
|
|
|
35
34
|
readonly utxos: UTXO[];
|
|
36
35
|
}
|
|
@@ -42,13 +41,6 @@ export interface FundingTransactionResponse {
|
|
|
42
41
|
readonly nextUTXOs: UTXO[];
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
export interface ChallengeSolutionResponse {
|
|
46
|
-
readonly tx: Transaction;
|
|
47
|
-
readonly original: ChallengeSolutionTransaction;
|
|
48
|
-
readonly estimatedFees: bigint;
|
|
49
|
-
readonly nextUTXOs: UTXO[];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
44
|
export interface BitcoinTransferBase {
|
|
53
45
|
readonly tx: string;
|
|
54
46
|
readonly estimatedFees: bigint;
|
|
@@ -60,11 +52,7 @@ export interface InteractionResponse {
|
|
|
60
52
|
readonly interactionTransaction: string;
|
|
61
53
|
readonly estimatedFees: bigint;
|
|
62
54
|
readonly nextUTXOs: UTXO[];
|
|
63
|
-
readonly preimage:
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface ChallengeSolution extends BitcoinTransferBase {
|
|
67
|
-
readonly original: ChallengeSolutionTransaction;
|
|
55
|
+
readonly preimage: RawChallenge;
|
|
68
56
|
}
|
|
69
57
|
|
|
70
58
|
export interface BitcoinTransferResponse extends BitcoinTransferBase {
|
|
@@ -246,7 +234,7 @@ export class TransactionFactory {
|
|
|
246
234
|
...this.getUTXOAsTransaction(signedTransaction.tx, interactionParameters.to, 0),
|
|
247
235
|
], // always 0
|
|
248
236
|
randomBytes: preTransaction.getRndBytes(),
|
|
249
|
-
|
|
237
|
+
challenge: preTransaction.getPreimage(),
|
|
250
238
|
nonWitnessUtxo: signedTransaction.tx.toBuffer(),
|
|
251
239
|
estimatedFees: preTransaction.estimatedFees,
|
|
252
240
|
optionalInputs: inputs,
|
|
@@ -265,7 +253,7 @@ export class TransactionFactory {
|
|
|
265
253
|
interactionParameters.from,
|
|
266
254
|
1,
|
|
267
255
|
), // always 1
|
|
268
|
-
preimage: preTransaction.getPreimage().
|
|
256
|
+
preimage: preTransaction.getPreimage().toRaw(),
|
|
269
257
|
};
|
|
270
258
|
}
|
|
271
259
|
|
|
@@ -343,7 +331,7 @@ export class TransactionFactory {
|
|
|
343
331
|
...deploymentParameters,
|
|
344
332
|
utxos: [newUtxo], // always 0
|
|
345
333
|
randomBytes: preTransaction.getRndBytes(),
|
|
346
|
-
|
|
334
|
+
challenge: preTransaction.getPreimage(),
|
|
347
335
|
nonWitnessUtxo: signedTransaction.toBuffer(),
|
|
348
336
|
estimatedFees: preTransaction.estimatedFees,
|
|
349
337
|
optionalInputs: inputs,
|
|
@@ -370,7 +358,7 @@ export class TransactionFactory {
|
|
|
370
358
|
contractAddress: finalTransaction.getContractAddress(), //finalTransaction.contractAddress.p2tr(deploymentParameters.network),
|
|
371
359
|
contractPubKey: finalTransaction.contractPubKey,
|
|
372
360
|
utxos: [refundUTXO],
|
|
373
|
-
preimage: preTransaction.getPreimage().
|
|
361
|
+
preimage: preTransaction.getPreimage().toRaw(),
|
|
374
362
|
};
|
|
375
363
|
}
|
|
376
364
|
|
|
@@ -395,27 +383,6 @@ export class TransactionFactory {
|
|
|
395
383
|
};
|
|
396
384
|
}
|
|
397
385
|
|
|
398
|
-
/**
|
|
399
|
-
* @description Creates a challenge solution transaction.
|
|
400
|
-
* @param {IChallengeSolutionTransactionParameters} parameters - The challenge solution transaction parameters
|
|
401
|
-
* @returns {Promise<ChallengeSolution>} - The signed transaction
|
|
402
|
-
*/
|
|
403
|
-
public async createChallengeSolution(
|
|
404
|
-
parameters: IChallengeSolutionTransactionParameters,
|
|
405
|
-
): Promise<ChallengeSolution> {
|
|
406
|
-
if (!parameters.from) {
|
|
407
|
-
throw new Error('Field "from" not provided.');
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const resp = await this._createChallengeSolution(parameters);
|
|
411
|
-
return {
|
|
412
|
-
estimatedFees: resp.estimatedFees,
|
|
413
|
-
original: resp.original,
|
|
414
|
-
tx: resp.tx.toHex(),
|
|
415
|
-
nextUTXOs: this.getAllNewUTXOs(resp.original, resp.tx, parameters.from),
|
|
416
|
-
};
|
|
417
|
-
}
|
|
418
|
-
|
|
419
386
|
/**
|
|
420
387
|
* Get all new UTXOs of a generated transaction.
|
|
421
388
|
* @param {TransactionBuilder<TransactionType>} original - The original transaction
|
|
@@ -520,28 +487,6 @@ export class TransactionFactory {
|
|
|
520
487
|
return deployment;
|
|
521
488
|
}
|
|
522
489
|
|
|
523
|
-
private async _createChallengeSolution(
|
|
524
|
-
parameters: IChallengeSolutionTransactionParameters,
|
|
525
|
-
): Promise<ChallengeSolutionResponse> {
|
|
526
|
-
if (!parameters.to) throw new Error('Field "to" not provided.');
|
|
527
|
-
|
|
528
|
-
const challengeTransaction: ChallengeSolutionTransaction = new ChallengeSolutionTransaction(
|
|
529
|
-
parameters,
|
|
530
|
-
);
|
|
531
|
-
|
|
532
|
-
const signedTransaction: Transaction = await challengeTransaction.signTransaction();
|
|
533
|
-
if (!signedTransaction) {
|
|
534
|
-
throw new Error('Could not sign funding transaction.');
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
return {
|
|
538
|
-
tx: signedTransaction,
|
|
539
|
-
original: challengeTransaction,
|
|
540
|
-
estimatedFees: challengeTransaction.estimatedFees,
|
|
541
|
-
nextUTXOs: this.getUTXOAsTransaction(signedTransaction, parameters.to, 0),
|
|
542
|
-
};
|
|
543
|
-
}
|
|
544
|
-
|
|
545
490
|
private async createFundTransaction(
|
|
546
491
|
parameters: IFundingTransactionParameters,
|
|
547
492
|
): Promise<FundingTransactionResponse> {
|
|
@@ -8,17 +8,17 @@ import { ICustomTransactionParameters } from '../builders/CustomScriptTransactio
|
|
|
8
8
|
|
|
9
9
|
export type InteractionParametersWithoutSigner = Omit<
|
|
10
10
|
IInteractionParameters,
|
|
11
|
-
'signer' | '
|
|
11
|
+
'signer' | 'challenge'
|
|
12
12
|
>;
|
|
13
13
|
|
|
14
14
|
export type IDeploymentParametersWithoutSigner = Omit<
|
|
15
15
|
IDeploymentParameters,
|
|
16
|
-
'signer' | 'network' | '
|
|
16
|
+
'signer' | 'network' | 'challenge'
|
|
17
17
|
>;
|
|
18
18
|
|
|
19
19
|
export type CustomTransactionWithoutSigner = Omit<
|
|
20
20
|
ICustomTransactionParameters,
|
|
21
|
-
'signer' | '
|
|
21
|
+
'signer' | 'challenge'
|
|
22
22
|
>;
|
|
23
23
|
|
|
24
24
|
export interface BroadcastTransactionOptions {
|
|
@@ -85,7 +85,7 @@ export interface Unisat {
|
|
|
85
85
|
|
|
86
86
|
getBalance(): Promise<Balance>;
|
|
87
87
|
|
|
88
|
-
signMessage(message: string, type?: MessageType): Promise<string>;
|
|
88
|
+
signMessage(message: string | Buffer, type?: MessageType): Promise<string>;
|
|
89
89
|
|
|
90
90
|
signData(hex: string, type?: SignatureType): Promise<string>;
|
|
91
91
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { TransactionType } from '../enums/TransactionType.js';
|
|
2
|
-
import { IChallengeSolutionTransactionParameters } from '../interfaces/ITransactionParameters.js';
|
|
1
|
+
/*import { TransactionType } from '../enums/TransactionType.js';
|
|
3
2
|
import { getFinalScripts, opcodes, Psbt, PsbtInput, script, Signer } from '@btc-vision/bitcoin';
|
|
4
3
|
import { TransactionBuilder } from './TransactionBuilder.js';
|
|
5
4
|
import { ECPairInterface } from 'ecpair';
|
|
@@ -69,7 +68,7 @@ export class ChallengeSolutionTransaction extends TransactionBuilder<Transaction
|
|
|
69
68
|
finalScriptWitness: Buffer | undefined;
|
|
70
69
|
} => {
|
|
71
70
|
const inputDecoded = this.inputs[inputIndex];
|
|
72
|
-
|
|
71
|
+
|
|
73
72
|
if (isP2SH && inputDecoded && inputDecoded.redeemScript) {
|
|
74
73
|
const scriptSig = script.compile([this.challengeSolution, inputDecoded.redeemScript]);
|
|
75
74
|
|
|
@@ -85,4 +84,4 @@ export class ChallengeSolutionTransaction extends TransactionBuilder<Transaction
|
|
|
85
84
|
protected override getSignerKey(): Signer | ECPairInterface {
|
|
86
85
|
return this.signer;
|
|
87
86
|
}
|
|
88
|
-
}
|
|
87
|
+
}*/
|
|
@@ -20,7 +20,8 @@ import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
|
20
20
|
import { AddressGenerator } from '../../generators/AddressGenerator.js';
|
|
21
21
|
import { ECPairInterface } from 'ecpair';
|
|
22
22
|
|
|
23
|
-
export interface ICustomTransactionParameters
|
|
23
|
+
export interface ICustomTransactionParameters
|
|
24
|
+
extends Omit<SharedInteractionParameters, 'challenge'> {
|
|
24
25
|
script: (Buffer | Stack)[];
|
|
25
26
|
witnesses: Buffer[];
|
|
26
27
|
|
|
@@ -27,15 +27,18 @@ import { SharedInteractionTransaction } from './SharedInteractionTransaction.js'
|
|
|
27
27
|
import { ECPairInterface } from 'ecpair';
|
|
28
28
|
import { Address } from '../../keypair/Address.js';
|
|
29
29
|
import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
|
|
30
|
-
import {
|
|
30
|
+
import { ITimeLockOutput, TimeLockGenerator } from '../mineable/TimelockGenerator.js';
|
|
31
|
+
import { ChallengeSolution } from '../../epoch/ChallengeSolution.js';
|
|
32
|
+
import { Feature, Features } from '../../generators/Features.js';
|
|
31
33
|
|
|
32
34
|
export class DeploymentTransaction extends TransactionBuilder<TransactionType.DEPLOYMENT> {
|
|
33
35
|
public static readonly MAXIMUM_CONTRACT_SIZE = 128 * 1024;
|
|
34
36
|
|
|
35
37
|
public type: TransactionType.DEPLOYMENT = TransactionType.DEPLOYMENT;
|
|
36
38
|
|
|
37
|
-
protected readonly preimage:
|
|
38
|
-
protected readonly
|
|
39
|
+
protected readonly preimage: ChallengeSolution;
|
|
40
|
+
protected readonly epochChallenge: ITimeLockOutput;
|
|
41
|
+
|
|
39
42
|
/**
|
|
40
43
|
* The contract address
|
|
41
44
|
* @protected
|
|
@@ -122,13 +125,13 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
122
125
|
this.verifyCalldata();
|
|
123
126
|
}
|
|
124
127
|
|
|
125
|
-
if (!parameters.
|
|
128
|
+
if (!parameters.challenge) throw new Error('Challenge solution is required');
|
|
126
129
|
|
|
127
130
|
this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
|
|
128
|
-
this.preimage = parameters.
|
|
131
|
+
this.preimage = parameters.challenge;
|
|
129
132
|
|
|
130
|
-
this.
|
|
131
|
-
this.preimage,
|
|
133
|
+
this.epochChallenge = TimeLockGenerator.generateTimeLockAddress(
|
|
134
|
+
this.preimage.publicKey.originalPublicKeyBuffer(),
|
|
132
135
|
this.network,
|
|
133
136
|
);
|
|
134
137
|
|
|
@@ -147,6 +150,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
147
150
|
this.preimage,
|
|
148
151
|
this.priorityFee,
|
|
149
152
|
this.calldata,
|
|
153
|
+
this.generateFeatures(parameters),
|
|
150
154
|
);
|
|
151
155
|
|
|
152
156
|
this.scriptTree = this.getScriptTree();
|
|
@@ -190,7 +194,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
190
194
|
* Get the contract bytecode
|
|
191
195
|
* @returns {Buffer} The contract bytecode
|
|
192
196
|
*/
|
|
193
|
-
public getPreimage():
|
|
197
|
+
public getPreimage(): ChallengeSolution {
|
|
194
198
|
return this.preimage;
|
|
195
199
|
}
|
|
196
200
|
|
|
@@ -271,7 +275,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
271
275
|
) {
|
|
272
276
|
this.addOutput({
|
|
273
277
|
value: Number(amountSpent - amountToCA),
|
|
274
|
-
address: this.
|
|
278
|
+
address: this.epochChallenge.address,
|
|
275
279
|
});
|
|
276
280
|
}
|
|
277
281
|
|
|
@@ -376,6 +380,20 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
|
|
|
376
380
|
};
|
|
377
381
|
}
|
|
378
382
|
|
|
383
|
+
private generateFeatures(parameters: IDeploymentParameters): Feature<Features>[] {
|
|
384
|
+
const features: Feature<Features>[] = [];
|
|
385
|
+
|
|
386
|
+
const submission = parameters.challenge.getSubmission();
|
|
387
|
+
if (submission) {
|
|
388
|
+
features.push({
|
|
389
|
+
opcode: Features.EPOCH_SUBMISSION,
|
|
390
|
+
data: submission,
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return features;
|
|
395
|
+
}
|
|
396
|
+
|
|
379
397
|
private verifyCalldata(): void {
|
|
380
398
|
if (
|
|
381
399
|
this.calldata &&
|
|
@@ -31,7 +31,7 @@ export class InteractionTransaction extends SharedInteractionTransaction<Transac
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
this.contractSecret = Buffer.from(parameters.contract.replace('0x', ''), 'hex');
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
if (this.contractSecret.length !== 32) {
|
|
36
36
|
throw new Error('Invalid contract secret length. Expected 32 bytes.');
|
|
37
37
|
}
|
|
@@ -39,7 +39,7 @@ export class InteractionTransaction extends SharedInteractionTransaction<Transac
|
|
|
39
39
|
this.compiledTargetScript = this.calldataGenerator.compile(
|
|
40
40
|
this.calldata,
|
|
41
41
|
this.contractSecret,
|
|
42
|
-
this.
|
|
42
|
+
this.challenge,
|
|
43
43
|
this.priorityFee,
|
|
44
44
|
this.generateFeatures(parameters),
|
|
45
45
|
);
|
|
@@ -58,6 +58,14 @@ export class InteractionTransaction extends SharedInteractionTransaction<Transac
|
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
const submission = parameters.challenge.getSubmission();
|
|
62
|
+
if (submission) {
|
|
63
|
+
features.push({
|
|
64
|
+
opcode: Features.EPOCH_SUBMISSION,
|
|
65
|
+
data: submission,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
61
69
|
return features;
|
|
62
70
|
}
|
|
63
71
|
}
|
|
@@ -8,7 +8,8 @@ import { Compressor } from '../../bytecode/Compressor.js';
|
|
|
8
8
|
import { EcKeyPair } from '../../keypair/EcKeyPair.js';
|
|
9
9
|
import { BitcoinUtils } from '../../utils/BitcoinUtils.js';
|
|
10
10
|
import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
|
|
11
|
-
import {
|
|
11
|
+
import { ITimeLockOutput, TimeLockGenerator } from '../mineable/TimelockGenerator.js';
|
|
12
|
+
import { ChallengeSolution } from '../../epoch/ChallengeSolution.js';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Shared interaction transaction
|
|
@@ -31,8 +32,8 @@ export abstract class SharedInteractionTransaction<
|
|
|
31
32
|
protected abstract readonly compiledTargetScript: Buffer;
|
|
32
33
|
protected abstract readonly scriptTree: Taptree;
|
|
33
34
|
|
|
34
|
-
protected readonly
|
|
35
|
-
protected readonly
|
|
35
|
+
protected readonly challenge: ChallengeSolution;
|
|
36
|
+
protected readonly epochChallenge: ITimeLockOutput;
|
|
36
37
|
|
|
37
38
|
protected calldataGenerator: CalldataGenerator;
|
|
38
39
|
|
|
@@ -67,15 +68,15 @@ export abstract class SharedInteractionTransaction<
|
|
|
67
68
|
throw new Error('Calldata is required');
|
|
68
69
|
}
|
|
69
70
|
|
|
70
|
-
if (!parameters.
|
|
71
|
-
throw new Error('
|
|
71
|
+
if (!parameters.challenge) {
|
|
72
|
+
throw new Error('Challenge solution is required');
|
|
72
73
|
}
|
|
73
74
|
|
|
74
|
-
this.
|
|
75
|
+
this.challenge = parameters.challenge;
|
|
75
76
|
|
|
76
77
|
this.disableAutoRefund = parameters.disableAutoRefund || false;
|
|
77
|
-
this.
|
|
78
|
-
this.
|
|
78
|
+
this.epochChallenge = TimeLockGenerator.generateTimeLockAddress(
|
|
79
|
+
this.challenge.publicKey.originalPublicKeyBuffer(),
|
|
79
80
|
this.network,
|
|
80
81
|
);
|
|
81
82
|
|
|
@@ -110,27 +111,10 @@ export abstract class SharedInteractionTransaction<
|
|
|
110
111
|
/**
|
|
111
112
|
* Get the preimage
|
|
112
113
|
*/
|
|
113
|
-
public getPreimage():
|
|
114
|
-
return this.
|
|
114
|
+
public getPreimage(): ChallengeSolution {
|
|
115
|
+
return this.challenge;
|
|
115
116
|
}
|
|
116
117
|
|
|
117
|
-
/**
|
|
118
|
-
* Generate the secret for the interaction
|
|
119
|
-
* @protected
|
|
120
|
-
* @returns {Buffer} The secret
|
|
121
|
-
* @throws {Error} If the to address is invalid
|
|
122
|
-
*/
|
|
123
|
-
|
|
124
|
-
/*protected generateSecret(): Buffer {
|
|
125
|
-
if (!this.to) throw new Error('To address is required');
|
|
126
|
-
|
|
127
|
-
if (this.to.startsWith('0x')) {
|
|
128
|
-
throw new Error(`Legacy not support at this time. Reserved for future use.`);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return address.fromBech32(this.to).data;
|
|
132
|
-
}*/
|
|
133
|
-
|
|
134
118
|
/**
|
|
135
119
|
* Get the internal pubkey as an x-only key
|
|
136
120
|
* @protected
|
|
@@ -381,7 +365,7 @@ export abstract class SharedInteractionTransaction<
|
|
|
381
365
|
) {
|
|
382
366
|
this.addOutput({
|
|
383
367
|
value: Number(amountSpent - amountToCA),
|
|
384
|
-
address: this.
|
|
368
|
+
address: this.epochChallenge.address,
|
|
385
369
|
});
|
|
386
370
|
}
|
|
387
371
|
|
|
@@ -148,6 +148,8 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
|
|
|
148
148
|
*/
|
|
149
149
|
protected isPubKeyDestination: boolean;
|
|
150
150
|
|
|
151
|
+
protected note?: Buffer;
|
|
152
|
+
|
|
151
153
|
protected constructor(parameters: ITransactionParameters) {
|
|
152
154
|
super(parameters);
|
|
153
155
|
|
|
@@ -164,6 +166,14 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
|
|
|
164
166
|
this.optionalInputs = parameters.optionalInputs || [];
|
|
165
167
|
this.to = parameters.to || undefined;
|
|
166
168
|
|
|
169
|
+
if (parameters.note) {
|
|
170
|
+
if (typeof parameters.note === 'string') {
|
|
171
|
+
this.note = Buffer.from(parameters.note, 'utf8');
|
|
172
|
+
} else {
|
|
173
|
+
this.note = parameters.note;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
167
177
|
this.isPubKeyDestination = this.to
|
|
168
178
|
? AddressVerificator.isValidPublicKey(this.to, this.network)
|
|
169
179
|
: false;
|
|
@@ -228,6 +238,15 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
|
|
|
228
238
|
return buffer;
|
|
229
239
|
}
|
|
230
240
|
|
|
241
|
+
public addOPReturn(buffer: Buffer): void {
|
|
242
|
+
const compileScript = script.compile([opcodes.OP_RETURN, buffer]);
|
|
243
|
+
|
|
244
|
+
this.addOutput({
|
|
245
|
+
value: 0,
|
|
246
|
+
script: compileScript,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
231
250
|
public async getFundingTransactionParameters(): Promise<IFundingTransactionParameters> {
|
|
232
251
|
if (!this.estimatedFees) {
|
|
233
252
|
this.estimatedFees = await this.estimateTransactionFees();
|
|
@@ -368,8 +387,23 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
|
|
|
368
387
|
* @returns {void}
|
|
369
388
|
*/
|
|
370
389
|
public addOutput(output: PsbtOutputExtended): void {
|
|
371
|
-
if (output.value === 0)
|
|
372
|
-
|
|
390
|
+
if (output.value === 0) {
|
|
391
|
+
const script = output as {
|
|
392
|
+
script: Buffer;
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
if (!script.script || script.script.length === 0) {
|
|
396
|
+
throw new Error('Output value is 0 and no script provided');
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (script.script.length < 2) {
|
|
400
|
+
throw new Error('Output script is too short');
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (script.script[0] !== opcodes.OP_RETURN) {
|
|
404
|
+
throw new Error('Output script must start with OP_RETURN when value is 0');
|
|
405
|
+
}
|
|
406
|
+
} else if (output.value < TransactionBuilder.MINIMUM_DUST) {
|
|
373
407
|
throw new Error(
|
|
374
408
|
`Output value is less than the minimum dust ${output.value} < ${TransactionBuilder.MINIMUM_DUST}`,
|
|
375
409
|
);
|
|
@@ -479,6 +513,10 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
|
|
|
479
513
|
* @returns {Promise<void>}
|
|
480
514
|
*/
|
|
481
515
|
protected async addRefundOutput(amountSpent: bigint): Promise<void> {
|
|
516
|
+
if (this.note) {
|
|
517
|
+
this.addOPReturn(this.note);
|
|
518
|
+
}
|
|
519
|
+
|
|
482
520
|
/** Add the refund output */
|
|
483
521
|
const sendBackAmount: bigint = this.totalInputAmount - amountSpent;
|
|
484
522
|
if (sendBackAmount >= TransactionBuilder.MINIMUM_DUST) {
|
|
@@ -2,6 +2,7 @@ import { UTXO } from '../../utxo/interfaces/IUTXO.js';
|
|
|
2
2
|
import { ITweakedTransactionData } from '../shared/TweakedTransaction.js';
|
|
3
3
|
import { ChainId } from '../../network/ChainId.js';
|
|
4
4
|
import { PsbtOutputExtended } from '@btc-vision/bitcoin';
|
|
5
|
+
import { ChallengeSolution } from '../../epoch/ChallengeSolution.js';
|
|
5
6
|
|
|
6
7
|
export interface LoadedStorage {
|
|
7
8
|
[key: string]: string[];
|
|
@@ -22,6 +23,8 @@ export interface ITransactionParameters extends ITweakedTransactionData {
|
|
|
22
23
|
chainId?: ChainId;
|
|
23
24
|
noSignatures?: boolean;
|
|
24
25
|
|
|
26
|
+
readonly note?: string | Buffer;
|
|
27
|
+
|
|
25
28
|
readonly feeRate: number;
|
|
26
29
|
readonly priorityFee: bigint;
|
|
27
30
|
readonly gasSatFee: bigint;
|
|
@@ -33,17 +36,11 @@ export interface IFundingTransactionParameters extends ITransactionParameters {
|
|
|
33
36
|
splitInputsInto?: number;
|
|
34
37
|
}
|
|
35
38
|
|
|
36
|
-
export interface IChallengeSolutionTransactionParameters extends ITransactionParameters {
|
|
37
|
-
amount: bigint;
|
|
38
|
-
|
|
39
|
-
readonly challengeSolution: Buffer;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
39
|
export interface SharedInteractionParameters extends ITransactionParameters {
|
|
43
40
|
calldata?: Buffer;
|
|
44
41
|
disableAutoRefund?: boolean;
|
|
45
42
|
|
|
46
|
-
readonly
|
|
43
|
+
readonly challenge: ChallengeSolution;
|
|
47
44
|
readonly randomBytes?: Buffer;
|
|
48
45
|
|
|
49
46
|
readonly loadedStorage?: LoadedStorage;
|
|
@@ -61,5 +58,5 @@ export interface IDeploymentParameters extends Omit<ITransactionParameters, 'to'
|
|
|
61
58
|
readonly calldata?: Buffer;
|
|
62
59
|
|
|
63
60
|
readonly randomBytes?: Buffer;
|
|
64
|
-
readonly
|
|
61
|
+
readonly challenge: ChallengeSolution;
|
|
65
62
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import bitcoin, { Network, networks, opcodes, script } from '@btc-vision/bitcoin';
|
|
2
|
+
|
|
3
|
+
export interface ITimeLockOutput {
|
|
4
|
+
address: string;
|
|
5
|
+
witnessScript: Buffer;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class TimeLockGenerator {
|
|
9
|
+
private static readonly CSV_BLOCKS = 75;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Generate a P2WSH address with CSV timelock
|
|
13
|
+
* Note: This uses ECDSA, not Schnorr (Schnorr only available in Taproot)
|
|
14
|
+
*/
|
|
15
|
+
public static generateTimeLockAddress(
|
|
16
|
+
publicKey: Buffer,
|
|
17
|
+
network: Network = networks.bitcoin,
|
|
18
|
+
csvBlocks: number = TimeLockGenerator.CSV_BLOCKS,
|
|
19
|
+
): ITimeLockOutput {
|
|
20
|
+
const witnessScript = script.compile([
|
|
21
|
+
script.number.encode(csvBlocks),
|
|
22
|
+
opcodes.OP_CHECKSEQUENCEVERIFY,
|
|
23
|
+
opcodes.OP_DROP,
|
|
24
|
+
publicKey,
|
|
25
|
+
opcodes.OP_CHECKSIG,
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
const p2wsh = bitcoin.payments.p2wsh({
|
|
29
|
+
redeem: { output: witnessScript },
|
|
30
|
+
network,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
if (!p2wsh.address) {
|
|
34
|
+
throw new Error('Failed to generate P2WSH address');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
address: p2wsh.address,
|
|
39
|
+
witnessScript: witnessScript,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|