229 lines
6.6 KiB
Rust
229 lines
6.6 KiB
Rust
use std::error::Error;
|
|
use std::fmt::{Debug, Display, Formatter};
|
|
|
|
use async_trait::async_trait;
|
|
use ethers::prelude::Address;
|
|
use ethers::providers::{
|
|
HttpClientError, JsonRpcClient, Middleware, Provider, ProviderError, Response,
|
|
};
|
|
use ethers::types::transaction::eip2718::TypedTransaction;
|
|
use ethers::types::transaction::eip2930::AccessList;
|
|
use ethers::types::{
|
|
BlockId, BlockNumber, Bytes, EIP1186ProofResponse, Eip1559TransactionRequest, FeeHistory,
|
|
Filter, Log, Transaction, TransactionReceipt, H256, U256,
|
|
};
|
|
use eyre::Result;
|
|
use serde::de::DeserializeOwned;
|
|
use serde::Serialize;
|
|
use serde_json::to_value;
|
|
use wasm_bindgen::JsValue;
|
|
|
|
use crate::types::CallOpts;
|
|
use common::errors::RpcError;
|
|
|
|
use super::ExecutionRpc;
|
|
|
|
use js_sys::Promise;
|
|
use wasm_bindgen::prelude::wasm_bindgen;
|
|
use wasm_bindgen_futures::JsFuture;
|
|
|
|
#[wasm_bindgen]
|
|
extern "C" {
|
|
#[wasm_bindgen(js_namespace = self)]
|
|
fn execution_rpc_handler(data: JsValue) -> Promise;
|
|
}
|
|
|
|
pub struct HttpRpc {
|
|
provider: Provider<LumeProvider>,
|
|
}
|
|
|
|
impl Clone for HttpRpc {
|
|
fn clone(&self) -> Self {
|
|
Self::new().unwrap()
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct LumeProvider {}
|
|
|
|
impl LumeProvider {
|
|
pub fn new() -> Self {
|
|
LumeProvider {}
|
|
}
|
|
}
|
|
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
|
|
impl JsonRpcClient for LumeProvider {
|
|
type Error = HttpClientError;
|
|
|
|
async fn request<T, R>(&self, method: &str, params: T) -> Result<R, Self::Error>
|
|
where
|
|
T: Debug + Serialize + Send + Sync,
|
|
R: DeserializeOwned,
|
|
{
|
|
let request = js_sys::Map::new();
|
|
request.set(&JsValue::from_str("method"), &JsValue::from_str(method));
|
|
|
|
if let Some(params) = Option::from(params) {
|
|
let js_params = to_value(¶ms).unwrap();
|
|
let json_str = serde_json::to_string(&js_params).unwrap();
|
|
request.set(&JsValue::from_str("params"), &JsValue::from_str(&json_str));
|
|
} else {
|
|
request.set(&JsValue::from_str("params"), &JsValue::null());
|
|
}
|
|
|
|
let js_future = JsFuture::from(execution_rpc_handler(JsValue::from(request)));
|
|
let result = js_future.await?;
|
|
let json = result.as_string().expect("response is not a string");
|
|
|
|
let body = json.as_bytes();
|
|
|
|
let raw = match serde_json::from_slice(&body) {
|
|
Ok(Response::Success { result, .. }) => result.to_owned(),
|
|
Ok(Response::Error { error, .. }) => return Err(error.into()),
|
|
Ok(_) => {
|
|
panic!(
|
|
"{} {}",
|
|
"unexpected notification over HTTP transport",
|
|
String::from_utf8_lossy(&body).to_string()
|
|
);
|
|
}
|
|
Err(err) => {
|
|
panic!(
|
|
"{} {}",
|
|
err.to_string(),
|
|
String::from_utf8_lossy(&body).to_string()
|
|
);
|
|
}
|
|
};
|
|
|
|
let res = serde_json::from_str(raw.get()).map_err(|err| HttpClientError::SerdeJson {
|
|
err,
|
|
text: raw.to_string(),
|
|
})?;
|
|
|
|
Ok(res)
|
|
}
|
|
}
|
|
|
|
#[async_trait(?Send)]
|
|
impl ExecutionRpc for HttpRpc {
|
|
fn new() -> Result<Self> {
|
|
let client = LumeProvider::new();
|
|
let provider = Provider::new(client);
|
|
|
|
Ok(HttpRpc { provider })
|
|
}
|
|
|
|
async fn get_proof(
|
|
&self,
|
|
address: &Address,
|
|
slots: &[H256],
|
|
block: u64,
|
|
) -> Result<EIP1186ProofResponse> {
|
|
let block = Some(BlockId::from(block));
|
|
let proof_response = self
|
|
.provider
|
|
.get_proof(*address, slots.to_vec(), block)
|
|
.await
|
|
.map_err(|e| RpcError::new("get_proof", e))?;
|
|
|
|
Ok(proof_response)
|
|
}
|
|
|
|
async fn create_access_list(&self, opts: &CallOpts, block: u64) -> Result<AccessList> {
|
|
let block = Some(BlockId::from(block));
|
|
|
|
let mut raw_tx = Eip1559TransactionRequest::new();
|
|
raw_tx.to = Some(opts.to.unwrap_or_default().into());
|
|
raw_tx.from = opts.from;
|
|
raw_tx.value = opts.value;
|
|
raw_tx.gas = Some(opts.gas.unwrap_or(U256::from(100_000_000)));
|
|
raw_tx.max_fee_per_gas = Some(U256::zero());
|
|
raw_tx.max_priority_fee_per_gas = Some(U256::zero());
|
|
raw_tx.data = opts
|
|
.data
|
|
.as_ref()
|
|
.map(|data| Bytes::from(data.as_slice().to_owned()));
|
|
|
|
let tx = TypedTransaction::Eip1559(raw_tx);
|
|
let list = self
|
|
.provider
|
|
.create_access_list(&tx, block)
|
|
.await
|
|
.map_err(|e| RpcError::new("create_access_list", e))?;
|
|
|
|
Ok(list.access_list)
|
|
}
|
|
|
|
async fn get_code(&self, address: &Address, block: u64) -> Result<Vec<u8>> {
|
|
let block = Some(BlockId::from(block));
|
|
let code = self
|
|
.provider
|
|
.get_code(*address, block)
|
|
.await
|
|
.map_err(|e| RpcError::new("get_code", e))?;
|
|
|
|
Ok(code.to_vec())
|
|
}
|
|
|
|
async fn send_raw_transaction(&self, bytes: &[u8]) -> Result<H256> {
|
|
let bytes = Bytes::from(bytes.to_owned());
|
|
let tx = self
|
|
.provider
|
|
.send_raw_transaction(bytes)
|
|
.await
|
|
.map_err(|e| RpcError::new("send_raw_transaction", e))?;
|
|
|
|
Ok(tx.tx_hash())
|
|
}
|
|
|
|
async fn get_transaction_receipt(&self, tx_hash: &H256) -> Result<Option<TransactionReceipt>> {
|
|
let receipt = self
|
|
.provider
|
|
.get_transaction_receipt(*tx_hash)
|
|
.await
|
|
.map_err(|e| RpcError::new("get_transaction_receipt", e))?;
|
|
|
|
Ok(receipt)
|
|
}
|
|
|
|
async fn get_transaction(&self, tx_hash: &H256) -> Result<Option<Transaction>> {
|
|
Ok(self
|
|
.provider
|
|
.get_transaction(*tx_hash)
|
|
.await
|
|
.map_err(|e| RpcError::new("get_transaction", e))?)
|
|
}
|
|
|
|
async fn get_logs(&self, filter: &Filter) -> Result<Vec<Log>> {
|
|
Ok(self
|
|
.provider
|
|
.get_logs(filter)
|
|
.await
|
|
.map_err(|e| RpcError::new("get_logs", e))?)
|
|
}
|
|
|
|
async fn chain_id(&self) -> Result<u64> {
|
|
Ok(self
|
|
.provider
|
|
.get_chainid()
|
|
.await
|
|
.map_err(|e| RpcError::new("chain_id", e))?
|
|
.as_u64())
|
|
}
|
|
|
|
async fn get_fee_history(
|
|
&self,
|
|
block_count: u64,
|
|
last_block: u64,
|
|
reward_percentiles: &[f64],
|
|
) -> Result<FeeHistory> {
|
|
let block = BlockNumber::from(last_block);
|
|
Ok(self
|
|
.provider
|
|
.fee_history(block_count, block, reward_percentiles)
|
|
.await
|
|
.map_err(|e| RpcError::new("fee_history", e))?)
|
|
}
|
|
}
|