@btc-vision/transaction 1.0.111 → 1.0.113

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 (61) hide show
  1. package/browser/_version.d.ts +1 -1
  2. package/browser/generators/Generator.d.ts +2 -0
  3. package/browser/index.js +1 -1
  4. package/browser/keypair/AddressVerificator.d.ts +15 -3
  5. package/browser/keypair/EcKeyPair.d.ts +9 -4
  6. package/browser/keypair/Wallet.d.ts +1 -0
  7. package/browser/signer/TweakedSigner.d.ts +2 -2
  8. package/browser/transaction/builders/FundingTransaction.d.ts +2 -1
  9. package/browser/transaction/builders/MultiSignTransaction.d.ts +2 -1
  10. package/browser/transaction/builders/SharedInteractionTransaction.d.ts +1 -1
  11. package/browser/transaction/builders/TransactionBuilder.d.ts +3 -2
  12. package/browser/transaction/shared/TweakedTransaction.d.ts +8 -7
  13. package/browser/verification/TapscriptVerificator.d.ts +1 -1
  14. package/build/_version.d.ts +1 -1
  15. package/build/_version.js +1 -1
  16. package/build/generators/Generator.d.ts +2 -0
  17. package/build/generators/Generator.js +5 -0
  18. package/build/generators/builders/CalldataGenerator.js +4 -2
  19. package/build/generators/builders/DeploymentGenerator.js +7 -4
  20. package/build/keypair/AddressVerificator.d.ts +15 -3
  21. package/build/keypair/AddressVerificator.js +74 -3
  22. package/build/keypair/EcKeyPair.d.ts +9 -4
  23. package/build/keypair/EcKeyPair.js +69 -7
  24. package/build/keypair/Wallet.d.ts +1 -0
  25. package/build/keypair/Wallet.js +5 -4
  26. package/build/signer/TweakedSigner.d.ts +2 -2
  27. package/build/signer/TweakedSigner.js +1 -1
  28. package/build/transaction/builders/CustomScriptTransaction.js +3 -3
  29. package/build/transaction/builders/DeploymentTransaction.js +4 -4
  30. package/build/transaction/builders/FundingTransaction.d.ts +2 -1
  31. package/build/transaction/builders/FundingTransaction.js +18 -4
  32. package/build/transaction/builders/MultiSignTransaction.d.ts +2 -1
  33. package/build/transaction/builders/SharedInteractionTransaction.d.ts +1 -1
  34. package/build/transaction/builders/SharedInteractionTransaction.js +4 -4
  35. package/build/transaction/builders/TransactionBuilder.d.ts +3 -2
  36. package/build/transaction/builders/TransactionBuilder.js +7 -2
  37. package/build/transaction/builders/UnwrapTransaction.js +2 -2
  38. package/build/transaction/shared/TweakedTransaction.d.ts +8 -7
  39. package/build/transaction/shared/TweakedTransaction.js +1 -1
  40. package/build/verification/TapscriptVerificator.d.ts +1 -1
  41. package/build/verification/TapscriptVerificator.js +2 -2
  42. package/package.json +2 -1
  43. package/src/_version.ts +1 -1
  44. package/src/generators/Generator.ts +12 -0
  45. package/src/generators/builders/CalldataGenerator.ts +6 -3
  46. package/src/generators/builders/DeploymentGenerator.ts +9 -4
  47. package/src/keypair/AddressVerificator.ts +144 -5
  48. package/src/keypair/EcKeyPair.ts +149 -13
  49. package/src/keypair/Wallet.ts +11 -3
  50. package/src/signer/TweakedSigner.ts +3 -2
  51. package/src/transaction/builders/CustomScriptTransaction.ts +6 -5
  52. package/src/transaction/builders/DeploymentTransaction.ts +6 -5
  53. package/src/transaction/builders/FundingTransaction.ts +18 -5
  54. package/src/transaction/builders/MultiSignTransaction.ts +6 -2
  55. package/src/transaction/builders/SharedInteractionTransaction.ts +5 -5
  56. package/src/transaction/builders/TransactionBuilder.ts +36 -10
  57. package/src/transaction/builders/UnwrapSegwitTransaction.ts +7 -3
  58. package/src/transaction/builders/UnwrapTransaction.ts +2 -2
  59. package/src/transaction/builders/WrapTransaction.ts +1 -6
  60. package/src/transaction/shared/TweakedTransaction.ts +12 -12
  61. package/src/verification/TapscriptVerificator.ts +3 -3
@@ -1,10 +1,12 @@
1
1
  import * as ecc from '@bitcoinerlab/secp256k1';
2
2
  import { Address } from '@btc-vision/bsi-binary';
3
3
  import bip32, { BIP32API, BIP32Factory, BIP32Interface } from 'bip32';
4
- import { address, initEccLib, Network, networks, payments } from 'bitcoinjs-lib';
4
+ import { address, initEccLib, Network, networks, payments, Signer } from 'bitcoinjs-lib';
5
5
  import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371.js';
6
6
  import { ECPairAPI, ECPairFactory, ECPairInterface } from 'ecpair';
7
7
  import { IWallet } from './interfaces/IWallet.js';
8
+ import { CURVE, Point, utils } from '@noble/secp256k1';
9
+ import { taggedHash } from 'bitcoinjs-lib/src/crypto.js';
8
10
 
9
11
  initEccLib(ecc);
10
12
 
@@ -42,23 +44,28 @@ export class EcKeyPair {
42
44
  * @returns {ECPairInterface} - The generated keypair
43
45
  */
44
46
  public static fromPrivateKey(
45
- privateKey: Buffer,
47
+ privateKey: Buffer | Uint8Array,
46
48
  network: Network = networks.bitcoin,
47
49
  ): ECPairInterface {
48
- return this.ECPair.fromPrivateKey(privateKey, { network });
50
+ return this.ECPair.fromPrivateKey(
51
+ !Buffer.isBuffer(privateKey) ? Buffer.from(privateKey) : privateKey,
52
+ { network },
53
+ );
49
54
  }
50
55
 
51
56
  /**
52
57
  * Generate a keypair from a public key
53
- * @param {Buffer} publicKey - The public key to use
58
+ * @param {Buffer | Uint8Array} publicKey - The public key to use
54
59
  * @param {Network} network - The network to use
55
60
  * @returns {ECPairInterface} - The generated keypair
56
61
  */
57
62
  public static fromPublicKey(
58
- publicKey: Buffer,
63
+ publicKey: Buffer | Uint8Array,
59
64
  network: Network = networks.bitcoin,
60
65
  ): ECPairInterface {
61
- return this.ECPair.fromPublicKey(publicKey, { network });
66
+ const buf = !Buffer.isBuffer(publicKey) ? Buffer.from(publicKey) : publicKey;
67
+
68
+ return this.ECPair.fromPublicKey(buf, { network });
62
69
  }
63
70
 
64
71
  /**
@@ -122,7 +129,7 @@ export class EcKeyPair {
122
129
  throw new Error('Failed to regenerate key');
123
130
  }
124
131
 
125
- return key.publicKey;
132
+ return Buffer.from(key.publicKey);
126
133
  });
127
134
  }
128
135
 
@@ -136,7 +143,7 @@ export class EcKeyPair {
136
143
  keyPair: ECPairInterface,
137
144
  network: Network = networks.bitcoin,
138
145
  ): Address {
139
- const res = payments.p2wpkh({ pubkey: keyPair.publicKey, network: network });
146
+ const res = payments.p2wpkh({ pubkey: Buffer.from(keyPair.publicKey), network: network });
140
147
 
141
148
  if (!res.address) {
142
149
  throw new Error('Failed to generate wallet');
@@ -145,6 +152,96 @@ export class EcKeyPair {
145
152
  return res.address;
146
153
  }
147
154
 
155
+ /**
156
+ * Get the address of a tweaked public key
157
+ * @param {string} tweakedPubKeyHex - The tweaked public key hex string
158
+ * @param {Network} network - The network to use
159
+ * @returns {Address} - The address
160
+ * @throws {Error} - If the address cannot be generated
161
+ */
162
+ public static tweakedPubKeyToAddress(tweakedPubKeyHex: string, network: Network): string {
163
+ if (tweakedPubKeyHex.startsWith('0x')) {
164
+ tweakedPubKeyHex = tweakedPubKeyHex.slice(2);
165
+ }
166
+
167
+ // Convert the tweaked public key hex string to a Buffer
168
+ const tweakedPubKeyBuffer = Buffer.from(tweakedPubKeyHex, 'hex');
169
+
170
+ // Generate the Taproot address using the p2tr payment method
171
+ const { address } = payments.p2tr({
172
+ pubkey: toXOnly(tweakedPubKeyBuffer),
173
+ network: network,
174
+ });
175
+
176
+ if (!address) {
177
+ throw new Error('Failed to generate Taproot address');
178
+ }
179
+
180
+ return address;
181
+ }
182
+
183
+ /**
184
+ * Get the address of a xOnly tweaked public key
185
+ * @param {string} tweakedPubKeyHex - The xOnly tweaked public key hex string
186
+ * @param {Network} network - The network to use
187
+ * @returns {Address} - The address
188
+ * @throws {Error} - If the address cannot be generated
189
+ */
190
+ public static xOnlyTweakedPubKeyToAddress(tweakedPubKeyHex: string, network: Network): string {
191
+ if (tweakedPubKeyHex.startsWith('0x')) {
192
+ tweakedPubKeyHex = tweakedPubKeyHex.slice(2);
193
+ }
194
+
195
+ // Convert the tweaked public key hex string to a Buffer
196
+ const tweakedPubKeyBuffer = Buffer.from(tweakedPubKeyHex, 'hex');
197
+
198
+ // Generate the Taproot address using the p2tr payment method
199
+ const { address } = payments.p2tr({
200
+ pubkey: tweakedPubKeyBuffer,
201
+ network: network,
202
+ });
203
+
204
+ if (!address) {
205
+ throw new Error('Failed to generate Taproot address');
206
+ }
207
+
208
+ return address;
209
+ }
210
+
211
+ /**
212
+ * Tweak a public key
213
+ * @param {string} compressedPubKeyHex - The compressed public key hex string
214
+ * @returns {string} - The tweaked public key hex string
215
+ * @throws {Error} - If the public key cannot be tweaked
216
+ */
217
+ public static tweakPublicKey(compressedPubKeyHex: string): string {
218
+ if (compressedPubKeyHex.startsWith('0x')) {
219
+ compressedPubKeyHex = compressedPubKeyHex.slice(2);
220
+ }
221
+
222
+ // Convert the compressed public key hex string to a Point on the curve
223
+ let P = Point.fromHex(compressedPubKeyHex);
224
+
225
+ // Ensure the point has an even y-coordinate
226
+ if (!P.hasEvenY()) {
227
+ // Negate the point to get an even y-coordinate
228
+ P = P.negate();
229
+ }
230
+
231
+ // Get the x-coordinate (32 bytes) of the point
232
+ const x = P.toRawBytes(true).slice(1); // Remove the prefix byte
233
+
234
+ // Compute the tweak t = H_tapTweak(x)
235
+ const tHash = taggedHash('TapTweak', Buffer.from(x));
236
+ const t = utils.mod(BigInt('0x' + Buffer.from(tHash).toString('hex')), CURVE.n);
237
+
238
+ // Compute Q = P + t*G (where G is the generator point)
239
+ const Q = P.add(Point.BASE.multiply(t));
240
+
241
+ // Return the tweaked public key in compressed form (hex string)
242
+ return Q.toHex(true);
243
+ }
244
+
148
245
  /**
149
246
  * Generate a random wallet
150
247
  * @param {Network} network - The network to use
@@ -164,7 +261,7 @@ export class EcKeyPair {
164
261
  return {
165
262
  address: wallet,
166
263
  privateKey: keyPair.toWIF(),
167
- publicKey: keyPair.publicKey.toString('hex'),
264
+ publicKey: Buffer.from(keyPair.publicKey).toString('hex'),
168
265
  };
169
266
  }
170
267
 
@@ -181,6 +278,28 @@ export class EcKeyPair {
181
278
  return !!address.toOutputScript(contractAddress, network);
182
279
  }
183
280
 
281
+ /**
282
+ * Get the legacy segwit address from a keypair
283
+ * @param {ECPairInterface} keyPair - The keypair to get the address for
284
+ * @param {Network} network - The network to use
285
+ * @returns {Address} - The legacy address
286
+ */
287
+ public static getLegacySegwitAddress(
288
+ keyPair: ECPairInterface,
289
+ network: Network = networks.bitcoin,
290
+ ): Address {
291
+ const wallet = payments.p2sh({
292
+ redeem: payments.p2wpkh({ pubkey: Buffer.from(keyPair.publicKey), network: network }),
293
+ network: network,
294
+ });
295
+
296
+ if (!wallet.address) {
297
+ throw new Error('Failed to generate wallet');
298
+ }
299
+
300
+ return wallet.address;
301
+ }
302
+
184
303
  /**
185
304
  * Get the legacy address from a keypair
186
305
  * @param {ECPairInterface} keyPair - The keypair to get the address for
@@ -191,8 +310,7 @@ export class EcKeyPair {
191
310
  keyPair: ECPairInterface,
192
311
  network: Network = networks.bitcoin,
193
312
  ): Address {
194
- const wallet = payments.p2pkh({ pubkey: keyPair.publicKey, network: network });
195
-
313
+ const wallet = payments.p2pkh({ pubkey: Buffer.from(keyPair.publicKey), network: network });
196
314
  if (!wallet.address) {
197
315
  throw new Error('Failed to generate wallet');
198
316
  }
@@ -200,6 +318,24 @@ export class EcKeyPair {
200
318
  return wallet.address;
201
319
  }
202
320
 
321
+ /**
322
+ * Get the legacy address from a keypair
323
+ * @param {ECPairInterface} keyPair - The keypair to get the address for
324
+ * @param {Network} network - The network to use
325
+ * @returns {Address} - The legacy address
326
+ */
327
+ public static getP2PKAddress(
328
+ keyPair: ECPairInterface,
329
+ network: Network = networks.bitcoin,
330
+ ): Address {
331
+ const wallet = payments.p2pk({ pubkey: Buffer.from(keyPair.publicKey), network: network });
332
+ if (!wallet.output) {
333
+ throw new Error('Failed to generate wallet');
334
+ }
335
+
336
+ return '0x' + wallet.output.toString('hex');
337
+ }
338
+
203
339
  /**
204
340
  * Generate a random keypair
205
341
  * @param {Network} network - The network to use
@@ -228,11 +364,11 @@ export class EcKeyPair {
228
364
  * @returns {Address} - The taproot address
229
365
  */
230
366
  public static getTaprootAddress(
231
- keyPair: ECPairInterface,
367
+ keyPair: ECPairInterface | Signer,
232
368
  network: Network = networks.bitcoin,
233
369
  ): Address {
234
370
  const { address } = payments.p2tr({
235
- internalPubkey: toXOnly(keyPair.publicKey),
371
+ internalPubkey: toXOnly(Buffer.from(keyPair.publicKey)),
236
372
  network: network,
237
373
  });
238
374
 
@@ -33,6 +33,12 @@ export class Wallet {
33
33
  */
34
34
  private readonly _legacy: Address;
35
35
 
36
+ /**
37
+ * Buffer public key
38
+ * @private
39
+ */
40
+ private readonly _bufferPubKey: Buffer;
41
+
36
42
  constructor(
37
43
  wallet: IWallet,
38
44
  public readonly network: Network = networks.bitcoin,
@@ -42,6 +48,8 @@ export class Wallet {
42
48
  this._p2wpkh = EcKeyPair.getP2WPKHAddress(this._keypair, this.network);
43
49
  this._p2tr = EcKeyPair.getTaprootAddress(this._keypair, this.network);
44
50
  this._legacy = EcKeyPair.getLegacyAddress(this._keypair, this.network);
51
+
52
+ this._bufferPubKey = Buffer.from(wallet.publicKey, 'hex');
45
53
  }
46
54
 
47
55
  /**
@@ -92,9 +100,9 @@ export class Wallet {
92
100
  * @returns {Buffer}
93
101
  */
94
102
  public get publicKey(): Buffer {
95
- if (!this.keypair) throw new Error('Keypair not set');
103
+ if (!this._bufferPubKey) throw new Error('Public key not set');
96
104
 
97
- return this.keypair.publicKey;
105
+ return this._bufferPubKey;
98
106
  }
99
107
 
100
108
  /**
@@ -105,7 +113,7 @@ export class Wallet {
105
113
  public get xOnly(): Buffer {
106
114
  if (!this.keypair) throw new Error('Keypair not set');
107
115
 
108
- return toXOnly(this.keypair.publicKey);
116
+ return toXOnly(this._bufferPubKey);
109
117
  }
110
118
 
111
119
  /**
@@ -31,8 +31,9 @@ export class TweakedSigner {
31
31
  * Tweak a signer
32
32
  * @param {Signer} signer - The signer to tweak
33
33
  * @param {TweakSettings} opts - The tweak settings
34
+ * @returns {ECPairInterface} - The tweaked signer
34
35
  */
35
- public static tweakSigner(signer: ECPairInterface, opts: TweakSettings = {}): Signer {
36
+ public static tweakSigner(signer: ECPairInterface, opts: TweakSettings = {}): ECPairInterface {
36
37
  let privateKey: Uint8Array | undefined = signer.privateKey;
37
38
  if (!privateKey) {
38
39
  throw new Error('Private key is required for tweaking signer!');
@@ -44,7 +45,7 @@ export class TweakedSigner {
44
45
 
45
46
  const tweakedPrivateKey = ecc.privateAdd(
46
47
  privateKey,
47
- tapTweakHash(toXOnly(signer.publicKey), opts.tweakHash),
48
+ tapTweakHash(toXOnly(Buffer.from(signer.publicKey)), opts.tweakHash),
48
49
  );
49
50
 
50
51
  if (!tweakedPrivateKey) {
@@ -11,6 +11,7 @@ import { EcKeyPair } from '../../keypair/EcKeyPair.js';
11
11
  import { AddressGenerator } from '../../generators/AddressGenerator.js';
12
12
  import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371.js';
13
13
  import { PsbtInput } from 'bip174/src/lib/interfaces.js';
14
+ import { ECPairInterface } from 'ecpair';
14
15
 
15
16
  export interface ICustomTransactionParameters extends SharedInteractionParameters {
16
17
  readonly script: (Buffer | Stack)[];
@@ -72,7 +73,7 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
72
73
  * The contract signer
73
74
  * @private
74
75
  */
75
- private readonly contractSigner: Signer;
76
+ private readonly contractSigner: Signer | ECPairInterface;
76
77
 
77
78
  /**
78
79
  * The contract salt random bytes
@@ -136,7 +137,7 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
136
137
  * @protected
137
138
  */
138
139
  protected contractSignerXOnlyPubKey(): Buffer {
139
- return toXOnly(this.contractSigner.publicKey);
140
+ return toXOnly(Buffer.from(this.contractSigner.publicKey));
140
141
  }
141
142
 
142
143
  /**
@@ -261,7 +262,7 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
261
262
  if (!this.tapLeafScript) {
262
263
  throw new Error('Tap leaf script is required');
263
264
  }
264
-
265
+
265
266
  const scriptSolution = this.witnesses;
266
267
  const witness = scriptSolution
267
268
  .concat(this.tapLeafScript.script)
@@ -277,10 +278,10 @@ export class CustomScriptTransaction extends TransactionBuilder<TransactionType.
277
278
  * @private
278
279
  */
279
280
  private getPubKeys(): Buffer[] {
280
- const pubkeys = [this.signer.publicKey];
281
+ const pubkeys = [Buffer.from(this.signer.publicKey)];
281
282
 
282
283
  if (this.contractSigner) {
283
- pubkeys.push(this.contractSigner.publicKey);
284
+ pubkeys.push(Buffer.from(this.contractSigner.publicKey));
284
285
  }
285
286
 
286
287
  return pubkeys;
@@ -13,6 +13,7 @@ import { Compressor } from '../../bytecode/Compressor.js';
13
13
  import { AddressGenerator } from '../../generators/AddressGenerator.js';
14
14
  import { Address } from '@btc-vision/bsi-binary';
15
15
  import { SharedInteractionTransaction } from './SharedInteractionTransaction.js';
16
+ import { ECPairInterface } from 'ecpair';
16
17
 
17
18
  export class DeploymentTransaction extends TransactionBuilder<TransactionType.DEPLOYMENT> {
18
19
  public static readonly MAXIMUM_CONTRACT_SIZE = 128 * 1024;
@@ -75,7 +76,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
75
76
  * The contract signer
76
77
  * @private
77
78
  */
78
- private readonly contractSigner: Signer;
79
+ private readonly contractSigner: Signer | ECPairInterface;
79
80
 
80
81
  /**
81
82
  * The contract salt random bytes
@@ -100,7 +101,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
100
101
  this.contractSigner = EcKeyPair.fromSeedKeyPair(this.contractSeed, this.network);
101
102
 
102
103
  this.deploymentGenerator = new DeploymentGenerator(
103
- this.internalPubKeyToXOnly(),
104
+ Buffer.from(this.signer.publicKey),
104
105
  this.contractSignerXOnlyPubKey(),
105
106
  this.network,
106
107
  );
@@ -145,7 +146,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
145
146
  * @protected
146
147
  */
147
148
  protected contractSignerXOnlyPubKey(): Buffer {
148
- return toXOnly(this.contractSigner.publicKey);
149
+ return toXOnly(Buffer.from(this.contractSigner.publicKey));
149
150
  }
150
151
 
151
152
  /**
@@ -323,10 +324,10 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
323
324
  * @private
324
325
  */
325
326
  private getPubKeys(): Buffer[] {
326
- const pubkeys = [this.signer.publicKey];
327
+ const pubkeys = [Buffer.from(this.signer.publicKey)];
327
328
 
328
329
  if (this.contractSigner) {
329
- pubkeys.push(this.contractSigner.publicKey);
330
+ pubkeys.push(Buffer.from(this.contractSigner.publicKey));
330
331
  }
331
332
 
332
333
  return pubkeys;
@@ -2,6 +2,7 @@ import { TransactionType } from '../enums/TransactionType.js';
2
2
  import { IFundingTransactionParameters } from '../interfaces/ITransactionParameters.js';
3
3
  import { Signer } from 'bitcoinjs-lib';
4
4
  import { TransactionBuilder } from './TransactionBuilder.js';
5
+ import { ECPairInterface } from 'ecpair';
5
6
 
6
7
  export class FundingTransaction extends TransactionBuilder<TransactionType.FUNDING> {
7
8
  public readonly type: TransactionType.FUNDING = TransactionType.FUNDING;
@@ -27,6 +28,11 @@ export class FundingTransaction extends TransactionBuilder<TransactionType.FUNDI
27
28
 
28
29
  if (this.splitInputsInto > 1) {
29
30
  this.splitInputs(this.amount);
31
+ } else if (this.isPubKeyDestination) {
32
+ this.addOutput({
33
+ value: Number(this.amount),
34
+ script: Buffer.from(this.to.slice(2), 'hex'),
35
+ });
30
36
  } else {
31
37
  this.addOutput({
32
38
  value: Number(this.amount),
@@ -45,14 +51,21 @@ export class FundingTransaction extends TransactionBuilder<TransactionType.FUNDI
45
51
  const splitAmount = amountSpent / BigInt(this.splitInputsInto);
46
52
 
47
53
  for (let i = 0; i < this.splitInputsInto; i++) {
48
- this.addOutput({
49
- value: Number(splitAmount),
50
- address: this.to,
51
- });
54
+ if (this.isPubKeyDestination) {
55
+ this.addOutput({
56
+ value: Number(splitAmount),
57
+ script: Buffer.from(this.to.slice(2), 'hex'),
58
+ });
59
+ } else {
60
+ this.addOutput({
61
+ value: Number(splitAmount),
62
+ address: this.to,
63
+ });
64
+ }
52
65
  }
53
66
  }
54
67
 
55
- protected override getSignerKey(): Signer {
68
+ protected override getSignerKey(): Signer | ECPairInterface {
56
69
  return this.signer;
57
70
  }
58
71
  }
@@ -10,6 +10,7 @@ import { Address } from '@btc-vision/bsi-binary';
10
10
  import { UTXO } from '../../utxo/interfaces/IUTXO.js';
11
11
  import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371.js';
12
12
  import { EcKeyPair } from '../../keypair/EcKeyPair.js';
13
+ import { ECPairInterface } from 'ecpair';
13
14
 
14
15
  export interface MultiSignParameters
15
16
  extends Omit<ITransactionParameters, 'priorityFee' | 'signer'> {
@@ -172,7 +173,7 @@ export class MultiSignTransaction extends TransactionBuilder<TransactionType.MUL
172
173
  */
173
174
  public static signPartial(
174
175
  psbt: Psbt,
175
- signer: Signer,
176
+ signer: Signer | ECPairInterface,
176
177
  originalInputCount: number,
177
178
  minimums: number[],
178
179
  ): {
@@ -498,7 +499,10 @@ export class MultiSignTransaction extends TransactionBuilder<TransactionType.MUL
498
499
  * @returns {Promise<boolean>}
499
500
  * @throws {Error} - If something went wrong while building the transaction
500
501
  */
501
- protected override async internalBuildTransaction(transaction: Psbt, checkPartialSigs: boolean = false): Promise<boolean> {
502
+ protected override async internalBuildTransaction(
503
+ transaction: Psbt,
504
+ checkPartialSigs: boolean = false,
505
+ ): Promise<boolean> {
502
506
  const inputs: PsbtInputExtended[] = this.getInputs();
503
507
  const outputs: PsbtOutputExtended[] = this.getOutputs();
504
508
 
@@ -50,7 +50,7 @@ export abstract class SharedInteractionTransaction<
50
50
  * Script signer for the interaction
51
51
  * @protected
52
52
  */
53
- protected readonly scriptSigner: Signer;
53
+ protected readonly scriptSigner: Signer | ECPairInterface;
54
54
 
55
55
  /**
56
56
  * Disable auto refund
@@ -73,7 +73,7 @@ export abstract class SharedInteractionTransaction<
73
73
  this.scriptSigner = this.generateKeyPairFromSeed();
74
74
 
75
75
  this.calldataGenerator = new CalldataGenerator(
76
- this.internalPubKeyToXOnly(),
76
+ Buffer.from(this.signer.publicKey),
77
77
  this.scriptSignerXOnlyPubKey(),
78
78
  this.network,
79
79
  );
@@ -113,7 +113,7 @@ export abstract class SharedInteractionTransaction<
113
113
  * @returns {Buffer} The internal pubkey as an x-only key
114
114
  */
115
115
  protected scriptSignerXOnlyPubKey(): Buffer {
116
- return toXOnly(this.scriptSigner.publicKey);
116
+ return toXOnly(Buffer.from(this.scriptSigner.publicKey));
117
117
  }
118
118
 
119
119
  /**
@@ -362,10 +362,10 @@ export abstract class SharedInteractionTransaction<
362
362
  * @returns {Buffer[]} The public keys
363
363
  */
364
364
  private getPubKeys(): Buffer[] {
365
- const pubkeys = [this.signer.publicKey];
365
+ const pubkeys = [Buffer.from(this.signer.publicKey)];
366
366
 
367
367
  if (this.scriptSigner) {
368
- pubkeys.push(this.scriptSigner.publicKey);
368
+ pubkeys.push(Buffer.from(this.scriptSigner.publicKey));
369
369
  }
370
370
 
371
371
  return pubkeys;
@@ -43,70 +43,90 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
43
43
  * @description Cost in satoshis of the transaction fee
44
44
  */
45
45
  public transactionFee: bigint = 0n;
46
+
46
47
  /**
47
48
  * @description The estimated fees of the transaction
48
49
  */
49
50
  public estimatedFees: bigint = 0n;
51
+
50
52
  /**
51
53
  * @param {ITransactionParameters} parameters - The transaction parameters
52
54
  */
53
-
54
55
  public optionalOutputs: PsbtOutputExtended[] | undefined;
56
+
55
57
  /**
56
58
  * @description The transaction itself.
57
59
  */
58
60
  protected transaction: Psbt;
61
+
59
62
  /**
60
63
  * @description Inputs to update later on.
61
64
  */
62
65
  protected readonly updateInputs: UpdateInput[] = [];
66
+
63
67
  /**
64
68
  * @description The outputs of the transaction
65
69
  */
66
70
  protected readonly outputs: PsbtOutputExtended[] = [];
71
+
67
72
  /**
68
73
  * @description Output that will be used to pay the fees
69
74
  */
70
75
  protected feeOutput: PsbtOutputExtended | null = null;
76
+
71
77
  /**
72
78
  * @description The total amount of satoshis in the inputs
73
79
  */
74
80
  protected totalInputAmount: bigint;
81
+
75
82
  /**
76
83
  * @description The signer of the transaction
77
84
  */
78
- protected readonly signer: Signer;
85
+ protected readonly signer: Signer | ECPairInterface;
86
+
79
87
  /**
80
88
  * @description The network where the transaction will be broadcasted
81
89
  */
82
90
  protected readonly network: Network;
91
+
83
92
  /**
84
93
  * @description The fee rate of the transaction
85
94
  */
86
95
  protected readonly feeRate: number;
96
+
87
97
  /**
88
98
  * @description The opnet priority fee of the transaction
89
99
  */
90
100
  protected priorityFee: bigint;
101
+
91
102
  /**
92
103
  * @description The utxos used in the transaction
93
104
  */
94
105
  protected utxos: UTXO[];
106
+
95
107
  /**
96
108
  * @description The address where the transaction is sent to
97
109
  * @protected
98
110
  */
99
111
  protected to: Address | undefined;
112
+
100
113
  /**
101
114
  * @description The address where the transaction is sent from
102
115
  * @protected
103
116
  */
104
117
  protected from: Address;
118
+
105
119
  /**
106
120
  * @description The maximum fee rate of the transaction
107
121
  */
108
122
  protected _maximumFeeRate: number = 100000000;
109
123
 
124
+ /**
125
+ * @description Is the destionation P2PK
126
+ * @protected
127
+ */
128
+ protected isPubKeyDestination: boolean;
129
+
110
130
  protected constructor(parameters: ITransactionParameters) {
111
131
  super(parameters);
112
132
 
@@ -121,13 +141,11 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
121
141
  this.utxos = parameters.utxos;
122
142
  this.to = parameters.to || undefined;
123
143
 
144
+ this.isPubKeyDestination = this.to ? this.to.startsWith('0x') : false;
145
+
124
146
  this.optionalOutputs = parameters.optionalOutputs;
125
147
 
126
- this.from = TransactionBuilder.getFrom(
127
- parameters.from,
128
- this.signer as ECPairInterface,
129
- this.network,
130
- );
148
+ this.from = TransactionBuilder.getFrom(parameters.from, this.signer, this.network);
131
149
 
132
150
  this.totalInputAmount = this.calculateTotalUTXOAmount();
133
151
 
@@ -143,7 +161,7 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
143
161
 
144
162
  public static getFrom(
145
163
  from: string | undefined,
146
- keypair: ECPairInterface,
164
+ keypair: ECPairInterface | Signer,
147
165
  network: Network,
148
166
  ): Address {
149
167
  return from || EcKeyPair.getTaprootAddress(keypair, network);
@@ -231,7 +249,11 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
231
249
  throw new Error('No UTXOs specified');
232
250
  }
233
251
 
234
- if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
252
+ if (
253
+ this.to &&
254
+ !this.isPubKeyDestination &&
255
+ !EcKeyPair.verifyContractAddress(this.to, this.network)
256
+ ) {
235
257
  throw new Error(
236
258
  'Invalid contract address. The contract address must be a taproot address.',
237
259
  );
@@ -261,7 +283,11 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
261
283
  public async generateTransactionMinimalSignatures(
262
284
  checkPartialSigs: boolean = false,
263
285
  ): Promise<void> {
264
- if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
286
+ if (
287
+ this.to &&
288
+ !this.isPubKeyDestination &&
289
+ !EcKeyPair.verifyContractAddress(this.to, this.network)
290
+ ) {
265
291
  throw new Error(
266
292
  'Invalid contract address. The contract address must be a taproot address.',
267
293
  );