Skip to content

Commit

Permalink
fix: correctly serialize eth_call params
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes committed May 24, 2024
1 parent f12cdd3 commit ddedd19
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 16 deletions.
6 changes: 4 additions & 2 deletions crates/provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,23 @@ async-stream = "0.3"
async-trait.workspace = true
auto_impl.workspace = true
dashmap = "5.5"
futures-utils-wasm.workspace = true
futures.workspace = true
lru = "0.12"
pin-project.workspace = true
reqwest = { workspace = true, optional = true }
serde_json.workspace = true
serde.workspace = true
tokio = { workspace = true, features = ["sync", "macros"] }
tracing.workspace = true
url = { workspace = true, optional = true }
futures-utils-wasm.workspace = true
pin-project.workspace = true

[dev-dependencies]
alloy-consensus = { workspace = true, features = ["std"] }
alloy-node-bindings.workspace = true
alloy-rpc-client = { workspace = true, features = ["reqwest"] }
alloy-rlp.workspace = true
alloy-sol-types.workspace = true
alloy-signer.workspace = true
alloy-signer-wallet.workspace = true
alloy-transport-http = { workspace = true, features = ["reqwest"] }
Expand Down
43 changes: 29 additions & 14 deletions crates/provider/src/provider/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,35 @@ use alloy_rpc_client::{RpcCall, WeakClient};
use alloy_rpc_types::state::StateOverride;
use alloy_transport::{Transport, TransportErrorKind, TransportResult};
use futures::FutureExt;
use std::{
borrow::Cow,
future::Future,
task::Poll::{self, Ready},
};

type RunningFut<'req, 'state, T, N> = RpcCall<
T,
(&'req <N as Network>::TransactionRequest, BlockId, Option<Cow<'state, StateOverride>>),
Bytes,
>;
use serde::ser::SerializeSeq;
use std::{future::Future, task::Poll};

type RunningFut<'req, 'state, T, N> = RpcCall<T, EthCallParams<'req, 'state, N>, Bytes>;

#[derive(Clone, Debug)]
#[doc(hidden)] // Not public API.
pub struct EthCallParams<'req, 'state, N: Network> {
data: &'req N::TransactionRequest,
block: BlockId,
overrides: Option<&'state StateOverride>,
}

impl<N: Network> serde::Serialize for EthCallParams<'_, '_, N> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let len = if self.overrides.is_some() { 3 } else { 2 };
let mut seq = serializer.serialize_seq(Some(len))?;
seq.serialize_element(&self.data)?;
seq.serialize_element(&self.block)?;
if let Some(overrides) = self.overrides {
seq.serialize_element(overrides)?;
}
seq.end()
}
}

/// The [`EthCallFut`] future is the future type for an `eth_call` RPC request.
#[derive(Debug, Clone)]
#[doc(hidden)] // Not public API.
pub enum EthCallFut<'req, 'state, T, N>
where
T: Transport + Clone,
Expand Down Expand Up @@ -58,12 +73,12 @@ where

let client = match client.upgrade().ok_or_else(TransportErrorKind::backend_gone) {
Ok(client) => client,
Err(e) => return Ready(Err(e)),
Err(e) => return Poll::Ready(Err(e)),
};

let overrides = overrides.map(Cow::Borrowed);
let params = EthCallParams { data, block: block.unwrap_or_default(), overrides };

let fut = client.request("eth_call", (data, block.unwrap_or_default(), overrides));
let fut = client.request("eth_call", params);

*self = Self::Running(fut);
self.poll_running(cx)
Expand Down
14 changes: 14 additions & 0 deletions crates/provider/src/provider/trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -922,9 +922,11 @@ impl<T: Transport + Clone, N: Network> Provider<T, N> for RootProvider<T, N> {
mod tests {
use super::*;
use crate::{ProviderBuilder, WalletProvider};
use alloy_network::TransactionBuilder;
use alloy_node_bindings::Anvil;
use alloy_primitives::{address, b256, bytes};
use alloy_rpc_types::request::TransactionRequest;
use alloy_sol_types::SolValue;

fn init_tracing() {
let _ = tracing_subscriber::fmt::try_init();
Expand Down Expand Up @@ -1338,4 +1340,16 @@ mod tests {
let count = provider.get_uncle_count(0.into()).await.unwrap();
assert_eq!(count, 0);
}

#[tokio::test]
async fn call_mainnet() {
init_tracing();
let url = "https://eth-mainnet.alchemyapi.io/v2/jGiK5vwDfC3F4r0bqukm-W2GqgdrxdSr";
let provider = ProviderBuilder::new().on_http(url.parse().unwrap());
let req = TransactionRequest::default()
.with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")) // WETH
.with_input(bytes!("06fdde03")); // `name()`
let result = provider.call(&req).await.unwrap();
assert_eq!(String::abi_decode(&result, true).unwrap(), "Wrapped Ether");
}
}

0 comments on commit ddedd19

Please sign in to comment.