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}