Skip to main content

percli_chain/
rpc.rs

1use anyhow::{Context, Result};
2use solana_client::rpc_client::RpcClient;
3use solana_sdk::{
4    commitment_config::CommitmentConfig,
5    instruction::Instruction,
6    pubkey::Pubkey,
7    signature::{Keypair, Signature},
8    signer::Signer,
9    transaction::Transaction,
10};
11
12pub struct ChainRpc {
13    client: RpcClient,
14}
15
16impl ChainRpc {
17    pub fn new(rpc_url: &str) -> Self {
18        Self {
19            client: RpcClient::new_with_commitment(
20                rpc_url.to_string(),
21                CommitmentConfig::confirmed(),
22            ),
23        }
24    }
25
26    pub fn send_tx(&self, ixs: &[Instruction], payer: &Keypair) -> Result<Signature> {
27        let recent_blockhash = self
28            .client
29            .get_latest_blockhash()
30            .context("Failed to get recent blockhash")?;
31
32        let tx = Transaction::new_signed_with_payer(
33            ixs,
34            Some(&payer.pubkey()),
35            &[payer],
36            recent_blockhash,
37        );
38
39        let sig = self
40            .client
41            .send_and_confirm_transaction(&tx)
42            .context("Transaction failed")?;
43
44        Ok(sig)
45    }
46
47    pub fn get_account_data(&self, pubkey: &Pubkey) -> Result<Vec<u8>> {
48        let account = self
49            .client
50            .get_account(pubkey)
51            .with_context(|| format!("Failed to fetch account {pubkey}"))?;
52        Ok(account.data)
53    }
54
55    pub fn account_exists(&self, pubkey: &Pubkey) -> Result<bool> {
56        match self.client.get_account(pubkey) {
57            Ok(_) => Ok(true),
58            Err(e) => {
59                let msg = e.to_string();
60                if msg.contains("AccountNotFound") || msg.contains("could not find account") {
61                    Ok(false)
62                } else {
63                    Err(e).context("RPC error checking account")
64                }
65            }
66        }
67    }
68
69    pub fn get_slot(&self) -> Result<u64> {
70        self.client.get_slot().context("Failed to get slot")
71    }
72
73    pub fn get_minimum_balance(&self, data_len: usize) -> Result<u64> {
74        self.client
75            .get_minimum_balance_for_rent_exemption(data_len)
76            .context("Failed to get rent")
77    }
78}