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