From 680220d345dcae5518d939abf405bffe1429ea28 Mon Sep 17 00:00:00 2001 From: BretasArthur1 Date: Tue, 26 Aug 2025 22:11:40 -0300 Subject: [PATCH 1/7] feat(cli): enhance airdrop address handling by adding default keypair support and updating return values --- crates/cli/src/cli/mod.rs | 15 +++++++++++---- crates/cli/src/cli/simnet/mod.rs | 8 ++++++-- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/crates/cli/src/cli/mod.rs b/crates/cli/src/cli/mod.rs index 100484e4..596b5cea 100644 --- a/crates/cli/src/cli/mod.rs +++ b/crates/cli/src/cli/mod.rs @@ -169,7 +169,7 @@ pub struct StartSimnet { #[arg(long = "airdrop-amount", short = 'q', default_value = DEFAULT_AIRDROP_AMOUNT)] pub airdrop_token_amount: u64, /// List of keypair paths to airdrop - #[arg(long = "airdrop-keypair-path", short = 'k', default_value = DEFAULT_SOLANA_KEYPAIR_PATH.as_str())] + #[arg(long = "airdrop-keypair-path", short = 'k')] pub airdrop_keypair_path: Vec, /// Disable explorer (default: false) #[clap(long = "no-explorer")] @@ -205,9 +205,10 @@ pub enum NetworkType { } impl StartSimnet { - pub fn get_airdrop_addresses(&self) -> (Vec, Vec) { + pub fn get_airdrop_addresses(&self) -> (Vec, Vec, bool) { let mut airdrop_addresses = vec![]; let mut errors = vec![]; + let mut using_default_keypair = false; for address in self.airdrop_addresses.iter() { match Pubkey::from_str(address).map_err(|e| e.to_string()) { Ok(pubkey) => { @@ -223,7 +224,13 @@ impl StartSimnet { } } - for keypair_path in self.airdrop_keypair_path.iter() { + let mut airdrop_keypair_path = self.airdrop_keypair_path.clone(); + if airdrop_keypair_path.is_empty() { + using_default_keypair = true; + airdrop_keypair_path.push(DEFAULT_SOLANA_KEYPAIR_PATH.clone()); + } + + for keypair_path in airdrop_keypair_path.iter() { let path = resolve_path(keypair_path); match Keypair::read_from_file(&path) { Ok(pubkey) => { @@ -238,7 +245,7 @@ impl StartSimnet { } } } - (airdrop_addresses, errors) + (airdrop_addresses, errors, using_default_keypair) } pub fn rpc_config(&self) -> RpcConfig { diff --git a/crates/cli/src/cli/simnet/mod.rs b/crates/cli/src/cli/simnet/mod.rs index dc9a20c5..50d1e42c 100644 --- a/crates/cli/src/cli/simnet/mod.rs +++ b/crates/cli/src/cli/simnet/mod.rs @@ -25,7 +25,7 @@ use txtx_core::kit::{ }; use txtx_gql::kit::reqwest; -use super::{Context, DEFAULT_CLOUD_URL, ExecuteRunbook, StartSimnet}; +use super::{Context, DEFAULT_CLOUD_URL, DEFAULT_SOLANA_KEYPAIR_PATH, ExecuteRunbook, StartSimnet}; use crate::{ http::start_subgraph_and_explorer_server, runbook::execute_runbook, @@ -51,7 +51,7 @@ pub async fn handle_start_local_surfnet_command( let simnet_events_tx = surfnet_svm.simnet_events_tx.clone(); // Check aidrop addresses - let (mut airdrop_addresses, airdrop_errors) = cmd.get_airdrop_addresses(); + let (mut airdrop_addresses, airdrop_errors, using_default_keypair) = cmd.get_airdrop_addresses(); let breaker = if cmd.no_tui { None @@ -144,6 +144,10 @@ pub async fn handle_start_local_surfnet_command( } } + if using_default_keypair { + let _ = simnet_events_tx.send(SimnetEvent::info(format!("No airdrop addresses provided; Using default one from {}", DEFAULT_SOLANA_KEYPAIR_PATH.as_str()))); + } + for error in airdrop_errors { let _ = simnet_events_tx.send(SimnetEvent::warn(error)); } From b0c98aeec18a7c063babc47dab50299767bfa63e Mon Sep 17 00:00:00 2001 From: BretasArthur1 Date: Tue, 26 Aug 2025 22:11:57 -0300 Subject: [PATCH 2/7] fix: fmt --- crates/cli/src/cli/simnet/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/cli/src/cli/simnet/mod.rs b/crates/cli/src/cli/simnet/mod.rs index 50d1e42c..3eb182b2 100644 --- a/crates/cli/src/cli/simnet/mod.rs +++ b/crates/cli/src/cli/simnet/mod.rs @@ -51,7 +51,8 @@ pub async fn handle_start_local_surfnet_command( let simnet_events_tx = surfnet_svm.simnet_events_tx.clone(); // Check aidrop addresses - let (mut airdrop_addresses, airdrop_errors, using_default_keypair) = cmd.get_airdrop_addresses(); + let (mut airdrop_addresses, airdrop_errors, using_default_keypair) = + cmd.get_airdrop_addresses(); let breaker = if cmd.no_tui { None @@ -145,7 +146,10 @@ pub async fn handle_start_local_surfnet_command( } if using_default_keypair { - let _ = simnet_events_tx.send(SimnetEvent::info(format!("No airdrop addresses provided; Using default one from {}", DEFAULT_SOLANA_KEYPAIR_PATH.as_str()))); + let _ = simnet_events_tx.send(SimnetEvent::info(format!( + "No airdrop addresses provided; Using default one from {}", + DEFAULT_SOLANA_KEYPAIR_PATH.as_str() + ))); } for error in airdrop_errors { From a2f91fca5375aac3b25a7a0fdcfbb85261a1aa8c Mon Sep 17 00:00:00 2001 From: Arthur Bretas <158767751+BretasArthur1@users.noreply.github.com> Date: Wed, 27 Aug 2025 10:43:21 -0300 Subject: [PATCH 3/7] Update crates/cli/src/cli/simnet/mod.rs Co-authored-by: Micaiah Reid --- crates/cli/src/cli/simnet/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/src/cli/simnet/mod.rs b/crates/cli/src/cli/simnet/mod.rs index 3eb182b2..d44bfcc3 100644 --- a/crates/cli/src/cli/simnet/mod.rs +++ b/crates/cli/src/cli/simnet/mod.rs @@ -147,7 +147,7 @@ pub async fn handle_start_local_surfnet_command( if using_default_keypair { let _ = simnet_events_tx.send(SimnetEvent::info(format!( - "No airdrop addresses provided; Using default one from {}", + "No airdrop addresses provided; Using default keypair at {}", DEFAULT_SOLANA_KEYPAIR_PATH.as_str() ))); } From f7212035d7afc41f68926f0951aebdc7fe2938c3 Mon Sep 17 00:00:00 2001 From: BretasArthur1 Date: Wed, 27 Aug 2025 11:11:40 -0300 Subject: [PATCH 4/7] docs(cli): add docs about default path to cli command --- crates/cli/src/cli/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/cli/src/cli/mod.rs b/crates/cli/src/cli/mod.rs index 596b5cea..05819a08 100644 --- a/crates/cli/src/cli/mod.rs +++ b/crates/cli/src/cli/mod.rs @@ -168,7 +168,7 @@ pub struct StartSimnet { /// Quantity of tokens to airdrop #[arg(long = "airdrop-amount", short = 'q', default_value = DEFAULT_AIRDROP_AMOUNT)] pub airdrop_token_amount: u64, - /// List of keypair paths to airdrop + /// List of keypair paths to airdrop (default: ~/.config/solana/id.json) #[arg(long = "airdrop-keypair-path", short = 'k')] pub airdrop_keypair_path: Vec, /// Disable explorer (default: false) From e4b2459b91f1cdd10cd4bc35d1a6c146e7e43af7 Mon Sep 17 00:00:00 2001 From: BretasArthur1 Date: Wed, 27 Aug 2025 18:16:54 -0300 Subject: [PATCH 5/7] fix(cli): update airdrop address handling to include default keypair loaded status in return values --- crates/cli/src/cli/mod.rs | 34 +++++++++++++++++++++++++------- crates/cli/src/cli/simnet/mod.rs | 4 ++-- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/crates/cli/src/cli/mod.rs b/crates/cli/src/cli/mod.rs index 05819a08..424fd0cc 100644 --- a/crates/cli/src/cli/mod.rs +++ b/crates/cli/src/cli/mod.rs @@ -205,10 +205,11 @@ pub enum NetworkType { } impl StartSimnet { - pub fn get_airdrop_addresses(&self) -> (Vec, Vec, bool) { + pub fn get_airdrop_addresses(&self) -> (Vec, Vec, bool, bool) { let mut airdrop_addresses = vec![]; let mut errors = vec![]; let mut using_default_keypair = false; + let mut default_keypair_loaded = false; for address in self.airdrop_addresses.iter() { match Pubkey::from_str(address).map_err(|e| e.to_string()) { Ok(pubkey) => { @@ -230,22 +231,41 @@ impl StartSimnet { airdrop_keypair_path.push(DEFAULT_SOLANA_KEYPAIR_PATH.clone()); } + let default_resolved_path = resolve_path(DEFAULT_SOLANA_KEYPAIR_PATH.as_str()); + for keypair_path in airdrop_keypair_path.iter() { let path = resolve_path(keypair_path); match Keypair::read_from_file(&path) { Ok(pubkey) => { airdrop_addresses.push(pubkey.pubkey()); + if using_default_keypair && path == default_resolved_path { + default_keypair_loaded = true; + } } - Err(e) => { - errors.push(format!( - "Unable to complete airdrop; Error reading keypair file: {}: {e}", - path.display() - )); + Err(_) => { + match using_default_keypair { + true => { + errors.push( + format!("No keypair found at {}, if you want to airdrop to a specific keypair provide the -k flag; skipping airdrops", DEFAULT_SOLANA_KEYPAIR_PATH.to_string()) + ); + } + false => { + errors.push(format!( + "No keypair found at provided path {}; skipping airdrops;", + path.display() + )); + } + } continue; } } } - (airdrop_addresses, errors, using_default_keypair) + ( + airdrop_addresses, + errors, + using_default_keypair, + default_keypair_loaded, + ) } pub fn rpc_config(&self) -> RpcConfig { diff --git a/crates/cli/src/cli/simnet/mod.rs b/crates/cli/src/cli/simnet/mod.rs index d44bfcc3..91470cba 100644 --- a/crates/cli/src/cli/simnet/mod.rs +++ b/crates/cli/src/cli/simnet/mod.rs @@ -51,7 +51,7 @@ pub async fn handle_start_local_surfnet_command( let simnet_events_tx = surfnet_svm.simnet_events_tx.clone(); // Check aidrop addresses - let (mut airdrop_addresses, airdrop_errors, using_default_keypair) = + let (mut airdrop_addresses, airdrop_errors, using_default_keypair, default_keypair_loaded) = cmd.get_airdrop_addresses(); let breaker = if cmd.no_tui { @@ -145,7 +145,7 @@ pub async fn handle_start_local_surfnet_command( } } - if using_default_keypair { + if using_default_keypair && default_keypair_loaded { let _ = simnet_events_tx.send(SimnetEvent::info(format!( "No airdrop addresses provided; Using default keypair at {}", DEFAULT_SOLANA_KEYPAIR_PATH.as_str() From e840f056331b760cf12da72c3a70eff5c9fcc271 Mon Sep 17 00:00:00 2001 From: BretasArthur1 Date: Wed, 27 Aug 2025 23:30:59 -0300 Subject: [PATCH 6/7] refactor(cli): simplify airdrop address handling by removing bolean variables and improving event logging --- crates/cli/src/cli/mod.rs | 93 +++++++++++++++++--------------- crates/cli/src/cli/simnet/mod.rs | 16 ++---- 2 files changed, 53 insertions(+), 56 deletions(-) diff --git a/crates/cli/src/cli/mod.rs b/crates/cli/src/cli/mod.rs index 424fd0cc..fe57bc40 100644 --- a/crates/cli/src/cli/mod.rs +++ b/crates/cli/src/cli/mod.rs @@ -9,8 +9,8 @@ use solana_signer::{EncodableKey, Signer}; use surfpool_mcp::McpOptions; use surfpool_types::{ CHANGE_TO_DEFAULT_STUDIO_PORT_ONCE_SUPERVISOR_MERGED, DEFAULT_NETWORK_HOST, DEFAULT_RPC_PORT, - DEFAULT_SLOT_TIME_MS, DEFAULT_WS_PORT, RpcConfig, SimnetConfig, StudioConfig, SubgraphConfig, - SurfpoolConfig, + DEFAULT_SLOT_TIME_MS, DEFAULT_WS_PORT, RpcConfig, SimnetConfig, SimnetEvent, StudioConfig, + SubgraphConfig, SurfpoolConfig, }; use txtx_cloud::LoginCommand; use txtx_core::manifest::WorkspaceManifest; @@ -205,67 +205,72 @@ pub enum NetworkType { } impl StartSimnet { - pub fn get_airdrop_addresses(&self) -> (Vec, Vec, bool, bool) { + pub fn get_airdrop_addresses(&self) -> (Vec, Vec) { let mut airdrop_addresses = vec![]; - let mut errors = vec![]; - let mut using_default_keypair = false; - let mut default_keypair_loaded = false; + let mut events = vec![]; + for address in self.airdrop_addresses.iter() { match Pubkey::from_str(address).map_err(|e| e.to_string()) { - Ok(pubkey) => { - airdrop_addresses.push(pubkey); - } + Ok(pubkey) => airdrop_addresses.push(pubkey), Err(e) => { - errors.push(format!( + events.push(SimnetEvent::error(format!( "Unable to airdrop pubkey {}: Error parsing pubkey: {e}", address - )); + ))); continue; } } } - let mut airdrop_keypair_path = self.airdrop_keypair_path.clone(); - if airdrop_keypair_path.is_empty() { - using_default_keypair = true; - airdrop_keypair_path.push(DEFAULT_SOLANA_KEYPAIR_PATH.clone()); - } + let airdrop_keypair_path = self.airdrop_keypair_path.clone(); + let default_keypair_path = DEFAULT_SOLANA_KEYPAIR_PATH.clone(); + let default_resolved_path = resolve_path(default_keypair_path.as_str()); - let default_resolved_path = resolve_path(DEFAULT_SOLANA_KEYPAIR_PATH.as_str()); + let mut none_provided_default_exists = false; + let mut none_provided_default_does_not_exist = false; - for keypair_path in airdrop_keypair_path.iter() { - let path = resolve_path(keypair_path); - match Keypair::read_from_file(&path) { - Ok(pubkey) => { - airdrop_addresses.push(pubkey.pubkey()); - if using_default_keypair && path == default_resolved_path { - default_keypair_loaded = true; - } + if airdrop_keypair_path.is_empty() { + // No keypair paths provided: try default + match Keypair::read_from_file(&default_resolved_path) { + Ok(kp) => { + airdrop_addresses.push(kp.pubkey()); + none_provided_default_exists = true; } Err(_) => { - match using_default_keypair { - true => { - errors.push( - format!("No keypair found at {}, if you want to airdrop to a specific keypair provide the -k flag; skipping airdrops", DEFAULT_SOLANA_KEYPAIR_PATH.to_string()) - ); - } - false => { - errors.push(format!( - "No keypair found at provided path {}; skipping airdrops;", - path.display() - )); - } + none_provided_default_does_not_exist = true; + } + } + } else { + // User provided paths: load each, warn on failures + for keypair_path in airdrop_keypair_path.iter() { + let path = resolve_path(keypair_path); + match Keypair::read_from_file(&path) { + Ok(pubkey) => { + airdrop_addresses.push(pubkey.pubkey()); + } + Err(_) => { + events.push(SimnetEvent::warn(format!( + "No keypair found at provided path {}; skipping airdrop for that keypair;", + path.display() + ))); } - continue; } } } - ( - airdrop_addresses, - errors, - using_default_keypair, - default_keypair_loaded, - ) + + if none_provided_default_exists { + events.push(SimnetEvent::info(format!( + "No airdrop addresses provided; Using default keypair at {}", + DEFAULT_SOLANA_KEYPAIR_PATH.as_str() + ))); + } else if none_provided_default_does_not_exist { + events.push(SimnetEvent::info(format!( + "No keypair found at default location {}, if you want to airdrop to a specific keypair provide the -k flag; skipping airdrops", + DEFAULT_SOLANA_KEYPAIR_PATH.as_str() + ))); + } + + (airdrop_addresses, events) } pub fn rpc_config(&self) -> RpcConfig { diff --git a/crates/cli/src/cli/simnet/mod.rs b/crates/cli/src/cli/simnet/mod.rs index 91470cba..496f0716 100644 --- a/crates/cli/src/cli/simnet/mod.rs +++ b/crates/cli/src/cli/simnet/mod.rs @@ -25,7 +25,7 @@ use txtx_core::kit::{ }; use txtx_gql::kit::reqwest; -use super::{Context, DEFAULT_CLOUD_URL, DEFAULT_SOLANA_KEYPAIR_PATH, ExecuteRunbook, StartSimnet}; +use super::{Context, DEFAULT_CLOUD_URL, ExecuteRunbook, StartSimnet}; use crate::{ http::start_subgraph_and_explorer_server, runbook::execute_runbook, @@ -51,8 +51,7 @@ pub async fn handle_start_local_surfnet_command( let simnet_events_tx = surfnet_svm.simnet_events_tx.clone(); // Check aidrop addresses - let (mut airdrop_addresses, airdrop_errors, using_default_keypair, default_keypair_loaded) = - cmd.get_airdrop_addresses(); + let (mut airdrop_addresses, airdrop_events) = cmd.get_airdrop_addresses(); let breaker = if cmd.no_tui { None @@ -145,15 +144,8 @@ pub async fn handle_start_local_surfnet_command( } } - if using_default_keypair && default_keypair_loaded { - let _ = simnet_events_tx.send(SimnetEvent::info(format!( - "No airdrop addresses provided; Using default keypair at {}", - DEFAULT_SOLANA_KEYPAIR_PATH.as_str() - ))); - } - - for error in airdrop_errors { - let _ = simnet_events_tx.send(SimnetEvent::warn(error)); + for event in airdrop_events { + let _ = simnet_events_tx.send(event); } let mut deploy_progress_rx = vec![]; From 8fcea58084d1836afb853ddb8e4a88e821fe2027 Mon Sep 17 00:00:00 2001 From: MicaiahReid Date: Thu, 28 Aug 2025 11:39:22 -0400 Subject: [PATCH 7/7] chore(cli): code cleanup --- crates/cli/src/cli/mod.rs | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/crates/cli/src/cli/mod.rs b/crates/cli/src/cli/mod.rs index fe57bc40..3a752be5 100644 --- a/crates/cli/src/cli/mod.rs +++ b/crates/cli/src/cli/mod.rs @@ -213,7 +213,7 @@ impl StartSimnet { match Pubkey::from_str(address).map_err(|e| e.to_string()) { Ok(pubkey) => airdrop_addresses.push(pubkey), Err(e) => { - events.push(SimnetEvent::error(format!( + events.push(SimnetEvent::warn(format!( "Unable to airdrop pubkey {}: Error parsing pubkey: {e}", address ))); @@ -223,21 +223,23 @@ impl StartSimnet { } let airdrop_keypair_path = self.airdrop_keypair_path.clone(); - let default_keypair_path = DEFAULT_SOLANA_KEYPAIR_PATH.clone(); - let default_resolved_path = resolve_path(default_keypair_path.as_str()); - - let mut none_provided_default_exists = false; - let mut none_provided_default_does_not_exist = false; if airdrop_keypair_path.is_empty() { + let default_resolved_path = resolve_path(&DEFAULT_SOLANA_KEYPAIR_PATH); // No keypair paths provided: try default match Keypair::read_from_file(&default_resolved_path) { Ok(kp) => { airdrop_addresses.push(kp.pubkey()); - none_provided_default_exists = true; + events.push(SimnetEvent::info(format!( + "No airdrop addresses provided; Using default keypair at {}", + DEFAULT_SOLANA_KEYPAIR_PATH.as_str() + ))); } Err(_) => { - none_provided_default_does_not_exist = true; + events.push(SimnetEvent::info(format!( + "No keypair found at default location {}, if you want to airdrop to a specific keypair provide the -k flag; skipping airdrops", + DEFAULT_SOLANA_KEYPAIR_PATH.as_str() + ))); } } } else { @@ -250,7 +252,7 @@ impl StartSimnet { } Err(_) => { events.push(SimnetEvent::warn(format!( - "No keypair found at provided path {}; skipping airdrop for that keypair;", + "No keypair found at provided path {}; skipping airdrop for that keypair", path.display() ))); } @@ -258,18 +260,6 @@ impl StartSimnet { } } - if none_provided_default_exists { - events.push(SimnetEvent::info(format!( - "No airdrop addresses provided; Using default keypair at {}", - DEFAULT_SOLANA_KEYPAIR_PATH.as_str() - ))); - } else if none_provided_default_does_not_exist { - events.push(SimnetEvent::info(format!( - "No keypair found at default location {}, if you want to airdrop to a specific keypair provide the -k flag; skipping airdrops", - DEFAULT_SOLANA_KEYPAIR_PATH.as_str() - ))); - } - (airdrop_addresses, events) }