194 lines
5.8 KiB
Rust
194 lines
5.8 KiB
Rust
use solana_client::{rpc_client::RpcClient, rpc_config::RpcSendTransactionConfig};
|
|
use solana_runtime::bank_client::BankClient;
|
|
use solana_sdk::{
|
|
account::Account,
|
|
client::{AsyncClient, SyncClient},
|
|
clock::Slot,
|
|
commitment_config::CommitmentConfig,
|
|
fee_calculator::FeeCalculator,
|
|
hash::Hash,
|
|
message::Message,
|
|
pubkey::Pubkey,
|
|
signature::{Signature, Signer},
|
|
signers::Signers,
|
|
system_instruction,
|
|
transaction::Transaction,
|
|
transport::{Result, TransportError},
|
|
};
|
|
use solana_transaction_status::TransactionStatus;
|
|
|
|
pub trait Client {
|
|
fn send_transaction1(&self, transaction: Transaction) -> Result<Signature>;
|
|
fn get_signature_statuses1(
|
|
&self,
|
|
signatures: &[Signature],
|
|
) -> Result<Vec<Option<TransactionStatus>>>;
|
|
fn get_balance1(&self, pubkey: &Pubkey) -> Result<u64>;
|
|
fn get_fees1(&self) -> Result<(Hash, FeeCalculator, Slot)>;
|
|
fn get_slot1(&self) -> Result<Slot>;
|
|
fn get_account1(&self, pubkey: &Pubkey) -> Result<Option<Account>>;
|
|
}
|
|
|
|
impl Client for RpcClient {
|
|
fn send_transaction1(&self, transaction: Transaction) -> Result<Signature> {
|
|
self.send_transaction_with_config(
|
|
&transaction,
|
|
RpcSendTransactionConfig {
|
|
skip_preflight: true,
|
|
},
|
|
)
|
|
.map_err(|e| TransportError::Custom(e.to_string()))
|
|
}
|
|
|
|
fn get_signature_statuses1(
|
|
&self,
|
|
signatures: &[Signature],
|
|
) -> Result<Vec<Option<TransactionStatus>>> {
|
|
self.get_signature_statuses(signatures)
|
|
.map(|response| response.value)
|
|
.map_err(|e| TransportError::Custom(e.to_string()))
|
|
}
|
|
|
|
fn get_balance1(&self, pubkey: &Pubkey) -> Result<u64> {
|
|
self.get_balance(pubkey)
|
|
.map_err(|e| TransportError::Custom(e.to_string()))
|
|
}
|
|
|
|
fn get_fees1(&self) -> Result<(Hash, FeeCalculator, Slot)> {
|
|
let result = self
|
|
.get_recent_blockhash_with_commitment(CommitmentConfig::default())
|
|
.map_err(|e| TransportError::Custom(e.to_string()))?;
|
|
Ok(result.value)
|
|
}
|
|
|
|
fn get_slot1(&self) -> Result<Slot> {
|
|
self.get_slot()
|
|
.map_err(|e| TransportError::Custom(e.to_string()))
|
|
}
|
|
|
|
fn get_account1(&self, pubkey: &Pubkey) -> Result<Option<Account>> {
|
|
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<Signature> {
|
|
self.async_send_transaction(transaction)
|
|
}
|
|
|
|
fn get_signature_statuses1(
|
|
&self,
|
|
signatures: &[Signature],
|
|
) -> Result<Vec<Option<TransactionStatus>>> {
|
|
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<u64> {
|
|
self.get_balance(pubkey)
|
|
}
|
|
|
|
fn get_fees1(&self) -> Result<(Hash, FeeCalculator, Slot)> {
|
|
self.get_recent_blockhash_with_commitment(CommitmentConfig::default())
|
|
}
|
|
|
|
fn get_slot1(&self) -> Result<Slot> {
|
|
self.get_slot()
|
|
}
|
|
|
|
fn get_account1(&self, pubkey: &Pubkey) -> Result<Option<Account>> {
|
|
self.get_account(pubkey)
|
|
}
|
|
}
|
|
|
|
pub struct ThinClient<'a> {
|
|
client: Box<dyn Client + 'a>,
|
|
dry_run: bool,
|
|
}
|
|
|
|
impl<'a> ThinClient<'a> {
|
|
pub fn new<C: Client + 'a>(client: C, dry_run: bool) -> Self {
|
|
Self {
|
|
client: Box::new(client),
|
|
dry_run,
|
|
}
|
|
}
|
|
|
|
pub fn send_transaction(&self, transaction: Transaction) -> Result<Signature> {
|
|
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<Vec<Option<TransactionStatus>>> {
|
|
self.client.get_signature_statuses1(signatures)
|
|
}
|
|
|
|
pub fn send_message<S: Signers>(
|
|
&self,
|
|
message: Message,
|
|
signers: &S,
|
|
) -> Result<(Transaction, Slot)> {
|
|
if self.dry_run {
|
|
return Ok((Transaction::new_unsigned(message), std::u64::MAX));
|
|
}
|
|
let (blockhash, _fee_caluclator, last_valid_slot) = self.get_fees()?;
|
|
|
|
let transaction = Transaction::new(signers, message, blockhash);
|
|
self.send_transaction(transaction.clone())?;
|
|
Ok((transaction, last_valid_slot))
|
|
}
|
|
|
|
pub fn transfer<S: Signer>(
|
|
&self,
|
|
lamports: u64,
|
|
sender_keypair: &S,
|
|
to_pubkey: &Pubkey,
|
|
) -> Result<(Transaction, u64)> {
|
|
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_fees(&self) -> Result<(Hash, FeeCalculator, Slot)> {
|
|
self.client.get_fees1()
|
|
}
|
|
|
|
pub fn get_slot(&self) -> Result<Slot> {
|
|
self.client.get_slot1()
|
|
}
|
|
|
|
pub fn get_balance(&self, pubkey: &Pubkey) -> Result<u64> {
|
|
self.client.get_balance1(pubkey)
|
|
}
|
|
|
|
pub fn get_account(&self, pubkey: &Pubkey) -> Result<Option<Account>> {
|
|
self.client.get_account1(pubkey)
|
|
}
|
|
}
|