1use crate::error::Error;
2use crate::Result;
3use reqwest::Client;
4use rootchain_core::types::{Address, GovernanceProposal};
5use serde::{Deserialize, Serialize};
6use serde_json::json;
7
8#[derive(Debug, Serialize, Deserialize)]
9pub struct ChainInfo {
10 pub chain_id: String,
11 pub height: u64,
12}
13
14#[derive(Debug, Serialize, Deserialize)]
15pub struct BalanceInfo {
16 pub address: Address,
17 pub balance: u128,
18}
19
20#[derive(Debug, Serialize, Deserialize)]
21pub struct ContractCode {
22 pub address: Address,
23 pub bytecode_hex: String,
24}
25
26#[derive(Debug, Serialize, Deserialize)]
27pub struct StorageValue {
28 pub key: String,
29 pub value: Option<String>,
30}
31#[derive(Debug, Serialize, Deserialize)]
32pub struct TransactionResponse {
33 pub hash: String,
34}
35
36pub struct RpcProvider {
37 client: Client,
38 url: String,
39}
40
41impl RpcProvider {
42 pub fn new(url: &str) -> Self {
43 Self {
44 client: Client::new(),
45 url: url.to_string(),
46 }
47 }
48
49 pub(crate) async fn call<R: for<'de> Deserialize<'de>>(
50 &self,
51 method: &str,
52 params: serde_json::Value,
53 ) -> Result<R> {
54 let request = json!({
55 "jsonrpc": "2.0",
56 "id": 1,
57 "method": method,
58 "params": params
59 });
60
61 let response = self
62 .client
63 .post(&self.url)
64 .json(&request)
65 .send()
66 .await?
67 .json::<serde_json::Value>()
68 .await?;
69
70 if let Some(error) = response.get("error") {
71 return Err(Error::Rpc(error.to_string()));
72 }
73
74 let result = response
75 .get("result")
76 .ok_or_else(|| Error::Rpc("Missing result field".to_string()))?;
77
78 serde_json::from_value(result.clone()).map_err(Into::into)
79 }
80
81 pub async fn get_chain_info(&self) -> Result<ChainInfo> {
82 self.call("rootchain_getChainInfo", json!([])).await
83 }
84
85 pub async fn get_balance(&self, address: &Address) -> Result<BalanceInfo> {
86 self.call("rootchain_getBalance", json!([address])).await
87 }
88
89 pub async fn send_raw_transaction(&self, tx_hex: &str) -> Result<String> {
90 let resp: TransactionResponse = self
91 .call("rootchain_sendRawTransaction", json!([tx_hex]))
92 .await?;
93 Ok(resp.hash)
94 }
95
96 pub async fn list_proposals(&self) -> Result<Vec<GovernanceProposal>> {
97 self.call("rootchain_listProposals", json!([])).await
98 }
99
100 pub async fn get_code(&self, address: &Address) -> Result<ContractCode> {
101 self.call("rootchain_getCode", json!([address])).await
102 }
103
104 pub async fn get_storage_at(&self, address: &Address, key: &str) -> Result<StorageValue> {
105 self.call("rootchain_getStorageAt", json!([address, key]))
106 .await
107 }
108}