@btc-vision/transaction 1.7.16 → 1.7.17

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.
@@ -1 +1 @@
1
- export declare const version = "1.7.16";
1
+ export declare const version = "1.7.17";
package/build/_version.js CHANGED
@@ -1 +1 @@
1
- export const version = '1.7.16';
1
+ export const version = '1.7.17';
@@ -1,4 +1,5 @@
1
1
  import { Network } from '@btc-vision/bitcoin';
2
+ import { BinaryWriter } from '../buffer/BinaryWriter.js';
2
3
  import { Feature, Features } from './Features.js';
3
4
  export declare abstract class Generator {
4
5
  static readonly DATA_CHUNK_SIZE: number;
@@ -12,7 +13,7 @@ export declare abstract class Generator {
12
13
  getHeader(maxPriority: bigint, features?: Features[]): Buffer;
13
14
  abstract compile(...args: unknown[]): Buffer;
14
15
  protected splitBufferIntoChunks(buffer: Buffer, chunkSize?: number): Array<Buffer[]>;
15
- protected encodeFeature(feature: Feature<Features>): Buffer[][];
16
+ protected encodeFeature(feature: Feature<Features>, finalBuffer: BinaryWriter): void;
16
17
  private encodeAccessListFeature;
17
18
  private encodeChallengeSubmission;
18
19
  private encodeLinkRequest;
@@ -38,22 +38,22 @@ export class Generator {
38
38
  }
39
39
  return chunks;
40
40
  }
41
- encodeFeature(feature) {
41
+ encodeFeature(feature, finalBuffer) {
42
42
  switch (feature.opcode) {
43
43
  case Features.ACCESS_LIST: {
44
- return this.splitBufferIntoChunks(this.encodeAccessListFeature(feature));
44
+ return this.encodeAccessListFeature(feature, finalBuffer);
45
45
  }
46
46
  case Features.EPOCH_SUBMISSION: {
47
- return this.splitBufferIntoChunks(this.encodeChallengeSubmission(feature));
47
+ return this.encodeChallengeSubmission(feature, finalBuffer);
48
48
  }
49
49
  case Features.MLDSA_LINK_PUBKEY: {
50
- return this.splitBufferIntoChunks(this.encodeLinkRequest(feature));
50
+ return this.encodeLinkRequest(feature, finalBuffer);
51
51
  }
52
52
  default:
53
53
  throw new Error(`Unknown feature type: ${feature.opcode}`);
54
54
  }
55
55
  }
56
- encodeAccessListFeature(feature) {
56
+ encodeAccessListFeature(feature, finalBuffer) {
57
57
  const writer = new BinaryWriter();
58
58
  writer.writeU16(Object.keys(feature.data).length);
59
59
  for (const contract in feature.data) {
@@ -69,9 +69,9 @@ export class Generator {
69
69
  writer.writeBytes(pointerBuffer);
70
70
  }
71
71
  }
72
- return Compressor.compress(Buffer.from(writer.getBuffer()));
72
+ finalBuffer.writeBytesWithLength(Compressor.compress(Buffer.from(writer.getBuffer())));
73
73
  }
74
- encodeChallengeSubmission(feature) {
74
+ encodeChallengeSubmission(feature, finalBuffer) {
75
75
  if ('verifySignature' in feature.data && !feature.data.verifySignature()) {
76
76
  throw new Error('Invalid signature in challenge submission feature');
77
77
  }
@@ -81,9 +81,9 @@ export class Generator {
81
81
  if (feature.data.graffiti) {
82
82
  writer.writeBytesWithLength(feature.data.graffiti);
83
83
  }
84
- return Buffer.from(writer.getBuffer());
84
+ finalBuffer.writeBytesWithLength(writer.getBuffer());
85
85
  }
86
- encodeLinkRequest(feature) {
86
+ encodeLinkRequest(feature, finalBuffer) {
87
87
  const data = feature.data;
88
88
  const writer = new BinaryWriter();
89
89
  writer.writeU8(data.level);
@@ -100,7 +100,7 @@ export class Generator {
100
100
  throw new Error('Legacy signature must be exactly 64 bytes');
101
101
  }
102
102
  writer.writeBytes(data.legacySignature);
103
- return Buffer.from(writer.getBuffer());
103
+ finalBuffer.writeBytesWithLength(writer.getBuffer());
104
104
  }
105
105
  }
106
106
  Generator.DATA_CHUNK_SIZE = 512;
@@ -2,6 +2,7 @@ import { crypto, networks, opcodes, script } from '@btc-vision/bitcoin';
2
2
  import { Compressor } from '../../bytecode/Compressor.js';
3
3
  import { EcKeyPair } from '../../keypair/EcKeyPair.js';
4
4
  import { Generator } from '../Generator.js';
5
+ import { BinaryWriter } from '../../buffer/BinaryWriter.js';
5
6
  export class CalldataGenerator extends Generator {
6
7
  constructor(senderPubKey, contractSaltPubKey, network = networks.bitcoin) {
7
8
  super(senderPubKey, contractSaltPubKey, network);
@@ -32,15 +33,15 @@ export class CalldataGenerator extends Generator {
32
33
  throw new Error('No data chunks found');
33
34
  const featuresList = [];
34
35
  const featureData = [];
35
- const features = featuresRaw.sort((a, b) => a.priority - b.priority);
36
- if (features.length) {
36
+ if (featuresRaw && featuresRaw.length) {
37
+ const features = featuresRaw.sort((a, b) => a.priority - b.priority);
38
+ const finalBuffer = new BinaryWriter();
37
39
  for (let i = 0; i < features.length; i++) {
38
40
  const feature = features[i];
39
41
  featuresList.push(feature.opcode);
40
- const data = this.encodeFeature(feature);
41
- featureData.push(...data);
42
- featureData.push(opcodes.OP_0);
42
+ this.encodeFeature(feature, finalBuffer);
43
43
  }
44
+ featureData.push(...this.splitBufferIntoChunks(Buffer.from(finalBuffer.getBuffer())));
44
45
  }
45
46
  let compiledData = [
46
47
  this.getHeader(maxPriority, featuresList),
@@ -1,5 +1,6 @@
1
1
  import { crypto, networks, opcodes, script } from '@btc-vision/bitcoin';
2
2
  import { Generator } from '../Generator.js';
3
+ import { BinaryWriter } from '../../buffer/BinaryWriter.js';
3
4
  export const OPNET_DEPLOYMENT_VERSION = 0x00;
4
5
  export const versionBuffer = Buffer.from([OPNET_DEPLOYMENT_VERSION]);
5
6
  export class DeploymentGenerator extends Generator {
@@ -22,15 +23,15 @@ export class DeploymentGenerator extends Generator {
22
23
  const calldataChunks = calldata ? this.splitBufferIntoChunks(calldata) : [];
23
24
  const featuresList = [];
24
25
  const featureData = [];
25
- if (featuresRaw) {
26
+ if (featuresRaw && featuresRaw.length) {
26
27
  const features = featuresRaw.sort((a, b) => a.priority - b.priority);
28
+ const finalBuffer = new BinaryWriter();
27
29
  for (let i = 0; i < features.length; i++) {
28
30
  const feature = features[i];
29
31
  featuresList.push(feature.opcode);
30
- const data = this.encodeFeature(feature);
31
- featureData.push(...data);
32
- featureData.push(opcodes.OP_0);
32
+ this.encodeFeature(feature, finalBuffer);
33
33
  }
34
+ featureData.push(...this.splitBufferIntoChunks(Buffer.from(finalBuffer.getBuffer())));
34
35
  }
35
36
  const compiledData = [
36
37
  this.getHeader(maxPriority, featuresList),
@@ -2,6 +2,7 @@ import { crypto, networks, opcodes, script } from '@btc-vision/bitcoin';
2
2
  import { Compressor } from '../../bytecode/Compressor.js';
3
3
  import { EcKeyPair } from '../../keypair/EcKeyPair.js';
4
4
  import { Generator } from '../Generator.js';
5
+ import { BinaryWriter } from '../../buffer/BinaryWriter.js';
5
6
  export class LegacyCalldataGenerator extends Generator {
6
7
  constructor(senderPubKey, network = networks.bitcoin) {
7
8
  super(senderPubKey, Buffer.alloc(0), network);
@@ -30,15 +31,15 @@ export class LegacyCalldataGenerator extends Generator {
30
31
  throw new Error('No data chunks found');
31
32
  const featuresList = [];
32
33
  const featureData = [];
33
- const features = featuresRaw.sort((a, b) => a.priority - b.priority);
34
- if (features.length) {
34
+ if (featuresRaw && featuresRaw.length) {
35
+ const features = featuresRaw.sort((a, b) => a.priority - b.priority);
36
+ const finalBuffer = new BinaryWriter();
35
37
  for (let i = 0; i < features.length; i++) {
36
38
  const feature = features[i];
37
39
  featuresList.push(feature.opcode);
38
- const data = this.encodeFeature(feature);
39
- featureData.push(...data);
40
- featureData.push(opcodes.OP_0);
40
+ this.encodeFeature(feature, finalBuffer);
41
41
  }
42
+ featureData.push(...this.splitBufferIntoChunks(Buffer.from(finalBuffer.getBuffer())));
42
43
  }
43
44
  let compiledData = [
44
45
  this.getHeader(maxPriority, featuresList),
@@ -9,5 +9,4 @@ export declare class P2WDAGenerator extends Generator {
9
9
  compile(calldata: Buffer, contractSecret: Buffer, challenge: ChallengeSolution, maxPriority: bigint, featuresRaw?: Feature<Features>[]): Buffer;
10
10
  getHeader(maxPriority: bigint, features?: Features[]): Buffer;
11
11
  private writeFeatures;
12
- private encodeFeatureData;
13
12
  }
@@ -1,6 +1,5 @@
1
1
  import { networks } from '@btc-vision/bitcoin';
2
2
  import { BinaryWriter } from '../../buffer/BinaryWriter.js';
3
- import { Features } from '../Features.js';
4
3
  import { Generator } from '../Generator.js';
5
4
  export class P2WDAGenerator extends Generator {
6
5
  constructor(senderPubKey, contractSaltPubKey, network = networks.bitcoin) {
@@ -40,23 +39,7 @@ export class P2WDAGenerator extends Generator {
40
39
  writer.writeU16(features.length);
41
40
  for (const feature of features) {
42
41
  writer.writeU8(feature.opcode);
43
- const encodedData = this.encodeFeatureData(feature);
44
- writer.writeU32(encodedData.length);
45
- writer.writeBytes(encodedData);
46
- }
47
- }
48
- encodeFeatureData(feature) {
49
- switch (feature.opcode) {
50
- case Features.ACCESS_LIST: {
51
- const chunks = this.encodeFeature(feature);
52
- return Buffer.concat(chunks.flat());
53
- }
54
- case Features.EPOCH_SUBMISSION: {
55
- const chunks = this.encodeFeature(feature);
56
- return Buffer.concat(chunks.flat());
57
- }
58
- default:
59
- throw new Error(`Unknown feature type: ${feature.opcode}`);
42
+ this.encodeFeature(feature, writer);
60
43
  }
61
44
  }
62
45
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@btc-vision/transaction",
3
3
  "type": "module",
4
- "version": "1.7.16",
4
+ "version": "1.7.17",
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.7.16';
1
+ export const version = '1.7.17';
@@ -105,29 +105,26 @@ export abstract class Generator {
105
105
  return chunks;
106
106
  }
107
107
 
108
- protected encodeFeature(feature: Feature<Features>): Buffer[][] {
108
+ protected encodeFeature(feature: Feature<Features>, finalBuffer: BinaryWriter): void {
109
109
  switch (feature.opcode) {
110
110
  case Features.ACCESS_LIST: {
111
- return this.splitBufferIntoChunks(
112
- this.encodeAccessListFeature(feature as AccessListFeature),
113
- );
111
+ return this.encodeAccessListFeature(feature as AccessListFeature, finalBuffer);
114
112
  }
115
113
  case Features.EPOCH_SUBMISSION: {
116
- return this.splitBufferIntoChunks(
117
- this.encodeChallengeSubmission(feature as EpochSubmissionFeature),
114
+ return this.encodeChallengeSubmission(
115
+ feature as EpochSubmissionFeature,
116
+ finalBuffer,
118
117
  );
119
118
  }
120
119
  case Features.MLDSA_LINK_PUBKEY: {
121
- return this.splitBufferIntoChunks(
122
- this.encodeLinkRequest(feature as MLDSALinkRequest),
123
- );
120
+ return this.encodeLinkRequest(feature as MLDSALinkRequest, finalBuffer);
124
121
  }
125
122
  default:
126
123
  throw new Error(`Unknown feature type: ${feature.opcode}`);
127
124
  }
128
125
  }
129
126
 
130
- private encodeAccessListFeature(feature: AccessListFeature): Buffer {
127
+ private encodeAccessListFeature(feature: AccessListFeature, finalBuffer: BinaryWriter): void {
131
128
  const writer = new BinaryWriter();
132
129
 
133
130
  writer.writeU16(Object.keys(feature.data).length);
@@ -150,10 +147,13 @@ export abstract class Generator {
150
147
  }
151
148
  }
152
149
 
153
- return Compressor.compress(Buffer.from(writer.getBuffer()));
150
+ finalBuffer.writeBytesWithLength(Compressor.compress(Buffer.from(writer.getBuffer())));
154
151
  }
155
152
 
156
- private encodeChallengeSubmission(feature: EpochSubmissionFeature): Buffer {
153
+ private encodeChallengeSubmission(
154
+ feature: EpochSubmissionFeature,
155
+ finalBuffer: BinaryWriter,
156
+ ): void {
157
157
  if ('verifySignature' in feature.data && !feature.data.verifySignature()) {
158
158
  throw new Error('Invalid signature in challenge submission feature');
159
159
  }
@@ -166,10 +166,10 @@ export abstract class Generator {
166
166
  writer.writeBytesWithLength(feature.data.graffiti);
167
167
  }
168
168
 
169
- return Buffer.from(writer.getBuffer());
169
+ finalBuffer.writeBytesWithLength(writer.getBuffer());
170
170
  }
171
171
 
172
- private encodeLinkRequest(feature: MLDSALinkRequest): Buffer {
172
+ private encodeLinkRequest(feature: MLDSALinkRequest, finalBuffer: BinaryWriter): void {
173
173
  const data = feature.data;
174
174
 
175
175
  const writer = new BinaryWriter();
@@ -194,6 +194,6 @@ export abstract class Generator {
194
194
 
195
195
  writer.writeBytes(data.legacySignature);
196
196
 
197
- return Buffer.from(writer.getBuffer());
197
+ finalBuffer.writeBytesWithLength(writer.getBuffer());
198
198
  }
199
199
  }
@@ -5,6 +5,7 @@ import { EcKeyPair } from '../../keypair/EcKeyPair.js';
5
5
  import { Feature, Features } from '../Features.js';
6
6
  import { Generator } from '../Generator.js';
7
7
  import { ChallengeSolution } from '../../epoch/ChallengeSolution.js';
8
+ import { BinaryWriter } from '../../buffer/BinaryWriter.js';
8
9
 
9
10
  /**
10
11
  * Class to generate bitcoin script for interaction transactions
@@ -78,18 +79,20 @@ export class CalldataGenerator extends Generator {
78
79
  const featuresList: Features[] = [];
79
80
  const featureData: (number | Buffer | Buffer[])[] = [];
80
81
 
81
- const features: Feature<Features>[] = featuresRaw.sort((a, b) => a.priority - b.priority);
82
- if (features.length) {
82
+ if (featuresRaw && featuresRaw.length) {
83
+ const features: Feature<Features>[] = featuresRaw.sort(
84
+ (a, b) => a.priority - b.priority,
85
+ );
86
+
87
+ const finalBuffer = new BinaryWriter();
83
88
  for (let i = 0; i < features.length; i++) {
84
89
  const feature = features[i];
85
90
  featuresList.push(feature.opcode);
86
91
 
87
- const data = this.encodeFeature(feature);
88
- featureData.push(...data);
89
-
90
- // Separator between features so decoder knows where each ends
91
- featureData.push(opcodes.OP_0);
92
+ this.encodeFeature(feature, finalBuffer);
92
93
  }
94
+
95
+ featureData.push(...this.splitBufferIntoChunks(Buffer.from(finalBuffer.getBuffer())));
93
96
  }
94
97
 
95
98
  let compiledData: (number | Buffer | Buffer[])[] = [
@@ -2,6 +2,7 @@ import { crypto, Network, networks, opcodes, script } from '@btc-vision/bitcoin'
2
2
  import { Generator } from '../Generator.js';
3
3
  import { Feature, Features } from '../Features.js';
4
4
  import { ChallengeSolution } from '../../epoch/ChallengeSolution.js';
5
+ import { BinaryWriter } from '../../buffer/BinaryWriter.js';
5
6
 
6
7
  export const OPNET_DEPLOYMENT_VERSION = 0x00;
7
8
  export const versionBuffer = Buffer.from([OPNET_DEPLOYMENT_VERSION]);
@@ -71,21 +72,20 @@ export class DeploymentGenerator extends Generator {
71
72
  const featuresList: Features[] = [];
72
73
  const featureData: (number | Buffer | Buffer[])[] = [];
73
74
 
74
- if (featuresRaw) {
75
+ if (featuresRaw && featuresRaw.length) {
75
76
  const features: Feature<Features>[] = featuresRaw.sort(
76
77
  (a, b) => a.priority - b.priority,
77
78
  );
78
79
 
80
+ const finalBuffer = new BinaryWriter();
79
81
  for (let i = 0; i < features.length; i++) {
80
82
  const feature = features[i];
81
83
  featuresList.push(feature.opcode);
82
84
 
83
- const data = this.encodeFeature(feature);
84
- featureData.push(...data);
85
-
86
- // Separator between features so decoder knows where each ends
87
- featureData.push(opcodes.OP_0);
85
+ this.encodeFeature(feature, finalBuffer);
88
86
  }
87
+
88
+ featureData.push(...this.splitBufferIntoChunks(Buffer.from(finalBuffer.getBuffer())));
89
89
  }
90
90
 
91
91
  const compiledData = [
@@ -4,6 +4,7 @@ import { Compressor } from '../../bytecode/Compressor.js';
4
4
  import { EcKeyPair } from '../../keypair/EcKeyPair.js';
5
5
  import { Generator } from '../Generator.js';
6
6
  import { Feature, Features } from '../Features.js';
7
+ import { BinaryWriter } from '../../buffer/BinaryWriter.js';
7
8
 
8
9
  /**
9
10
  * Class to generate bitcoin script for interaction transactions
@@ -71,19 +72,21 @@ export class LegacyCalldataGenerator extends Generator {
71
72
 
72
73
  const featuresList: Features[] = [];
73
74
  const featureData: (number | Buffer | Buffer[])[] = [];
74
- const features: Feature<Features>[] = featuresRaw.sort((a, b) => a.priority - b.priority);
75
75
 
76
- if (features.length) {
76
+ if (featuresRaw && featuresRaw.length) {
77
+ const features: Feature<Features>[] = featuresRaw.sort(
78
+ (a, b) => a.priority - b.priority,
79
+ );
80
+
81
+ const finalBuffer = new BinaryWriter();
77
82
  for (let i = 0; i < features.length; i++) {
78
83
  const feature = features[i];
79
84
  featuresList.push(feature.opcode);
80
85
 
81
- const data = this.encodeFeature(feature);
82
- featureData.push(...data);
83
-
84
- // Separator between features so decoder knows where each ends
85
- featureData.push(opcodes.OP_0);
86
+ this.encodeFeature(feature, finalBuffer);
86
87
  }
88
+
89
+ featureData.push(...this.splitBufferIntoChunks(Buffer.from(finalBuffer.getBuffer())));
87
90
  }
88
91
 
89
92
  let compiledData = [
@@ -32,9 +32,6 @@ export class P2WDAGenerator extends Generator {
32
32
  maxWitnessFields: number = 10,
33
33
  maxBytesPerWitness: number = 80,
34
34
  ): boolean {
35
- // Account for Schnorr signature (64 bytes) and compression
36
- // Assume 30% compression ratio (conservative estimate)
37
-
38
35
  const signatureSize = 64;
39
36
  const compressionRatio = 0.7;
40
37
 
@@ -79,12 +76,10 @@ export class P2WDAGenerator extends Generator {
79
76
 
80
77
  const writer = new BinaryWriter();
81
78
 
82
- // Version byte
83
79
  writer.writeU8(P2WDAGenerator.P2WDA_VERSION);
84
80
 
85
81
  const features: Feature<Features>[] = featuresRaw.sort((a, b) => a.priority - b.priority);
86
82
 
87
- // Header
88
83
  writer.writeBytes(
89
84
  this.getHeader(
90
85
  maxPriority,
@@ -92,33 +87,19 @@ export class P2WDAGenerator extends Generator {
92
87
  ),
93
88
  );
94
89
 
95
- // Contract secret
96
90
  writer.writeBytes(contractSecret);
97
91
 
98
- // Challenge components for epoch rewards
99
92
  writer.writeBytes(challenge.publicKey.toBuffer());
100
93
  writer.writeBytes(challenge.solution);
101
94
 
102
- // Calldata with length prefix
103
95
  writer.writeU32(calldata.length);
104
96
  writer.writeBytes(calldata);
105
97
 
106
- // Features
107
98
  this.writeFeatures(writer, features);
108
99
 
109
100
  return Buffer.from(writer.getBuffer());
110
101
  }
111
102
 
112
- /**
113
- * Create a minimal header for P2WDA operations
114
- *
115
- * The header contains essential transaction metadata in a compact format:
116
- * [sender_pubkey_prefix(1)] [feature_flags(3)] [max_priority(8)]
117
- *
118
- * @param maxPriority Maximum priority fee
119
- * @param features Feature opcodes to set in flags
120
- * @returns 12-byte header
121
- */
122
103
  public override getHeader(maxPriority: bigint, features: Features[] = []): Buffer {
123
104
  return super.getHeader(maxPriority, features);
124
105
  }
@@ -133,48 +114,11 @@ export class P2WDAGenerator extends Generator {
133
114
  * @param features Array of features to encode
134
115
  */
135
116
  private writeFeatures(writer: BinaryWriter, features: Feature<Features>[]): void {
136
- // Write feature count
137
117
  writer.writeU16(features.length);
138
118
 
139
119
  for (const feature of features) {
140
- // Write feature opcode
141
120
  writer.writeU8(feature.opcode);
142
-
143
- // Encode feature data
144
- const encodedData = this.encodeFeatureData(feature);
145
-
146
- // Write feature data with length prefix
147
- writer.writeU32(encodedData.length);
148
- writer.writeBytes(encodedData);
149
- }
150
- }
151
-
152
- /**
153
- * Encode a single feature's data
154
- *
155
- * Unlike the base Generator class, we don't split into chunks here
156
- * since P2WDA handles chunking at the witness level
157
- *
158
- * @param feature The feature to encode
159
- * @returns Encoded feature data
160
- */
161
- private encodeFeatureData(feature: Feature<Features>): Buffer {
162
- switch (feature.opcode) {
163
- case Features.ACCESS_LIST: {
164
- // Access lists are already encoded efficiently by the parent class
165
- const chunks = this.encodeFeature(feature);
166
- // Flatten chunks since P2WDA doesn't need script-level chunking
167
- return Buffer.concat(chunks.flat());
168
- }
169
-
170
- case Features.EPOCH_SUBMISSION: {
171
- // Epoch submissions are also handled by parent
172
- const chunks = this.encodeFeature(feature);
173
- return Buffer.concat(chunks.flat());
174
- }
175
-
176
- default:
177
- throw new Error(`Unknown feature type: ${feature.opcode}`);
121
+ this.encodeFeature(feature, writer);
178
122
  }
179
123
  }
180
124
  }