use anyhow::Result;
use solana_client::nonblocking::rpc_client::RpcClient;
use solana_sdk::{
hash::Hash,
signature::{Keypair, Signature},
transaction::VersionedTransaction,
};
pub trait TransactionExtension {
fn sign_transaction(
&mut self,
recent_blockhash: &Hash,
signers: &[&Keypair],
) -> Result<VersionedTransaction>;
#[allow(async_fn_in_trait)]
async fn send_transaction(
&mut self,
rpc_client: &RpcClient,
signers: &[&Keypair],
) -> Result<Signature>;
#[allow(async_fn_in_trait)]
async fn send_and_confirm(
&mut self,
rpc_client: &RpcClient,
signers: &[&Keypair],
) -> Result<Signature>;
#[allow(async_fn_in_trait)]
async fn simulate(
&mut self,
rpc_client: &RpcClient,
signers: &[&Keypair],
) -> Result<solana_client::rpc_response::RpcSimulateTransactionResult>;
}
impl TransactionExtension for VersionedTransaction {
fn sign_transaction(
&mut self,
recent_blockhash: &Hash,
signers: &[&Keypair],
) -> Result<VersionedTransaction> {
self.message.set_recent_blockhash(*recent_blockhash);
let signed_tx = VersionedTransaction::try_new(self.message.clone(), signers)
.map_err(|e| anyhow::anyhow!("Failed to sign transaction: {}", e))?;
*self = signed_tx.clone();
Ok(signed_tx)
}
async fn send_transaction(
&mut self,
rpc_client: &RpcClient,
signers: &[&Keypair],
) -> Result<Signature> {
let recent_blockhash = rpc_client.get_latest_blockhash().await?;
self.sign_transaction(&recent_blockhash, signers)?;
let signature = rpc_client
.send_transaction(self)
.await
.map_err(|e| anyhow::anyhow!("Failed to send transaction: {}", e))?;
Ok(signature)
}
async fn send_and_confirm(
&mut self,
rpc_client: &RpcClient,
signers: &[&Keypair],
) -> Result<Signature> {
let recent_blockhash = rpc_client.get_latest_blockhash().await?;
self.sign_transaction(&recent_blockhash, signers)?;
let signature = rpc_client
.send_and_confirm_transaction(self)
.await
.map_err(|e| anyhow::anyhow!("Failed to send and confirm transaction: {}", e))?;
Ok(signature)
}
async fn simulate(
&mut self,
rpc_client: &RpcClient,
signers: &[&Keypair],
) -> Result<solana_client::rpc_response::RpcSimulateTransactionResult> {
let recent_blockhash = rpc_client.get_latest_blockhash().await?;
self.sign_transaction(&recent_blockhash, signers)?;
let response = rpc_client
.simulate_transaction(self)
.await
.map_err(|e| anyhow::anyhow!("Failed to simulate transaction: {}", e))?;
if let Some(err) = response.value.err {
return Err(anyhow::anyhow!("Failed to simulate transaction: {}", err));
}
Ok(response.value)
}
}