@btc-vision/transaction 1.0.111 → 1.0.112

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 (30) hide show
  1. package/browser/generators/Generator.d.ts +2 -0
  2. package/browser/index.js +1 -1
  3. package/browser/keypair/EcKeyPair.d.ts +2 -0
  4. package/browser/transaction/builders/TransactionBuilder.d.ts +1 -0
  5. package/browser/verification/TapscriptVerificator.d.ts +1 -1
  6. package/build/generators/Generator.d.ts +2 -0
  7. package/build/generators/Generator.js +5 -0
  8. package/build/generators/builders/CalldataGenerator.js +4 -2
  9. package/build/generators/builders/DeploymentGenerator.js +7 -4
  10. package/build/keypair/EcKeyPair.d.ts +2 -0
  11. package/build/keypair/EcKeyPair.js +17 -0
  12. package/build/transaction/builders/DeploymentTransaction.js +1 -1
  13. package/build/transaction/builders/FundingTransaction.js +18 -4
  14. package/build/transaction/builders/SharedInteractionTransaction.js +1 -1
  15. package/build/transaction/builders/TransactionBuilder.d.ts +1 -0
  16. package/build/transaction/builders/TransactionBuilder.js +7 -2
  17. package/build/transaction/builders/UnwrapTransaction.js +1 -1
  18. package/build/verification/TapscriptVerificator.d.ts +1 -1
  19. package/build/verification/TapscriptVerificator.js +2 -2
  20. package/package.json +1 -1
  21. package/src/generators/Generator.ts +12 -0
  22. package/src/generators/builders/CalldataGenerator.ts +6 -3
  23. package/src/generators/builders/DeploymentGenerator.ts +9 -4
  24. package/src/keypair/EcKeyPair.ts +40 -1
  25. package/src/transaction/builders/DeploymentTransaction.ts +1 -1
  26. package/src/transaction/builders/FundingTransaction.ts +16 -4
  27. package/src/transaction/builders/SharedInteractionTransaction.ts +1 -1
  28. package/src/transaction/builders/TransactionBuilder.ts +18 -2
  29. package/src/transaction/builders/UnwrapTransaction.ts +1 -1
  30. package/src/verification/TapscriptVerificator.ts +3 -3
@@ -14,7 +14,9 @@ export declare class EcKeyPair {
14
14
  static getP2WPKHAddress(keyPair: ECPairInterface, network?: Network): Address;
15
15
  static generateWallet(network?: Network): IWallet;
16
16
  static verifyContractAddress(contractAddress: Address, network?: Network): boolean;
17
+ static getLegacySegwitAddress(keyPair: ECPairInterface, network?: Network): Address;
17
18
  static getLegacyAddress(keyPair: ECPairInterface, network?: Network): Address;
19
+ static getP2PKAddress(keyPair: ECPairInterface, network?: Network): Address;
18
20
  static generateRandomKeyPair(network?: Network): ECPairInterface;
19
21
  static fromSeed(seed: Buffer, network?: Network): BIP32Interface;
20
22
  static getTaprootAddress(keyPair: ECPairInterface, network?: Network): Address;
@@ -28,6 +28,7 @@ export declare abstract class TransactionBuilder<T extends TransactionType> exte
28
28
  protected to: Address | undefined;
29
29
  protected from: Address;
30
30
  protected _maximumFeeRate: number;
31
+ protected isPubKeyDestination: boolean;
31
32
  protected constructor(parameters: ITransactionParameters);
32
33
  static getFrom(from: string | undefined, keypair: ECPairInterface, network: Network): Address;
33
34
  static witnessStackToScriptWitness(witness: Buffer[]): Buffer;
@@ -1,7 +1,7 @@
1
1
  import { Network } from 'bitcoinjs-lib';
2
2
  import { Taptree } from 'bitcoinjs-lib/src/types.js';
3
3
  export interface ContractAddressVerificationParams {
4
- readonly deployerPubKeyXOnly: Buffer;
4
+ readonly deployerPubKey: Buffer;
5
5
  readonly contractSaltPubKey: Buffer;
6
6
  readonly originalSalt: Buffer;
7
7
  readonly bytecode: Buffer;
@@ -3,9 +3,11 @@ export declare abstract class Generator {
3
3
  static readonly DATA_CHUNK_SIZE: number;
4
4
  static readonly MAGIC: Buffer;
5
5
  protected readonly senderPubKey: Buffer;
6
+ protected readonly xSenderPubKey: Buffer;
6
7
  protected readonly contractSaltPubKey?: Buffer;
7
8
  protected readonly network: Network;
8
9
  protected constructor(senderPubKey: Buffer, contractSaltPubKey?: Buffer, network?: Network);
10
+ get senderFirstByte(): Buffer;
9
11
  abstract compile(...args: unknown[]): Buffer;
10
12
  protected splitBufferIntoChunks(buffer: Buffer, chunkSize?: number): Array<Buffer[]>;
11
13
  }
@@ -1,10 +1,15 @@
1
1
  import { networks } from 'bitcoinjs-lib';
2
+ import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371.js';
2
3
  export class Generator {
3
4
  constructor(senderPubKey, contractSaltPubKey, network = networks.bitcoin) {
4
5
  this.network = networks.bitcoin;
5
6
  this.senderPubKey = senderPubKey;
6
7
  this.contractSaltPubKey = contractSaltPubKey;
7
8
  this.network = network;
9
+ this.xSenderPubKey = toXOnly(senderPubKey);
10
+ }
11
+ get senderFirstByte() {
12
+ return Buffer.from([this.senderPubKey[0], 0, 0, 0]);
8
13
  }
9
14
  splitBufferIntoChunks(buffer, chunkSize = Generator.DATA_CHUNK_SIZE) {
10
15
  const chunks = [];
@@ -32,12 +32,14 @@ export class CalldataGenerator extends Generator {
32
32
  if (!dataChunks.length)
33
33
  throw new Error('No data chunks found');
34
34
  let compiledData = [
35
- this.senderPubKey,
35
+ this.senderFirstByte,
36
+ opcodes.OP_TOALTSTACK,
37
+ this.xSenderPubKey,
36
38
  opcodes.OP_CHECKSIGVERIFY,
37
39
  this.contractSaltPubKey,
38
40
  opcodes.OP_CHECKSIGVERIFY,
39
41
  opcodes.OP_HASH160,
40
- crypto.hash160(this.senderPubKey),
42
+ crypto.hash160(this.xSenderPubKey),
41
43
  opcodes.OP_EQUALVERIFY,
42
44
  opcodes.OP_HASH160,
43
45
  crypto.hash160(contractSecret),
@@ -18,13 +18,15 @@ export class DeploymentGenerator extends Generator {
18
18
  throw new Error('Contract salt public key not set');
19
19
  const dataChunks = this.splitBufferIntoChunks(contractBytecode);
20
20
  const calldataChunks = calldata ? this.splitBufferIntoChunks(calldata) : [];
21
- return [
22
- this.senderPubKey,
21
+ const compiledData = [
22
+ this.senderFirstByte,
23
+ opcodes.OP_TOALTSTACK,
24
+ this.xSenderPubKey,
23
25
  opcodes.OP_CHECKSIGVERIFY,
24
26
  this.contractSaltPubKey,
25
27
  opcodes.OP_CHECKSIGVERIFY,
26
28
  opcodes.OP_HASH160,
27
- crypto.hash160(this.senderPubKey),
29
+ crypto.hash160(this.xSenderPubKey),
28
30
  opcodes.OP_EQUALVERIFY,
29
31
  opcodes.OP_HASH256,
30
32
  crypto.hash256(contractSalt),
@@ -41,6 +43,7 @@ export class DeploymentGenerator extends Generator {
41
43
  opcodes.OP_ELSE,
42
44
  opcodes.OP_1,
43
45
  opcodes.OP_ENDIF,
44
- ].flat();
46
+ ];
47
+ return compiledData.flat();
45
48
  }
46
49
  }
@@ -14,7 +14,9 @@ export declare class EcKeyPair {
14
14
  static getP2WPKHAddress(keyPair: ECPairInterface, network?: Network): Address;
15
15
  static generateWallet(network?: Network): IWallet;
16
16
  static verifyContractAddress(contractAddress: Address, network?: Network): boolean;
17
+ static getLegacySegwitAddress(keyPair: ECPairInterface, network?: Network): Address;
17
18
  static getLegacyAddress(keyPair: ECPairInterface, network?: Network): Address;
19
+ static getP2PKAddress(keyPair: ECPairInterface, network?: Network): Address;
18
20
  static generateRandomKeyPair(network?: Network): ECPairInterface;
19
21
  static fromSeed(seed: Buffer, network?: Network): BIP32Interface;
20
22
  static getTaprootAddress(keyPair: ECPairInterface, network?: Network): Address;
@@ -67,6 +67,16 @@ export class EcKeyPair {
67
67
  static verifyContractAddress(contractAddress, network = networks.bitcoin) {
68
68
  return !!address.toOutputScript(contractAddress, network);
69
69
  }
70
+ static getLegacySegwitAddress(keyPair, network = networks.bitcoin) {
71
+ const wallet = payments.p2sh({
72
+ redeem: payments.p2wpkh({ pubkey: keyPair.publicKey, network: network }),
73
+ network: network,
74
+ });
75
+ if (!wallet.address) {
76
+ throw new Error('Failed to generate wallet');
77
+ }
78
+ return wallet.address;
79
+ }
70
80
  static getLegacyAddress(keyPair, network = networks.bitcoin) {
71
81
  const wallet = payments.p2pkh({ pubkey: keyPair.publicKey, network: network });
72
82
  if (!wallet.address) {
@@ -74,6 +84,13 @@ export class EcKeyPair {
74
84
  }
75
85
  return wallet.address;
76
86
  }
87
+ static getP2PKAddress(keyPair, network = networks.bitcoin) {
88
+ const wallet = payments.p2pk({ pubkey: keyPair.publicKey, network: network });
89
+ if (!wallet.output) {
90
+ throw new Error('Failed to generate wallet');
91
+ }
92
+ return '0x' + wallet.output.toString('hex');
93
+ }
77
94
  static generateRandomKeyPair(network = networks.bitcoin) {
78
95
  return this.ECPair.makeRandom({
79
96
  network: network,
@@ -44,7 +44,7 @@ export class DeploymentTransaction extends TransactionBuilder {
44
44
  this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
45
45
  this.contractSeed = this.getContractSeed();
46
46
  this.contractSigner = EcKeyPair.fromSeedKeyPair(this.contractSeed, this.network);
47
- this.deploymentGenerator = new DeploymentGenerator(this.internalPubKeyToXOnly(), this.contractSignerXOnlyPubKey(), this.network);
47
+ this.deploymentGenerator = new DeploymentGenerator(this.signer.publicKey, this.contractSignerXOnlyPubKey(), this.network);
48
48
  this.compiledTargetScript = this.deploymentGenerator.compile(this.bytecode, this.randomBytes, this.calldata);
49
49
  this.scriptTree = this.getScriptTree();
50
50
  this.internalInit();
@@ -16,6 +16,12 @@ export class FundingTransaction extends TransactionBuilder {
16
16
  if (this.splitInputsInto > 1) {
17
17
  this.splitInputs(this.amount);
18
18
  }
19
+ else if (this.isPubKeyDestination) {
20
+ this.addOutput({
21
+ value: Number(this.amount),
22
+ script: Buffer.from(this.to.slice(2), 'hex'),
23
+ });
24
+ }
19
25
  else {
20
26
  this.addOutput({
21
27
  value: Number(this.amount),
@@ -30,10 +36,18 @@ export class FundingTransaction extends TransactionBuilder {
30
36
  }
31
37
  const splitAmount = amountSpent / BigInt(this.splitInputsInto);
32
38
  for (let i = 0; i < this.splitInputsInto; i++) {
33
- this.addOutput({
34
- value: Number(splitAmount),
35
- address: this.to,
36
- });
39
+ if (this.isPubKeyDestination) {
40
+ this.addOutput({
41
+ value: Number(splitAmount),
42
+ script: Buffer.from(this.to.slice(2), 'hex'),
43
+ });
44
+ }
45
+ else {
46
+ this.addOutput({
47
+ value: Number(splitAmount),
48
+ address: this.to,
49
+ });
50
+ }
37
51
  }
38
52
  }
39
53
  getSignerKey() {
@@ -32,7 +32,7 @@ export class SharedInteractionTransaction extends TransactionBuilder {
32
32
  this.calldata = Compressor.compress(parameters.calldata);
33
33
  this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
34
34
  this.scriptSigner = this.generateKeyPairFromSeed();
35
- this.calldataGenerator = new CalldataGenerator(this.internalPubKeyToXOnly(), this.scriptSignerXOnlyPubKey(), this.network);
35
+ this.calldataGenerator = new CalldataGenerator(this.signer.publicKey, this.scriptSignerXOnlyPubKey(), this.network);
36
36
  }
37
37
  getContractSecret() {
38
38
  return this.contractSecret;
@@ -28,6 +28,7 @@ export declare abstract class TransactionBuilder<T extends TransactionType> exte
28
28
  protected to: Address | undefined;
29
29
  protected from: Address;
30
30
  protected _maximumFeeRate: number;
31
+ protected isPubKeyDestination: boolean;
31
32
  protected constructor(parameters: ITransactionParameters);
32
33
  static getFrom(from: string | undefined, keypair: ECPairInterface, network: Network): Address;
33
34
  static witnessStackToScriptWitness(witness: Buffer[]): Buffer;
@@ -25,6 +25,7 @@ export class TransactionBuilder extends TweakedTransaction {
25
25
  this.priorityFee = parameters.priorityFee ?? 0n;
26
26
  this.utxos = parameters.utxos;
27
27
  this.to = parameters.to || undefined;
28
+ this.isPubKeyDestination = this.to ? this.to.startsWith('0x') : false;
28
29
  this.optionalOutputs = parameters.optionalOutputs;
29
30
  this.from = TransactionBuilder.getFrom(parameters.from, this.signer, this.network);
30
31
  this.totalInputAmount = this.calculateTotalUTXOAmount();
@@ -87,7 +88,9 @@ export class TransactionBuilder extends TweakedTransaction {
87
88
  if (!this.utxos.length) {
88
89
  throw new Error('No UTXOs specified');
89
90
  }
90
- if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
91
+ if (this.to &&
92
+ !this.isPubKeyDestination &&
93
+ !EcKeyPair.verifyContractAddress(this.to, this.network)) {
91
94
  throw new Error('Invalid contract address. The contract address must be a taproot address.');
92
95
  }
93
96
  if (this.signed)
@@ -104,7 +107,9 @@ export class TransactionBuilder extends TweakedTransaction {
104
107
  throw new Error('Could not sign transaction');
105
108
  }
106
109
  async generateTransactionMinimalSignatures(checkPartialSigs = false) {
107
- if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
110
+ if (this.to &&
111
+ !this.isPubKeyDestination &&
112
+ !EcKeyPair.verifyContractAddress(this.to, this.network)) {
108
113
  throw new Error('Invalid contract address. The contract address must be a taproot address.');
109
114
  }
110
115
  await this.buildTransaction();
@@ -33,7 +33,7 @@ export class UnwrapTransaction extends SharedInteractionTransaction {
33
33
  this.estimatedFeeLoss = UnwrapTransaction.preEstimateTaprootTransactionFees(BigInt(this.feeRate), this.calculateNumInputs(this.vaultUTXOs), 2n, this.calculateNumSignatures(this.vaultUTXOs), 65n, this.calculateNumEmptyWitnesses(this.vaultUTXOs));
34
34
  this.amount = parameters.amount;
35
35
  this.contractSecret = this.generateSecret();
36
- this.calldataGenerator = new CalldataGenerator(toXOnly(this.signer.publicKey), this.scriptSignerXOnlyPubKey(), this.network);
36
+ this.calldataGenerator = new CalldataGenerator(this.signer.publicKey, this.scriptSignerXOnlyPubKey(), this.network);
37
37
  this.compiledTargetScript = this.calldataGenerator.compile(this.calldata, this.contractSecret, [Features.UNWRAP]);
38
38
  this.scriptTree = this.getScriptTree();
39
39
  this.internalInit();
@@ -1,7 +1,7 @@
1
1
  import { Network } from 'bitcoinjs-lib';
2
2
  import { Taptree } from 'bitcoinjs-lib/src/types.js';
3
3
  export interface ContractAddressVerificationParams {
4
- readonly deployerPubKeyXOnly: Buffer;
4
+ readonly deployerPubKey: Buffer;
5
5
  readonly contractSaltPubKey: Buffer;
6
6
  readonly originalSalt: Buffer;
7
7
  readonly bytecode: Buffer;
@@ -6,7 +6,7 @@ import { AddressGenerator } from '../generators/AddressGenerator.js';
6
6
  export class TapscriptVerificator {
7
7
  static getContractAddress(params) {
8
8
  const network = params.network || networks.bitcoin;
9
- const scriptBuilder = new DeploymentGenerator(params.deployerPubKeyXOnly, toXOnly(params.contractSaltPubKey), network);
9
+ const scriptBuilder = new DeploymentGenerator(params.deployerPubKey, toXOnly(params.contractSaltPubKey), network);
10
10
  const compiledTargetScript = scriptBuilder.compile(params.bytecode, params.originalSalt, params.calldata);
11
11
  const scriptTree = [
12
12
  {
@@ -32,7 +32,7 @@ export class TapscriptVerificator {
32
32
  static generateAddressFromScript(params, scriptTree) {
33
33
  const network = params.network || networks.bitcoin;
34
34
  const transactionData = {
35
- internalPubkey: params.deployerPubKeyXOnly,
35
+ internalPubkey: toXOnly(params.deployerPubKey),
36
36
  network: network,
37
37
  scriptTree: scriptTree,
38
38
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@btc-vision/transaction",
3
3
  "type": "module",
4
- "version": "1.0.111",
4
+ "version": "1.0.112",
5
5
  "author": "BlobMaster41",
6
6
  "description": "OPNet transaction library allows you to create and sign transactions for the OPNet network.",
7
7
  "engines": {
@@ -1,4 +1,5 @@
1
1
  import { Network, networks } from 'bitcoinjs-lib';
2
+ import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371.js';
2
3
 
3
4
  /** Bitcoin Script Generator */
4
5
  export abstract class Generator {
@@ -18,6 +19,12 @@ export abstract class Generator {
18
19
  */
19
20
  protected readonly senderPubKey: Buffer;
20
21
 
22
+ /**
23
+ * The public key of the sender
24
+ * @protected
25
+ */
26
+ protected readonly xSenderPubKey: Buffer;
27
+
21
28
  /**
22
29
  * The public key of the contract salt
23
30
  * @protected
@@ -38,6 +45,11 @@ export abstract class Generator {
38
45
  this.senderPubKey = senderPubKey;
39
46
  this.contractSaltPubKey = contractSaltPubKey;
40
47
  this.network = network;
48
+ this.xSenderPubKey = toXOnly(senderPubKey);
49
+ }
50
+
51
+ public get senderFirstByte(): Buffer {
52
+ return Buffer.from([this.senderPubKey[0], 0, 0, 0]);
41
53
  }
42
54
 
43
55
  /**
@@ -75,14 +75,17 @@ export class CalldataGenerator extends Generator {
75
75
  if (!dataChunks.length) throw new Error('No data chunks found');
76
76
 
77
77
  let compiledData = [
78
- this.senderPubKey,
78
+ this.senderFirstByte,
79
+ opcodes.OP_TOALTSTACK,
80
+
81
+ this.xSenderPubKey,
79
82
  opcodes.OP_CHECKSIGVERIFY,
80
83
 
81
84
  this.contractSaltPubKey,
82
85
  opcodes.OP_CHECKSIGVERIFY,
83
86
 
84
87
  opcodes.OP_HASH160,
85
- crypto.hash160(this.senderPubKey),
88
+ crypto.hash160(this.xSenderPubKey),
86
89
  opcodes.OP_EQUALVERIFY,
87
90
 
88
91
  opcodes.OP_HASH160,
@@ -96,7 +99,7 @@ export class CalldataGenerator extends Generator {
96
99
 
97
100
  Generator.MAGIC,
98
101
  ];
99
-
102
+
100
103
  // write pub keys, when requested.
101
104
  if (vaultPublicKeys.length > 0) {
102
105
  const pubKeyBuffer = CalldataGenerator.getPubKeyAsBuffer(vaultPublicKeys, this.network);
@@ -42,15 +42,18 @@ export class DeploymentGenerator extends Generator {
42
42
  const dataChunks: Buffer[][] = this.splitBufferIntoChunks(contractBytecode);
43
43
  const calldataChunks: Buffer[][] = calldata ? this.splitBufferIntoChunks(calldata) : [];
44
44
 
45
- return [
46
- this.senderPubKey,
45
+ const compiledData = [
46
+ this.senderFirstByte,
47
+ opcodes.OP_TOALTSTACK,
48
+
49
+ this.xSenderPubKey,
47
50
  opcodes.OP_CHECKSIGVERIFY,
48
51
 
49
52
  this.contractSaltPubKey,
50
53
  opcodes.OP_CHECKSIGVERIFY,
51
54
 
52
55
  opcodes.OP_HASH160,
53
- crypto.hash160(this.senderPubKey),
56
+ crypto.hash160(this.xSenderPubKey),
54
57
  opcodes.OP_EQUALVERIFY,
55
58
 
56
59
  opcodes.OP_HASH256,
@@ -71,6 +74,8 @@ export class DeploymentGenerator extends Generator {
71
74
  opcodes.OP_ELSE,
72
75
  opcodes.OP_1,
73
76
  opcodes.OP_ENDIF,
74
- ].flat();
77
+ ];
78
+
79
+ return compiledData.flat();
75
80
  }
76
81
  }
@@ -181,6 +181,28 @@ export class EcKeyPair {
181
181
  return !!address.toOutputScript(contractAddress, network);
182
182
  }
183
183
 
184
+ /**
185
+ * Get the legacy segwit address from a keypair
186
+ * @param {ECPairInterface} keyPair - The keypair to get the address for
187
+ * @param {Network} network - The network to use
188
+ * @returns {Address} - The legacy address
189
+ */
190
+ public static getLegacySegwitAddress(
191
+ keyPair: ECPairInterface,
192
+ network: Network = networks.bitcoin,
193
+ ): Address {
194
+ const wallet = payments.p2sh({
195
+ redeem: payments.p2wpkh({ pubkey: keyPair.publicKey, network: network }),
196
+ network: network,
197
+ });
198
+
199
+ if (!wallet.address) {
200
+ throw new Error('Failed to generate wallet');
201
+ }
202
+
203
+ return wallet.address;
204
+ }
205
+
184
206
  /**
185
207
  * Get the legacy address from a keypair
186
208
  * @param {ECPairInterface} keyPair - The keypair to get the address for
@@ -192,7 +214,6 @@ export class EcKeyPair {
192
214
  network: Network = networks.bitcoin,
193
215
  ): Address {
194
216
  const wallet = payments.p2pkh({ pubkey: keyPair.publicKey, network: network });
195
-
196
217
  if (!wallet.address) {
197
218
  throw new Error('Failed to generate wallet');
198
219
  }
@@ -200,6 +221,24 @@ export class EcKeyPair {
200
221
  return wallet.address;
201
222
  }
202
223
 
224
+ /**
225
+ * Get the legacy address from a keypair
226
+ * @param {ECPairInterface} keyPair - The keypair to get the address for
227
+ * @param {Network} network - The network to use
228
+ * @returns {Address} - The legacy address
229
+ */
230
+ public static getP2PKAddress(
231
+ keyPair: ECPairInterface,
232
+ network: Network = networks.bitcoin,
233
+ ): Address {
234
+ const wallet = payments.p2pk({ pubkey: keyPair.publicKey, network: network });
235
+ if (!wallet.output) {
236
+ throw new Error('Failed to generate wallet');
237
+ }
238
+
239
+ return '0x' + wallet.output.toString('hex');
240
+ }
241
+
203
242
  /**
204
243
  * Generate a random keypair
205
244
  * @param {Network} network - The network to use
@@ -100,7 +100,7 @@ export class DeploymentTransaction extends TransactionBuilder<TransactionType.DE
100
100
  this.contractSigner = EcKeyPair.fromSeedKeyPair(this.contractSeed, this.network);
101
101
 
102
102
  this.deploymentGenerator = new DeploymentGenerator(
103
- this.internalPubKeyToXOnly(),
103
+ this.signer.publicKey,
104
104
  this.contractSignerXOnlyPubKey(),
105
105
  this.network,
106
106
  );
@@ -27,6 +27,11 @@ export class FundingTransaction extends TransactionBuilder<TransactionType.FUNDI
27
27
 
28
28
  if (this.splitInputsInto > 1) {
29
29
  this.splitInputs(this.amount);
30
+ } else if (this.isPubKeyDestination) {
31
+ this.addOutput({
32
+ value: Number(this.amount),
33
+ script: Buffer.from(this.to.slice(2), 'hex'),
34
+ });
30
35
  } else {
31
36
  this.addOutput({
32
37
  value: Number(this.amount),
@@ -45,10 +50,17 @@ export class FundingTransaction extends TransactionBuilder<TransactionType.FUNDI
45
50
  const splitAmount = amountSpent / BigInt(this.splitInputsInto);
46
51
 
47
52
  for (let i = 0; i < this.splitInputsInto; i++) {
48
- this.addOutput({
49
- value: Number(splitAmount),
50
- address: this.to,
51
- });
53
+ if (this.isPubKeyDestination) {
54
+ this.addOutput({
55
+ value: Number(splitAmount),
56
+ script: Buffer.from(this.to.slice(2), 'hex'),
57
+ });
58
+ } else {
59
+ this.addOutput({
60
+ value: Number(splitAmount),
61
+ address: this.to,
62
+ });
63
+ }
52
64
  }
53
65
  }
54
66
 
@@ -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
+ this.signer.publicKey,
77
77
  this.scriptSignerXOnlyPubKey(),
78
78
  this.network,
79
79
  );
@@ -107,6 +107,12 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
107
107
  */
108
108
  protected _maximumFeeRate: number = 100000000;
109
109
 
110
+ /**
111
+ * @description Is the destionation P2PK
112
+ * @protected
113
+ */
114
+ protected isPubKeyDestination: boolean;
115
+
110
116
  protected constructor(parameters: ITransactionParameters) {
111
117
  super(parameters);
112
118
 
@@ -121,6 +127,8 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
121
127
  this.utxos = parameters.utxos;
122
128
  this.to = parameters.to || undefined;
123
129
 
130
+ this.isPubKeyDestination = this.to ? this.to.startsWith('0x') : false;
131
+
124
132
  this.optionalOutputs = parameters.optionalOutputs;
125
133
 
126
134
  this.from = TransactionBuilder.getFrom(
@@ -231,7 +239,11 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
231
239
  throw new Error('No UTXOs specified');
232
240
  }
233
241
 
234
- if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
242
+ if (
243
+ this.to &&
244
+ !this.isPubKeyDestination &&
245
+ !EcKeyPair.verifyContractAddress(this.to, this.network)
246
+ ) {
235
247
  throw new Error(
236
248
  'Invalid contract address. The contract address must be a taproot address.',
237
249
  );
@@ -261,7 +273,11 @@ export abstract class TransactionBuilder<T extends TransactionType> extends Twea
261
273
  public async generateTransactionMinimalSignatures(
262
274
  checkPartialSigs: boolean = false,
263
275
  ): Promise<void> {
264
- if (this.to && !EcKeyPair.verifyContractAddress(this.to, this.network)) {
276
+ if (
277
+ this.to &&
278
+ !this.isPubKeyDestination &&
279
+ !EcKeyPair.verifyContractAddress(this.to, this.network)
280
+ ) {
265
281
  throw new Error(
266
282
  'Invalid contract address. The contract address must be a taproot address.',
267
283
  );
@@ -109,7 +109,7 @@ export class UnwrapTransaction extends SharedInteractionTransaction<TransactionT
109
109
  this.contractSecret = this.generateSecret();
110
110
 
111
111
  this.calldataGenerator = new CalldataGenerator(
112
- toXOnly(this.signer.publicKey),
112
+ this.signer.publicKey,
113
113
  this.scriptSignerXOnlyPubKey(),
114
114
  this.network,
115
115
  );
@@ -6,7 +6,7 @@ import { TransactionBuilder } from '../transaction/builders/TransactionBuilder.j
6
6
  import { AddressGenerator } from '../generators/AddressGenerator.js';
7
7
 
8
8
  export interface ContractAddressVerificationParams {
9
- readonly deployerPubKeyXOnly: Buffer;
9
+ readonly deployerPubKey: Buffer;
10
10
  readonly contractSaltPubKey: Buffer;
11
11
  readonly originalSalt: Buffer;
12
12
  readonly bytecode: Buffer;
@@ -22,7 +22,7 @@ export class TapscriptVerificator {
22
22
  ): string | undefined {
23
23
  const network = params.network || networks.bitcoin;
24
24
  const scriptBuilder: DeploymentGenerator = new DeploymentGenerator(
25
- params.deployerPubKeyXOnly,
25
+ params.deployerPubKey,
26
26
  toXOnly(params.contractSaltPubKey),
27
27
  network,
28
28
  );
@@ -80,7 +80,7 @@ export class TapscriptVerificator {
80
80
  const network = params.network || networks.bitcoin;
81
81
 
82
82
  const transactionData: Payment = {
83
- internalPubkey: params.deployerPubKeyXOnly,
83
+ internalPubkey: toXOnly(params.deployerPubKey),
84
84
  network: network,
85
85
  scriptTree: scriptTree,
86
86
  };