forester_utils/
utils.rs

1use account_compression::processor::initialize_address_merkle_tree::Pubkey;
2use anchor_lang::solana_program::system_instruction;
3use light_client::{
4    indexer::Indexer,
5    rpc::{Rpc, RpcError},
6};
7use solana_sdk::{signature::Signer, transaction::Transaction};
8use tokio::time::sleep;
9use tracing::{debug, error};
10
11use crate::error::ForesterUtilsError;
12
13pub async fn airdrop_lamports<R: Rpc>(
14    rpc: &mut R,
15    destination_pubkey: &Pubkey,
16    lamports: u64,
17) -> Result<(), RpcError> {
18    let transfer_instruction =
19        system_instruction::transfer(&rpc.get_payer().pubkey(), destination_pubkey, lamports);
20    let latest_blockhash = rpc.get_latest_blockhash().await?;
21    let transaction = Transaction::new_signed_with_payer(
22        &[transfer_instruction],
23        Some(&rpc.get_payer().pubkey()),
24        &vec![&rpc.get_payer()],
25        latest_blockhash.0,
26    );
27    rpc.process_transaction_with_context(transaction).await?;
28    Ok(())
29}
30
31pub async fn wait_for_indexer<R: Rpc, I: Indexer>(
32    rpc: &mut R,
33    indexer: &I,
34) -> Result<(), ForesterUtilsError> {
35    let rpc_slot = rpc
36        .get_slot()
37        .await
38        .map_err(|_| ForesterUtilsError::Rpc("Failed to get rpc slot".into()))?;
39
40    let indexer_slot = indexer.get_indexer_slot(None).await;
41
42    let mut indexer_slot = match indexer_slot {
43        Ok(slot) => slot,
44        Err(e) => {
45            error!("failed to get indexer slot from indexer: {:?}", e);
46            return Err(ForesterUtilsError::Indexer(
47                "Failed to get indexer slot".into(),
48            ));
49        }
50    };
51
52    let max_attempts = 20;
53    let mut attempts = 0;
54
55    while rpc_slot > indexer_slot {
56        if attempts >= max_attempts {
57            return Err(ForesterUtilsError::Indexer(
58                "Maximum attempts reached waiting for indexer to catch up".into(),
59            ));
60        }
61
62        debug!(
63            "waiting for indexer to catch up, rpc_slot: {}, indexer_slot: {}",
64            rpc_slot, indexer_slot
65        );
66
67        tokio::task::yield_now().await;
68        sleep(std::time::Duration::from_millis(500)).await;
69        indexer_slot = indexer.get_indexer_slot(None).await.map_err(|e| {
70            error!("failed to get indexer slot from indexer: {:?}", e);
71            ForesterUtilsError::Indexer("Failed to get indexer slot".into())
72        })?;
73
74        attempts += 1;
75    }
76    Ok(())
77}