linera_ethereum/
common.rs1use std::num::ParseIntError;
5
6#[cfg(not(target_arch = "wasm32"))]
7use linera_alloy::rpc::json_rpc;
8use linera_alloy::{
9 primitives::{Address, B256, U256},
10 rpc::types::eth::Log,
11};
12use num_bigint::{BigInt, BigUint};
13use num_traits::cast::ToPrimitive;
14use serde::{Deserialize, Serialize};
15use thiserror::Error;
16
17#[derive(Error, Debug)]
18pub enum EthereumQueryError {
19 #[error("the is should be matching")]
21 IdIsNotMatching,
22
23 #[error("wrong jsonrpc version")]
25 WrongJsonRpcVersion,
26}
27
28#[derive(Debug, Error)]
29pub enum EthereumServiceError {
30 #[error(transparent)]
32 EthereumQueryError(#[from] EthereumQueryError),
33
34 #[error(transparent)]
36 ParseIntError(#[from] ParseIntError),
37
38 #[error("Failed to deploy the smart contract")]
39 DeployError,
40
41 #[error("Json error occurred")]
42 JsonError,
43
44 #[error("Unsupported Ethereum type")]
45 UnsupportedEthereumTypeError,
46
47 #[error("Event parsing error")]
48 EventParsingError,
49
50 #[error(transparent)]
52 ParseBigIntError(#[from] num_bigint::ParseBigIntError),
53
54 #[error("Ethereum parsing error")]
56 EthereumParsingError,
57
58 #[error("Parse bool error")]
60 ParseBoolError,
61
62 #[error(transparent)]
64 FromHexError(#[from] linera_alloy::primitives::hex::FromHexError),
65
66 #[error(transparent)]
68 SerdeJsonError(#[from] serde_json::Error),
69
70 #[error(transparent)]
72 #[cfg(not(target_arch = "wasm32"))]
73 RpcError(#[from] json_rpc::RpcError<linera_alloy::transports::TransportErrorKind>),
74
75 #[error(transparent)]
77 #[cfg(not(target_arch = "wasm32"))]
78 UrlParseError(#[from] url::ParseError),
79
80 #[error(transparent)]
82 #[cfg(not(target_arch = "wasm32"))]
83 AlloyReqwestError(#[from] linera_alloy::transports::http::reqwest::Error),
84}
85
86#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
89pub enum EthereumDataType {
90 Address(String),
91 Uint256(U256),
92 Uint64(u64),
93 Int64(i64),
94 Uint32(u32),
95 Int32(i32),
96 Uint16(u16),
97 Int16(i16),
98 Uint8(u8),
99 Int8(i8),
100 Bool(bool),
101}
102
103pub fn event_name_from_expanded(event_name_expanded: &str) -> String {
107 event_name_expanded.replace(" indexed", "").to_string()
108}
109
110fn parse_entry(entry: B256, ethereum_type: &str) -> Result<EthereumDataType, EthereumServiceError> {
111 if ethereum_type == "address" {
112 let address = Address::from_word(entry);
113 let address = format!("{:?}", address);
114 return Ok(EthereumDataType::Address(address));
115 }
116 if ethereum_type == "uint256" {
117 let entry = U256::from_be_bytes(entry.0);
118 return Ok(EthereumDataType::Uint256(entry));
119 }
120 if ethereum_type == "uint64" {
121 let entry = BigUint::from_bytes_be(&entry.0);
122 let entry = entry.to_u64().unwrap();
123 return Ok(EthereumDataType::Uint64(entry));
124 }
125 if ethereum_type == "int64" {
126 let entry = BigInt::from_signed_bytes_be(&entry.0);
127 let entry = entry.to_i64().unwrap();
128 return Ok(EthereumDataType::Int64(entry));
129 }
130 if ethereum_type == "uint32" {
131 let entry = BigUint::from_bytes_be(&entry.0);
132 let entry = entry.to_u32().unwrap();
133 return Ok(EthereumDataType::Uint32(entry));
134 }
135 if ethereum_type == "int32" {
136 let entry = BigInt::from_signed_bytes_be(&entry.0);
137 let entry = entry.to_i32().unwrap();
138 return Ok(EthereumDataType::Int32(entry));
139 }
140 if ethereum_type == "uint16" {
141 let entry = BigUint::from_bytes_be(&entry.0);
142 let entry = entry.to_u16().unwrap();
143 return Ok(EthereumDataType::Uint16(entry));
144 }
145 if ethereum_type == "int16" {
146 let entry = BigInt::from_signed_bytes_be(&entry.0);
147 let entry = entry.to_i16().unwrap();
148 return Ok(EthereumDataType::Int16(entry));
149 }
150 if ethereum_type == "uint8" {
151 let entry = BigUint::from_bytes_be(&entry.0);
152 let entry = entry.to_u8().unwrap();
153 return Ok(EthereumDataType::Uint8(entry));
154 }
155 if ethereum_type == "int8" {
156 let entry = BigInt::from_signed_bytes_be(&entry.0);
157 let entry = entry.to_i8().unwrap();
158 return Ok(EthereumDataType::Int8(entry));
159 }
160 if ethereum_type == "bool" {
161 let entry = BigUint::from_bytes_be(&entry.0);
162 let entry = entry.to_u8().unwrap();
163 let entry = match entry {
164 1 => true,
165 0 => false,
166 _ => {
167 return Err(EthereumServiceError::ParseBoolError);
168 }
169 };
170 return Ok(EthereumDataType::Bool(entry));
171 }
172 Err(EthereumServiceError::UnsupportedEthereumTypeError)
173}
174
175#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
177pub struct EthereumEvent {
178 pub values: Vec<EthereumDataType>,
179 pub block_number: u64,
180}
181
182fn get_inner_event_type(event_name_expanded: &str) -> Result<String, EthereumServiceError> {
183 if let Some(opening_paren_index) = event_name_expanded.find('(') {
184 if let Some(closing_paren_index) = event_name_expanded.find(')') {
185 let inner_types = &event_name_expanded[opening_paren_index + 1..closing_paren_index];
187 return Ok(inner_types.to_string());
188 }
189 }
190 Err(EthereumServiceError::EventParsingError)
191}
192
193pub fn parse_log(
194 event_name_expanded: &str,
195 log: Log,
196) -> Result<EthereumEvent, EthereumServiceError> {
197 let inner_types = get_inner_event_type(event_name_expanded)?;
198 let ethereum_types = inner_types
199 .split(',')
200 .map(|s| s.to_string())
201 .collect::<Vec<_>>();
202 let mut values = Vec::new();
203 let mut topic_index = 0;
204 let mut data_index = 0;
205 let mut vec = [0_u8; 32];
206 let log_data = log.data();
207 let topics = log_data.topics();
208 for ethereum_type in ethereum_types {
209 values.push(match ethereum_type.strip_suffix(" indexed") {
210 None => {
211 for (i, val) in vec.iter_mut().enumerate() {
212 *val = log_data.data[data_index * 32 + i];
213 }
214 data_index += 1;
215 let entry = vec.into();
216 parse_entry(entry, ðereum_type)?
217 }
218 Some(ethereum_type) => {
219 topic_index += 1;
220 parse_entry(topics[topic_index], ethereum_type)?
221 }
222 });
223 }
224 let block_number = log.block_number.unwrap();
225 Ok(EthereumEvent {
226 values,
227 block_number,
228 })
229}