antelope/api/v1/
chain.rs

1use std::fmt::Debug;
2
3use serde_json::{self, Value};
4
5use crate::api::v1::structs::{ABIResponse, EncodingError, GetBlockResponse, ServerError};
6use crate::{
7    api::{
8        client::Provider,
9        v1::structs::{
10            AccountObject, ClientError, ErrorResponse, GetInfoResponse, GetTableRowsParams,
11            GetTableRowsResponse, SendTransactionResponse, SendTransactionResponseError,
12            TableIndexType,
13        },
14    },
15    chain::{
16        name::Name,
17        transaction::{CompressionType, PackedTransaction, SignedTransaction},
18        Decoder, Packer,
19    },
20    name,
21    serializer::formatter::{JSONObject, ValueTo},
22    util::hex_to_bytes,
23};
24
25#[derive(Debug, Default, Clone)]
26pub struct ChainAPI<T: Provider> {
27    provider: T,
28}
29
30impl<T: Provider> ChainAPI<T> {
31    pub fn new(provider: T) -> Self {
32        ChainAPI { provider }
33    }
34
35    // pub async fn get_abi(&self) -> Result<
36
37    pub async fn get_account(
38        &self,
39        account_name: String,
40    ) -> Result<AccountObject, ClientError<ErrorResponse>> {
41        let payload = serde_json::json!({ "account_name": account_name });
42
43        let result = self
44            .provider
45            .post(
46                String::from("/v1/chain/get_account"),
47                Some(payload.to_string()),
48            )
49            .await;
50
51        match result {
52            Ok(response) => {
53                match serde_json::from_str::<AccountObject>(&response) {
54                    Ok(account_object) => Ok(account_object),
55                    Err(_) => {
56                        // Attempt to parse the error response
57                        match serde_json::from_str::<ErrorResponse>(&response) {
58                            Ok(error_response) => Err(ClientError::SERVER(ServerError {
59                                error: error_response,
60                            })),
61                            Err(_) => Err(ClientError::ENCODING(EncodingError {
62                                message: "Failed to parse JSON".into(),
63                            })),
64                        }
65                    }
66                }
67            }
68            Err(msg) => Err(ClientError::NETWORK(msg)),
69        }
70    }
71
72    pub async fn get_abi(
73        &self,
74        account_name: String,
75    ) -> Result<ABIResponse, ClientError<ErrorResponse>> {
76        let payload = serde_json::json!({
77            "account_name": account_name,
78        });
79
80        let result = self
81            .provider
82            .post(String::from("/v1/chain/get_abi"), Some(payload.to_string()))
83            .await;
84
85        match result {
86            Ok(response) => {
87                match serde_json::from_str::<ABIResponse>(&response) {
88                    Ok(abi_response) => Ok(abi_response),
89                    Err(_) => {
90                        // Attempt to parse the error response
91                        match serde_json::from_str::<ErrorResponse>(&response) {
92                            Ok(error_response) => Err(ClientError::SERVER(ServerError {
93                                error: error_response,
94                            })),
95                            Err(_) => Err(ClientError::ENCODING(EncodingError {
96                                message: "Failed to parse JSON".into(),
97                            })),
98                        }
99                    }
100                }
101            }
102            Err(msg) => Err(ClientError::NETWORK(msg)),
103        }
104    }
105
106    pub async fn get_block(
107        &self,
108        block_num_or_id: String,
109    ) -> Result<GetBlockResponse, ClientError<ErrorResponse>> {
110        let payload = serde_json::json!({
111            "block_num_or_id": block_num_or_id,
112        });
113
114        let result = self
115            .provider
116            .post(
117                String::from("/v1/chain/get_block"),
118                Some(payload.to_string()),
119            )
120            .await;
121
122        match result {
123            Ok(response) => {
124                match serde_json::from_str::<GetBlockResponse>(&response) {
125                    Ok(block_response) => Ok(block_response),
126                    Err(_) => {
127                        // Attempt to parse the error response
128                        match serde_json::from_str::<ErrorResponse>(&response) {
129                            Ok(error_response) => Err(ClientError::SERVER(ServerError {
130                                error: error_response,
131                            })),
132                            Err(_) => Err(ClientError::ENCODING(EncodingError {
133                                message: "Failed to parse JSON".into(),
134                            })),
135                        }
136                    }
137                }
138            }
139            Err(msg) => Err(ClientError::NETWORK(msg)),
140        }
141    }
142
143    pub async fn get_info(&self) -> Result<GetInfoResponse, ClientError<()>> {
144        let result = self.provider.get(String::from("/v1/chain/get_info")).await;
145
146        match result {
147            Ok(response) => serde_json::from_str::<GetInfoResponse>(&response).map_err(|e| {
148                let message = format!("Failed to parse JSON: {}", e);
149                ClientError::encoding(message)
150            }),
151            Err(_) => Err(ClientError::encoding("Request failed".into())),
152        }
153    }
154
155    pub async fn send_transaction(
156        &self,
157        trx: SignedTransaction,
158    ) -> Result<SendTransactionResponse, ClientError<SendTransactionResponseError>> {
159        let packed = PackedTransaction::from_signed(trx, CompressionType::ZLIB)
160            .map_err(|_| ClientError::encoding("Failed to pack transaction".into()))?;
161
162        let trx_json = packed.to_json();
163        let result = self
164            .provider
165            .post(String::from("/v1/chain/send_transaction"), Some(trx_json))
166            .await
167            .map_err(|_| ClientError::NETWORK("Failed to send transaction".into()))?;
168
169        // Try to deserialize the successful response
170        match serde_json::from_str::<SendTransactionResponse>(&result) {
171            Ok(response) => Ok(response),
172            Err(_) => {
173                // Attempt to parse the error response
174                match serde_json::from_str::<ErrorResponse>(&result) {
175                    Ok(error_response) => {
176                        // Create a ClientError::SERVER error with the nested error from the response
177                        Err(ClientError::SERVER(ServerError {
178                            error: error_response.error,
179                        }))
180                    }
181                    Err(e) => {
182                        // If parsing the error response also fails, consider it an encoding error
183                        Err(ClientError::ENCODING(EncodingError {
184                            message: format!("Failed to parse response: {}", e),
185                        }))
186                    }
187                }
188            }
189        }
190    }
191
192    pub async fn get_table_rows<P: Packer + Default>(
193        &self,
194        params: GetTableRowsParams,
195    ) -> Result<GetTableRowsResponse<P>, ClientError<()>> {
196        let result = self.provider.post(
197            String::from("/v1/chain/get_table_rows"),
198            Some(params.to_json()),
199        );
200
201        let json: Value = serde_json::from_str(result.await.unwrap().as_str()).unwrap();
202        let response_obj = JSONObject::new(json);
203        let more = response_obj.get_bool("more")?;
204        let next_key_str = response_obj.get_string("next_key")?;
205        let rows_value = response_obj.get_vec("rows")?;
206        let mut rows: Vec<P> = Vec::with_capacity(rows_value.len());
207        for encoded_row in rows_value {
208            let row_bytes_hex = &ValueTo::string(Some(encoded_row))?;
209            let row_bytes = hex_to_bytes(row_bytes_hex);
210            let mut decoder = Decoder::new(&row_bytes);
211            let mut row = P::default();
212            decoder.unpack(&mut row);
213            rows.push(row);
214        }
215
216        let next_key = TableIndexType::NAME(name!(next_key_str.as_str()));
217
218        Ok(GetTableRowsResponse {
219            rows,
220            more,
221            ram_payers: None,
222            next_key: Some(next_key),
223        })
224    }
225}