@btc-vision/transaction 1.4.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/browser/buffer/BinaryReader.d.ts +1 -1
  2. package/browser/generators/builders/DeploymentGenerator.d.ts +2 -0
  3. package/browser/index.js +1 -1
  4. package/browser/index.js.LICENSE.txt +1 -3
  5. package/browser/keypair/Address.d.ts +1 -0
  6. package/browser/keypair/AddressVerificator.d.ts +1 -0
  7. package/browser/keypair/EcKeyPair.d.ts +4 -1
  8. package/browser/transaction/TransactionFactory.d.ts +0 -1
  9. package/browser/transaction/browser/Web3Provider.d.ts +2 -0
  10. package/browser/transaction/builders/CustomScriptTransaction.d.ts +9 -6
  11. package/browser/transaction/builders/DeploymentTransaction.d.ts +6 -3
  12. package/browser/transaction/builders/MultiSignTransaction.d.ts +5 -5
  13. package/browser/transaction/builders/SharedInteractionTransaction.d.ts +5 -5
  14. package/browser/transaction/shared/TweakedTransaction.d.ts +5 -5
  15. package/build/buffer/BinaryReader.d.ts +1 -1
  16. package/build/buffer/BinaryReader.js +1 -1
  17. package/build/buffer/BinaryWriter.js +2 -2
  18. package/build/generators/builders/DeploymentGenerator.d.ts +2 -0
  19. package/build/generators/builders/DeploymentGenerator.js +2 -0
  20. package/build/keypair/Address.d.ts +1 -0
  21. package/build/keypair/Address.js +15 -2
  22. package/build/keypair/AddressVerificator.d.ts +1 -0
  23. package/build/keypair/AddressVerificator.js +4 -0
  24. package/build/keypair/EcKeyPair.d.ts +4 -1
  25. package/build/keypair/EcKeyPair.js +48 -21
  26. package/build/transaction/TransactionFactory.d.ts +0 -1
  27. package/build/transaction/TransactionFactory.js +18 -4
  28. package/build/transaction/browser/Web3Provider.d.ts +2 -0
  29. package/build/transaction/builders/CustomScriptTransaction.d.ts +9 -6
  30. package/build/transaction/builders/CustomScriptTransaction.js +29 -6
  31. package/build/transaction/builders/DeploymentTransaction.d.ts +6 -3
  32. package/build/transaction/builders/DeploymentTransaction.js +16 -7
  33. package/build/transaction/builders/MultiSignTransaction.d.ts +5 -5
  34. package/build/transaction/builders/MultiSignTransaction.js +5 -1
  35. package/build/transaction/builders/SharedInteractionTransaction.d.ts +5 -5
  36. package/build/transaction/builders/SharedInteractionTransaction.js +5 -1
  37. package/build/transaction/builders/TransactionBuilder.js +3 -2
  38. package/build/transaction/shared/TweakedTransaction.d.ts +5 -5
  39. package/build/transaction/shared/TweakedTransaction.js +5 -3
  40. package/build/verification/TapscriptVerificator.js +0 -1
  41. package/package.json +18 -18
  42. package/src/buffer/BinaryReader.ts +2 -2
  43. package/src/buffer/BinaryWriter.ts +2 -2
  44. package/src/generators/builders/DeploymentGenerator.ts +4 -0
  45. package/src/keypair/Address.ts +21 -0
  46. package/src/keypair/AddressVerificator.ts +6 -1
  47. package/src/keypair/EcKeyPair.ts +91 -34
  48. package/src/transaction/TransactionFactory.ts +21 -7
  49. package/src/transaction/browser/Web3Provider.ts +6 -0
  50. package/src/transaction/builders/CustomScriptTransaction.ts +51 -14
  51. package/src/transaction/builders/DeploymentTransaction.ts +36 -14
  52. package/src/transaction/builders/MultiSignTransaction.ts +10 -6
  53. package/src/transaction/builders/SharedInteractionTransaction.ts +9 -5
  54. package/src/transaction/builders/TransactionBuilder.ts +4 -3
  55. package/src/transaction/shared/TweakedTransaction.ts +10 -6
  56. package/src/verification/TapscriptVerificator.ts +1 -1
@@ -1,18 +1,23 @@
1
1
  import * as ecc from '@bitcoinerlab/secp256k1';
2
2
  import bip32, { BIP32API, BIP32Factory, BIP32Interface } from 'bip32';
3
- import {
3
+ import bitcoin, {
4
4
  address,
5
+ fromOutputScript,
5
6
  initEccLib,
6
7
  Network,
7
8
  networks,
9
+ opcodes,
8
10
  payments,
11
+ script,
9
12
  Signer,
10
- taggedHash,
11
13
  toXOnly,
12
14
  } from '@btc-vision/bitcoin';
13
15
  import { ECPairAPI, ECPairFactory, ECPairInterface } from 'ecpair';
14
16
  import { IWallet } from './interfaces/IWallet.js';
15
- import { CURVE, ProjectivePoint as Point } from '@noble/secp256k1';
17
+ import { secp256k1 } from '@noble/curves/secp256k1';
18
+ import { bytesToNumberBE, concatBytes, utf8ToBytes } from '@noble/curves/abstract/utils';
19
+ import { mod } from '@noble/curves/abstract/modular';
20
+ import { sha256 } from '@noble/hashes/sha2';
16
21
 
17
22
  initEccLib(ecc);
18
23
 
@@ -21,10 +26,16 @@ if (!BIP32factory) {
21
26
  throw new Error('Failed to load BIP32 library');
22
27
  }
23
28
 
24
- const mod = (a: bigint, b: bigint): bigint => {
25
- const result = a % b;
26
- return result >= 0n ? result : result + b;
27
- };
29
+ secp256k1.utils.precompute(8);
30
+
31
+ const { ProjectivePoint: Point, CURVE } = secp256k1;
32
+
33
+ const TAP_TAG = utf8ToBytes('TapTweak');
34
+ const TAP_TAG_HASH = sha256(TAP_TAG);
35
+
36
+ function tapTweakHash(x: Uint8Array): Uint8Array {
37
+ return sha256(concatBytes(TAP_TAG_HASH, TAP_TAG_HASH, x));
38
+ }
28
39
 
29
40
  /**
30
41
  * Class for handling EC key pairs
@@ -195,6 +206,32 @@ export class EcKeyPair {
195
206
  return address;
196
207
  }
197
208
 
209
+ /**
210
+ * Generate a P2OP address
211
+ * @param bytes - The bytes to use for the P2OP address
212
+ * @param network - The network to use
213
+ * @param deploymentVersion - The deployment version (default is 0)
214
+ * @returns {string} - The generated P2OP address
215
+ */
216
+ public static p2op(
217
+ bytes: Buffer | Uint8Array,
218
+ network: Network = networks.bitcoin,
219
+ deploymentVersion: number = 0,
220
+ ): string {
221
+ // custom opnet contract addresses
222
+ const witnessProgram = Buffer.concat([
223
+ Buffer.from([deploymentVersion]),
224
+ bitcoin.crypto.hash160(Buffer.from(bytes)),
225
+ ]);
226
+
227
+ if (witnessProgram.length < 2 || witnessProgram.length > 40) {
228
+ throw new Error('Witness program must be 2-40 bytes.');
229
+ }
230
+
231
+ const scriptData = script.compile([opcodes.OP_16, witnessProgram]);
232
+ return fromOutputScript(scriptData, network);
233
+ }
234
+
198
235
  /**
199
236
  * Get the address of a xOnly tweaked public key
200
237
  * @param {string} tweakedPubKeyHex - The xOnly tweaked public key hex string
@@ -225,42 +262,44 @@ export class EcKeyPair {
225
262
 
226
263
  /**
227
264
  * Tweak a public key
228
- * @param {string | Buffer} compressedPubKeyHex - The compressed public key hex string
265
+ * @param {Buffer | Uint8Array | string} pub - The public key to tweak
229
266
  * @returns {Buffer} - The tweaked public key hex string
230
267
  * @throws {Error} - If the public key cannot be tweaked
231
268
  */
232
- public static tweakPublicKey(compressedPubKeyHex: string | Buffer): Buffer {
233
- if (typeof compressedPubKeyHex === 'string' && compressedPubKeyHex.startsWith('0x')) {
234
- compressedPubKeyHex = compressedPubKeyHex.slice(2);
235
- }
236
-
237
- if (typeof compressedPubKeyHex !== 'string') {
238
- compressedPubKeyHex = compressedPubKeyHex.toString('hex');
239
- }
269
+ public static tweakPublicKey(pub: Uint8Array | Buffer | string): Buffer {
270
+ if (typeof pub === 'string' && pub.startsWith('0x')) pub = pub.slice(2);
240
271
 
241
- // Convert the compressed public key hex string to a Point on the curve
242
- let P = Point.fromHex(compressedPubKeyHex);
272
+ const P = Point.fromHex(pub);
273
+ const Peven = (P.y & 1n) === 0n ? P : P.negate();
243
274
 
244
- // Ensure the point has an even y-coordinate
245
- if ((P.y & 1n) !== 0n) {
246
- // Negate the point to get an even y-coordinate
247
- P = P.negate();
248
- }
249
-
250
- // Get the x-coordinate (32 bytes) of the point
251
- const x = P.toRawBytes(true).slice(1); // Remove the prefix byte
252
-
253
- // Compute the tweak t = H_tapTweak(x)
254
- const tHash = taggedHash('TapTweak', Buffer.from(x));
255
- const t = mod(BigInt('0x' + Buffer.from(tHash).toString('hex')), CURVE.n);
275
+ const xBytes = Peven.toRawBytes(true).subarray(1);
276
+ const tBytes = tapTweakHash(xBytes);
277
+ const t = mod(bytesToNumberBE(tBytes), CURVE.n);
256
278
 
257
- // Compute Q = P + t*G (where G is the generator point)
258
- const Q = P.add(Point.BASE.mul(t));
259
-
260
- // Return the tweaked public key in compressed form (hex string)
279
+ const Q = Peven.add(Point.BASE.multiply(t));
261
280
  return Buffer.from(Q.toRawBytes(true));
262
281
  }
263
282
 
283
+ /**
284
+ * Tweak a batch of public keys
285
+ * @param {readonly Uint8Array[]} pubkeys - The public keys to tweak
286
+ * @param {bigint} tweakScalar - The scalar to use for tweaking
287
+ * @returns {Uint8Array[]} - The tweaked public keys
288
+ */
289
+ public static tweakBatchSharedT(
290
+ pubkeys: readonly Uint8Array[],
291
+ tweakScalar: bigint,
292
+ ): Uint8Array[] {
293
+ const T = Point.BASE.multiply(tweakScalar);
294
+
295
+ return pubkeys.map((bytes) => {
296
+ const P = Point.fromHex(bytes);
297
+ const P_even = P.hasEvenY() ? P : P.negate();
298
+ const Q = P_even.add(T);
299
+ return Q.toRawBytes(true);
300
+ });
301
+ }
302
+
264
303
  /**
265
304
  * Generate a random wallet
266
305
  * @param {Network} network - The network to use
@@ -337,6 +376,24 @@ export class EcKeyPair {
337
376
  return wallet.address;
338
377
  }
339
378
 
379
+ /**
380
+ * Get the legacy address from a keypair
381
+ * @param publicKey
382
+ * @param {Network} network - The network to use
383
+ * @returns {string} - The legacy address
384
+ */
385
+ public static getP2PKH(
386
+ publicKey: Buffer | Uint8Array,
387
+ network: Network = networks.bitcoin,
388
+ ): string {
389
+ const wallet = payments.p2pkh({ pubkey: Buffer.from(publicKey), network: network });
390
+ if (!wallet.address) {
391
+ throw new Error('Failed to generate wallet');
392
+ }
393
+
394
+ return wallet.address;
395
+ }
396
+
340
397
  /**
341
398
  * Get the legacy address from a keypair
342
399
  * @param {ECPairInterface} keyPair - The keypair to get the address for
@@ -30,8 +30,6 @@ export interface DeploymentResult {
30
30
 
31
31
  readonly contractAddress: string;
32
32
  readonly contractPubKey: string;
33
- readonly p2trAddress: string;
34
-
35
33
  readonly preimage: string;
36
34
 
37
35
  readonly utxos: UTXO[];
@@ -89,13 +87,22 @@ export class TransactionFactory {
89
87
  throw new Error('Field "from" not provided.');
90
88
  }
91
89
 
90
+ if (!interactionParameters.utxos[0]) {
91
+ throw new Error('Missing at least one UTXO.');
92
+ }
93
+
94
+ if (!('signer' in interactionParameters)) {
95
+ throw new Error('Field "signer" not provided, OP_WALLET not detected.');
96
+ }
97
+
98
+ const inputs = this.parseOptionalInputs(interactionParameters.optionalInputs);
92
99
  const preTransaction: CustomScriptTransaction = new CustomScriptTransaction({
93
100
  ...interactionParameters,
94
101
  utxos: [interactionParameters.utxos[0]], // we simulate one input here.
102
+ optionalInputs: inputs,
95
103
  });
96
104
 
97
105
  // we don't sign that transaction, we just need the parameters.
98
-
99
106
  await preTransaction.generateTransactionMinimalSignatures();
100
107
 
101
108
  const parameters: IFundingTransactionParameters =
@@ -119,7 +126,12 @@ export class TransactionFactory {
119
126
 
120
127
  parameters.estimatedFees = feeEstimationFundingTransaction.estimatedFees;
121
128
 
122
- const signedTransaction = await this.createFundTransaction(parameters);
129
+ const signedTransaction = await this.createFundTransaction({
130
+ ...parameters,
131
+ optionalOutputs: [],
132
+ optionalInputs: [],
133
+ });
134
+
123
135
  if (!signedTransaction) {
124
136
  throw new Error('Could not sign funding transaction.');
125
137
  }
@@ -132,10 +144,13 @@ export class TransactionFactory {
132
144
 
133
145
  const newParams: ICustomTransactionParameters = {
134
146
  ...interactionParameters,
135
- utxos: this.getUTXOAsTransaction(signedTransaction.tx, interactionParameters.to, 0), // always 0
147
+ utxos: [
148
+ ...this.getUTXOAsTransaction(signedTransaction.tx, interactionParameters.to, 0),
149
+ ], // always 0
136
150
  randomBytes: preTransaction.getRndBytes(),
137
151
  nonWitnessUtxo: signedTransaction.tx.toBuffer(),
138
152
  estimatedFees: preTransaction.estimatedFees,
153
+ optionalInputs: inputs,
139
154
  };
140
155
 
141
156
  const finalTransaction: CustomScriptTransaction = new CustomScriptTransaction(newParams);
@@ -352,9 +367,8 @@ export class TransactionFactory {
352
367
 
353
368
  return {
354
369
  transaction: [signedTransaction.toHex(), outTx.toHex()],
355
- contractAddress: finalTransaction.contractAddress.p2tr(deploymentParameters.network),
370
+ contractAddress: finalTransaction.getContractAddress(), //finalTransaction.contractAddress.p2tr(deploymentParameters.network),
356
371
  contractPubKey: finalTransaction.contractPubKey,
357
- p2trAddress: finalTransaction.p2trAddress,
358
372
  utxos: [refundUTXO],
359
373
  preimage: preTransaction.getPreimage().toString('hex'),
360
374
  };
@@ -4,6 +4,7 @@ import {
4
4
  } from '../interfaces/ITransactionParameters.js';
5
5
  import { UTXO } from '../../utxo/interfaces/IUTXO.js';
6
6
  import { DeploymentResult, InteractionResponse } from '../TransactionFactory';
7
+ import { ICustomTransactionParameters } from '../builders/CustomScriptTransaction.js';
7
8
 
8
9
  export type InteractionParametersWithoutSigner = Omit<
9
10
  IInteractionParameters,
@@ -15,6 +16,11 @@ export type IDeploymentParametersWithoutSigner = Omit<
15
16
  'signer' | 'network' | 'preimage'
16
17
  >;
17
18
 
19
+ export type CustomTransactionWithoutSigner = Omit<
20
+ ICustomTransactionParameters,
21
+ 'signer' | 'preimage'
22
+ >;
23
+
18
24
  export interface BroadcastTransactionOptions {
19
25
  raw: string;
20
26
  psbt: boolean;
@@ -1,6 +1,8 @@
1
1
  import {
2
2
  crypto as bitCrypto,
3
+ P2TRPayment,
3
4
  Payment,
5
+ PaymentType,
4
6
  Psbt,
5
7
  PsbtInput,
6
8
  Signer,
@@ -19,10 +21,13 @@ import { AddressGenerator } from '../../generators/AddressGenerator.js';
19
21
  import { ECPairInterface } from 'ecpair';
20
22
 
21
23
  export interface ICustomTransactionParameters extends SharedInteractionParameters {
22
- readonly script: (Buffer | Stack)[];
23
- readonly witnesses: Buffer[];
24
+ script: (Buffer | Stack)[];
25
+ witnesses: Buffer[];
24
26
 
25
- readonly to: string;
27
+ /** optional Taproot annex payload (without the 0x50 prefix) */
28
+ annex?: Buffer;
29
+
30
+ to: string;
26
31
  }
27
32
 
28
33
  /**
@@ -46,12 +51,12 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
46
51
  * The target script redeem
47
52
  * @private
48
53
  */
49
- private targetScriptRedeem: Payment | null = null;
54
+ private targetScriptRedeem: P2TRPayment | null = null;
50
55
  /**
51
56
  * The left over funds script redeem
52
57
  * @private
53
58
  */
54
- private leftOverFundsScriptRedeem: Payment | null = null;
59
+ private leftOverFundsScriptRedeem: P2TRPayment | null = null;
55
60
  /**
56
61
  * The compiled target script
57
62
  * @private
@@ -91,6 +96,7 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
91
96
  * @private
92
97
  */
93
98
  private readonly witnesses: Buffer[];
99
+ private readonly annexData?: Buffer;
94
100
 
95
101
  public constructor(parameters: ICustomTransactionParameters) {
96
102
  super(parameters);
@@ -154,7 +160,7 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
154
160
  this.to = this.getScriptAddress();
155
161
  }
156
162
 
157
- const selectedRedeem = this.contractSigner
163
+ const selectedRedeem: Payment | null = this.contractSigner
158
164
  ? this.targetScriptRedeem
159
165
  : this.leftOverFundsScriptRedeem;
160
166
 
@@ -202,7 +208,10 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
202
208
  for (let i = 0; i < transaction.data.inputs.length; i++) {
203
209
  if (i === 0) {
204
210
  // multi sig input
205
- transaction.signInput(0, this.contractSigner);
211
+ try {
212
+ transaction.signInput(0, this.contractSigner);
213
+ } catch (e) {}
214
+
206
215
  transaction.signInput(0, this.getSignerKey());
207
216
 
208
217
  transaction.finalizeInput(0, this.customFinalizer);
@@ -217,11 +226,12 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
217
226
  * Get the tap output
218
227
  * @protected
219
228
  */
220
- protected override generateScriptAddress(): Payment {
229
+ protected override generateScriptAddress(): P2TRPayment {
221
230
  return {
222
231
  internalPubkey: this.internalPubKeyToXOnly(),
223
232
  network: this.network,
224
233
  scriptTree: this.scriptTree,
234
+ name: PaymentType.P2TR,
225
235
  };
226
236
  }
227
237
 
@@ -229,7 +239,7 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
229
239
  * Generate the tap data
230
240
  * @protected
231
241
  */
232
- protected override generateTapData(): Payment {
242
+ protected override generateTapData(): P2TRPayment {
233
243
  const selectedRedeem = this.contractSigner
234
244
  ? this.targetScriptRedeem
235
245
  : this.leftOverFundsScriptRedeem;
@@ -247,9 +257,25 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
247
257
  network: this.network,
248
258
  scriptTree: this.scriptTree,
249
259
  redeem: selectedRedeem,
260
+ name: PaymentType.P2TR,
250
261
  };
251
262
  }
252
263
 
264
+ protected getScriptSolution(input: PsbtInput): Buffer[] {
265
+ if (!input.tapScriptSig) {
266
+ throw new Error('Tap script signature is required');
267
+ }
268
+
269
+ const witnesses: Buffer[] = [...this.witnesses];
270
+ if (input.tapScriptSig) {
271
+ for (const sig of input.tapScriptSig) {
272
+ witnesses.push(sig.signature);
273
+ }
274
+ }
275
+
276
+ return witnesses;
277
+ }
278
+
253
279
  /**
254
280
  * Generate the contract seed for the deployment
255
281
  * @private
@@ -261,18 +287,27 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
261
287
  /**
262
288
  * Finalize the transaction
263
289
  * @param _inputIndex
264
- * @param _input
290
+ * @param input
265
291
  */
266
- private customFinalizer = (_inputIndex: number, _input: PsbtInput) => {
292
+ private customFinalizer = (_inputIndex: number, input: PsbtInput) => {
267
293
  if (!this.tapLeafScript) {
268
294
  throw new Error('Tap leaf script is required');
269
295
  }
270
296
 
271
- const scriptSolution = this.witnesses;
297
+ const scriptSolution = this.getScriptSolution(input);
272
298
  const witness = scriptSolution
273
299
  .concat(this.tapLeafScript.script)
274
300
  .concat(this.tapLeafScript.controlBlock);
275
301
 
302
+ if (this.annexData && this.annexData.length > 0) {
303
+ const annex =
304
+ this.annexData[0] === 0x50
305
+ ? this.annexData
306
+ : Buffer.concat([Buffer.from([0x50]), this.annexData]);
307
+
308
+ witness.push(annex);
309
+ }
310
+
276
311
  return {
277
312
  finalScriptWitness: TransactionBuilder.witnessStackToScriptWitness(witness),
278
313
  };
@@ -298,13 +333,15 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
298
333
  */
299
334
  private generateRedeemScripts(): void {
300
335
  this.targetScriptRedeem = {
301
- pubkeys: this.getPubKeys(),
336
+ name: PaymentType.P2TR,
337
+ //pubkeys: this.getPubKeys(),
302
338
  output: this.compiledTargetScript,
303
339
  redeemVersion: 192,
304
340
  };
305
341
 
306
342
  this.leftOverFundsScriptRedeem = {
307
- pubkeys: this.getPubKeys(),
343
+ name: PaymentType.P2TR,
344
+ //pubkeys: this.getPubKeys(),
308
345
  output: this.getLeafScript(),
309
346
  redeemVersion: 192,
310
347
  };
@@ -2,7 +2,8 @@ import { TransactionType } from '../enums/TransactionType.js';
2
2
  import { IDeploymentParameters } from '../interfaces/ITransactionParameters.js';
3
3
  import {
4
4
  crypto as bitCrypto,
5
- Payment,
5
+ P2TRPayment,
6
+ PaymentType,
6
7
  Psbt,
7
8
  PsbtInput,
8
9
  Signer,
@@ -15,7 +16,10 @@ import {
15
16
  TransactionBuilder,
16
17
  } from './TransactionBuilder.js';
17
18
  import { TapLeafScript } from '../interfaces/Tap.js';
18
- import { DeploymentGenerator } from '../../generators/builders/DeploymentGenerator.js';
19
+ import {
20
+ DeploymentGenerator,
21
+ versionBuffer,
22
+ } from '../../generators/builders/DeploymentGenerator.js';
19
23
  import { EcKeyPair } from '../../keypair/EcKeyPair.js';
20
24
  import { BitcoinUtils } from '../../utils/BitcoinUtils.js';
21
25
  import { Compressor } from '../../bytecode/Compressor.js';
@@ -25,15 +29,13 @@ import { Address } from '../../keypair/Address.js';
25
29
  import { UnisatSigner } from '../browser/extensions/UnisatSigner.js';
26
30
  import { ChallengeGenerator, IMineableReward } from '../mineable/ChallengeGenerator.js';
27
31
 
28
- const p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn;
29
-
30
32
  export class DeploymentTransaction extends TransactionBuilder<TransactionType.DEPLOYMENT> {
31
33
  public static readonly MAXIMUM_CONTRACT_SIZE = 128 * 1024;
34
+
32
35
  public type: TransactionType.DEPLOYMENT = TransactionType.DEPLOYMENT;
33
36
 
34
37
  protected readonly preimage: Buffer; // ALWAYS 128 bytes for the preimage
35
38
  protected readonly rewardChallenge: IMineableReward;
36
-
37
39
  /**
38
40
  * The contract address
39
41
  * @protected
@@ -44,16 +46,17 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
44
46
  * @private
45
47
  */
46
48
  protected tapLeafScript: TapLeafScript | null = null;
49
+ private readonly deploymentVersion: number = 0x00;
47
50
  /**
48
51
  * The target script redeem
49
52
  * @private
50
53
  */
51
- private targetScriptRedeem: Payment | null = null;
54
+ private targetScriptRedeem: P2TRPayment | null = null;
52
55
  /**
53
56
  * The left over funds script redeem
54
57
  * @private
55
58
  */
56
- private leftOverFundsScriptRedeem: Payment | null = null;
59
+ private leftOverFundsScriptRedeem: P2TRPayment | null = null;
57
60
  /**
58
61
  * The compiled target script
59
62
  * @private
@@ -105,12 +108,13 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
105
108
  * @private
106
109
  */
107
110
  private readonly randomBytes: Buffer;
111
+ private _computedAddress: string | undefined;
108
112
 
109
113
  public constructor(parameters: IDeploymentParameters) {
110
- // TODO: Add legacy deployment, this is only p2tr.
111
114
  super(parameters);
112
115
 
113
- this.bytecode = Compressor.compress(parameters.bytecode);
116
+ this.bytecode = Compressor.compress(Buffer.concat([versionBuffer, parameters.bytecode]));
117
+
114
118
  this.verifyBytecode();
115
119
 
116
120
  if (parameters.calldata) {
@@ -190,6 +194,20 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
190
194
  return this.preimage;
191
195
  }
192
196
 
197
+ public getContractAddress(): string {
198
+ if (this._computedAddress) {
199
+ return this._computedAddress;
200
+ }
201
+
202
+ this._computedAddress = EcKeyPair.p2op(
203
+ this.contractSeed,
204
+ this.network,
205
+ this.deploymentVersion,
206
+ );
207
+
208
+ return this._computedAddress;
209
+ }
210
+
193
211
  /**
194
212
  * Get the contract signer public key
195
213
  * @protected
@@ -243,7 +261,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
243
261
  // ALWAYS THE FIRST INPUT.
244
262
  this.addOutput({
245
263
  value: Number(amountToCA),
246
- address: this.contractAddress.p2tr(this.network),
264
+ address: this.getContractAddress(),
247
265
  });
248
266
 
249
267
  // ALWAYS SECOND.
@@ -323,8 +341,9 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
323
341
  * Get the tap output
324
342
  * @protected
325
343
  */
326
- protected override generateScriptAddress(): Payment {
344
+ protected override generateScriptAddress(): P2TRPayment {
327
345
  return {
346
+ name: PaymentType.P2TR,
328
347
  internalPubkey: this.internalPubKeyToXOnly(),
329
348
  network: this.network,
330
349
  scriptTree: this.scriptTree,
@@ -335,7 +354,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
335
354
  * Generate the tap data
336
355
  * @protected
337
356
  */
338
- protected override generateTapData(): Payment {
357
+ protected override generateTapData(): P2TRPayment {
339
358
  const selectedRedeem = this.contractSigner
340
359
  ? this.targetScriptRedeem
341
360
  : this.leftOverFundsScriptRedeem;
@@ -349,6 +368,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
349
368
  }
350
369
 
351
370
  return {
371
+ name: PaymentType.P2TR,
352
372
  internalPubkey: this.internalPubKeyToXOnly(),
353
373
  network: this.network,
354
374
  scriptTree: this.scriptTree,
@@ -440,13 +460,15 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
440
460
  */
441
461
  private generateRedeemScripts(): void {
442
462
  this.targetScriptRedeem = {
443
- pubkeys: this.getPubKeys(),
463
+ name: PaymentType.P2TR,
464
+ //pubkeys: this.getPubKeys(),
444
465
  output: this.compiledTargetScript,
445
466
  redeemVersion: 192,
446
467
  };
447
468
 
448
469
  this.leftOverFundsScriptRedeem = {
449
- pubkeys: this.getPubKeys(),
470
+ name: PaymentType.P2TR,
471
+ //pubkeys: this.getPubKeys(),
450
472
  output: this.getLeafScript(),
451
473
  redeemVersion: 192,
452
474
  };
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  crypto as bitcoinCrypto,
3
3
  opcodes,
4
- Payment,
4
+ P2TRPayment,
5
+ PaymentType,
5
6
  Psbt,
6
7
  PsbtInput,
7
8
  PsbtInputExtended,
@@ -58,8 +59,8 @@ export class MultiSignTransaction extends TransactionBuilder<TransactionType.MUL
58
59
 
59
60
  public type: TransactionType.MULTI_SIG = TransactionType.MULTI_SIG;
60
61
 
61
- protected targetScriptRedeem: Payment | null = null;
62
- protected leftOverFundsScriptRedeem: Payment | null = null;
62
+ protected targetScriptRedeem: P2TRPayment | null = null;
63
+ protected leftOverFundsScriptRedeem: P2TRPayment | null = null;
63
64
 
64
65
  protected readonly compiledTargetScript: Buffer;
65
66
  protected readonly scriptTree: Taptree;
@@ -545,16 +546,16 @@ export class MultiSignTransaction extends TransactionBuilder<TransactionType.MUL
545
546
  */
546
547
  protected override async signInputs(_transaction: Psbt): Promise<void> {}
547
548
 
548
- protected override generateScriptAddress(): Payment {
549
+ protected override generateScriptAddress(): P2TRPayment {
549
550
  return {
550
551
  internalPubkey: toXOnly(MultiSignTransaction.numsPoint), //this.internalPubKeyToXOnly(),
551
552
  network: this.network,
552
553
  scriptTree: this.scriptTree,
553
- //pubkeys: this.publicKeys,
554
+ name: PaymentType.P2TR,
554
555
  };
555
556
  }
556
557
 
557
- protected override generateTapData(): Payment {
558
+ protected override generateTapData(): P2TRPayment {
558
559
  const selectedRedeem = this.targetScriptRedeem;
559
560
  if (!selectedRedeem) {
560
561
  throw new Error('Left over funds script redeem is required');
@@ -569,6 +570,7 @@ export class MultiSignTransaction extends TransactionBuilder<TransactionType.MUL
569
570
  network: this.network,
570
571
  scriptTree: this.scriptTree,
571
572
  redeem: selectedRedeem,
573
+ name: PaymentType.P2TR,
572
574
  };
573
575
  }
574
576
 
@@ -662,11 +664,13 @@ export class MultiSignTransaction extends TransactionBuilder<TransactionType.MUL
662
664
  */
663
665
  private generateRedeemScripts(): void {
664
666
  this.targetScriptRedeem = {
667
+ name: PaymentType.P2TR,
665
668
  output: this.compiledTargetScript,
666
669
  redeemVersion: 192,
667
670
  };
668
671
 
669
672
  this.leftOverFundsScriptRedeem = {
673
+ name: PaymentType.P2TR,
670
674
  output: MultiSignTransaction.LOCK_LEAF_SCRIPT,
671
675
  redeemVersion: 192,
672
676
  };