rosetta_client/
client.rs

1use crate::types::{
2    AccountBalanceRequest, AccountBalanceResponse, AccountCoinsRequest, AccountCoinsResponse,
3    AccountFaucetRequest, BlockRequest, BlockResponse, BlockTransactionRequest,
4    BlockTransactionResponse, ConstructionCombineRequest, ConstructionCombineResponse,
5    ConstructionDeriveRequest, ConstructionDeriveResponse, ConstructionHashRequest,
6    ConstructionMetadataRequest, ConstructionMetadataResponse, ConstructionParseRequest,
7    ConstructionParseResponse, ConstructionPayloadsRequest, ConstructionPayloadsResponse,
8    ConstructionPreprocessRequest, ConstructionPreprocessResponse, ConstructionSubmitRequest,
9    EventsBlocksRequest, EventsBlocksResponse, MempoolResponse, MempoolTransactionRequest,
10    MempoolTransactionResponse, MetadataRequest, NetworkIdentifier, NetworkListResponse,
11    NetworkOptionsResponse, NetworkRequest, NetworkStatusResponse, SearchTransactionsRequest,
12    SearchTransactionsResponse, TransactionIdentifierResponse,
13};
14use anyhow::Result;
15use rosetta_core::types::{CallRequest, CallResponse};
16use serde::{de::DeserializeOwned, Serialize};
17
18/// The client struct to interface with a rosetta endpoint.
19#[derive(Clone)]
20pub struct Client {
21    /// The http client.
22    http: surf::Client,
23}
24
25impl Client {
26    /// `url` should have the form `http[s]://hostname:port`.
27    pub fn new(url: &str) -> Result<Self> {
28        let http = surf::Config::new().set_base_url(url.parse()?).try_into()?;
29        Ok(Self { http })
30    }
31
32    /// Makes a POST request to the rosetta endpoint.
33    async fn post<Q: Serialize, R: DeserializeOwned>(&self, path: &str, request: &Q) -> Result<R> {
34        let mut res = self
35            .http
36            .post(path)
37            .body_json(request)
38            .map_err(|e| e.into_inner())?
39            .send()
40            .await
41            .map_err(|e| e.into_inner())?;
42        match res.status() as u16 {
43            200 => Ok(res.body_json().await.map_err(|e| e.into_inner())?),
44            404 => anyhow::bail!("unsupported endpoint {}", path),
45            500 => {
46                let error: crate::types::Error =
47                    res.body_json().await.map_err(|e| e.into_inner())?;
48                log::error!("{:#?}", error);
49                Err(error.into())
50            }
51            _ => anyhow::bail!("unexpected status code {}", res.status()),
52        }
53    }
54
55    /// Make a call to the /network/list endpoint.
56    pub async fn network_list(&self) -> Result<Vec<NetworkIdentifier>> {
57        let request = MetadataRequest { metadata: None };
58        let response: NetworkListResponse = self.post("/network/list", &request).await?;
59        Ok(response.network_identifiers)
60    }
61
62    /// Make a call to the /network/options endpoint.
63    pub async fn network_options(
64        &self,
65        network_identifier: NetworkIdentifier,
66    ) -> Result<NetworkOptionsResponse> {
67        let request = NetworkRequest {
68            network_identifier,
69            metadata: None,
70        };
71        self.post("/network/options", &request).await
72    }
73
74    /// Make a call to the /network/status endpoint.
75    pub async fn network_status(
76        &self,
77        network_identifier: NetworkIdentifier,
78    ) -> Result<NetworkStatusResponse> {
79        let request = NetworkRequest {
80            network_identifier,
81            metadata: None,
82        };
83        self.post("/network/status", &request).await
84    }
85
86    /// Make a call to the /account/balance endpoint.
87    pub async fn account_balance(
88        &self,
89        request: &AccountBalanceRequest,
90    ) -> Result<AccountBalanceResponse> {
91        self.post("/account/balance", &request).await
92    }
93
94    /// Make a call to the /account/coins endpoint.
95    pub async fn account_coins(
96        &self,
97        request: &AccountCoinsRequest,
98    ) -> Result<AccountCoinsResponse> {
99        self.post("/account/coins", &request).await
100    }
101
102    /// Make a call to the /account/faucet endpoint.
103    pub async fn account_faucet(
104        &self,
105        request: &AccountFaucetRequest,
106    ) -> Result<TransactionIdentifierResponse> {
107        self.post("/account/faucet", &request).await
108    }
109
110    /// Make a call to the /block endpoint.
111    pub async fn block(&self, request: &BlockRequest) -> Result<BlockResponse> {
112        self.post("/block", &request).await
113    }
114
115    /// Make a call to the /block/transaction endpoint.
116    pub async fn block_transaction(
117        &self,
118        request: &BlockTransactionRequest,
119    ) -> Result<BlockTransactionResponse> {
120        self.post("/block/transaction", &request).await
121    }
122
123    /// Make a call to the /mempool endpoint.
124    pub async fn mempool(&self, network_identifier: NetworkIdentifier) -> Result<MempoolResponse> {
125        let request = NetworkRequest {
126            network_identifier,
127            metadata: None,
128        };
129        self.post("/mempool", &request).await
130    }
131
132    /// Make a call to the /mempool/transaction endpoint.
133    pub async fn mempool_transaction(
134        &self,
135        request: &MempoolTransactionRequest,
136    ) -> Result<MempoolTransactionResponse> {
137        self.post("/mempool/transaction", &request).await
138    }
139
140    /// Make a call to the /call endpoint.
141    pub async fn call(&self, request: &CallRequest) -> Result<CallResponse> {
142        self.post("/call", &request).await
143    }
144
145    /// Make a call to the /construction/combine endpoint.
146    pub async fn construction_combine(
147        &self,
148        request: &ConstructionCombineRequest,
149    ) -> Result<ConstructionCombineResponse> {
150        self.post("/construction/combine", &request).await
151    }
152
153    /// Make a call to the /construction/derive endpoint.
154    pub async fn construction_derive(
155        &self,
156        request: &ConstructionDeriveRequest,
157    ) -> Result<ConstructionDeriveResponse> {
158        self.post("/construction/derive", &request).await
159    }
160
161    /// Make a call to the /construction/hash endpoint.
162    pub async fn construction_hash(
163        &self,
164        request: &ConstructionHashRequest,
165    ) -> Result<TransactionIdentifierResponse> {
166        self.post("/construction/hash", &request).await
167    }
168
169    /// Make a call to the /construction/metadata endpoint.
170    pub async fn construction_metadata(
171        &self,
172        request: &ConstructionMetadataRequest,
173    ) -> Result<ConstructionMetadataResponse> {
174        self.post("/construction/metadata", &request).await
175    }
176
177    /// Make a call to the /construction/parse endpoint.
178    pub async fn construction_parse(
179        &self,
180        request: &ConstructionParseRequest,
181    ) -> Result<ConstructionParseResponse> {
182        self.post("/construction/parse", &request).await
183    }
184
185    /// Make a call to the /construction/payloads endpoint.
186    pub async fn construction_payloads(
187        &self,
188        request: &ConstructionPayloadsRequest,
189    ) -> Result<ConstructionPayloadsResponse> {
190        self.post("/construction/payloads", &request).await
191    }
192
193    /// Make a call to the /construction/preprocess endpoint.
194    pub async fn construction_preprocess(
195        &self,
196        request: &ConstructionPreprocessRequest,
197    ) -> Result<ConstructionPreprocessResponse> {
198        self.post("/construction/preprocess", &request).await
199    }
200
201    /// Make a call to the /construction/submit endpoint.
202    pub async fn construction_submit(
203        &self,
204        request: &ConstructionSubmitRequest,
205    ) -> Result<TransactionIdentifierResponse> {
206        self.post("/construction/submit", &request).await
207    }
208
209    /// Make a call to the /events/blocks endpoint.
210    pub async fn events_blocks(
211        &self,
212        request: &EventsBlocksRequest,
213    ) -> Result<EventsBlocksResponse> {
214        self.post("/events/blocks", &request).await
215    }
216
217    /// Make a call to the /search/transactions endpoint.
218    pub async fn search_transactions(
219        &self,
220        request: &SearchTransactionsRequest,
221    ) -> Result<SearchTransactionsResponse> {
222        self.post("/search/transactions", &request).await
223    }
224}