@developeruche/tx-spammer-sdk 1.0.1 → 1.0.3

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,5 +1,4 @@
1
- import { type Hash } from 'viem';
2
- import { SpamSequenceConfig } from './types';
1
+ import { SpamSequenceConfig, SpamResult } from './types';
3
2
  /**
4
3
  * The central coordinator for the spam sequence.
5
4
  *
@@ -38,8 +37,5 @@ export declare class SpamOrchestrator {
38
37
  *
39
38
  * Stops when the duration expires or gas limits are reached.
40
39
  */
41
- start(): Promise<{
42
- blockNumber: bigint;
43
- txHash: Hash | null;
44
- }>;
40
+ start(): Promise<SpamResult>;
45
41
  }
@@ -104,8 +104,9 @@ class SpamOrchestrator {
104
104
  : Infinity;
105
105
  const startTime = Date.now();
106
106
  let lastTxHash = null;
107
+ const activeGuardians = [this.gasGuardian];
107
108
  // Helper to run a strategy loop for a subset of workers
108
- const runLoop = async (workers, stratConfig, guardian) => {
109
+ const runLoop = async (workers, stratConfig, guardian, onSuccess) => {
109
110
  const loopTasks = workers.map(async (worker, index) => {
110
111
  while (true) {
111
112
  if (guardian.isLimitReached)
@@ -114,17 +115,25 @@ class SpamOrchestrator {
114
115
  break;
115
116
  try {
116
117
  let txHash;
118
+ let executed = false;
117
119
  if (stratConfig.mode === 'transfer') {
118
120
  txHash = await (0, strategies_1.executeEthTransfer)(worker, stratConfig, guardian, this.publicClient);
121
+ executed = true;
119
122
  }
120
123
  else if (stratConfig.mode === 'deploy') {
121
124
  txHash = await (0, strategies_1.executeContractDeploy)(worker, stratConfig, guardian, this.publicClient);
125
+ executed = true;
122
126
  }
123
127
  else if (stratConfig.mode === 'read') {
124
128
  await (0, strategies_1.executeContractRead)(worker, stratConfig, guardian, this.publicClient);
129
+ executed = true;
125
130
  }
126
131
  else if (stratConfig.mode === 'write') {
127
132
  txHash = await (0, strategies_1.executeContractWrite)(worker, stratConfig, guardian, this.publicClient);
133
+ executed = true;
134
+ }
135
+ if (executed) {
136
+ onSuccess();
128
137
  }
129
138
  if (txHash) {
130
139
  lastTxHash = txHash;
@@ -142,6 +151,7 @@ class SpamOrchestrator {
142
151
  });
143
152
  await Promise.all(loopTasks);
144
153
  };
154
+ const stats = {};
145
155
  if (strategy.mode === 'mixed') {
146
156
  console.log('Executing Mixed Strategy...');
147
157
  let workerOffset = 0;
@@ -167,25 +177,43 @@ class SpamOrchestrator {
167
177
  // but we can assign a portion of the max limit to its guardian just in case.
168
178
  const gasLimitShare = BigInt(Math.floor(Number(this.config.maxGasLimit) * sharePercent));
169
179
  const subGuardian = new GasGuardian_1.GasGuardian(gasLimitShare);
180
+ activeGuardians.push(subGuardian);
170
181
  console.log(`- Sub-strategy '${subStrat.config.mode}': ${count} workers, ~${gasLimitShare} gas limit`);
171
- tasks.push(runLoop(assignedWorkers, subStrat.config, subGuardian));
182
+ const label = `Strategy ${i} (${subStrat.config.mode})`;
183
+ stats[label] = 0;
184
+ tasks.push(runLoop(assignedWorkers, subStrat.config, subGuardian, () => {
185
+ stats[label]++;
186
+ }));
172
187
  }
173
188
  await Promise.all(tasks);
174
189
  }
175
190
  else {
176
191
  // Single Mode
177
- await runLoop(this.workers, strategy, this.gasGuardian);
192
+ const label = `Strategy (${strategy.mode})`;
193
+ stats[label] = 0;
194
+ await runLoop(this.workers, strategy, this.gasGuardian, () => {
195
+ stats[label]++;
196
+ });
178
197
  }
179
198
  console.log('Spam sequence finished.');
199
+ let blockNumber;
180
200
  if (lastTxHash) {
181
201
  console.log(`Waiting for last transaction ${lastTxHash} to be mined...`);
182
202
  const receipt = await this.publicClient.waitForTransactionReceipt({ hash: lastTxHash });
183
- return { blockNumber: receipt.blockNumber, txHash: lastTxHash };
203
+ blockNumber = receipt.blockNumber;
184
204
  }
185
205
  else {
186
- const blockNumber = await this.publicClient.getBlockNumber();
187
- return { blockNumber, txHash: null };
206
+ blockNumber = await this.publicClient.getBlockNumber();
188
207
  }
208
+ const statsBlock = await this.publicClient.getBlock({ blockNumber });
209
+ const totalGasUsed = activeGuardians.reduce((acc, g) => acc + g.gasUsed, 0n);
210
+ return {
211
+ blockNumber,
212
+ txHash: lastTxHash,
213
+ totalGasUsed,
214
+ finalBlockGasUsed: statsBlock.gasUsed,
215
+ stats,
216
+ };
189
217
  }
190
218
  }
191
219
  exports.SpamOrchestrator = SpamOrchestrator;
package/dist/types.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { z } from 'zod';
2
+ import { Hex } from 'viem';
2
3
  /**
3
4
  * Configuration for ETH transfer spam strategy.
4
5
  * Includes depth for recursive transfers (if implemented) and recipient handling.
@@ -204,3 +205,20 @@ export type MixedStrategyConfig = z.infer<typeof MixedStrategyConfigSchema>;
204
205
  export type SpamStrategyConfig = z.infer<typeof SpamStrategySchema>;
205
206
  /** TypeScript type alias for the full Spam Sequence config. */
206
207
  export type SpamSequenceConfig = z.infer<typeof SpamSequenceConfigSchema>;
208
+ /**
209
+ * Result returned after the spam sequence completes.
210
+ */
211
+ export interface SpamResult {
212
+ /** The block number of the last transaction mined (or current block if no txs). */
213
+ blockNumber: bigint;
214
+ /** The hash of the last transaction sent, if any. */
215
+ txHash: Hex | null;
216
+ /** Total cumulative gas used by all transactions in this sequence (local estimate). */
217
+ totalGasUsed: bigint;
218
+ /** The total gas used in the block corresponding to blockNumber. */
219
+ finalBlockGasUsed: bigint;
220
+ /** Breakdown of operations performed by each strategy. Key is strategy label, value is count. */
221
+ stats: {
222
+ [key: string]: number;
223
+ };
224
+ }
package/dist/types.js CHANGED
@@ -111,7 +111,7 @@ exports.SpamSequenceConfigSchema = zod_1.z.object({
111
111
  /** The selected spam strategy configuration. */
112
112
  strategy: exports.SpamStrategySchema,
113
113
  /** Optional duration in seconds to run the spam sequence. */
114
- durationSeconds: zod_1.z.number().int().positive().optional(),
114
+ durationSeconds: zod_1.z.number().int().nonnegative().optional(),
115
115
  /** Optional maximum total transactions to attempts (if implemented). */
116
116
  totalTxs: zod_1.z.number().int().positive().optional(),
117
117
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@developeruche/tx-spammer-sdk",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [
@@ -30,4 +30,4 @@
30
30
  "ts-node": "^10.9.2",
31
31
  "typescript": "^5.9.3"
32
32
  }
33
- }
33
+ }