1use std::fmt::Debug;
5
6use alloy::rpc::types::eth::{
7 request::{TransactionInput, TransactionRequest},
8 BlockId, BlockNumberOrTag, Filter, Log,
9};
10use alloy_primitives::{Address, Bytes, U256, U64};
11use async_trait::async_trait;
12use linera_base::ensure;
13use serde::{de::DeserializeOwned, Deserialize, Serialize};
14use serde_json::value::RawValue;
15
16use crate::common::{
17 event_name_from_expanded, parse_log, EthereumEvent, EthereumQueryError, EthereumServiceError,
18};
19
20#[async_trait]
22pub trait JsonRpcClient {
23 type Error: From<serde_json::Error> + From<EthereumQueryError>;
24
25 async fn request_inner(&self, payload: Vec<u8>) -> Result<Vec<u8>, Self::Error>;
27
28 async fn get_id(&self) -> u64;
30
31 async fn request<T, R>(&self, method: &str, params: T) -> Result<R, Self::Error>
33 where
34 T: Debug + Serialize + Send + Sync,
35 R: DeserializeOwned + Send,
36 {
37 let id = self.get_id().await;
38 let payload = JsonRpcRequest::new(id, method, params);
39 let payload = serde_json::to_vec(&payload)?;
40 let body = self.request_inner(payload).await?;
41 let result = serde_json::from_slice::<JsonRpcResponse>(&body)?;
42 let raw = result.result;
43 let res = serde_json::from_str(raw.get())?;
44 ensure!(id == result.id, EthereumQueryError::IdIsNotMatching);
45 ensure!(
46 "2.0" == result.jsonrpc,
47 EthereumQueryError::WrongJsonRpcVersion
48 );
49 Ok(res)
50 }
51}
52
53#[derive(Serialize, Deserialize, Debug)]
54struct JsonRpcRequest<'a, T> {
55 id: u64,
56 jsonrpc: &'a str,
57 method: &'a str,
58 params: T,
59}
60
61impl<'a, T> JsonRpcRequest<'a, T> {
62 pub fn new(id: u64, method: &'a str, params: T) -> Self {
64 Self {
65 id,
66 jsonrpc: "2.0",
67 method,
68 params,
69 }
70 }
71}
72
73#[derive(Debug, Deserialize)]
74pub struct JsonRpcResponse {
75 id: u64,
76 jsonrpc: String,
77 result: Box<RawValue>,
78}
79
80#[async_trait]
83pub trait EthereumQueries {
84 type Error;
85
86 async fn get_accounts(&self) -> Result<Vec<String>, Self::Error>;
88
89 async fn get_block_number(&self) -> Result<u64, Self::Error>;
91
92 async fn get_balance(&self, address: &str, block_number: u64) -> Result<U256, Self::Error>;
96
97 async fn read_events(
106 &self,
107 contract_address: &str,
108 event_name_expanded: &str,
109 from_block: u64,
110 to_block: u64,
111 ) -> Result<Vec<EthereumEvent>, Self::Error>;
112
113 async fn non_executive_call(
118 &self,
119 contract_address: &str,
120 data: Bytes,
121 from: &str,
122 block: u64,
123 ) -> Result<Bytes, Self::Error>;
124}
125
126pub(crate) fn get_block_id(block_number: u64) -> BlockId {
127 let number = BlockNumberOrTag::Number(block_number);
128 BlockId::Number(number)
129}
130
131#[async_trait]
132impl<C> EthereumQueries for C
133where
134 C: JsonRpcClient + Sync,
135 EthereumServiceError: From<<C as JsonRpcClient>::Error>,
136{
137 type Error = EthereumServiceError;
138
139 async fn get_accounts(&self) -> Result<Vec<String>, Self::Error> {
140 let results: Vec<String> = self.request("eth_accounts", ()).await?;
141 Ok(results
142 .into_iter()
143 .map(|x| x.to_lowercase())
144 .collect::<Vec<_>>())
145 }
146
147 async fn get_block_number(&self) -> Result<u64, Self::Error> {
148 let result = self.request::<_, U64>("eth_blockNumber", ()).await?;
149 Ok(result.to::<u64>())
150 }
151
152 async fn get_balance(&self, address: &str, block_number: u64) -> Result<U256, Self::Error> {
153 let address = address.parse::<Address>()?;
154 let tag = get_block_id(block_number);
155 Ok(self.request("eth_getBalance", (address, tag)).await?)
156 }
157
158 async fn read_events(
159 &self,
160 contract_address: &str,
161 event_name_expanded: &str,
162 from_block: u64,
163 to_block: u64,
164 ) -> Result<Vec<EthereumEvent>, Self::Error> {
165 let contract_address = contract_address.parse::<Address>()?;
166 let event_name = event_name_from_expanded(event_name_expanded);
167 let filter = Filter::new()
168 .address(contract_address)
169 .event(&event_name)
170 .from_block(from_block)
171 .to_block(to_block - 1);
172 let events = self
173 .request::<_, Vec<Log>>("eth_getLogs", (filter,))
174 .await?;
175 events
176 .into_iter()
177 .map(|x| parse_log(event_name_expanded, x))
178 .collect::<Result<_, _>>()
179 }
180
181 async fn non_executive_call(
182 &self,
183 contract_address: &str,
184 data: Bytes,
185 from: &str,
186 block: u64,
187 ) -> Result<Bytes, Self::Error> {
188 let contract_address = contract_address.parse::<Address>()?;
189 let from = from.parse::<Address>()?;
190 let input = TransactionInput::new(data);
191 let tx = TransactionRequest::default()
192 .from(from)
193 .to(contract_address)
194 .input(input);
195 let tag = get_block_id(block);
196 Ok(self.request::<_, Bytes>("eth_call", (tx, tag)).await?)
197 }
198}