@btc-vision/transaction 1.0.110 → 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 (43) hide show
  1. package/browser/_version.d.ts +1 -1
  2. package/browser/generators/Generator.d.ts +2 -0
  3. package/browser/generators/builders/DeploymentGenerator.d.ts +1 -1
  4. package/browser/index.js +1 -1
  5. package/browser/keypair/EcKeyPair.d.ts +2 -0
  6. package/browser/transaction/builders/DeploymentTransaction.d.ts +3 -0
  7. package/browser/transaction/builders/SharedInteractionTransaction.d.ts +1 -0
  8. package/browser/transaction/builders/TransactionBuilder.d.ts +1 -0
  9. package/browser/transaction/interfaces/ITransactionParameters.d.ts +1 -0
  10. package/browser/verification/TapscriptVerificator.d.ts +2 -1
  11. package/build/_version.d.ts +1 -1
  12. package/build/_version.js +1 -1
  13. package/build/generators/Generator.d.ts +2 -0
  14. package/build/generators/Generator.js +5 -0
  15. package/build/generators/builders/CalldataGenerator.js +4 -2
  16. package/build/generators/builders/DeploymentGenerator.d.ts +1 -1
  17. package/build/generators/builders/DeploymentGenerator.js +13 -7
  18. package/build/keypair/EcKeyPair.d.ts +2 -0
  19. package/build/keypair/EcKeyPair.js +17 -0
  20. package/build/transaction/builders/DeploymentTransaction.d.ts +3 -0
  21. package/build/transaction/builders/DeploymentTransaction.js +21 -6
  22. package/build/transaction/builders/FundingTransaction.js +18 -4
  23. package/build/transaction/builders/SharedInteractionTransaction.d.ts +1 -0
  24. package/build/transaction/builders/SharedInteractionTransaction.js +2 -1
  25. package/build/transaction/builders/TransactionBuilder.d.ts +1 -0
  26. package/build/transaction/builders/TransactionBuilder.js +7 -2
  27. package/build/transaction/builders/UnwrapTransaction.js +1 -1
  28. package/build/transaction/interfaces/ITransactionParameters.d.ts +1 -0
  29. package/build/verification/TapscriptVerificator.d.ts +2 -1
  30. package/build/verification/TapscriptVerificator.js +3 -3
  31. package/package.json +1 -1
  32. package/src/_version.ts +1 -1
  33. package/src/generators/Generator.ts +12 -0
  34. package/src/generators/builders/CalldataGenerator.ts +6 -3
  35. package/src/generators/builders/DeploymentGenerator.ts +21 -8
  36. package/src/keypair/EcKeyPair.ts +40 -1
  37. package/src/transaction/builders/DeploymentTransaction.ts +31 -4
  38. package/src/transaction/builders/FundingTransaction.ts +16 -4
  39. package/src/transaction/builders/SharedInteractionTransaction.ts +3 -1
  40. package/src/transaction/builders/TransactionBuilder.ts +18 -2
  41. package/src/transaction/builders/UnwrapTransaction.ts +1 -1
  42. package/src/transaction/interfaces/ITransactionParameters.ts +2 -0
  43. package/src/verification/TapscriptVerificator.ts +5 -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;
@@ -16,6 +16,7 @@ export declare class DeploymentTransaction extends TransactionBuilder<Transactio
16
16
  private deploymentGenerator;
17
17
  private readonly contractSeed;
18
18
  private readonly bytecode;
19
+ private readonly calldata?;
19
20
  private readonly contractSigner;
20
21
  private readonly randomBytes;
21
22
  constructor(parameters: IDeploymentParameters);
@@ -27,6 +28,8 @@ export declare class DeploymentTransaction extends TransactionBuilder<Transactio
27
28
  protected signInputs(transaction: Psbt): Promise<void>;
28
29
  protected generateScriptAddress(): Payment;
29
30
  protected generateTapData(): Payment;
31
+ private verifyCalldata;
32
+ private verifyBytecode;
30
33
  private getContractSeed;
31
34
  private customFinalizer;
32
35
  private getPubKeys;
@@ -7,6 +7,7 @@ import { TransactionType } from '../enums/TransactionType.js';
7
7
  import { CalldataGenerator } from '../../generators/builders/CalldataGenerator.js';
8
8
  import { SharedInteractionParameters } from '../interfaces/ITransactionParameters.js';
9
9
  export declare abstract class SharedInteractionTransaction<T extends TransactionType> extends TransactionBuilder<T> {
10
+ static readonly MAXIMUM_CALLDATA_SIZE: number;
10
11
  readonly randomBytes: Buffer;
11
12
  protected targetScriptRedeem: Payment | null;
12
13
  protected leftOverFundsScriptRedeem: Payment | null;
@@ -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;
@@ -42,5 +42,6 @@ export interface IUnwrapParameters extends Omit<SharedInteractionParameters, 'op
42
42
  }
43
43
  export interface IDeploymentParameters extends Omit<ITransactionParameters, 'to'> {
44
44
  readonly bytecode: Buffer;
45
+ readonly calldata?: Buffer;
45
46
  readonly randomBytes?: Buffer;
46
47
  }
@@ -1,10 +1,11 @@
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;
8
+ readonly calldata?: Buffer;
8
9
  readonly network?: Network;
9
10
  }
10
11
  export declare class TapscriptVerificator {
@@ -1 +1 @@
1
- export declare const version = "1.0.108";
1
+ export declare const version = "1.0.111";
package/build/_version.js CHANGED
@@ -1 +1 @@
1
- export const version = '1.0.108';
1
+ export const version = '1.0.111';
@@ -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),
@@ -2,6 +2,6 @@ import { Network } from 'bitcoinjs-lib';
2
2
  import { Generator } from '../Generator.js';
3
3
  export declare class DeploymentGenerator extends Generator {
4
4
  constructor(senderPubKey: Buffer, contractSaltPubKey: Buffer, network?: Network);
5
- compile(contractBytecode: Buffer, contractSalt: Buffer): Buffer;
5
+ compile(contractBytecode: Buffer, contractSalt: Buffer, calldata?: Buffer): Buffer;
6
6
  private getAsm;
7
7
  }
@@ -4,8 +4,8 @@ export class DeploymentGenerator extends Generator {
4
4
  constructor(senderPubKey, contractSaltPubKey, network = networks.bitcoin) {
5
5
  super(senderPubKey, contractSaltPubKey, network);
6
6
  }
7
- compile(contractBytecode, contractSalt) {
8
- const asm = this.getAsm(contractBytecode, contractSalt);
7
+ compile(contractBytecode, contractSalt, calldata) {
8
+ const asm = this.getAsm(contractBytecode, contractSalt, calldata);
9
9
  const compiled = script.compile(asm);
10
10
  const decompiled = script.decompile(compiled);
11
11
  if (!decompiled) {
@@ -13,17 +13,20 @@ export class DeploymentGenerator extends Generator {
13
13
  }
14
14
  return compiled;
15
15
  }
16
- getAsm(contractBytecode, contractSalt) {
16
+ getAsm(contractBytecode, contractSalt, calldata) {
17
17
  if (!this.contractSaltPubKey)
18
18
  throw new Error('Contract salt public key not set');
19
19
  const dataChunks = this.splitBufferIntoChunks(contractBytecode);
20
- return [
21
- this.senderPubKey,
20
+ const calldataChunks = calldata ? this.splitBufferIntoChunks(calldata) : [];
21
+ const compiledData = [
22
+ this.senderFirstByte,
23
+ opcodes.OP_TOALTSTACK,
24
+ this.xSenderPubKey,
22
25
  opcodes.OP_CHECKSIGVERIFY,
23
26
  this.contractSaltPubKey,
24
27
  opcodes.OP_CHECKSIGVERIFY,
25
28
  opcodes.OP_HASH160,
26
- crypto.hash160(this.senderPubKey),
29
+ crypto.hash160(this.xSenderPubKey),
27
30
  opcodes.OP_EQUALVERIFY,
28
31
  opcodes.OP_HASH256,
29
32
  crypto.hash256(contractSalt),
@@ -33,11 +36,14 @@ export class DeploymentGenerator extends Generator {
33
36
  opcodes.OP_NUMEQUAL,
34
37
  opcodes.OP_IF,
35
38
  Generator.MAGIC,
39
+ opcodes.OP_0,
40
+ ...calldataChunks,
36
41
  opcodes.OP_1NEGATE,
37
42
  ...dataChunks,
38
43
  opcodes.OP_ELSE,
39
44
  opcodes.OP_1,
40
45
  opcodes.OP_ENDIF,
41
- ].flat();
46
+ ];
47
+ return compiledData.flat();
42
48
  }
43
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,
@@ -16,6 +16,7 @@ export declare class DeploymentTransaction extends TransactionBuilder<Transactio
16
16
  private deploymentGenerator;
17
17
  private readonly contractSeed;
18
18
  private readonly bytecode;
19
+ private readonly calldata?;
19
20
  private readonly contractSigner;
20
21
  private readonly randomBytes;
21
22
  constructor(parameters: IDeploymentParameters);
@@ -27,6 +28,8 @@ export declare class DeploymentTransaction extends TransactionBuilder<Transactio
27
28
  protected signInputs(transaction: Psbt): Promise<void>;
28
29
  protected generateScriptAddress(): Payment;
29
30
  protected generateTapData(): Payment;
31
+ private verifyCalldata;
32
+ private verifyBytecode;
30
33
  private getContractSeed;
31
34
  private customFinalizer;
32
35
  private getPubKeys;
@@ -7,6 +7,7 @@ import { EcKeyPair } from '../../keypair/EcKeyPair.js';
7
7
  import { BitcoinUtils } from '../../utils/BitcoinUtils.js';
8
8
  import { Compressor } from '../../bytecode/Compressor.js';
9
9
  import { AddressGenerator } from '../../generators/AddressGenerator.js';
10
+ import { SharedInteractionTransaction } from './SharedInteractionTransaction.js';
10
11
  export class DeploymentTransaction extends TransactionBuilder {
11
12
  constructor(parameters) {
12
13
  super(parameters);
@@ -35,15 +36,16 @@ export class DeploymentTransaction extends TransactionBuilder {
35
36
  };
36
37
  };
37
38
  this.bytecode = Compressor.compress(parameters.bytecode);
38
- if (!this.bytecode)
39
- throw new Error('Bytecode is required');
40
- if (this.bytecode.length > DeploymentTransaction.MAXIMUM_CONTRACT_SIZE)
41
- throw new Error('Contract size overflow.');
39
+ this.verifyBytecode();
40
+ if (parameters.calldata) {
41
+ this.calldata = parameters.calldata;
42
+ this.verifyCalldata();
43
+ }
42
44
  this.randomBytes = parameters.randomBytes || BitcoinUtils.rndBytes();
43
45
  this.contractSeed = this.getContractSeed();
44
46
  this.contractSigner = EcKeyPair.fromSeedKeyPair(this.contractSeed, this.network);
45
- this.deploymentGenerator = new DeploymentGenerator(this.internalPubKeyToXOnly(), this.contractSignerXOnlyPubKey(), this.network);
46
- this.compiledTargetScript = this.deploymentGenerator.compile(this.bytecode, this.randomBytes);
47
+ this.deploymentGenerator = new DeploymentGenerator(this.signer.publicKey, this.contractSignerXOnlyPubKey(), this.network);
48
+ this.compiledTargetScript = this.deploymentGenerator.compile(this.bytecode, this.randomBytes, this.calldata);
47
49
  this.scriptTree = this.getScriptTree();
48
50
  this.internalInit();
49
51
  this._contractAddress = AddressGenerator.generatePKSH(this.contractSeed, this.network);
@@ -130,6 +132,19 @@ export class DeploymentTransaction extends TransactionBuilder {
130
132
  redeem: selectedRedeem,
131
133
  };
132
134
  }
135
+ verifyCalldata() {
136
+ if (this.calldata &&
137
+ this.calldata.length > SharedInteractionTransaction.MAXIMUM_CALLDATA_SIZE) {
138
+ throw new Error('Calldata size overflow.');
139
+ }
140
+ }
141
+ verifyBytecode() {
142
+ if (!this.bytecode)
143
+ throw new Error('Bytecode is required');
144
+ if (this.bytecode.length > DeploymentTransaction.MAXIMUM_CONTRACT_SIZE) {
145
+ throw new Error('Contract size overflow.');
146
+ }
147
+ }
133
148
  getContractSeed() {
134
149
  if (!this.bytecode) {
135
150
  throw new Error('Bytecode is required');
@@ -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() {
@@ -7,6 +7,7 @@ import { TransactionType } from '../enums/TransactionType.js';
7
7
  import { CalldataGenerator } from '../../generators/builders/CalldataGenerator.js';
8
8
  import { SharedInteractionParameters } from '../interfaces/ITransactionParameters.js';
9
9
  export declare abstract class SharedInteractionTransaction<T extends TransactionType> extends TransactionBuilder<T> {
10
+ static readonly MAXIMUM_CALLDATA_SIZE: number;
10
11
  readonly randomBytes: Buffer;
11
12
  protected targetScriptRedeem: Payment | null;
12
13
  protected leftOverFundsScriptRedeem: Payment | null;
@@ -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;
@@ -205,3 +205,4 @@ export class SharedInteractionTransaction extends TransactionBuilder {
205
205
  };
206
206
  }
207
207
  }
208
+ SharedInteractionTransaction.MAXIMUM_CALLDATA_SIZE = 1024 * 1024;
@@ -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();
@@ -42,5 +42,6 @@ export interface IUnwrapParameters extends Omit<SharedInteractionParameters, 'op
42
42
  }
43
43
  export interface IDeploymentParameters extends Omit<ITransactionParameters, 'to'> {
44
44
  readonly bytecode: Buffer;
45
+ readonly calldata?: Buffer;
45
46
  readonly randomBytes?: Buffer;
46
47
  }
@@ -1,10 +1,11 @@
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;
8
+ readonly calldata?: Buffer;
8
9
  readonly network?: Network;
9
10
  }
10
11
  export declare class TapscriptVerificator {
@@ -6,8 +6,8 @@ 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);
10
- const compiledTargetScript = scriptBuilder.compile(params.bytecode, params.originalSalt);
9
+ const scriptBuilder = new DeploymentGenerator(params.deployerPubKey, toXOnly(params.contractSaltPubKey), network);
10
+ const compiledTargetScript = scriptBuilder.compile(params.bytecode, params.originalSalt, params.calldata);
11
11
  const scriptTree = [
12
12
  {
13
13
  output: compiledTargetScript,
@@ -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.110",
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": {
package/src/_version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '1.0.108';
1
+ export const version = '1.0.111';
@@ -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);
@@ -14,10 +14,11 @@ export class DeploymentGenerator extends Generator {
14
14
  * Compile a bitcoin script representing a contract deployment
15
15
  * @param {Buffer} contractBytecode - The contract bytecode
16
16
  * @param {Buffer} contractSalt - The contract salt
17
+ * @param {Buffer} [calldata] - The calldata to be passed to the contract
17
18
  * @returns {Buffer} - The compiled script
18
19
  */
19
- public compile(contractBytecode: Buffer, contractSalt: Buffer): Buffer {
20
- const asm = this.getAsm(contractBytecode, contractSalt);
20
+ public compile(contractBytecode: Buffer, contractSalt: Buffer, calldata?: Buffer): Buffer {
21
+ const asm = this.getAsm(contractBytecode, contractSalt, calldata);
21
22
  const compiled = script.compile(asm);
22
23
 
23
24
  /**
@@ -31,20 +32,28 @@ export class DeploymentGenerator extends Generator {
31
32
  return compiled;
32
33
  }
33
34
 
34
- private getAsm(contractBytecode: Buffer, contractSalt: Buffer): (number | Buffer)[] {
35
+ private getAsm(
36
+ contractBytecode: Buffer,
37
+ contractSalt: Buffer,
38
+ calldata?: Buffer,
39
+ ): (number | Buffer)[] {
35
40
  if (!this.contractSaltPubKey) throw new Error('Contract salt public key not set');
36
41
 
37
- const dataChunks = this.splitBufferIntoChunks(contractBytecode);
42
+ const dataChunks: Buffer[][] = this.splitBufferIntoChunks(contractBytecode);
43
+ const calldataChunks: Buffer[][] = calldata ? this.splitBufferIntoChunks(calldata) : [];
38
44
 
39
- return [
40
- this.senderPubKey,
45
+ const compiledData = [
46
+ this.senderFirstByte,
47
+ opcodes.OP_TOALTSTACK,
48
+
49
+ this.xSenderPubKey,
41
50
  opcodes.OP_CHECKSIGVERIFY,
42
51
 
43
52
  this.contractSaltPubKey,
44
53
  opcodes.OP_CHECKSIGVERIFY,
45
54
 
46
55
  opcodes.OP_HASH160,
47
- crypto.hash160(this.senderPubKey),
56
+ crypto.hash160(this.xSenderPubKey),
48
57
  opcodes.OP_EQUALVERIFY,
49
58
 
50
59
  opcodes.OP_HASH256,
@@ -57,12 +66,16 @@ export class DeploymentGenerator extends Generator {
57
66
  opcodes.OP_IF,
58
67
 
59
68
  Generator.MAGIC,
69
+ opcodes.OP_0,
70
+ ...calldataChunks,
60
71
  opcodes.OP_1NEGATE,
61
72
  ...dataChunks,
62
73
 
63
74
  opcodes.OP_ELSE,
64
75
  opcodes.OP_1,
65
76
  opcodes.OP_ENDIF,
66
- ].flat();
77
+ ];
78
+
79
+ return compiledData.flat();
67
80
  }
68
81
  }