Skip to content

Commit 930292b

Browse files
committed
Changed code to generate multiple wallets faster
1 parent 1c7463b commit 930292b

File tree

1 file changed

+252
-49
lines changed

1 file changed

+252
-49
lines changed

crates/task-sender/src/commands.rs

Lines changed: 252 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use aligned_sdk::verification_layer::{
55
use ethers::prelude::*;
66
use ethers::utils::parse_ether;
77
use k256::ecdsa::SigningKey;
8-
use log::{debug, error, info};
8+
use log::{debug, error, info, warn};
99
use rand::seq::SliceRandom;
1010
use rand::thread_rng;
1111
use std::fs::{self, File};
@@ -149,70 +149,273 @@ pub async fn generate_and_fund_wallets(args: GenerateAndFundWalletsArgs) {
149149
.expect("Invalid private key")
150150
.with_chain_id(chain_id.as_u64());
151151

152-
for i in 0..args.number_of_wallets {
153-
// this is necessary because of the move
154-
let eth_rpc_provider = eth_rpc_provider.clone();
155-
let funding_wallet = funding_wallet.clone();
156-
let amount_to_deposit = args.amount_to_deposit.clone();
157-
let amount_to_deposit_aligned = args.amount_to_deposit_to_aligned.clone();
152+
// Generate all wallets first
153+
let mut wallets = Vec::new();
154+
let mut wallet_private_keys = Vec::new();
158155

159-
// Generate new wallet
156+
info!("Generating {} wallets...", args.number_of_wallets);
157+
for i in 0..args.number_of_wallets {
160158
let wallet = Wallet::new(&mut thread_rng()).with_chain_id(chain_id.as_u64());
161159
info!("Generated wallet {} with address {:?}", i, wallet.address());
162160

163-
// Fund the wallet
164-
let signer = SignerMiddleware::new(eth_rpc_provider.clone(), funding_wallet.clone());
165-
let amount_to_deposit =
166-
parse_ether(&amount_to_deposit).expect("Ether format should be: XX.XX");
167-
info!("Depositing {}wei to wallet {}", amount_to_deposit, i);
168-
let tx = TransactionRequest::new()
169-
.from(funding_wallet.address())
170-
.to(wallet.address())
171-
.value(amount_to_deposit);
172-
173-
let pending_transaction = match signer.send_transaction(tx, None).await {
174-
Ok(tx) => tx,
161+
let signer_bytes = wallet.signer().to_bytes();
162+
let secret_key_hex = ethers::utils::hex::encode(signer_bytes);
163+
wallet_private_keys.push(secret_key_hex);
164+
wallets.push(wallet);
165+
}
166+
167+
// Get base nonce for funding wallet to avoid nonce conflicts
168+
let mut current_nonce = match eth_rpc_provider
169+
.get_transaction_count(
170+
funding_wallet.address(),
171+
Some(ethers::types::BlockNumber::Pending.into()),
172+
)
173+
.await
174+
{
175+
Ok(nonce) => nonce,
176+
Err(err) => {
177+
error!("Could not get base nonce for funding wallet: {}", err);
178+
return;
179+
}
180+
};
181+
182+
let batch_size = 25;
183+
let amount_to_deposit =
184+
parse_ether(&args.amount_to_deposit).expect("Ether format should be: XX.XX");
185+
let amount_to_deposit_to_aligned =
186+
parse_ether(&args.amount_to_deposit_to_aligned).expect("Ether format should be: XX.XX");
187+
188+
let mut total_successful = 0;
189+
let total_batches = args.number_of_wallets.div_ceil(batch_size);
190+
191+
// Process wallets in batches
192+
for (batch_idx, wallet_chunk) in wallets.chunks(batch_size).enumerate() {
193+
info!(
194+
"Processing batch {} of {} ({} wallets)...",
195+
batch_idx + 1,
196+
total_batches,
197+
wallet_chunk.len()
198+
);
199+
200+
// Refresh nonce for each batch to avoid stale nonce issues
201+
current_nonce = match eth_rpc_provider
202+
.get_transaction_count(
203+
funding_wallet.address(),
204+
Some(ethers::types::BlockNumber::Pending.into()),
205+
)
206+
.await
207+
{
208+
Ok(nonce) => {
209+
info!("Batch {}: Using fresh nonce {}", batch_idx + 1, nonce);
210+
nonce
211+
}
175212
Err(err) => {
176-
error!("Could not fund wallet {}", err);
177-
return;
213+
error!("Could not get fresh nonce for batch {}: {}", batch_idx + 1, err);
214+
current_nonce // Use previous nonce as fallback
178215
}
179216
};
180-
if let Err(err) = pending_transaction.await {
181-
error!("Could not fund wallet {}", err);
217+
218+
// ETH funding phase for this batch
219+
info!(
220+
"Batch {}: Starting ETH funding transactions...",
221+
batch_idx + 1
222+
);
223+
let mut eth_funding_handles = Vec::new();
224+
225+
for (chunk_idx, wallet) in wallet_chunk.iter().enumerate() {
226+
let global_idx = batch_idx * batch_size + chunk_idx;
227+
let eth_rpc_provider = eth_rpc_provider.clone();
228+
let funding_wallet = funding_wallet.clone();
229+
let wallet_address = wallet.address();
230+
let nonce = current_nonce + U256::from(chunk_idx);
231+
232+
let handle = tokio::spawn(async move {
233+
234+
info!(
235+
"Submitting ETH funding transaction for wallet {} with nonce {}",
236+
global_idx, nonce
237+
);
238+
let signer = SignerMiddleware::new(eth_rpc_provider, funding_wallet.clone());
239+
240+
// Get current gas price and bump it by 20% to avoid replacement issues
241+
let base_gas_price = match signer.provider().get_gas_price().await {
242+
Ok(price) => price,
243+
Err(_) => U256::from(20_000_000_000u64), // 20 gwei fallback
244+
};
245+
let bumped_gas_price = base_gas_price * 120 / 100; // 20% bump
246+
247+
let tx = TransactionRequest::new()
248+
.from(funding_wallet.address())
249+
.to(wallet_address)
250+
.value(amount_to_deposit)
251+
.nonce(nonce)
252+
.gas_price(bumped_gas_price);
253+
254+
let result = {
255+
match signer.send_transaction(tx, None).await {
256+
Ok(pending_tx) => {
257+
info!(
258+
"ETH funding transaction submitted for wallet {}",
259+
global_idx
260+
);
261+
pending_tx.await
262+
}
263+
Err(err) => {
264+
error!(
265+
"Could not submit ETH funding transaction for wallet {}: {}",
266+
global_idx, err
267+
);
268+
return None;
269+
}
270+
}
271+
};
272+
273+
match result {
274+
Ok(receipt) => {
275+
if let Some(receipt) = receipt {
276+
info!(
277+
"ETH funding confirmed for wallet {} (tx: {:?})",
278+
global_idx, receipt.transaction_hash
279+
);
280+
} else {
281+
info!(
282+
"ETH funding confirmed for wallet {} (no receipt)",
283+
global_idx
284+
);
285+
}
286+
Some(global_idx)
287+
}
288+
Err(err) => {
289+
error!("ETH funding failed for wallet {}: {}", global_idx, err);
290+
None
291+
}
292+
}
293+
});
294+
eth_funding_handles.push(handle);
295+
}
296+
297+
// Wait for ETH funding to complete
298+
let mut funded_indices = Vec::new();
299+
for handle in eth_funding_handles {
300+
if let Ok(Some(idx)) = handle.await {
301+
funded_indices.push(idx);
302+
}
182303
}
183-
info!("Wallet {} funded", i);
184304

185-
// Deposit to aligned
186-
let amount_to_deposit_to_aligned =
187-
parse_ether(&amount_to_deposit_aligned).expect("Ether format should be: XX.XX");
188305
info!(
189-
"Depositing {}wei to aligned {}",
190-
amount_to_deposit_to_aligned, i
306+
"Batch {}: ETH funding completed for {} out of {} wallets",
307+
batch_idx + 1,
308+
funded_indices.len(),
309+
wallet_chunk.len()
191310
);
192-
let signer = SignerMiddleware::new(eth_rpc_provider.clone(), wallet.clone());
193-
if let Err(err) = deposit_to_aligned(
194-
amount_to_deposit_to_aligned,
195-
signer,
196-
args.network.clone().into(),
197-
)
198-
.await
199-
{
200-
error!("Could not deposit to aligned, err: {:?}", err);
201-
return;
311+
312+
if funded_indices.is_empty() {
313+
warn!(
314+
"Batch {}: No wallets were funded, skipping Aligned deposits",
315+
batch_idx + 1
316+
);
317+
current_nonce += U256::from(wallet_chunk.len());
318+
continue;
202319
}
203-
info!("Successfully deposited to aligned for wallet {}", i);
204320

205-
// Store private key
206-
info!("Storing private key");
207-
let signer_bytes = wallet.signer().to_bytes();
208-
let secret_key_hex = ethers::utils::hex::encode(signer_bytes);
321+
// Aligned deposit phase for funded wallets in this batch
322+
info!(
323+
"Batch {}: Starting Aligned deposit transactions...",
324+
batch_idx + 1
325+
);
326+
let mut aligned_deposit_handles = Vec::new();
327+
328+
for &idx in &funded_indices {
329+
let wallet = wallets[idx].clone();
330+
let eth_rpc_provider = eth_rpc_provider.clone();
331+
let network = args.network.clone();
332+
333+
let handle = tokio::spawn(async move {
209334

210-
if let Err(err) = writeln!(file, "{}", secret_key_hex) {
211-
error!("Could not store private key: {}", err);
212-
} else {
213-
info!("Private key {} stored", i);
335+
info!("Submitting Aligned deposit for wallet {}", idx);
336+
let signer = SignerMiddleware::new(eth_rpc_provider, wallet);
337+
338+
match deposit_to_aligned(amount_to_deposit_to_aligned, signer, network.into()).await
339+
{
340+
Ok(_) => {
341+
info!("Successfully deposited to aligned for wallet {}", idx);
342+
Ok(idx)
343+
}
344+
Err(err) => {
345+
error!("Could not deposit to aligned for wallet {}: {:?}", idx, err);
346+
Err(idx)
347+
}
348+
}
349+
});
350+
aligned_deposit_handles.push(handle);
351+
}
352+
353+
// Wait for Aligned deposits to complete and write private keys immediately
354+
let mut batch_successful = 0;
355+
for handle in aligned_deposit_handles {
356+
if let Ok(Ok(idx)) = handle.await {
357+
let wallet_address = wallets[idx].address();
358+
let private_key = &wallet_private_keys[idx];
359+
360+
// Write to original file (private key only) for compatibility
361+
if let Err(err) = writeln!(file, "{}", private_key) {
362+
error!("Could not store private key for wallet {}: {}", idx, err);
363+
continue;
364+
}
365+
366+
// Write to new file (private_key;address format)
367+
let detailed_filepath = format!("{}.detailed", args.private_keys_filepath);
368+
let detailed_file = std::fs::OpenOptions::new()
369+
.create(true)
370+
.append(true)
371+
.open(&detailed_filepath);
372+
373+
match detailed_file {
374+
Ok(mut f) => {
375+
if let Err(err) = writeln!(f, "{};{:?}", private_key, wallet_address) {
376+
error!("Could not store detailed info for wallet {}: {}", idx, err);
377+
} else {
378+
info!("Wallet {} stored: private key and address saved", idx);
379+
batch_successful += 1;
380+
}
381+
}
382+
Err(err) => {
383+
error!("Could not open detailed file {}: {}", detailed_filepath, err);
384+
// Still count as successful since main file was written
385+
info!("Private key for wallet {} stored (detailed file failed)", idx);
386+
batch_successful += 1;
387+
}
388+
}
389+
}
214390
}
391+
392+
total_successful += batch_successful;
393+
current_nonce += U256::from(wallet_chunk.len());
394+
395+
info!(
396+
"Batch {} completed: {} wallets successfully funded and deposited (Total: {} / {})",
397+
batch_idx + 1,
398+
batch_successful,
399+
total_successful,
400+
args.number_of_wallets
401+
);
402+
403+
// Optional: Small delay between batches (commented out for speed)
404+
// if batch_idx + 1 < total_batches {
405+
// tokio::time::sleep(Duration::from_millis(50)).await;
406+
// }
215407
}
408+
409+
info!(
410+
"All batches completed! Successfully created and funded {} wallets out of {} requested",
411+
total_successful, args.number_of_wallets
412+
);
413+
info!(
414+
"Private keys for {} successful wallets stored in:",
415+
total_successful
416+
);
417+
info!(" - {} (private keys only, for compatibility)", args.private_keys_filepath);
418+
info!(" - {}.detailed (private_key;address format)", args.private_keys_filepath);
216419
}
217420

218421
/// infinitely hangs connections

0 commit comments

Comments
 (0)