diff --git a/src/bin/sys-lend.rs b/src/bin/sys-lend.rs index 1589c15..cf99c90 100644 --- a/src/bin/sys-lend.rs +++ b/src/bin/sys-lend.rs @@ -35,6 +35,7 @@ use { kamino, marginfi_v2, solend::{self, math::TryMul}, }, + RpcClients, }, }; @@ -449,15 +450,21 @@ async fn main() -> Result<(), Box> { let app_matches = app.get_matches(); - let json_rpc_url = - normalize_to_url_if_moniker(value_t_or_exit!(app_matches, "json_rpc_url", String)); - let rpc_client = RpcClient::new_with_commitment(&json_rpc_url, CommitmentConfig::confirmed()); - let send_json_rpc_url = match value_t!(app_matches, "send_json_rpc_url", String).ok() { - Some(send_json_rpc_url) => normalize_to_url_if_moniker(send_json_rpc_url), - None => json_rpc_url, + let rpc_clients = RpcClients { + default: RpcClient::new_with_commitment( + normalize_to_url_if_moniker(value_t_or_exit!(app_matches, "json_rpc_url", String)), + CommitmentConfig::confirmed(), + ), + send: value_t!(app_matches, "send_json_rpc_url", String) + .ok() + .map(|send_json_rpc_url| { + RpcClient::new_with_commitment( + normalize_to_url_if_moniker(send_json_rpc_url), + CommitmentConfig::confirmed(), + ) + }), }; - let send_rpc_client = - RpcClient::new_with_commitment(send_json_rpc_url, CommitmentConfig::confirmed()); + let rpc_client = &rpc_clients.default; let priority_fee = if let Ok(ui_priority_fee) = value_t!(app_matches, "priority_fee_exact", f64) { @@ -524,7 +531,7 @@ async fn main() -> Result<(), Box> { let mut pool_apy = BTreeMap::new(); for pool in pools { let apy = apr_to_apy(pool_supply_apr( - &rpc_client, + rpc_client, &pool, token, &mut account_data_cache, @@ -596,14 +603,9 @@ async fn main() -> Result<(), Box> { let mut total_amount = 0; let mut non_empty_pools_count = 0; for pool in &pools { - let (amount, remaining_outflow) = pool_supply_balance( - &rpc_client, - pool, - token, - address, - &mut account_data_cache, - )?; - let apr = pool_supply_apr(&rpc_client, pool, token, &mut account_data_cache)?; + let (amount, remaining_outflow) = + pool_supply_balance(rpc_client, pool, token, address, &mut account_data_cache)?; + let apr = pool_supply_apr(rpc_client, pool, token, &mut account_data_cache)?; let msg = format!( "{:>15}: {} supplied at {:.2}%{}", @@ -674,7 +676,7 @@ async fn main() -> Result<(), Box> { .unwrap_or_else(|| supported_pools_for_token(token)); let minimum_apy_bps = value_t!(matches, "minimum_apy", u16).unwrap_or(0); - let token_balance = maybe_token.balance(&rpc_client, &address)?; + let token_balance = maybe_token.balance(rpc_client, &address)?; let amount = match matches.value_of("amount").unwrap() { "ALL" => { if cmd == Command::Deposit { @@ -711,7 +713,7 @@ async fn main() -> Result<(), Box> { .iter() .map(|pool| { let (supply_balance, remaining_outflow) = pool_supply_balance( - &rpc_client, + rpc_client, pool, token, address, @@ -735,7 +737,7 @@ async fn main() -> Result<(), Box> { .iter() .map(|pool| { let supply_apr = - pool_supply_apr(&rpc_client, pool, token, &mut account_data_cache) + pool_supply_apr(rpc_client, pool, token, &mut account_data_cache) .unwrap_or_else(|err| panic!("Unable to read apr for {pool}: {err}")); (pool.clone(), supply_apr) }) @@ -818,7 +820,7 @@ async fn main() -> Result<(), Box> { let result = if pool.starts_with("kamino-") { kamino_deposit_or_withdraw( op, - &rpc_client, + rpc_client, pool, address, token, @@ -828,7 +830,7 @@ async fn main() -> Result<(), Box> { } else if pool.starts_with("solend-") { solend_deposit_or_withdraw( op, - &rpc_client, + rpc_client, pool, address, token, @@ -838,7 +840,7 @@ async fn main() -> Result<(), Box> { } else if pool == "mfi" { mfi_deposit_or_withdraw( op, - &rpc_client, + rpc_client, address, token, amount, @@ -966,7 +968,7 @@ async fn main() -> Result<(), Box> { } apply_priority_fee( - &rpc_client, + rpc_client, &mut instructions, required_compute_units, priority_fee, @@ -1035,16 +1037,13 @@ async fn main() -> Result<(), Box> { ), }; - let simulation_result = send_rpc_client.simulate_transaction(&transaction)?.value; + let simulation_result = rpc_client.simulate_transaction(&transaction)?.value; if simulation_result.err.is_some() { return Err(format!("Simulation failure: {simulation_result:?}").into()); } - if !send_transaction_until_expired( - &send_rpc_client, - &transaction, - last_valid_block_height, - ) { + if !send_transaction_until_expired(&rpc_clients, &transaction, last_valid_block_height) + { let msg = format!("Transaction failed: {signature}"); notifier.send(&msg).await; return Err(msg.into()); diff --git a/src/lib.rs b/src/lib.rs index 510ddb8..21b5fa3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,9 +22,14 @@ pub fn app_version() -> String { }) } +pub struct RpcClients { + pub default: RpcClient, + pub send: Option, +} + // Assumes `transaction` has already been signed and simulated... pub fn send_transaction_until_expired( - rpc_client: &RpcClient, + rpc_clients: &RpcClients, transaction: &impl SerializableTransaction, last_valid_block_height: u64, ) -> bool { @@ -36,6 +41,8 @@ pub fn send_transaction_until_expired( }, }; + let rpc_client = rpc_clients.send.as_ref().unwrap_or(&rpc_clients.default); + let mut last_send_attempt = None; let config = RpcSendTransactionConfig { diff --git a/src/main.rs b/src/main.rs index 91b50e8..ae3a0a7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -53,6 +53,7 @@ use { send_transaction_until_expired, token::*, //tulip, + RpcClients, }, }; @@ -427,7 +428,7 @@ async fn process_sync_exchange( #[allow(clippy::too_many_arguments)] async fn process_exchange_deposit( db: &mut Db, - rpc_client: &RpcClient, + rpc_clients: &RpcClients, exchange: Exchange, exchange_client: &dyn ExchangeClient, token: MaybeToken, @@ -442,6 +443,8 @@ async fn process_exchange_deposit( lot_numbers: Option>, priority_fee: PriorityFee, ) -> Result<(), Box> { + let rpc_client = &rpc_clients.default; + if let Some(if_exchange_balance_less_than) = if_exchange_balance_less_than { let exchange_balance = exchange_client .balances() @@ -656,7 +659,7 @@ async fn process_exchange_deposit( lot_selection_method, lot_numbers, )?; - if !send_transaction_until_expired(rpc_client, &transaction, last_valid_block_height) { + if !send_transaction_until_expired(rpc_clients, &transaction, last_valid_block_height) { return Err("Deposit failed".into()); } Ok(()) @@ -1019,7 +1022,7 @@ async fn process_jup_quote( #[allow(clippy::too_many_arguments)] async fn process_jup_swap( db: &mut Db, - rpc_client: &RpcClient, + rpc_clients: &RpcClients, address: Pubkey, from_token: MaybeToken, to_token: MaybeToken, @@ -1034,6 +1037,8 @@ async fn process_jup_swap( priority_fee: PriorityFee, notifier: &Notifier, ) -> Result<(), Box> { + let rpc_client = &rpc_clients.default; + let from_account = db .get_account(address, from_token) .ok_or_else(|| format!("{from_token} account does not exist for {address}"))?; @@ -1230,7 +1235,7 @@ async fn process_jup_swap( lot_selection_method, )?; - if !send_transaction_until_expired(rpc_client, &transaction, last_valid_block_height) { + if !send_transaction_until_expired(rpc_clients, &transaction, last_valid_block_height) { db.cancel_swap(signature)?; return Err("Swap failed".into()); } @@ -2947,7 +2952,7 @@ async fn process_account_xls( #[allow(clippy::too_many_arguments)] async fn process_account_merge( db: &mut Db, - rpc_client: &RpcClient, + rpc_clients: &RpcClients, from_address: Pubkey, into_address: Pubkey, authority_address: Pubkey, @@ -2955,6 +2960,7 @@ async fn process_account_merge( priority_fee: PriorityFee, existing_signature: Option, ) -> Result<(), Box> { + let rpc_client = &rpc_clients.default; let token = MaybeToken::SOL(); // TODO: Support merging tokens one day if let Some(existing_signature) = existing_signature { @@ -3054,7 +3060,7 @@ async fn process_account_merge( None, )?; - if !send_transaction_until_expired(rpc_client, &transaction, last_valid_block_height) { + if !send_transaction_until_expired(rpc_clients, &transaction, last_valid_block_height) { db.cancel_transfer(signature)?; return Err("Merge failed".into()); } @@ -3068,7 +3074,7 @@ async fn process_account_merge( #[allow(clippy::too_many_arguments)] async fn process_account_sweep( db: &mut Db, - rpc_client: &RpcClient, + rpc_clients: &RpcClients, from_address: Pubkey, token: MaybeToken, retain_amount: u64, @@ -3081,6 +3087,8 @@ async fn process_account_sweep( priority_fee: PriorityFee, existing_signature: Option, ) -> Result<(), Box> { + let rpc_client = &rpc_clients.default; + let (recent_blockhash, last_valid_block_height) = rpc_client.get_latest_blockhash_with_commitment(rpc_client.commitment())?; let fee_calculator = get_deprecated_fee_calculator(rpc_client)?; @@ -3398,7 +3406,7 @@ async fn process_account_sweep( )?; if let Some(transaction) = maybe_transaction { - if !send_transaction_until_expired(rpc_client, &transaction, last_valid_block_height) { + if !send_transaction_until_expired(rpc_clients, &transaction, last_valid_block_height) { db.cancel_transfer(signature)?; if let Some((transitory_stake_account, ..)) = via_transitory_stake.as_ref() { db.remove_transitory_sweep_stake_address(transitory_stake_account.pubkey())?; @@ -3418,7 +3426,7 @@ async fn process_account_sweep( #[allow(clippy::too_many_arguments)] async fn process_account_split( db: &mut Db, - rpc_client: &RpcClient, + rpc_clients: &RpcClients, from_address: Pubkey, amount: Option, description: Option, @@ -3430,6 +3438,8 @@ async fn process_account_split( if_balance_exceeds: Option, priority_fee: PriorityFee, ) -> Result<(), Box> { + let rpc_client = &rpc_clients.default; + // TODO: Support splitting two system accounts? Tokens? Otherwise at least error cleanly when it's attempted let token = MaybeToken::SOL(); // TODO: Support splitting tokens one day @@ -3536,7 +3546,7 @@ async fn process_account_split( lot_numbers, )?; - if !send_transaction_until_expired(rpc_client, &transaction, last_valid_block_height) { + if !send_transaction_until_expired(rpc_clients, &transaction, last_valid_block_height) { db.cancel_transfer(signature)?; db.remove_account(into_keypair.pubkey(), MaybeToken::SOL())?; return Err("Split failed".into()); @@ -3557,7 +3567,7 @@ async fn process_account_split( #[allow(clippy::too_many_arguments)] async fn process_account_redelegate( db: &mut Db, - rpc_client: &RpcClient, + rpc_clients: &RpcClients, from_address: Pubkey, vote_account_address: Pubkey, lot_selection_method: LotSelectionMethod, @@ -3565,6 +3575,7 @@ async fn process_account_redelegate( signers: &T, into_keypair: Option, ) -> Result<(), Box> { + let rpc_client = &rpc_clients.default; let (recent_blockhash, last_valid_block_height) = rpc_client.get_latest_blockhash_with_commitment(rpc_client.commitment())?; @@ -3649,7 +3660,7 @@ async fn process_account_redelegate( None, )?; - if !send_transaction_until_expired(rpc_client, &transaction, last_valid_block_height) { + if !send_transaction_until_expired(rpc_clients, &transaction, last_valid_block_height) { db.cancel_transfer(signature)?; db.remove_account(into_keypair.pubkey(), MaybeToken::SOL())?; return Err("Redelegate failed".into()); @@ -3663,15 +3674,16 @@ async fn process_account_redelegate( async fn process_account_sync( db: &mut Db, - rpc_client: &RpcClient, + rpc_clients: &RpcClients, address: Option, max_epochs_to_process: Option, reconcile_no_sync_account_balances: bool, force_rescan_balances: bool, notifier: &Notifier, ) -> Result<(), Box> { + let rpc_client = &rpc_clients.default; process_account_sync_pending_transfers(db, rpc_client).await?; - process_account_sync_sweep(db, rpc_client, notifier).await?; + process_account_sync_sweep(db, rpc_clients, notifier).await?; let (mut accounts, mut no_sync_accounts): (_, Vec<_>) = match address { Some(address) => { @@ -3893,7 +3905,7 @@ async fn process_account_sync( #[allow(clippy::too_many_arguments)] async fn process_account_wrap( db: &mut Db, - rpc_client: &RpcClient, + rpc_clients: &RpcClients, address: Pubkey, amount: Amount, if_source_balance_exceeds: Option, @@ -3903,6 +3915,7 @@ async fn process_account_wrap( signers: T, priority_fee: PriorityFee, ) -> Result<(), Box> { + let rpc_client = &rpc_clients.default; let sol = MaybeToken::SOL(); let wsol = Token::wSOL; let wsol_address = wsol.ata(&address); @@ -3986,7 +3999,7 @@ async fn process_account_wrap( lot_numbers, )?; - if !send_transaction_until_expired(rpc_client, &transaction, last_valid_block_height) { + if !send_transaction_until_expired(rpc_clients, &transaction, last_valid_block_height) { db.cancel_transfer(signature)?; return Err("Wrap failed".into()); } @@ -4000,7 +4013,7 @@ async fn process_account_wrap( #[allow(clippy::too_many_arguments)] async fn process_account_unwrap( db: &mut Db, - rpc_client: &RpcClient, + rpc_clients: &RpcClients, address: Pubkey, amount: Option, lot_selection_method: LotSelectionMethod, @@ -4009,6 +4022,7 @@ async fn process_account_unwrap( signers: T, priority_fee: PriorityFee, ) -> Result<(), Box> { + let rpc_client = &rpc_clients.default; let sol = MaybeToken::SOL(); let wsol = Token::wSOL; @@ -4084,7 +4098,7 @@ async fn process_account_unwrap( lot_numbers, )?; - if !send_transaction_until_expired(rpc_client, &transaction, last_valid_block_height) { + if !send_transaction_until_expired(rpc_clients, &transaction, last_valid_block_height) { db.cancel_transfer(signature)?; return Err("Wrap failed".into()); } @@ -4141,9 +4155,10 @@ async fn process_account_sync_pending_transfers( async fn process_account_sync_sweep( db: &mut Db, - rpc_client: &RpcClient, + rpc_clients: &RpcClients, _notifier: &Notifier, ) -> Result<(), Box> { + let rpc_client = &rpc_clients.default; let token = MaybeToken::SOL(); let transitory_sweep_stake_addresses = db.get_transitory_sweep_stake_addresses(); @@ -4282,7 +4297,7 @@ async fn process_account_sync_sweep( None, )?; - if !send_transaction_until_expired(rpc_client, &transaction, last_valid_block_height) { + if !send_transaction_until_expired(rpc_clients, &transaction, last_valid_block_height) { db.cancel_transfer(signature)?; return Err("Merge failed".into()); } @@ -4368,6 +4383,15 @@ async fn main() -> Result<(), Box> { .default_value(default_json_rpc_url) .help("JSON RPC URL for the cluster"), ) + .arg( + Arg::with_name("send_json_rpc_url") + .long("send-url") + .value_name("URL") + .takes_value(true) + .validator(is_url_or_moniker) + .help("Optional addition JSON RPC URL for the cluster to be used only \ + for submitting transactions [default: same as --url]"), + ) .arg( Arg::with_name("verbose") .short("v") @@ -5931,11 +5955,22 @@ async fn main() -> Result<(), Box> { PriorityFee::default_auto() }; - let rpc_client = RpcClient::new_with_timeout_and_commitment( - normalize_to_url_if_moniker(value_t_or_exit!(app_matches, "json_rpc_url", String)), - std::time::Duration::from_secs(120), - CommitmentConfig::confirmed(), - ); + let rpc_clients = RpcClients { + default: RpcClient::new_with_commitment( + normalize_to_url_if_moniker(value_t_or_exit!(app_matches, "json_rpc_url", String)), + CommitmentConfig::confirmed(), + ), + send: value_t!(app_matches, "send_json_rpc_url", String) + .ok() + .map(|send_json_rpc_url| { + RpcClient::new_with_commitment( + normalize_to_url_if_moniker(send_json_rpc_url), + CommitmentConfig::confirmed(), + ) + }), + }; + let rpc_client = &rpc_clients.default; + let mut wallet_manager = None; let notifier = Notifier::default(); @@ -5972,12 +6007,12 @@ async fn main() -> Result<(), Box> { let (price, verbose_msg) = if let Some(when) = when { ( - token.get_historical_price(&rpc_client, when).await?, + token.get_historical_price(rpc_client, when).await?, format!("Historical {token} price on {when}"), ) } else { ( - token.get_current_price(&rpc_client).await?, + token.get_current_price(rpc_client).await?, format!("Current {token} price"), ) }; @@ -5986,7 +6021,7 @@ async fn main() -> Result<(), Box> { println!("{verbose_msg}: ${price:.6}"); if let Some(liquidity_token) = token.liquidity_token() { - let rate = token.get_current_liquidity_token_rate(&rpc_client).await?; + let rate = token.get_current_liquidity_token_rate(rpc_client).await?; println!( "Liquidity token: {} (rate: {}, inv: {})", liquidity_token, @@ -6000,7 +6035,7 @@ async fn main() -> Result<(), Box> { } ("sync", Some(arg_matches)) => { let max_epochs_to_process = value_t!(arg_matches, "max_epochs_to_process", u64).ok(); - process_sync_swaps(&mut db, &rpc_client, ¬ifier).await?; + process_sync_swaps(&mut db, rpc_client, ¬ifier).await?; for (exchange, exchange_credentials, exchange_account) in db.get_default_accounts_from_configured_exchanges() { @@ -6010,14 +6045,14 @@ async fn main() -> Result<(), Box> { &mut db, exchange, exchange_client.as_ref(), - &rpc_client, + rpc_client, ¬ifier, ) .await? } process_account_sync( &mut db, - &rpc_client, + &rpc_clients, None, max_epochs_to_process, false, @@ -6132,7 +6167,7 @@ async fn main() -> Result<(), Box> { process_account_add( &mut db, - &rpc_client, + rpc_client, address, token.into(), description, @@ -6147,7 +6182,7 @@ async fn main() -> Result<(), Box> { .await?; process_account_sync( &mut db, - &rpc_client, + &rpc_clients, Some(address), None, false, @@ -6173,7 +6208,7 @@ async fn main() -> Result<(), Box> { process_account_dispose( &mut db, - &rpc_client, + rpc_client, address, token.into(), amount, @@ -6191,7 +6226,7 @@ async fn main() -> Result<(), Box> { let account_filter = pubkey_of(arg_matches, "account"); process_account_list( &db, - &rpc_client, + rpc_client, account_filter, all, summary, @@ -6253,7 +6288,7 @@ async fn main() -> Result<(), Box> { format!("Failed to read {}: {}", stake_authority.display(), err) })?; let (sweep_stake_authorized, _vote_account_address) = - rpc_client_utils::get_stake_authorized(&rpc_client, address)?; + rpc_client_utils::get_stake_authorized(rpc_client, address)?; if sweep_stake_authorized.staker != sweep_stake_authority_keypair.pubkey() { return Err("Stake authority mismatch".into()); @@ -6324,7 +6359,7 @@ async fn main() -> Result<(), Box> { process_account_merge( &mut db, - &rpc_client, + &rpc_clients, from_address, into_address, authority_address, @@ -6349,7 +6384,7 @@ async fn main() -> Result<(), Box> { process_account_sweep( &mut db, - &rpc_client, + &rpc_clients, from_address, token, token.amount(retain_ui_amount), @@ -6390,7 +6425,7 @@ async fn main() -> Result<(), Box> { process_account_split( &mut db, - &rpc_client, + &rpc_clients, from_address, amount, description, @@ -6424,7 +6459,7 @@ async fn main() -> Result<(), Box> { process_account_redelegate( &mut db, - &rpc_client, + &rpc_clients, from_address, vote_account_address, lot_selection_method, @@ -6443,7 +6478,7 @@ async fn main() -> Result<(), Box> { value_t!(arg_matches, "max_epochs_to_process", u64).ok(); process_account_sync( &mut db, - &rpc_client, + &rpc_clients, address, max_epochs_to_process, reconcile_no_sync_account_balances, @@ -6482,7 +6517,7 @@ async fn main() -> Result<(), Box> { process_account_wrap( &mut db, - &rpc_client, + &rpc_clients, address, amount, if_source_balance_exceeds, @@ -6517,7 +6552,7 @@ async fn main() -> Result<(), Box> { process_account_unwrap( &mut db, - &rpc_client, + &rpc_clients, address, amount, lot_selection_method, @@ -6562,7 +6597,7 @@ async fn main() -> Result<(), Box> { process_jup_swap( &mut db, - &rpc_client, + &rpc_clients, address, from_token, to_token, @@ -6578,7 +6613,7 @@ async fn main() -> Result<(), Box> { ¬ifier, ) .await?; - process_sync_swaps(&mut db, &rpc_client, ¬ifier).await?; + process_sync_swaps(&mut db, rpc_client, ¬ifier).await?; } _ => unreachable!(), }, @@ -6612,7 +6647,7 @@ async fn main() -> Result<(), Box> { stake_spreader::run( &mut db, - &rpc_client, + &rpc_clients, epoch_completed_percentage, epoch_history, num_validators, @@ -6893,11 +6928,11 @@ async fn main() -> Result<(), Box> { &exchange_account, token, deposit_address, - &rpc_client, + rpc_client, )?; process_exchange_deposit( &mut db, - &rpc_client, + &rpc_clients, exchange, exchange_client.as_ref(), token, @@ -6917,7 +6952,7 @@ async fn main() -> Result<(), Box> { &mut db, exchange, exchange_client.as_ref(), - &rpc_client, + rpc_client, ¬ifier, ) .await?; @@ -6945,7 +6980,7 @@ async fn main() -> Result<(), Box> { &exchange_account, token, deposit_address, - &rpc_client, + rpc_client, )?; process_exchange_withdraw( @@ -6966,7 +7001,7 @@ async fn main() -> Result<(), Box> { &mut db, exchange, exchange_client.as_ref(), - &rpc_client, + rpc_client, ¬ifier, ) .await?; @@ -7004,7 +7039,7 @@ async fn main() -> Result<(), Box> { &mut db, exchange, exchange_client.as_ref(), - &rpc_client, + rpc_client, ¬ifier, ) .await?; @@ -7045,7 +7080,7 @@ async fn main() -> Result<(), Box> { &mut db, exchange, exchange_client.as_ref(), - &rpc_client, + rpc_client, ¬ifier, ) .await?; @@ -7094,7 +7129,7 @@ async fn main() -> Result<(), Box> { &mut db, exchange, exchange_client.as_ref(), - &rpc_client, + rpc_client, ¬ifier, ) .await?; @@ -7197,7 +7232,7 @@ async fn main() -> Result<(), Box> { &mut db, exchange, exchange_client.as_ref(), - &rpc_client, + rpc_client, ¬ifier, ) .await?; diff --git a/src/stake_spreader.rs b/src/stake_spreader.rs index d1e69a2..667efdd 100644 --- a/src/stake_spreader.rs +++ b/src/stake_spreader.rs @@ -21,7 +21,7 @@ use { }, solana_transaction_status::Reward, std::collections::{BTreeMap, HashMap, HashSet}, - sys::{notifier::*, send_transaction_until_expired, token::*}, + sys::{notifier::*, send_transaction_until_expired, token::*, RpcClients}, }; const MAX_RPC_VOTE_ACCOUNT_INFO_EPOCH_CREDITS_HISTORY: usize = 5; // Remove once Solana 1.15 ships. Ref: https://github.com/solana-labs/solana/pull/28096 @@ -148,7 +148,7 @@ fn get_validator_credit_scores( #[allow(clippy::too_many_arguments)] pub async fn run( db: &mut Db, - rpc_client: &RpcClient, + rpc_clients: &RpcClients, epoch_completed_percentage: u8, epoch_history: u64, num_validators: usize, @@ -158,6 +158,7 @@ pub async fn run( signers: T, notifier: &Notifier, ) -> Result<(), Box> { + let rpc_client = &rpc_clients.default; let epoch_info = rpc_client.get_epoch_info()?; let current_epoch = epoch_info.epoch; @@ -394,7 +395,7 @@ pub async fn run( None, )?; - if !send_transaction_until_expired(rpc_client, &transaction, last_valid_block_height) { + if !send_transaction_until_expired(rpc_clients, &transaction, last_valid_block_height) { db.cancel_transfer(signature)?; eprintln!("Merge failed"); } else { @@ -594,7 +595,7 @@ pub async fn run( println!("Transaction signature: {signature}"); if !send_transaction_until_expired( - rpc_client, + rpc_clients, &transaction, last_valid_block_height, ) { @@ -604,7 +605,7 @@ pub async fn run( } else { crate::process_account_redelegate( db, - rpc_client, + rpc_clients, stake_account_address, *vote_account_address, LotSelectionMethod::default(),