linera_ethereum/
provider.rs1use async_lock::Mutex;
5use async_trait::async_trait;
6use linera_alloy::{
7 primitives::{Address, Bytes, U256},
8 providers::{Provider, ProviderBuilder, RootProvider},
9 rpc::types::eth::{
10 request::{TransactionInput, TransactionRequest},
11 Filter,
12 },
13 transports::http::reqwest::{header::CONTENT_TYPE, Client},
14};
15use url::Url;
16
17use crate::client::{EthereumQueries, JsonRpcClient};
18
19pub type HttpProvider = RootProvider<linera_alloy::transports::http::Http<Client>>;
20
21use crate::{
22 client::get_block_id,
23 common::{event_name_from_expanded, parse_log, EthereumEvent, EthereumServiceError},
24};
25
26pub struct EthereumClientSimplified {
28 pub url: String,
29 pub id: Mutex<u64>,
30}
31
32#[async_trait]
33impl JsonRpcClient for EthereumClientSimplified {
34 type Error = EthereumServiceError;
35
36 async fn get_id(&self) -> u64 {
37 let mut id = self.id.lock().await;
38 *id += 1;
39 *id
40 }
41
42 async fn request_inner(&self, payload: Vec<u8>) -> Result<Vec<u8>, Self::Error> {
43 let res = Client::new()
44 .post(self.url.clone())
45 .body(payload)
46 .header(CONTENT_TYPE, "application/json")
47 .send()
48 .await?;
49 let body = res.bytes().await?;
50 Ok(body.as_ref().to_vec())
51 }
52}
53
54impl EthereumClientSimplified {
55 pub fn new(url: String) -> Self {
58 let id = Mutex::new(1);
59 Self { url, id }
60 }
61}
62
63#[derive(Clone)]
64pub struct EthereumClient<M> {
65 pub provider: M,
66}
67
68#[async_trait]
69impl EthereumQueries for EthereumClient<HttpProvider> {
70 type Error = EthereumServiceError;
71
72 async fn get_accounts(&self) -> Result<Vec<String>, EthereumServiceError> {
73 Ok(self
74 .provider
75 .get_accounts()
76 .await?
77 .into_iter()
78 .map(|x| format!("{:?}", x))
79 .collect::<Vec<_>>())
80 }
81
82 async fn get_block_number(&self) -> Result<u64, EthereumServiceError> {
83 Ok(self.provider.get_block_number().await?)
84 }
85
86 async fn get_balance(
87 &self,
88 address: &str,
89 block_number: u64,
90 ) -> Result<U256, EthereumServiceError> {
91 let address = address.parse::<Address>()?;
92 let block_id = get_block_id(block_number);
93 let request = self.provider.get_balance(address).block_id(block_id);
94 Ok(request.await?)
95 }
96
97 async fn read_events(
98 &self,
99 contract_address: &str,
100 event_name_expanded: &str,
101 from_block: u64,
102 to_block: u64,
103 ) -> Result<Vec<EthereumEvent>, EthereumServiceError> {
104 let contract_address = contract_address.parse::<Address>()?;
105 let event_name = event_name_from_expanded(event_name_expanded);
106 let filter = Filter::new()
107 .address(contract_address)
108 .event(&event_name)
109 .from_block(from_block)
110 .to_block(to_block - 1);
111 let events = self.provider.get_logs(&filter).await?;
112 events
113 .into_iter()
114 .map(|x| parse_log(event_name_expanded, x))
115 .collect::<Result<_, _>>()
116 }
117
118 async fn non_executive_call(
119 &self,
120 contract_address: &str,
121 data: Bytes,
122 from: &str,
123 block: u64,
124 ) -> Result<Bytes, EthereumServiceError> {
125 let contract_address = contract_address.parse::<Address>()?;
126 let from = from.parse::<Address>()?;
127 let input = TransactionInput::new(data);
128 let tx = TransactionRequest::default()
129 .from(from)
130 .to(contract_address)
131 .input(input);
132 let block_id = get_block_id(block);
133 let eth_call = self.provider.call(&tx).block(block_id);
134 Ok(eth_call.await?)
135 }
136}
137
138impl EthereumClient<HttpProvider> {
139 pub fn new(url: String) -> Result<Self, EthereumServiceError> {
142 let rpc_url = Url::parse(&url)?;
143 let provider = ProviderBuilder::new().on_http(rpc_url);
144 let endpoint = Self { provider };
145 Ok(endpoint)
146 }
147}