@btc-vision/transaction 1.0.117 → 1.0.119

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 (39) hide show
  1. package/browser/_version.d.ts +1 -1
  2. package/browser/deterministic/Map.d.ts +1 -0
  3. package/browser/event/NetEvent.d.ts +3 -3
  4. package/browser/generators/builders/LegacyCalldataGenerator.d.ts +8 -0
  5. package/browser/index.js +1 -1
  6. package/browser/keypair/Address.d.ts +1 -0
  7. package/browser/keypair/AddressVerificator.d.ts +2 -3
  8. package/browser/opnet.d.ts +1 -0
  9. package/browser/transaction/shared/TweakedTransaction.d.ts +9 -0
  10. package/browser/utxo/interfaces/IUTXO.d.ts +3 -0
  11. package/build/_version.d.ts +1 -1
  12. package/build/_version.js +1 -1
  13. package/build/deterministic/Map.d.ts +1 -0
  14. package/build/deterministic/Map.js +7 -0
  15. package/build/event/NetEvent.d.ts +3 -3
  16. package/build/event/NetEvent.js +3 -3
  17. package/build/generators/builders/LegacyCalldataGenerator.d.ts +8 -0
  18. package/build/generators/builders/LegacyCalldataGenerator.js +75 -0
  19. package/build/keypair/Address.d.ts +1 -0
  20. package/build/keypair/Address.js +3 -0
  21. package/build/keypair/AddressVerificator.d.ts +2 -3
  22. package/build/keypair/AddressVerificator.js +16 -9
  23. package/build/opnet.d.ts +1 -0
  24. package/build/opnet.js +1 -0
  25. package/build/transaction/builders/TransactionBuilder.js +1 -1
  26. package/build/transaction/shared/TweakedTransaction.d.ts +9 -0
  27. package/build/transaction/shared/TweakedTransaction.js +93 -3
  28. package/build/utxo/interfaces/IUTXO.d.ts +3 -0
  29. package/package.json +1 -1
  30. package/src/_version.ts +1 -1
  31. package/src/deterministic/Map.ts +8 -0
  32. package/src/event/NetEvent.ts +2 -2
  33. package/src/generators/builders/LegacyCalldataGenerator.ts +141 -0
  34. package/src/keypair/Address.ts +8 -0
  35. package/src/keypair/AddressVerificator.ts +25 -12
  36. package/src/opnet.ts +1 -0
  37. package/src/transaction/builders/TransactionBuilder.ts +1 -1
  38. package/src/transaction/shared/TweakedTransaction.ts +157 -2
  39. package/src/utxo/interfaces/IUTXO.ts +3 -0
@@ -11,6 +11,7 @@ export declare class Address extends Uint8Array {
11
11
  static fromString(pubKey: string): Address;
12
12
  static wrap(bytes: ArrayLike<number>): Address;
13
13
  toHex(): string;
14
+ toBuffer(): Buffer;
14
15
  equals(a: Address): boolean;
15
16
  lessThan(a: Address): boolean;
16
17
  greaterThan(a: Address): boolean;
@@ -1,8 +1,6 @@
1
1
  import { Network } from 'bitcoinjs-lib';
2
2
  export declare enum AddressTypes {
3
3
  P2PKH = "P2PKH",
4
- P2SH = "P2SH",
5
- P2SH_P2WPKH = "P2SH-P2WPKH",
6
4
  P2SH_OR_P2SH_P2WPKH = "P2SH_OR_P2SH-P2WPKH",
7
5
  P2PK = "P2PK",
8
6
  P2TR = "P2TR",
@@ -13,5 +11,6 @@ export declare class AddressVerificator {
13
11
  static isP2WPKHAddress(inAddress: string, network: Network): boolean;
14
12
  static isP2PKHOrP2SH(addy: string, network: Network): boolean;
15
13
  static isValidPublicKey(input: string, network: Network): boolean;
16
- static validateBitcoinAddress(addy: string, network: Network): AddressTypes | null;
14
+ static requireRedeemScript(addy: string, network: Network): boolean;
15
+ static detectAddressType(addy: string, network: Network): AddressTypes | null;
17
16
  }
@@ -2,6 +2,7 @@ export { version } from './_version.js';
2
2
  export * from './bytecode/Compressor.js';
3
3
  export * from './generators/Generator.js';
4
4
  export * from './generators/builders/CalldataGenerator.js';
5
+ export * from './generators/builders/LegacyCalldataGenerator.js';
5
6
  export * from './generators/builders/DeploymentGenerator.js';
6
7
  export * from './generators/builders/CustomGenerator.js';
7
8
  export * from './generators/builders/MultiSignGenerator.js';
@@ -54,5 +54,14 @@ export declare abstract class TweakedTransaction extends Logger {
54
54
  protected internalInit(): void;
55
55
  protected tweakSigner(): void;
56
56
  protected getTweakedSigner(useTweakedHash?: boolean, signer?: Signer | ECPairInterface): ECPairInterface | undefined;
57
+ protected generateP2SHRedeemScript(customWitnessScript: Buffer): Buffer | undefined;
58
+ protected generateP2SHRedeemScriptLegacy(inputAddr: string): {
59
+ redeemScript: Buffer;
60
+ outputScript: Buffer;
61
+ } | undefined;
57
62
  protected generatePsbtInputExtended(utxo: UTXO, i: number): PsbtInputExtended;
63
+ protected customFinalizerP2SH: (inputIndex: number, input: PsbtInput, scriptA: Buffer, isSegwit: boolean, isP2SH: boolean, isP2WSH: boolean) => {
64
+ finalScriptSig: Buffer | undefined;
65
+ finalScriptWitness: Buffer | undefined;
66
+ };
58
67
  }
@@ -4,6 +4,9 @@ export interface UTXO {
4
4
  readonly outputIndex: number;
5
5
  readonly value: bigint;
6
6
  readonly scriptPubKey: ScriptPubKey;
7
+ redeemScript?: string | Buffer;
8
+ witnessScript?: string | Buffer;
9
+ nonWitnessUtxo?: string | Buffer;
7
10
  }
8
11
  export interface FetchUTXOParams {
9
12
  readonly address: string;
@@ -1 +1 @@
1
- export declare const version = "1.0.117";
1
+ export declare const version = "1.0.119";
package/build/_version.js CHANGED
@@ -1 +1 @@
1
- export const version = '1.0.117';
1
+ export const version = '1.0.119';
@@ -5,6 +5,7 @@ export declare class Map<K, V> {
5
5
  get size(): i32;
6
6
  keys(): K[];
7
7
  values(): V[];
8
+ entires(): [K, V][];
8
9
  set(key: K, value: V): void;
9
10
  indexOf(key: K): i32;
10
11
  get(key: K): V | undefined;
@@ -12,6 +12,13 @@ export class Map {
12
12
  values() {
13
13
  return this._values;
14
14
  }
15
+ entires() {
16
+ const result = [];
17
+ for (let i = 0; i < this._keys.length; i++) {
18
+ result.push([this._keys[i], this._values[i]]);
19
+ }
20
+ return result;
21
+ }
15
22
  set(key, value) {
16
23
  const index = this.indexOf(key);
17
24
  if (index == -1) {
@@ -1,5 +1,5 @@
1
1
  export declare class NetEvent {
2
- readonly eventType: string;
3
- readonly eventData: Uint8Array;
4
- constructor(eventType: string, eventData: Uint8Array);
2
+ readonly type: string;
3
+ readonly data: Uint8Array;
4
+ constructor(type: string, data: Uint8Array);
5
5
  }
@@ -1,6 +1,6 @@
1
1
  export class NetEvent {
2
- constructor(eventType, eventData) {
3
- this.eventType = eventType;
4
- this.eventData = eventData;
2
+ constructor(type, data) {
3
+ this.type = type;
4
+ this.data = data;
5
5
  }
6
6
  }
@@ -0,0 +1,8 @@
1
+ import { Network } from 'bitcoinjs-lib';
2
+ import { Features } from '../Features.js';
3
+ import { Generator } from '../Generator.js';
4
+ export declare class LegacyCalldataGenerator extends Generator {
5
+ constructor(senderPubKey: Buffer, network?: Network);
6
+ static getPubKeyAsBuffer(witnessKeys: Buffer[], network: Network): Buffer;
7
+ compile(calldata: Buffer, contractSecret: Buffer, features?: Features[], vaultPublicKeys?: Buffer[], minimumSignatures?: number): Buffer;
8
+ }
@@ -0,0 +1,75 @@
1
+ import { networks, opcodes, script } from 'bitcoinjs-lib';
2
+ import { Compressor } from '../../bytecode/Compressor.js';
3
+ import { EcKeyPair } from '../../keypair/EcKeyPair.js';
4
+ import { FeatureOpCodes } from '../Features.js';
5
+ import { Generator } from '../Generator.js';
6
+ export class LegacyCalldataGenerator extends Generator {
7
+ constructor(senderPubKey, network = networks.bitcoin) {
8
+ super(senderPubKey, Buffer.alloc(0), network);
9
+ }
10
+ static getPubKeyAsBuffer(witnessKeys, network) {
11
+ let finalBuffer = Buffer.alloc(0);
12
+ for (const pubKey of witnessKeys) {
13
+ const key = EcKeyPair.fromPublicKey(pubKey, network);
14
+ if (!key.compressed) {
15
+ throw new Error('Public key must be compressed');
16
+ }
17
+ if (pubKey.byteLength !== 33) {
18
+ throw new Error(`Public key must be 33 bytes, got ${pubKey.byteLength} bytes.`);
19
+ }
20
+ finalBuffer = Buffer.concat([finalBuffer, pubKey]);
21
+ }
22
+ const compressed = Compressor.compress(finalBuffer);
23
+ if (compressed.byteLength >= finalBuffer.byteLength) {
24
+ return finalBuffer;
25
+ }
26
+ return compressed;
27
+ }
28
+ compile(calldata, contractSecret, features = [], vaultPublicKeys = [], minimumSignatures = 0) {
29
+ const dataChunks = this.splitBufferIntoChunks(calldata);
30
+ if (!dataChunks.length)
31
+ throw new Error('No data chunks found');
32
+ let compiledData = [
33
+ this.senderPubKey,
34
+ opcodes.OP_CHECKSIGVERIFY,
35
+ contractSecret,
36
+ opcodes.OP_TOALTSTACK,
37
+ opcodes.OP_DEPTH,
38
+ opcodes.OP_1,
39
+ opcodes.OP_NUMEQUAL,
40
+ opcodes.OP_IF,
41
+ Generator.MAGIC,
42
+ ];
43
+ if (vaultPublicKeys.length > 0) {
44
+ const pubKeyBuffer = LegacyCalldataGenerator.getPubKeyAsBuffer(vaultPublicKeys, this.network);
45
+ const pubKeyDataChunks = this.splitBufferIntoChunks(pubKeyBuffer);
46
+ compiledData = compiledData.concat(...[
47
+ opcodes.OP_0,
48
+ ...pubKeyDataChunks,
49
+ ]);
50
+ if (minimumSignatures) {
51
+ if (minimumSignatures > 255) {
52
+ throw new Error('Minimum signatures cannot exceed 255');
53
+ }
54
+ const minSigBuffer = Buffer.alloc(2);
55
+ minSigBuffer.writeUint16LE(minimumSignatures, 0);
56
+ compiledData = compiledData.concat(...[
57
+ opcodes.OP_1,
58
+ minSigBuffer,
59
+ ]);
60
+ }
61
+ else {
62
+ throw new Error('Minimum signatures must be provided');
63
+ }
64
+ }
65
+ const featureOpcodes = features.map((feature) => FeatureOpCodes[feature]);
66
+ compiledData = compiledData.concat(...featureOpcodes, ...[opcodes.OP_1NEGATE, ...dataChunks, opcodes.OP_ELSE, opcodes.OP_1, opcodes.OP_ENDIF]);
67
+ const asm = compiledData.flat();
68
+ const compiled = script.compile(asm);
69
+ const decompiled = script.decompile(compiled);
70
+ if (!decompiled) {
71
+ throw new Error('Failed to decompile script??');
72
+ }
73
+ return compiled;
74
+ }
75
+ }
@@ -11,6 +11,7 @@ export declare class Address extends Uint8Array {
11
11
  static fromString(pubKey: string): Address;
12
12
  static wrap(bytes: ArrayLike<number>): Address;
13
13
  toHex(): string;
14
+ toBuffer(): Buffer;
14
15
  equals(a: Address): boolean;
15
16
  lessThan(a: Address): boolean;
16
17
  greaterThan(a: Address): boolean;
@@ -53,6 +53,9 @@ export class Address extends Uint8Array {
53
53
  toHex() {
54
54
  return '0x' + Buffer.from(this).toString('hex');
55
55
  }
56
+ toBuffer() {
57
+ return Buffer.from(this);
58
+ }
56
59
  equals(a) {
57
60
  const b = this.isP2TROnly ? this : __classPrivateFieldGet(this, _Address_tweakedBytes, "f");
58
61
  const c = a.isP2TROnly ? a : __classPrivateFieldGet(a, _Address_tweakedBytes, "f");
@@ -1,8 +1,6 @@
1
1
  import { Network } from 'bitcoinjs-lib';
2
2
  export declare enum AddressTypes {
3
3
  P2PKH = "P2PKH",
4
- P2SH = "P2SH",
5
- P2SH_P2WPKH = "P2SH-P2WPKH",
6
4
  P2SH_OR_P2SH_P2WPKH = "P2SH_OR_P2SH-P2WPKH",
7
5
  P2PK = "P2PK",
8
6
  P2TR = "P2TR",
@@ -13,5 +11,6 @@ export declare class AddressVerificator {
13
11
  static isP2WPKHAddress(inAddress: string, network: Network): boolean;
14
12
  static isP2PKHOrP2SH(addy: string, network: Network): boolean;
15
13
  static isValidPublicKey(input: string, network: Network): boolean;
16
- static validateBitcoinAddress(addy: string, network: Network): AddressTypes | null;
14
+ static requireRedeemScript(addy: string, network: Network): boolean;
15
+ static detectAddressType(addy: string, network: Network): AddressTypes | null;
17
16
  }
@@ -5,8 +5,6 @@ initEccLib(ecc);
5
5
  export var AddressTypes;
6
6
  (function (AddressTypes) {
7
7
  AddressTypes["P2PKH"] = "P2PKH";
8
- AddressTypes["P2SH"] = "P2SH";
9
- AddressTypes["P2SH_P2WPKH"] = "P2SH-P2WPKH";
10
8
  AddressTypes["P2SH_OR_P2SH_P2WPKH"] = "P2SH_OR_P2SH-P2WPKH";
11
9
  AddressTypes["P2PK"] = "P2PK";
12
10
  AddressTypes["P2TR"] = "P2TR";
@@ -68,12 +66,24 @@ export class AddressVerificator {
68
66
  return true;
69
67
  }
70
68
  }
71
- catch (error) {
69
+ catch {
72
70
  return false;
73
71
  }
74
72
  return false;
75
73
  }
76
- static validateBitcoinAddress(addy, network) {
74
+ static requireRedeemScript(addy, network) {
75
+ try {
76
+ const decodedBase58 = address.fromBase58Check(addy);
77
+ if (decodedBase58.version === network.pubKeyHash) {
78
+ return false;
79
+ }
80
+ return decodedBase58.version === network.scriptHash;
81
+ }
82
+ catch {
83
+ return false;
84
+ }
85
+ }
86
+ static detectAddressType(addy, network) {
77
87
  if (AddressVerificator.isValidPublicKey(addy, network)) {
78
88
  return AddressTypes.P2PK;
79
89
  }
@@ -86,8 +96,7 @@ export class AddressVerificator {
86
96
  return AddressTypes.P2SH_OR_P2SH_P2WPKH;
87
97
  }
88
98
  }
89
- catch (error) {
90
- }
99
+ catch { }
91
100
  try {
92
101
  const decodedBech32 = address.fromBech32(addy);
93
102
  if (decodedBech32.prefix === network.bech32) {
@@ -99,9 +108,7 @@ export class AddressVerificator {
99
108
  }
100
109
  }
101
110
  }
102
- catch (error) {
103
- console.log(error);
104
- }
111
+ catch { }
105
112
  return null;
106
113
  }
107
114
  }
package/build/opnet.d.ts CHANGED
@@ -2,6 +2,7 @@ export { version } from './_version.js';
2
2
  export * from './bytecode/Compressor.js';
3
3
  export * from './generators/Generator.js';
4
4
  export * from './generators/builders/CalldataGenerator.js';
5
+ export * from './generators/builders/LegacyCalldataGenerator.js';
5
6
  export * from './generators/builders/DeploymentGenerator.js';
6
7
  export * from './generators/builders/CustomGenerator.js';
7
8
  export * from './generators/builders/MultiSignGenerator.js';
package/build/opnet.js CHANGED
@@ -2,6 +2,7 @@ export { version } from './_version.js';
2
2
  export * from './bytecode/Compressor.js';
3
3
  export * from './generators/Generator.js';
4
4
  export * from './generators/builders/CalldataGenerator.js';
5
+ export * from './generators/builders/LegacyCalldataGenerator.js';
5
6
  export * from './generators/builders/DeploymentGenerator.js';
6
7
  export * from './generators/builders/CustomGenerator.js';
7
8
  export * from './generators/builders/MultiSignGenerator.js';
@@ -343,4 +343,4 @@ export class TransactionBuilder extends TweakedTransaction {
343
343
  TransactionBuilder.LOCK_LEAF_SCRIPT = script.compile([
344
344
  opcodes.OP_0,
345
345
  ]);
346
- TransactionBuilder.MINIMUM_DUST = 330n;
346
+ TransactionBuilder.MINIMUM_DUST = 50n;
@@ -54,5 +54,14 @@ export declare abstract class TweakedTransaction extends Logger {
54
54
  protected internalInit(): void;
55
55
  protected tweakSigner(): void;
56
56
  protected getTweakedSigner(useTweakedHash?: boolean, signer?: Signer | ECPairInterface): ECPairInterface | undefined;
57
+ protected generateP2SHRedeemScript(customWitnessScript: Buffer): Buffer | undefined;
58
+ protected generateP2SHRedeemScriptLegacy(inputAddr: string): {
59
+ redeemScript: Buffer;
60
+ outputScript: Buffer;
61
+ } | undefined;
57
62
  protected generatePsbtInputExtended(utxo: UTXO, i: number): PsbtInputExtended;
63
+ protected customFinalizerP2SH: (inputIndex: number, input: PsbtInput, scriptA: Buffer, isSegwit: boolean, isP2SH: boolean, isP2WSH: boolean) => {
64
+ finalScriptSig: Buffer | undefined;
65
+ finalScriptWitness: Buffer | undefined;
66
+ };
58
67
  }
@@ -1,8 +1,8 @@
1
1
  import { Logger } from '@btc-vision/logger';
2
- import { payments, } from 'bitcoinjs-lib';
2
+ import { address as bitAddress, crypto as bitCrypto, getFinalScripts, opcodes, payments, script, } from 'bitcoinjs-lib';
3
3
  import { TweakedSigner } from '../../signer/TweakedSigner.js';
4
4
  import { toXOnly } from 'bitcoinjs-lib/src/psbt/bip371.js';
5
- import { AddressVerificator } from '../../keypair/AddressVerificator.js';
5
+ import { AddressTypes, AddressVerificator } from '../../keypair/AddressVerificator.js';
6
6
  import { varuint } from 'bitcoinjs-lib/src/bufferutils.js';
7
7
  export var TransactionSequence;
8
8
  (function (TransactionSequence) {
@@ -23,6 +23,21 @@ export class TweakedTransaction extends Logger {
23
23
  this.isBrowser = false;
24
24
  this.regenerated = false;
25
25
  this.ignoreSignatureErrors = false;
26
+ this.customFinalizerP2SH = (inputIndex, input, scriptA, isSegwit, isP2SH, isP2WSH) => {
27
+ const inputDecoded = this.inputs[inputIndex];
28
+ if (isP2SH && input.partialSig && inputDecoded && inputDecoded.redeemScript) {
29
+ const signatures = input.partialSig.map((sig) => sig.signature);
30
+ const scriptSig = script.compile([
31
+ ...signatures,
32
+ inputDecoded.redeemScript,
33
+ ]);
34
+ return {
35
+ finalScriptSig: scriptSig,
36
+ finalScriptWitness: undefined,
37
+ };
38
+ }
39
+ return getFinalScripts(inputIndex, input, scriptA, isSegwit, isP2SH, isP2WSH);
40
+ };
26
41
  this.signer = data.signer;
27
42
  this.network = data.network;
28
43
  this.nonWitnessUtxo = data.nonWitnessUtxo;
@@ -223,6 +238,7 @@ export class TweakedTransaction extends Logger {
223
238
  }
224
239
  await Promise.all(promises);
225
240
  }
241
+ transaction.finalizeInput(0, this.customFinalizerP2SH);
226
242
  try {
227
243
  transaction.finalizeAllInputs();
228
244
  this.finalized = true;
@@ -255,16 +271,90 @@ export class TweakedTransaction extends Logger {
255
271
  }
256
272
  return TweakedSigner.tweakSigner(signer, settings);
257
273
  }
274
+ generateP2SHRedeemScript(customWitnessScript) {
275
+ const p2wsh = payments.p2wsh({
276
+ redeem: { output: customWitnessScript },
277
+ network: this.network,
278
+ });
279
+ const p2sh = payments.p2sh({
280
+ redeem: p2wsh,
281
+ network: this.network,
282
+ });
283
+ return p2sh.output;
284
+ }
285
+ generateP2SHRedeemScriptLegacy(inputAddr) {
286
+ const pubKeyHash = bitCrypto.hash160(this.signer.publicKey);
287
+ const redeemScript = script.compile([
288
+ opcodes.OP_DUP,
289
+ opcodes.OP_HASH160,
290
+ pubKeyHash,
291
+ opcodes.OP_EQUALVERIFY,
292
+ opcodes.OP_CHECKSIG,
293
+ ]);
294
+ const redeemScriptHash = bitCrypto.hash160(redeemScript);
295
+ const outputScript = script.compile([
296
+ opcodes.OP_HASH160,
297
+ redeemScriptHash,
298
+ opcodes.OP_EQUAL,
299
+ ]);
300
+ const p2wsh = payments.p2wsh({
301
+ redeem: { output: redeemScript },
302
+ network: this.network,
303
+ });
304
+ const p2sh = payments.p2sh({
305
+ redeem: p2wsh,
306
+ network: this.network,
307
+ });
308
+ const address = bitAddress.fromOutputScript(outputScript, this.network);
309
+ if (address === inputAddr && p2sh.redeem && p2sh.redeem.output) {
310
+ return {
311
+ redeemScript,
312
+ outputScript: p2sh.redeem.output,
313
+ };
314
+ }
315
+ return;
316
+ }
258
317
  generatePsbtInputExtended(utxo, i) {
259
318
  const input = {
260
319
  hash: utxo.transactionId,
261
320
  index: utxo.outputIndex,
321
+ sequence: this.sequence,
262
322
  witnessUtxo: {
263
323
  value: Number(utxo.value),
264
324
  script: Buffer.from(utxo.scriptPubKey.hex, 'hex'),
265
325
  },
266
- sequence: this.sequence,
267
326
  };
327
+ if (utxo.scriptPubKey.address) {
328
+ try {
329
+ const addressType = AddressVerificator.detectAddressType(utxo.scriptPubKey.address, this.network);
330
+ if (addressType === AddressTypes.P2SH_OR_P2SH_P2WPKH) {
331
+ const redeemScript = this.generateP2SHRedeemScriptLegacy(utxo.scriptPubKey.address);
332
+ if (!redeemScript) {
333
+ throw new Error('Failed to generate redeem script');
334
+ }
335
+ input.redeemScript = redeemScript.outputScript;
336
+ input.witnessScript = redeemScript.redeemScript;
337
+ }
338
+ }
339
+ catch (e) {
340
+ this.error(`Failed to detect address type for ${utxo.scriptPubKey.address} - ${e}`);
341
+ }
342
+ }
343
+ if (utxo.nonWitnessUtxo) {
344
+ input.nonWitnessUtxo = Buffer.isBuffer(utxo.nonWitnessUtxo)
345
+ ? utxo.nonWitnessUtxo
346
+ : Buffer.from(utxo.nonWitnessUtxo, 'hex');
347
+ }
348
+ if (utxo.redeemScript) {
349
+ input.redeemScript = Buffer.isBuffer(utxo.redeemScript)
350
+ ? utxo.redeemScript
351
+ : Buffer.from(utxo.redeemScript, 'hex');
352
+ if (utxo.witnessScript) {
353
+ input.witnessScript = Buffer.isBuffer(utxo.witnessScript)
354
+ ? utxo.witnessScript
355
+ : Buffer.from(utxo.witnessScript, 'hex');
356
+ }
357
+ }
268
358
  if (this.sighashTypes) {
269
359
  const inputSign = TweakedTransaction.calculateSignHash(this.sighashTypes);
270
360
  if (inputSign)
@@ -4,6 +4,9 @@ export interface UTXO {
4
4
  readonly outputIndex: number;
5
5
  readonly value: bigint;
6
6
  readonly scriptPubKey: ScriptPubKey;
7
+ redeemScript?: string | Buffer;
8
+ witnessScript?: string | Buffer;
9
+ nonWitnessUtxo?: string | Buffer;
7
10
  }
8
11
  export interface FetchUTXOParams {
9
12
  readonly address: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@btc-vision/transaction",
3
3
  "type": "module",
4
- "version": "1.0.117",
4
+ "version": "1.0.119",
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.117';
1
+ export const version = '1.0.119';
@@ -15,6 +15,14 @@ export class Map<K, V> {
15
15
  public values(): V[] {
16
16
  return this._values;
17
17
  }
18
+
19
+ public entires(): [K, V][] {
20
+ const result: [K, V][] = [];
21
+ for (let i: i32 = 0; i < this._keys.length; i++) {
22
+ result.push([this._keys[i], this._values[i]]);
23
+ }
24
+ return result;
25
+ }
18
26
 
19
27
  public set(key: K, value: V): void {
20
28
  const index: i32 = this.indexOf(key);
@@ -1,6 +1,6 @@
1
1
  export class NetEvent {
2
2
  public constructor(
3
- public readonly eventType: string,
4
- public readonly eventData: Uint8Array,
3
+ public readonly type: string,
4
+ public readonly data: Uint8Array,
5
5
  ) {}
6
6
  }
@@ -0,0 +1,141 @@
1
+ import { Network, networks, opcodes, script } from 'bitcoinjs-lib';
2
+ import { ECPairInterface } from 'ecpair';
3
+ import { Compressor } from '../../bytecode/Compressor.js';
4
+ import { EcKeyPair } from '../../keypair/EcKeyPair.js';
5
+ import { FeatureOpCodes, Features } from '../Features.js';
6
+ import { Generator } from '../Generator.js';
7
+
8
+ /**
9
+ * Class to generate bitcoin script for interaction transactions
10
+ */
11
+ export class LegacyCalldataGenerator extends Generator {
12
+ constructor(senderPubKey: Buffer, network: Network = networks.bitcoin) {
13
+ super(senderPubKey, Buffer.alloc(0), network);
14
+ }
15
+
16
+ /**
17
+ * Get the public key as a buffer
18
+ * @param {Buffer[]} witnessKeys - The public keys
19
+ * @param {Network} network - The network to use
20
+ * @private
21
+ * @returns {Buffer} - The public key as a buffer
22
+ */
23
+ public static getPubKeyAsBuffer(witnessKeys: Buffer[], network: Network): Buffer {
24
+ let finalBuffer: Buffer = Buffer.alloc(0);
25
+
26
+ for (const pubKey of witnessKeys) {
27
+ const key: ECPairInterface = EcKeyPair.fromPublicKey(pubKey, network);
28
+
29
+ if (!key.compressed) {
30
+ throw new Error('Public key must be compressed');
31
+ }
32
+
33
+ if (pubKey.byteLength !== 33) {
34
+ throw new Error(`Public key must be 33 bytes, got ${pubKey.byteLength} bytes.`);
35
+ }
36
+
37
+ finalBuffer = Buffer.concat([finalBuffer, pubKey]);
38
+ }
39
+
40
+ // compress the public keys
41
+ const compressed: Buffer = Compressor.compress(finalBuffer);
42
+ if (compressed.byteLength >= finalBuffer.byteLength) {
43
+ // we ensure that the user pays the smallest amount of fees. [micro-optimization]
44
+ return finalBuffer;
45
+ }
46
+
47
+ // if compressed is smaller, return compressed.
48
+ return compressed;
49
+ }
50
+
51
+ /**
52
+ * Compile an interaction bitcoin script
53
+ * @param {Buffer} calldata - The calldata to use
54
+ * @param {Buffer} contractSecret - The contract secret
55
+ * @param {number[]} [features=[]] - The features to use (optional)
56
+ * @param {Buffer[]} [vaultPublicKeys=[]] - The public keys of the vault (optional)
57
+ * @param {number} [minimumSignatures=0] - The minimum number of signatures (optional)
58
+ * @returns {Buffer} - The compiled script
59
+ * @throws {Error} - If something goes wrong
60
+ */
61
+ public compile(
62
+ calldata: Buffer,
63
+ contractSecret: Buffer,
64
+ features: Features[] = [],
65
+ vaultPublicKeys: Buffer[] = [],
66
+ minimumSignatures: number = 0,
67
+ ): Buffer {
68
+ const dataChunks: Buffer[][] = this.splitBufferIntoChunks(calldata);
69
+ if (!dataChunks.length) throw new Error('No data chunks found');
70
+
71
+ let compiledData = [
72
+ this.senderPubKey,
73
+ opcodes.OP_CHECKSIGVERIFY,
74
+
75
+ contractSecret,
76
+ opcodes.OP_TOALTSTACK,
77
+
78
+ opcodes.OP_DEPTH,
79
+ opcodes.OP_1,
80
+ opcodes.OP_NUMEQUAL,
81
+ opcodes.OP_IF,
82
+
83
+ Generator.MAGIC,
84
+ ];
85
+
86
+ // write pub keys, when requested.
87
+ if (vaultPublicKeys.length > 0) {
88
+ const pubKeyBuffer = LegacyCalldataGenerator.getPubKeyAsBuffer(
89
+ vaultPublicKeys,
90
+ this.network,
91
+ );
92
+ const pubKeyDataChunks: Buffer[][] = this.splitBufferIntoChunks(pubKeyBuffer);
93
+
94
+ compiledData = compiledData.concat(
95
+ ...[
96
+ opcodes.OP_0, // provide opnet public keys
97
+ ...pubKeyDataChunks,
98
+ ],
99
+ );
100
+
101
+ if (minimumSignatures) {
102
+ // verify that the minimum is not greater than 255
103
+ if (minimumSignatures > 255) {
104
+ throw new Error('Minimum signatures cannot exceed 255');
105
+ }
106
+
107
+ // we use a 2 bytes buffer even if we limit to 255 so it does not use an opcode for the number
108
+ const minSigBuffer = Buffer.alloc(2);
109
+ minSigBuffer.writeUint16LE(minimumSignatures, 0);
110
+
111
+ compiledData = compiledData.concat(
112
+ ...[
113
+ opcodes.OP_1, // provide minimum signatures
114
+ minSigBuffer,
115
+ ],
116
+ );
117
+ } else {
118
+ throw new Error('Minimum signatures must be provided');
119
+ }
120
+ }
121
+
122
+ const featureOpcodes = features.map((feature) => FeatureOpCodes[feature]); // Get the opcodes for the features
123
+
124
+ // Write calldata
125
+ compiledData = compiledData.concat(
126
+ ...featureOpcodes,
127
+ ...[opcodes.OP_1NEGATE, ...dataChunks, opcodes.OP_ELSE, opcodes.OP_1, opcodes.OP_ENDIF],
128
+ );
129
+
130
+ const asm = compiledData.flat();
131
+ const compiled = script.compile(asm);
132
+
133
+ /** Verify the validity of the script */
134
+ const decompiled = script.decompile(compiled);
135
+ if (!decompiled) {
136
+ throw new Error('Failed to decompile script??');
137
+ }
138
+
139
+ return compiled;
140
+ }
141
+ }