123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- use crate::{
- AsSigner, ClientError, Config, EventContext, EventUnsubscriber, Program,
- ProgramAccountsIterator, RequestBuilder,
- };
- use anchor_lang::{prelude::Pubkey, AccountDeserialize, Discriminator};
- use solana_client::nonblocking::rpc_client::RpcClient as AsyncRpcClient;
- use solana_client::{rpc_config::RpcSendTransactionConfig, rpc_filter::RpcFilterType};
- use solana_sdk::{
- commitment_config::CommitmentConfig, signature::Signature, signer::Signer,
- transaction::Transaction,
- };
- use std::{marker::PhantomData, ops::Deref, sync::Arc};
- use tokio::sync::RwLock;
- impl<'a> EventUnsubscriber<'a> {
- /// Unsubscribe gracefully.
- pub async fn unsubscribe(self) {
- self.unsubscribe_internal().await
- }
- }
- pub trait ThreadSafeSigner: Signer + Send + Sync + 'static {
- fn to_signer(&self) -> &dyn Signer;
- }
- impl<T: Signer + Send + Sync + 'static> ThreadSafeSigner for T {
- fn to_signer(&self) -> &dyn Signer {
- self
- }
- }
- impl AsSigner for Arc<dyn ThreadSafeSigner> {
- fn as_signer(&self) -> &dyn Signer {
- self.to_signer()
- }
- }
- impl<C: Deref<Target = impl Signer> + Clone> Program<C> {
- pub fn new(
- program_id: Pubkey,
- cfg: Config<C>,
- #[cfg(feature = "mock")] rpc_client: AsyncRpcClient,
- ) -> Result<Self, ClientError> {
- #[cfg(not(feature = "mock"))]
- let rpc_client = {
- let comm_config = cfg.options.unwrap_or_default();
- let cluster_url = cfg.cluster.url().to_string();
- AsyncRpcClient::new_with_commitment(cluster_url.clone(), comm_config)
- };
- Ok(Self {
- program_id,
- cfg,
- sub_client: Arc::new(RwLock::new(None)),
- internal_rpc_client: rpc_client,
- })
- }
- // We disable the `rpc` method for `mock` feature because otherwise we'd either have to
- // return a new `RpcClient` instance (which is different to the one used internally)
- // or require the user to pass another one in for blocking (since we use the non-blocking one under the hood).
- // The former of these would be confusing and the latter would be very annoying, especially since a user
- // using the mock feature likely already has a `RpcClient` instance at hand anyway.
- #[cfg(not(feature = "mock"))]
- pub fn rpc(&self) -> AsyncRpcClient {
- AsyncRpcClient::new_with_commitment(
- self.cfg.cluster.url().to_string(),
- self.cfg.options.unwrap_or_default(),
- )
- }
- /// Returns a threadsafe request builder
- pub fn request(&self) -> RequestBuilder<'_, C, Arc<dyn ThreadSafeSigner>> {
- RequestBuilder::from(
- self.program_id,
- self.cfg.cluster.url(),
- self.cfg.payer.clone(),
- self.cfg.options,
- &self.internal_rpc_client,
- )
- }
- /// Returns the account at the given address.
- pub async fn account<T: AccountDeserialize>(&self, address: Pubkey) -> Result<T, ClientError> {
- self.account_internal(address).await
- }
- /// Returns all program accounts of the given type matching the given filters
- pub async fn accounts<T: AccountDeserialize + Discriminator>(
- &self,
- filters: Vec<RpcFilterType>,
- ) -> Result<Vec<(Pubkey, T)>, ClientError> {
- self.accounts_lazy(filters).await?.collect()
- }
- /// Returns all program accounts of the given type matching the given filters as an iterator
- /// Deserialization is executed lazily
- pub async fn accounts_lazy<T: AccountDeserialize + Discriminator>(
- &self,
- filters: Vec<RpcFilterType>,
- ) -> Result<ProgramAccountsIterator<T>, ClientError> {
- self.accounts_lazy_internal(filters).await
- }
- /// Subscribe to program logs.
- ///
- /// Returns an [`EventUnsubscriber`] to unsubscribe and close connection gracefully.
- pub async fn on<T: anchor_lang::Event + anchor_lang::AnchorDeserialize>(
- &self,
- f: impl Fn(&EventContext, T) + Send + 'static,
- ) -> Result<EventUnsubscriber, ClientError> {
- let (handle, rx) = self.on_internal(f).await?;
- Ok(EventUnsubscriber {
- handle,
- rx,
- _lifetime_marker: PhantomData,
- })
- }
- }
- impl<'a, C: Deref<Target = impl Signer> + Clone> RequestBuilder<'a, C, Arc<dyn ThreadSafeSigner>> {
- pub fn from(
- program_id: Pubkey,
- cluster: &str,
- payer: C,
- options: Option<CommitmentConfig>,
- rpc_client: &'a AsyncRpcClient,
- ) -> Self {
- Self {
- program_id,
- payer,
- cluster: cluster.to_string(),
- accounts: Vec::new(),
- options: options.unwrap_or_default(),
- instructions: Vec::new(),
- instruction_data: None,
- signers: Vec::new(),
- internal_rpc_client: rpc_client,
- _phantom: PhantomData,
- }
- }
- #[must_use]
- pub fn signer<T: ThreadSafeSigner>(mut self, signer: T) -> Self {
- self.signers.push(Arc::new(signer));
- self
- }
- pub async fn signed_transaction(&self) -> Result<Transaction, ClientError> {
- self.signed_transaction_internal().await
- }
- pub async fn send(self) -> Result<Signature, ClientError> {
- self.send_internal().await
- }
- pub async fn send_with_spinner_and_config(
- self,
- config: RpcSendTransactionConfig,
- ) -> Result<Signature, ClientError> {
- self.send_with_spinner_and_config_internal(config).await
- }
- }
|