use solana_client::rpc_client::RpcClient; use solana_runtime::bank_client::BankClient; use solana_sdk::{ account::Account, client::{AsyncClient, SyncClient}, fee_calculator::FeeCalculator, hash::Hash, message::Message, pubkey::Pubkey, signature::{Signature, Signer}, signers::Signers, system_instruction, sysvar::{ recent_blockhashes::{self, RecentBlockhashes}, Sysvar, }, transaction::Transaction, transport::{Result, TransportError}, }; use solana_transaction_status::TransactionStatus; pub trait Client { fn send_transaction1(&self, transaction: Transaction) -> Result; fn get_signature_statuses1( &self, signatures: &[Signature], ) -> Result>>; fn get_balance1(&self, pubkey: &Pubkey) -> Result; fn get_recent_blockhash1(&self) -> Result<(Hash, FeeCalculator)>; fn get_account1(&self, pubkey: &Pubkey) -> Result>; } impl Client for RpcClient { fn send_transaction1(&self, transaction: Transaction) -> Result { self.send_transaction(&transaction) .map_err(|e| TransportError::Custom(e.to_string())) } fn get_signature_statuses1( &self, signatures: &[Signature], ) -> Result>> { self.get_signature_statuses(signatures) .map(|response| response.value) .map_err(|e| TransportError::Custom(e.to_string())) } fn get_balance1(&self, pubkey: &Pubkey) -> Result { self.get_balance(pubkey) .map_err(|e| TransportError::Custom(e.to_string())) } fn get_recent_blockhash1(&self) -> Result<(Hash, FeeCalculator)> { self.get_recent_blockhash() .map_err(|e| TransportError::Custom(e.to_string())) } fn get_account1(&self, pubkey: &Pubkey) -> Result> { self.get_account(pubkey) .map(Some) .map_err(|e| TransportError::Custom(e.to_string())) } } impl Client for BankClient { fn send_transaction1(&self, transaction: Transaction) -> Result { self.async_send_transaction(transaction) } fn get_signature_statuses1( &self, signatures: &[Signature], ) -> Result>> { signatures .iter() .map(|signature| { self.get_signature_status(signature).map(|opt| { opt.map(|status| TransactionStatus { slot: 0, confirmations: None, status, err: None, }) }) }) .collect() } fn get_balance1(&self, pubkey: &Pubkey) -> Result { self.get_balance(pubkey) } fn get_recent_blockhash1(&self) -> Result<(Hash, FeeCalculator)> { self.get_recent_blockhash() } fn get_account1(&self, pubkey: &Pubkey) -> Result> { self.get_account(pubkey) } } pub struct ThinClient { client: C, dry_run: bool, } impl ThinClient { pub fn new(client: C, dry_run: bool) -> Self { Self { client, dry_run } } pub fn send_transaction(&self, transaction: Transaction) -> Result { if self.dry_run { return Ok(Signature::default()); } self.client.send_transaction1(transaction) } pub fn poll_for_confirmation(&self, signature: &Signature) -> Result<()> { while self.get_signature_statuses(&[*signature])?[0].is_none() { std::thread::sleep(std::time::Duration::from_millis(500)); } Ok(()) } pub fn get_signature_statuses( &self, signatures: &[Signature], ) -> Result>> { self.client.get_signature_statuses1(signatures) } pub fn send_message(&self, message: Message, signers: &S) -> Result { if self.dry_run { return Ok(Transaction::new_unsigned(message)); } let (blockhash, _fee_caluclator) = self.get_recent_blockhash()?; let transaction = Transaction::new(signers, message, blockhash); self.send_transaction(transaction.clone())?; Ok(transaction) } pub fn transfer( &self, lamports: u64, sender_keypair: &S, to_pubkey: &Pubkey, ) -> Result { let create_instruction = system_instruction::transfer(&sender_keypair.pubkey(), &to_pubkey, lamports); let message = Message::new(&[create_instruction]); self.send_message(message, &[sender_keypair]) } pub fn get_recent_blockhash(&self) -> Result<(Hash, FeeCalculator)> { self.client.get_recent_blockhash1() } pub fn get_balance(&self, pubkey: &Pubkey) -> Result { self.client.get_balance1(pubkey) } pub fn get_account(&self, pubkey: &Pubkey) -> Result> { self.client.get_account1(pubkey) } pub fn get_recent_blockhashes(&self) -> Result> { let opt_blockhashes_account = self.get_account(&recent_blockhashes::id())?; let blockhashes_account = opt_blockhashes_account.unwrap(); let recent_blockhashes = RecentBlockhashes::from_account(&blockhashes_account).unwrap(); let hashes = recent_blockhashes.iter().map(|x| x.blockhash).collect(); Ok(hashes) } }