circles_types/
rpc.rs

1use alloy_primitives::{Address, U256};
2use serde::{Deserialize, Serialize};
3
4/// JSON-RPC request structure
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct JsonRpcRequest<T = serde_json::Value> {
7    pub jsonrpc: String,
8    pub id: serde_json::Value, // Can be number or string
9    pub method: String,
10    pub params: T,
11}
12
13impl<T> JsonRpcRequest<T> {
14    pub fn new(id: impl Into<serde_json::Value>, method: String, params: T) -> Self {
15        Self {
16            jsonrpc: "2.0".to_string(),
17            id: id.into(),
18            method,
19            params,
20        }
21    }
22}
23
24/// JSON-RPC error object
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct JsonRpcError {
27    pub code: i32,
28    pub message: String,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub data: Option<serde_json::Value>,
31}
32
33/// JSON-RPC response structure
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct JsonRpcResponse<T = serde_json::Value> {
36    pub jsonrpc: String,
37    pub id: serde_json::Value,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub result: Option<T>,
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub error: Option<JsonRpcError>,
42}
43
44impl<T> JsonRpcResponse<T> {
45    pub fn success(id: impl Into<serde_json::Value>, result: T) -> Self {
46        Self {
47            jsonrpc: "2.0".to_string(),
48            id: id.into(),
49            result: Some(result),
50            error: None,
51        }
52    }
53
54    pub fn error(id: impl Into<serde_json::Value>, error: JsonRpcError) -> Self {
55        Self {
56            jsonrpc: "2.0".to_string(),
57            id: id.into(),
58            result: None,
59            error: Some(error),
60        }
61    }
62}
63
64/// Circles query response format
65/// Used for circles_query RPC method results
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct CirclesQueryResponse {
68    pub columns: Vec<String>,
69    pub rows: Vec<Vec<serde_json::Value>>,
70}
71
72/// Generic query response wrapper
73/// Used for internal query transformations and type-safe responses
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct QueryResponse<T = serde_json::Value> {
76    pub result: T,
77    #[serde(skip_serializing_if = "Option::is_none")]
78    pub error: Option<serde_json::Value>,
79}
80
81impl<T> QueryResponse<T> {
82    pub fn success(result: T) -> Self {
83        Self {
84            result,
85            error: None,
86        }
87    }
88
89    pub fn error(error: serde_json::Value) -> Self {
90        Self {
91            result: unsafe { std::mem::zeroed() }, // This is a hack, in practice we'd use Option<T>
92            error: Some(error),
93        }
94    }
95}
96
97/// Better version of QueryResponse that's more idiomatic
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct SafeQueryResponse<T> {
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub result: Option<T>,
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub error: Option<serde_json::Value>,
104}
105
106impl<T> SafeQueryResponse<T> {
107    pub fn success(result: T) -> Self {
108        Self {
109            result: Some(result),
110            error: None,
111        }
112    }
113
114    pub fn error(error: serde_json::Value) -> Self {
115        Self {
116            result: None,
117            error: Some(error),
118        }
119    }
120}
121
122/// Balance type that can be either raw U256 or formatted as TimeCircles floating point
123#[derive(Debug, Clone, Serialize, Deserialize)]
124#[serde(untagged)]
125pub enum Balance {
126    Raw(U256),
127    TimeCircles(f64),
128}
129
130/// Token balance response from circles_getTokenBalances
131#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct TokenBalanceResponse {
133    #[serde(rename = "tokenId")]
134    pub token_id: Address,
135    pub balance: Balance,
136    /// Static atto-circles (inflationary wrappers) when provided by the backend.
137    #[serde(default, rename = "staticAttoCircles")]
138    pub static_atto_circles: Option<U256>,
139    #[serde(default, rename = "staticCircles")]
140    pub static_circles: Option<f64>,
141    pub token_owner: Address,
142}