poseidon_client/rpc_client/
rpc.rs1use crate::{Cluster, Commitment, PoseidonResult, RpcTxError, SendTxResponse, Transaction};
2use borsh::{BorshDeserialize, BorshSerialize};
3use json::JsonValue;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug)]
7pub struct RpcClient {
8 cluster: Cluster,
9 headers: Vec<(String, String)>,
10 body: JsonValue,
11 commitment: Commitment,
12}
13
14impl RpcClient {
15 pub fn new() -> Self {
16 RpcClient {
17 cluster: Cluster::default(),
18 headers: vec![("Content-Type".to_owned(), "application/json".to_owned())],
19 body: JsonValue::Null,
20 commitment: Commitment::Finalized,
21 }
22 }
23
24 pub fn add_header(&mut self, key: &str, value: &str) -> &mut Self {
25 self.headers.push((key.to_owned(), value.to_owned()));
26
27 self
28 }
29
30 pub fn add_body(&mut self, body: JsonValue) -> &mut Self {
31 self.body = body;
32
33 self
34 }
35
36 pub fn add_commitment(&mut self, commitment: Commitment) -> &mut Self {
37 self.commitment = commitment;
38
39 self
40 }
41
42 pub fn common_methods(&mut self, body: JsonValue) -> &mut Self {
43 self.add_body(body);
44
45 self
46 }
47
48 pub fn prepare_transaction(&mut self, transaction: &Transaction) -> PoseidonResult<&mut Self> {
49 let commitment: &str = self.commitment.into();
50
51 let body = json::object! {
52 jsonrpc: "2.0",
53 id: 1u8,
54 method: "sendTransaction",
55 params: json::array![
56 transaction.to_base58()?,
57 json::object!{commitment: commitment }
58 ]
59 };
60
61 self.body = body;
62
63 Ok(self)
64 }
65
66 pub fn send(&self) -> smol::Task<PoseidonResult<minreq::Response>> {
67 let cluster_url = self.cluster.url();
68 let body = self.body.clone().to_string();
69 let headers = self.headers.clone();
70
71 smol::spawn(async move {
72 let mut request = minreq::post(cluster_url).with_body(body);
73
74 for header in headers {
75 request = request.with_header(&header.0, &header.1);
76 }
77
78 Ok(request.send()?)
79 })
80 }
81}
82
83#[derive(Debug, Clone)]
84pub enum TxSendOutcome {
85 Success(SendTxResponse),
86 Failure(RpcTxError),
87}
88
89impl TxSendOutcome {
90 pub fn parse_tx(response: minreq::Response) -> PoseidonResult<TxSendOutcome> {
91 let first_response = serde_json::from_str::<SendTxResponse>(&response.as_str()?);
92
93 match first_response {
94 Ok(value) => Ok(TxSendOutcome::Success(value)),
95 Err(first_error) => {
96 let err_response = serde_json::from_str::<RpcTxError>(&response.as_str()?);
97 match err_response {
98 Ok(value) => Ok(TxSendOutcome::Failure(value)),
99 Err(_) => Err(first_error.into()),
100 }
101 }
102 }
103 }
104}
105
106#[derive(Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
107#[serde(rename = "camelCase")]
108pub struct RpcResponse<T> {
109 pub jsonrpc: String,
110 pub id: u8,
111 pub result: T,
112}
113
114#[derive(Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
115#[serde(rename = "camelCase")]
116pub struct RpcResponseWithResult<T> {
117 pub jsonrpc: String,
118 pub id: u8,
119 pub result: RpcResult<T>,
120}
121
122#[derive(Debug, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
123#[serde(rename = "camelCase")]
124pub struct RpcResult<T> {
125 pub context: Context,
126 pub value: T,
127}
128
129#[derive(
130 Debug,
131 PartialEq,
132 Eq,
133 Ord,
134 PartialOrd,
135 Clone,
136 Deserialize,
137 Serialize,
138 BorshSerialize,
139 BorshDeserialize,
140)]
141#[serde(rename_all = "camelCase")]
142pub struct Context {
143 pub api_version: String,
144 pub slot: u64,
145}
146
147pub(crate) async fn request<T: serde::de::DeserializeOwned>(
148 body: json::JsonValue,
149) -> PoseidonResult<RpcResponse<T>> {
150 let mut rpc = RpcClient::new();
151 rpc.common_methods(body);
152 let response = rpc.send().await?;
153 let deser_response: RpcResponse<T> = serde_json::from_str(response.as_str()?)?;
154
155 Ok(deser_response)
156}
157
158pub(crate) async fn request_with_result<T: serde::de::DeserializeOwned>(
159 body: json::JsonValue,
160) -> PoseidonResult<RpcResponseWithResult<T>> {
161 let mut rpc = RpcClient::new();
162 rpc.common_methods(body);
163 let response = rpc.send().await?;
164 dbg!(&response.as_str()?);
165 let deser_response: RpcResponseWithResult<T> = serde_json::from_str(response.as_str()?)?;
166
167 Ok(deser_response)
168}