sui_rpc/client/v2/
mod.rs

1use std::time::Duration;
2use tap::Pipe;
3use tonic::codec::CompressionEncoding;
4use tonic::transport::channel::ClientTlsConfig;
5
6mod coin_selection;
7mod lists;
8mod staking_rewards;
9mod transaction_execution;
10
11pub use transaction_execution::ExecuteAndWaitError;
12
13use crate::client::AuthInterceptor;
14use crate::proto::sui::rpc::v2::ledger_service_client::LedgerServiceClient;
15use crate::proto::sui::rpc::v2::move_package_service_client::MovePackageServiceClient;
16use crate::proto::sui::rpc::v2::signature_verification_service_client::SignatureVerificationServiceClient;
17use crate::proto::sui::rpc::v2::state_service_client::StateServiceClient;
18use crate::proto::sui::rpc::v2::subscription_service_client::SubscriptionServiceClient;
19use crate::proto::sui::rpc::v2::transaction_execution_service_client::TransactionExecutionServiceClient;
20
21type Result<T, E = tonic::Status> = std::result::Result<T, E>;
22type BoxError = Box<dyn std::error::Error + Send + Sync + 'static>;
23type Channel<'a> = tonic::service::interceptor::InterceptedService<
24    &'a mut tonic::transport::Channel,
25    &'a mut AuthInterceptor,
26>;
27
28#[derive(Clone)]
29pub struct Client {
30    uri: http::Uri,
31    channel: tonic::transport::Channel,
32    auth: AuthInterceptor,
33    max_decoding_message_size: Option<usize>,
34}
35
36impl Client {
37    /// URL for the public-good, Sui Foundation provided fullnodes for mainnet.
38    pub const MAINNET_FULLNODE: &str = "https://fullnode.mainnet.sui.io";
39
40    /// URL for the public-good, Sui Foundation provided fullnodes for testnet.
41    pub const TESTNET_FULLNODE: &str = "https://fullnode.testnet.sui.io";
42
43    /// URL for the public-good, Sui Foundation provided fullnodes for devnet.
44    pub const DEVNET_FULLNODE: &str = "https://fullnode.devnet.sui.io";
45
46    /// URL for the public-good, Sui Foundation provided archive for mainnet.
47    pub const MAINNET_ARCHIVE: &str = "https://archive.mainnet.sui.io";
48
49    /// URL for the public-good, Sui Foundation provided archive for testnet.
50    pub const TESTNET_ARCHIVE: &str = "https://archive.testnet.sui.io";
51
52    #[allow(clippy::result_large_err)]
53    pub fn new<T>(uri: T) -> Result<Self>
54    where
55        T: TryInto<http::Uri>,
56        T::Error: Into<BoxError>,
57    {
58        let uri = uri
59            .try_into()
60            .map_err(Into::into)
61            .map_err(tonic::Status::from_error)?;
62        let mut endpoint = tonic::transport::Endpoint::from(uri.clone());
63        if uri.scheme() == Some(&http::uri::Scheme::HTTPS) {
64            endpoint = endpoint
65                .tls_config(ClientTlsConfig::new().with_enabled_roots())
66                .map_err(Into::into)
67                .map_err(tonic::Status::from_error)?;
68        }
69        let channel = endpoint
70            .connect_timeout(Duration::from_secs(5))
71            .http2_keep_alive_interval(Duration::from_secs(5))
72            .connect_lazy();
73
74        Ok(Self {
75            uri,
76            channel,
77            auth: Default::default(),
78            max_decoding_message_size: None,
79        })
80    }
81
82    pub fn with_auth(mut self, auth: AuthInterceptor) -> Self {
83        self.auth = auth;
84        self
85    }
86
87    pub fn with_max_decoding_message_size(mut self, limit: usize) -> Self {
88        self.max_decoding_message_size = Some(limit);
89        self
90    }
91
92    pub fn uri(&self) -> &http::Uri {
93        &self.uri
94    }
95
96    pub fn ledger_client(&mut self) -> LedgerServiceClient<Channel<'_>> {
97        LedgerServiceClient::with_interceptor(&mut self.channel, &mut self.auth)
98            .accept_compressed(CompressionEncoding::Zstd)
99            .pipe(|client| {
100                if let Some(limit) = self.max_decoding_message_size {
101                    client.max_decoding_message_size(limit)
102                } else {
103                    client
104                }
105            })
106    }
107
108    pub fn state_client(&mut self) -> StateServiceClient<Channel<'_>> {
109        StateServiceClient::with_interceptor(&mut self.channel, &mut self.auth)
110            .accept_compressed(CompressionEncoding::Zstd)
111            .pipe(|client| {
112                if let Some(limit) = self.max_decoding_message_size {
113                    client.max_decoding_message_size(limit)
114                } else {
115                    client
116                }
117            })
118    }
119
120    pub fn execution_client(&mut self) -> TransactionExecutionServiceClient<Channel<'_>> {
121        TransactionExecutionServiceClient::with_interceptor(&mut self.channel, &mut self.auth)
122            .accept_compressed(CompressionEncoding::Zstd)
123            .pipe(|client| {
124                if let Some(limit) = self.max_decoding_message_size {
125                    client.max_decoding_message_size(limit)
126                } else {
127                    client
128                }
129            })
130    }
131
132    pub fn package_client(&mut self) -> MovePackageServiceClient<Channel<'_>> {
133        MovePackageServiceClient::with_interceptor(&mut self.channel, &mut self.auth)
134            .accept_compressed(CompressionEncoding::Zstd)
135            .pipe(|client| {
136                if let Some(limit) = self.max_decoding_message_size {
137                    client.max_decoding_message_size(limit)
138                } else {
139                    client
140                }
141            })
142    }
143
144    pub fn signature_verification_client(
145        &mut self,
146    ) -> SignatureVerificationServiceClient<Channel<'_>> {
147        SignatureVerificationServiceClient::with_interceptor(&mut self.channel, &mut self.auth)
148            .accept_compressed(CompressionEncoding::Zstd)
149            .pipe(|client| {
150                if let Some(limit) = self.max_decoding_message_size {
151                    client.max_decoding_message_size(limit)
152                } else {
153                    client
154                }
155            })
156    }
157
158    pub fn subscription_client(&mut self) -> SubscriptionServiceClient<Channel<'_>> {
159        SubscriptionServiceClient::with_interceptor(&mut self.channel, &mut self.auth)
160            .accept_compressed(CompressionEncoding::Zstd)
161            .pipe(|client| {
162                if let Some(limit) = self.max_decoding_message_size {
163                    client.max_decoding_message_size(limit)
164                } else {
165                    client
166                }
167            })
168    }
169}