Skip to content

Commit bc2c1ce

Browse files
committed
small fixes
1 parent 85ecf66 commit bc2c1ce

File tree

3 files changed

+347
-1701
lines changed

3 files changed

+347
-1701
lines changed

src/commands/helper/activity.ts

Lines changed: 104 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
1-
import { Command, Flags } from '@oclif/core'
1+
/* eslint-disable no-await-in-loop */
2+
import {confirm} from '@inquirer/prompts'
3+
import {Command, Flags} from '@oclif/core'
24
import chalk from 'chalk'
3-
import { ethers } from 'ethers'
5+
import {SingleBar} from 'cli-progress'
6+
import {ethers} from 'ethers'
47
import path from 'node:path'
5-
import { confirm } from '@inquirer/prompts';
6-
import cliProgress from 'cli-progress';
78

8-
import { parseTomlConfig } from '../../utils/config-parser.js'
9-
import { txLink } from '../../utils/onchain/txLink.js'
10-
import { BlockExplorerParams } from '../../utils/onchain/constructBlockExplorerUrl.js';
9+
import {parseTomlConfig} from '../../utils/config-parser.js'
10+
// import { BlockExplorerParams } from '../../utils/onchain/constructBlockExplorerUrl.js';
11+
// import { txLink } from '../../utils/onchain/txLink.js'
1112

1213
enum Layer {
1314
L1 = 'l1',
1415
L2 = 'l2',
15-
RPC = 'rpc'
16+
RPC = 'rpc',
1617
}
1718

1819
export default class HelperActivity extends Command {
19-
private providers: Record<Layer, ethers.JsonRpcProvider> = {} as Record<Layer, ethers.JsonRpcProvider>;
20-
private rpcUrls: Record<Layer, string> = {} as Record<Layer, string>;
21-
private flags: any;
22-
private nonceTrackers: Record<Layer, number> = {} as Record<Layer, number>;
23-
2420
static description = 'Generate transactions on the specified network(s) to produce more blocks'
25-
2621
static flags = {
2722
config: Flags.string({
2823
char: 'c',
2924
default: './config.toml',
3025
description: 'Path to config.toml file',
3126
}),
27+
debug: Flags.boolean({
28+
char: 'd',
29+
default: false,
30+
description: 'Enable debug mode for more detailed logging',
31+
}),
3232
interval: Flags.integer({
3333
char: 'i',
3434
default: 3,
@@ -40,9 +40,9 @@ export default class HelperActivity extends Command {
4040
description: 'Generate activity on Layer 1',
4141
}),
4242
layer2: Flags.boolean({
43+
allowNo: true,
4344
char: 't',
4445
default: true,
45-
allowNo: true,
4646
description: 'Generate activity on Layer 2',
4747
}),
4848
pod: Flags.boolean({
@@ -62,29 +62,17 @@ export default class HelperActivity extends Command {
6262
char: 'r',
6363
description: 'RPC URL (overrides config for both layers)',
6464
}),
65-
debug: Flags.boolean({
66-
char: 'd',
67-
default: false,
68-
description: 'Enable debug mode for more detailed logging',
69-
}),
7065
}
7166

72-
private debugLog(message: string): void {
73-
if (this.flags && this.flags.debug) {
74-
this.log(chalk.gray(`[DEBUG] ${message}`))
75-
}
76-
}
67+
private flags: any
68+
private nonceTrackers: Record<Layer, number> = {} as Record<Layer, number>
7769

78-
private async initializeNonceTrackers(wallets: Record<Layer, ethers.Wallet>) {
79-
for (const [layer, wallet] of Object.entries(wallets)) {
80-
const nonce = await wallet.getNonce();
81-
this.nonceTrackers[layer as Layer] = nonce;
82-
this.debugLog(`Initialized nonce for ${layer}: ${nonce}`);
83-
}
84-
}
70+
private providers: Record<Layer, ethers.JsonRpcProvider> = {} as Record<Layer, ethers.JsonRpcProvider>
71+
72+
private rpcUrls: Record<Layer, string> = {} as Record<Layer, string>
8573

8674
public async run(): Promise<void> {
87-
const { flags } = await this.parse(HelperActivity)
75+
const {flags} = await this.parse(HelperActivity)
8876
this.flags = flags // Assign parsed flags to the instance property
8977

9078
const configPath = path.resolve(flags.config)
@@ -100,11 +88,11 @@ export default class HelperActivity extends Command {
10088
const recipientAddr = flags.recipient ?? publicKey
10189

10290
const layers: Layer[] = []
103-
if (!flags.rpc) {
91+
if (flags.rpc) {
92+
layers.push(Layer.RPC)
93+
} else {
10494
if (flags.layer1) layers.push(Layer.L1)
10595
if (flags.layer2) layers.push(Layer.L2)
106-
} else {
107-
layers.push(Layer.RPC)
10896
}
10997

11098
if (layers.length === 0) {
@@ -127,107 +115,122 @@ export default class HelperActivity extends Command {
127115
this.error(`Missing RPC URL for ${layer.toUpperCase()}. Please check your config file or provide --rpc flag.`)
128116
}
129117

130-
this.providers[layer] = new ethers.JsonRpcProvider(rpcUrl);
131-
this.rpcUrls[layer] = rpcUrl;
118+
this.providers[layer] = new ethers.JsonRpcProvider(rpcUrl)
119+
this.rpcUrls[layer] = rpcUrl
132120
wallets[layer] = new ethers.Wallet(privateKey, this.providers[layer])
133121

134122
this.log(rpcUrl)
135123

136-
const currentNonce = await this.providers[layer].getTransactionCount(publicKey, 'latest');
137-
const pendingNonce = await this.providers[layer].getTransactionCount(publicKey, 'pending');
138-
const pendingTxCount = pendingNonce - currentNonce;
124+
const currentNonce = await this.providers[layer].getTransactionCount(publicKey, 'latest')
125+
const pendingNonce = await this.providers[layer].getTransactionCount(publicKey, 'pending')
126+
const pendingTxCount = pendingNonce - currentNonce
139127

140128
if (pendingTxCount > 0) {
141-
this.log(chalk.red(`${pendingTxCount} pending transactions detected for ${publicKey} on ${layer.toUpperCase()}.`));
129+
this.log(
130+
chalk.red(`${pendingTxCount} pending transactions detected for ${publicKey} on ${layer.toUpperCase()}.`),
131+
)
142132

143133
const replacePending = await confirm({
144134
message: `Do you want to replace the ${pendingTxCount} pending transactions with higher gas prices?`,
145-
});
135+
})
146136

147137
if (replacePending) {
148-
this.log('Replacing pending txs...');
149-
await this.replaceTransactions(wallets[layer], currentNonce, pendingNonce, layer);
150-
return;
151-
} else {
152-
this.log("Wait for pending tx to clear.")
153-
return;
138+
this.log('Replacing pending txs...')
139+
await this.replaceTransactions(wallets[layer], currentNonce, pendingNonce, layer)
140+
return
154141
}
142+
143+
this.log('Wait for pending tx to clear.')
144+
return
155145
}
156146

157147
this.log(
158148
chalk.cyan(
159149
`Starting activity generation on ${layers.map((l) => l.toUpperCase()).join(' and ')}. Press Ctrl+C to stop.`,
160150
),
161151
)
162-
this.log(
163-
chalk.magenta(
164-
`Sender: ${publicKey} | Recipient: ${recipientAddr}`,
165-
),
166-
)
152+
this.log(chalk.magenta(`Sender: ${publicKey} | Recipient: ${recipientAddr}`))
167153
}
168154

169-
await this.initializeNonceTrackers(wallets);
155+
await this.initializeNonceTrackers(wallets)
170156

171-
// eslint-disable-next-line no-constant-condition
172157
layers.map(async (layer) => {
173158
while (true) {
174-
for (const layer of layers) {
175-
// eslint-disable-next-line no-await-in-loop
176-
await this.sendTransaction(wallets[layer], recipientAddr, layer)
177-
}
159+
// for (const layer of layers) {
160+
await this.sendTransaction(wallets[layer], recipientAddr, layer)
161+
// }
178162

179-
// eslint-disable-next-line no-await-in-loop, no-promise-executor-return
180163
await new Promise((resolve) => setTimeout(resolve, flags.interval * 1000))
181164
}
182-
183165
})
184166
}
185167

168+
private debugLog(message: string): void {
169+
if (this.flags && this.flags.debug) {
170+
this.log(chalk.gray(`[DEBUG] ${message}`))
171+
}
172+
}
173+
174+
private async initializeNonceTrackers(wallets: Record<Layer, ethers.Wallet>) {
175+
for (const [layer, wallet] of Object.entries(wallets)) {
176+
const nonce = await wallet.getNonce()
177+
this.nonceTrackers[layer as Layer] = nonce
178+
this.debugLog(`Initialized nonce for ${layer}: ${nonce}`)
179+
}
180+
}
181+
186182
private async replaceTransactions(wallet: ethers.Wallet, startNonce: number, endNonce: number, layer: Layer) {
187-
const batchSize = 100;
188-
const currentGasPrice = await this.providers[layer].getFeeData();
183+
const batchSize = 100
184+
const currentGasPrice = await this.providers[layer].getFeeData()
189185

190-
const progressBar = new cliProgress.SingleBar({
191-
format: 'Replacing transactions |' + chalk.cyan('{bar}') + '| {percentage}% || {value}/{total} Transactions',
186+
const progressBar = new SingleBar({
192187
barCompleteChar: '\u2588',
193188
barIncompleteChar: '\u2591',
194-
hideCursor: true
195-
});
189+
format: 'Replacing transactions |' + chalk.cyan('{bar}') + '| {percentage}% || {value}/{total} Transactions',
190+
hideCursor: true,
191+
})
196192

197-
progressBar.start(endNonce - startNonce, 0);
193+
progressBar.start(endNonce - startNonce, 0)
198194

199195
for (let i = startNonce; i < endNonce; i += batchSize) {
200-
const promises = [];
196+
const promises = []
201197
for (let j = i; j < Math.min(i + batchSize, endNonce); j++) {
202198
const newTx = {
199+
gasLimit: 21_000, // standard gas limit for simple transfers
200+
maxFeePerGas: currentGasPrice.maxFeePerGas ? currentGasPrice.maxFeePerGas * 3n : undefined,
201+
maxPriorityFeePerGas: currentGasPrice.maxPriorityFeePerGas
202+
? currentGasPrice.maxPriorityFeePerGas * 3n
203+
: undefined,
204+
nonce: j,
203205
to: wallet.address, // sending to self
204206
value: 0, // 0 ETH
205-
nonce: j,
206-
maxFeePerGas: currentGasPrice.maxFeePerGas ? currentGasPrice.maxFeePerGas * 3n : undefined,
207-
maxPriorityFeePerGas: currentGasPrice.maxPriorityFeePerGas ? currentGasPrice.maxPriorityFeePerGas * 3n : undefined,
208-
gasLimit: 21000, // standard gas limit for simple transfers
209-
};
207+
}
210208

211-
promises.push(this.sendReplacementTransaction(wallet, newTx, layer));
209+
promises.push(this.sendReplacementTransaction(wallet, newTx))
210+
// promises.push(this.sendReplacementTransaction(wallet, newTx, layer))
212211
}
213212

214-
const results = await Promise.allSettled(promises);
215-
const successCount = results.filter(r => r.status === 'fulfilled').length;
216-
progressBar.increment(successCount);
213+
const results = await Promise.allSettled(promises)
214+
const successCount = results.filter((r) => r.status === 'fulfilled').length
215+
progressBar.increment(successCount)
217216
}
218217

219-
progressBar.stop();
220-
this.log(chalk.green(`Replacement of transactions completed.`));
218+
progressBar.stop()
219+
this.log(chalk.green(`Replacement of transactions completed.`))
221220
}
222221

223-
private async sendReplacementTransaction(wallet: ethers.Wallet, tx: ethers.TransactionRequest, layer: Layer): Promise<boolean> {
222+
private async sendReplacementTransaction(
223+
wallet: ethers.Wallet,
224+
tx: ethers.TransactionRequest,
225+
// layer: Layer,
226+
): Promise<boolean> {
224227
try {
225-
const sentTx = await wallet.sendTransaction(tx);
226-
await sentTx.wait();
227-
return true;
228-
} catch (error) {
228+
const sentTx = await wallet.sendTransaction(tx)
229+
await sentTx.wait()
230+
return true
231+
} catch {
229232
// Silently fail, we'll handle the overall progress in the replaceTransactions method
230-
return false;
233+
return false
231234
}
232235
}
233236

@@ -236,27 +239,27 @@ export default class HelperActivity extends Command {
236239
this.debugLog(`Preparing transaction for ${layer.toUpperCase()}`)
237240
this.debugLog(`Sender: ${wallet.address}, Recipient: ${recipient}`)
238241

239-
const currentNonce = this.nonceTrackers[layer];
240-
this.debugLog(`Current nonce for ${layer}: ${currentNonce}`);
242+
const currentNonce = this.nonceTrackers[layer]
243+
this.debugLog(`Current nonce for ${layer}: ${currentNonce}`)
241244

242245
const tx = await wallet.sendTransaction({
246+
nonce: currentNonce,
243247
to: recipient,
244248
value: ethers.parseUnits('0.1', 'gwei'),
245-
nonce: currentNonce,
246249
})
247250

248251
this.debugLog(`Transaction created: ${JSON.stringify(tx, null, 2)}`)
249252

250253
// Increment the nonce tracker immediately after sending the transaction
251-
this.nonceTrackers[layer]++;
252-
this.debugLog(`Updated nonce for ${layer}: ${this.nonceTrackers[layer]}`);
254+
this.nonceTrackers[layer]++
255+
this.debugLog(`Updated nonce for ${layer}: ${this.nonceTrackers[layer]}`)
253256

254257
const timeoutPromise = new Promise((_, reject) =>
255-
setTimeout(() => reject(new Error('Transaction taking longer than expected')), 5000)
256-
);
258+
setTimeout(() => reject(new Error('Transaction taking longer than expected')), 5000),
259+
)
257260

258261
try {
259-
const receipt = await Promise.race([tx.wait(), timeoutPromise]) as ethers.TransactionReceipt | null;
262+
const receipt = (await Promise.race([tx.wait(), timeoutPromise])) as ethers.TransactionReceipt | null
260263
if (receipt) {
261264
this.log(chalk.green(`${layer.toUpperCase()} Transaction sent: ${tx.hash} (Block: ${receipt.blockNumber})`))
262265
this.debugLog(`Full receipt: ${JSON.stringify(receipt, null, 2)}`)
@@ -270,16 +273,19 @@ export default class HelperActivity extends Command {
270273
} catch (error) {
271274
this.log(
272275
chalk.red(
273-
`Failed to send ${layer.toUpperCase()} transaction: ${error instanceof Error ? error.message : 'Unknown error'}`
274-
)
276+
`Failed to send ${layer.toUpperCase()} transaction: ${
277+
error instanceof Error ? error.message : 'Unknown error'
278+
}`,
279+
),
275280
)
276281
if (error instanceof Error) {
277282
this.debugLog(`Error stack: ${error.stack}`)
278283
if ('code' in error) {
279284
this.debugLog(`Error code: ${(error as any).code}`)
280285
}
281286
}
287+
282288
this.debugLog(`Full error object: ${JSON.stringify(error, null, 2)}`)
283289
}
284290
}
285-
}
291+
}

0 commit comments

Comments
 (0)