solana_client_helpers/
client.rs

1use std::ops::{Deref, DerefMut};
2
3pub use solana_client::{client_error, rpc_client::RpcClient};
4use solana_sdk::{
5    hash::Hash,
6    program_error::ProgramError,
7    pubkey::Pubkey,
8    signature::{Keypair, Signature, Signer},
9    system_instruction,
10    transaction::Transaction,
11};
12use thiserror::Error;
13
14#[derive(Debug, Error)]
15pub enum ClientError {
16    #[error(transparent)]
17    Client(#[from] client_error::ClientError),
18
19    #[error(transparent)]
20    Program(#[from] ProgramError),
21}
22
23pub type ClientResult<T> = Result<T, ClientError>;
24
25pub struct Client {
26    pub client: RpcClient,
27    pub payer: Keypair,
28}
29
30impl Client {
31    pub fn payer(&self) -> &Keypair {
32        &self.payer
33    }
34
35    pub fn payer_pubkey(&self) -> Pubkey {
36        self.payer.pubkey()
37    }
38
39    pub fn latest_blockhash(&self) -> ClientResult<Hash> {
40        Ok(self.client.get_latest_blockhash()?)
41    }
42
43    pub fn process_transaction(&self, transaction: &Transaction) -> ClientResult<()> {
44        self.send_and_confirm_transaction(transaction)?;
45        Ok(())
46    }
47
48    pub fn create_account(
49        &self,
50        owner: &Pubkey,
51        account_data_len: usize,
52        lamports: Option<u64>,
53    ) -> ClientResult<Keypair> {
54        let account = Keypair::new();
55        let lamports = if let Some(lamports) = lamports {
56            lamports
57        } else {
58            self.get_minimum_balance_for_rent_exemption(account_data_len)?
59        };
60
61        let mut transaction = Transaction::new_with_payer(
62            &[system_instruction::create_account(
63                &self.payer_pubkey(),
64                &account.pubkey(),
65                lamports,
66                account_data_len as u64,
67                owner,
68            )],
69            Some(&self.payer_pubkey()),
70        );
71        transaction.sign(&[self.payer(), &account], self.latest_blockhash()?);
72        self.process_transaction(&transaction)?;
73
74        Ok(account)
75    }
76
77    pub fn airdrop(&self, to_pubkey: &Pubkey, lamports: u64) -> ClientResult<Signature> {
78        let blockhash = self.client.get_latest_blockhash()?;
79        let signature = self.request_airdrop_with_blockhash(to_pubkey, lamports, &blockhash)?;
80        self.confirm_transaction_with_spinner(&signature, &blockhash, self.commitment())?;
81
82        Ok(signature)
83    }
84}
85
86impl Deref for Client {
87    type Target = RpcClient;
88
89    fn deref(&self) -> &Self::Target {
90        &self.client
91    }
92}
93
94impl DerefMut for Client {
95    fn deref_mut(&mut self) -> &mut Self::Target {
96        &mut self.client
97    }
98}