use ethers::{abi::AbiEncode, types::{Address, U256}}; use eyre::Result; use std::{fmt::Display, net::SocketAddr, str::FromStr, sync::Arc}; use serde::{Deserialize, Serialize}; use jsonrpsee::{ core::{async_trait, Error}, http_server::{HttpServerBuilder, HttpServerHandle}, proc_macros::rpc, }; use crate::common::utils::hex_str_to_bytes; use super::Client; pub struct Rpc { client: Arc, handle: Option, } impl Rpc { pub fn new(client: Arc) -> Self { Rpc { client, handle: None, } } pub async fn start(&mut self) -> Result { let rpc_inner = RpcInner { client: self.client.clone(), }; let (handle, addr) = start(rpc_inner).await?; self.handle = Some(handle); Ok(addr) } } #[rpc(client, server, namespace = "eth")] trait EthRpc { #[method(name = "getBalance")] async fn get_balance(&self, address: &str, block: &str) -> Result; #[method(name = "getTransactionCount")] async fn get_transaction_count(&self, address: &str, block: &str) -> Result; #[method(name = "getCode")] async fn get_code(&self, address: &str, block: &str) -> Result; #[method(name = "call")] async fn call(&self, opts: CallOpts, block: &str) -> Result; } struct RpcInner { pub client: Arc, } #[async_trait] impl EthRpcServer for RpcInner { async fn get_balance(&self, address: &str, block: &str) -> Result { match block { "latest" => { let address = convert_err(Address::from_str(address))?; let balance = convert_err(self.client.get_balance(&address).await)?; Ok(balance.encode_hex()) } _ => Err(Error::Custom("Invalid Block Number".to_string())), } } async fn get_transaction_count(&self, address: &str, block: &str) -> Result { match block { "latest" => { let address = convert_err(Address::from_str(address))?; let nonce = convert_err(self.client.get_nonce(&address).await)?; Ok(nonce.encode_hex()) } _ => Err(Error::Custom("Invalid Block Number".to_string())), } } async fn get_code(&self, address: &str, block: &str) -> Result { match block { "latest" => { let address = convert_err(Address::from_str(address))?; let code = convert_err(self.client.get_code(&address).await)?; Ok(hex::encode(code)) } _ => Err(Error::Custom("Invalid Block Number".to_string())), } } async fn call(&self, opts: CallOpts, block: &str) -> Result { match block { "latest" => { let to = convert_err(Address::from_str(&opts.to))?; let data = convert_err(hex_str_to_bytes(&opts.data.unwrap_or("0x".to_string())))?; let value = convert_err(U256::from_str_radix(&opts.value.unwrap_or("0x0".to_string()), 16))?; let res = convert_err(self.client.call(&to, &data, value).await)?; Ok(hex::encode(res)) }, _ => Err(Error::Custom("Invalid Block Number".to_string())), } } } async fn start(rpc: RpcInner) -> Result<(HttpServerHandle, SocketAddr)> { let server = HttpServerBuilder::default().build("127.0.0.1:8545").await?; let addr = server.local_addr()?; let handle = server.start(rpc.into_rpc())?; Ok((handle, addr)) } fn convert_err(res: Result) -> Result { res.map_err(|err| Error::Custom(err.to_string())) } #[derive(Deserialize, Serialize)] pub struct CallOpts { from: Option, to: String, gas: Option, value: Option, data: Option, }