Skip to content
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
4d2c5a5
XC-412: Initialize new empty `evm_rpc_client` crate
lpahlavi Aug 6, 2025
d10ee6a
XC-412: Add skeleton for client
lpahlavi Aug 6, 2025
4b71bd1
XC-412: Add `eth_getLogs` to new client
lpahlavi Aug 6, 2025
07c8712
XC-412: Add empty changelog
lpahlavi Aug 6, 2025
d5d3413
XC-412: Add more type conversions to `alloy`
lpahlavi Aug 7, 2025
99d82b2
XC-412: Use `try_from` instead of `from`
lpahlavi Aug 7, 2025
34c70b9
XC-412: Add `get_logs` to client
lpahlavi Aug 7, 2025
fb4a545
XC-412: Don't expose private types
lpahlavi Aug 7, 2025
041a47b
XC-412: Remove new `ProviderId` type
lpahlavi Aug 7, 2025
33e50df
XC-412: Refactor `and_then`
lpahlavi Aug 7, 2025
4619b97
XC-412: Make `f` mutable
lpahlavi Aug 8, 2025
e8e4eb2
XC-412: Basic `PocketIcRuntime`
lpahlavi Aug 8, 2025
74e00f1
XC-412: Clippy
lpahlavi Aug 8, 2025
266373a
XC-412: Add some type conversions
lpahlavi Aug 19, 2025
c1e031e
XC-412: Fix mock iteration
lpahlavi Aug 19, 2025
5e8aeed
XC-412: Fix repository link
lpahlavi Aug 20, 2025
fff88e0
XC-412: Require docs
lpahlavi Aug 20, 2025
a547409
XC-412: Add rustdoc and examples
lpahlavi Aug 20, 2025
5e5c55a
XC-412: Move type conversions to separate files
lpahlavi Aug 20, 2025
4a73233
XC-412: Flesh out examples
lpahlavi Aug 20, 2025
99d031c
XC-412: Move more type conversions to separate files
lpahlavi Aug 20, 2025
ab47bb8
XC-412: Add TODO for conversion from `alloy_rpc_types::Filter` to `Ge…
lpahlavi Aug 20, 2025
59801f2
XC-412: Add some alloy conversion unit tests
lpahlavi Aug 21, 2025
ccb0f5d
XC-412: Add unit tests for `and_then` method
lpahlavi Aug 21, 2025
438dd53
Merge branch 'main' into lpahlavi/XC-412-evm-rpc-client
lpahlavi Aug 21, 2025
b152927
XC-412: Formatting
lpahlavi Aug 21, 2025
5de395d
XC-412: Add more unit tests
lpahlavi Aug 21, 2025
398be24
Merge branch 'lpahlavi/XC-412-evm-rpc-client' into lpahlavi/XC-412-ev…
lpahlavi Aug 21, 2025
93874e6
XC-412: Add `#[allow(missing_docs)]` to `pocket_ic`
lpahlavi Aug 21, 2025
9802e56
XC-412: change `forbit` to `deny`
lpahlavi Aug 21, 2025
4e62c83
XC-412: Formatting
lpahlavi Aug 21, 2025
52e8b63
XC-412: Fix `RepeatExt` implementation
lpahlavi Aug 21, 2025
f3752e8
XC-412: Fix rustdoc
lpahlavi Aug 21, 2025
3bc9ab2
Add correct TODO link
lpahlavi Aug 22, 2025
9d1c8b1
XC-412: Refactor remaining `eth_getLogs` tests
lpahlavi Aug 22, 2025
7f4dbd5
XC-412: Clippy
lpahlavi Aug 22, 2025
472a0e6
XC-412: Fix mocking logic
lpahlavi Aug 26, 2025
41df297
Merge branch 'main' into lpahlavi/XC-412-evm-rpc-client-int-tests
lpahlavi Aug 26, 2025
b19309f
XC-412: Revert merge mistake
lpahlavi Aug 26, 2025
bd4fae6
XC-412: Remove debugging code
lpahlavi Aug 26, 2025
4735b53
XC-412: Clippy
lpahlavi Aug 26, 2025
d5e5b24
XC-412: Add support for `eth_getBlockByNumber` method to client
lpahlavi Aug 26, 2025
b33867e
XC-412: Formatting
lpahlavi Aug 26, 2025
9470eba
XC-412: Formatting
lpahlavi Aug 26, 2025
f810211
XC-412: Add unit tests for conversion
lpahlavi Aug 27, 2025
882dbe5
XC-412: Formatting
lpahlavi Aug 27, 2025
50d9bc8
XC-412: Fix error message
lpahlavi Aug 27, 2025
2794755
XC-412: Remove useless conversion
lpahlavi Aug 27, 2025
fdf1a5c
Merge branch 'main' into lpahlavi/XC-412-eth-get-block-by-number
lpahlavi Sep 4, 2025
0011c38
XC-412: Remove `runtime/pocket_ic`
lpahlavi Sep 4, 2025
027e2c0
XC-412: Remove unneeded dependencies
lpahlavi Sep 4, 2025
a0b941b
XC-412: Hide import in docs
lpahlavi Sep 5, 2025
ea49605
XC-412: Remove `with_cycles` from docs
lpahlavi Sep 5, 2025
17bc345
XC-412: Remove `alloy` from default features
lpahlavi Sep 5, 2025
dde85ef
XC-412: Add more prop tests for `alloy` conversions
lpahlavi Sep 5, 2025
7d37186
XC-412: Handle pre- and post-Paris `difficulty`
lpahlavi Sep 5, 2025
84160e9
XC-412: Formatting
lpahlavi Sep 8, 2025
2ee22d1
XC-412: Fix `Nat256` to `U256` conversion
lpahlavi Sep 8, 2025
60e1f55
XC-412: Split unit tests in pre- and post-Paris
lpahlavi Sep 8, 2025
20d8c70
XC-412: Move canonicalization to functions
lpahlavi Sep 8, 2025
bdbdac7
XC-412: Apply canonicalization less generously
lpahlavi Sep 11, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 54 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ zeroize = { version = "1.8", features = ["zeroize_derive"] }
regex = "1.11"

[dev-dependencies]
alloy-consensus = { workspace = true }
alloy-primitives = { workspace = true }
alloy-rpc-types = { workspace = true }
assert_matches = { workspace = true }
Expand All @@ -67,6 +68,7 @@ rand = "0.8"
tokio = "1.44.1"

[workspace.dependencies]
alloy-consensus = "1.0.26"
alloy-primitives = "1.3.0"
alloy-rpc-types = "1.0.23"
assert_matches = "1.5.0"
Expand Down
2 changes: 1 addition & 1 deletion evm_rpc_client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ serde = { workspace = true }
strum = { workspace = true }

[dev-dependencies]
tokio = { workspace = true, features = ["full"] }
tokio = { workspace = true, features = ["full"] }
68 changes: 65 additions & 3 deletions evm_rpc_client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,11 @@ pub mod fixtures;
mod request;
mod runtime;

use crate::request::{Request, RequestBuilder};
use crate::request::{
GetBlockByNumberRequest, GetBlockByNumberRequestBuilder, Request, RequestBuilder,
};
use candid::{CandidType, Principal};
use evm_rpc_types::{ConsensusStrategy, GetLogsArgs, RpcConfig, RpcServices};
use evm_rpc_types::{BlockTag, ConsensusStrategy, GetLogsArgs, RpcConfig, RpcServices};
use ic_error_types::RejectCode;
use request::{GetLogsRequest, GetLogsRequestBuilder};
pub use runtime::{IcRuntime, Runtime};
Expand Down Expand Up @@ -319,6 +321,67 @@ impl<R> ClientBuilder<R> {
}

impl<R> EvmRpcClient<R> {
/// Call `eth_getBlockByNumber` on the EVM RPC canister.
///
/// # Examples
///
/// ```rust
/// use alloy_primitives::{address, b256, bytes};
/// use alloy_rpc_types::BlockNumberOrTag;
/// use evm_rpc_client::EvmRpcClient;
///
/// # use evm_rpc_types::{Block, Hex, Hex20, Hex32, Hex256, MultiRpcResult, Nat256};
/// # use std::str::FromStr;
/// # #[tokio::main]
/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
/// let client = EvmRpcClient::builder_for_ic()
/// # .with_default_stub_response(MultiRpcResult::Consistent(Ok(Block {
/// # base_fee_per_gas: None,
/// # number: Nat256::ZERO,
/// # difficulty: Some(Nat256::ZERO),
/// # extra_data: Hex::from(vec![]),
/// # gas_limit: Nat256::ZERO,
/// # gas_used: Nat256::ZERO,
/// # hash: Hex32::from(b256!("0x47302c2ebfb29611c74f917a380f3cf45c9dfe9de3554e18bff9a9ca7c8454e2")),
/// # logs_bloom: Hex256::from([0; 256]),
/// # miner: Hex20::from([0; 20]),
/// # mix_hash: Hex32::from([0; 32]),
/// # nonce: Nat256::ZERO,
/// # parent_hash: Hex32::from([0; 32]),
/// # receipts_root: Hex32::from([0; 32]),
/// # sha3_uncles: Hex32::from([0; 32]),
/// # size: Nat256::ZERO,
/// # state_root: Hex32::from([0; 32]),
/// # timestamp: Nat256::ZERO,
/// # total_difficulty: Some(Nat256::ZERO),
/// # transactions: vec![],
/// # transactions_root: Some(Hex32::from([0; 32])),
/// # uncles: vec![],
/// # })))
/// .build();
///
/// let result = client
/// .get_block_by_number(BlockNumberOrTag::Number(23225439))
/// .send()
/// .await
/// .expect_consistent()
/// .unwrap();
///
/// assert_eq!(result.hash(), b256!("0x47302c2ebfb29611c74f917a380f3cf45c9dfe9de3554e18bff9a9ca7c8454e2"));
/// # Ok(())
/// # }
/// ```
pub fn get_block_by_number(
&self,
params: impl Into<BlockTag>,
) -> GetBlockByNumberRequestBuilder<R> {
RequestBuilder::new(
self.clone(),
GetBlockByNumberRequest::new(params.into()),
10_000_000_000,
)
}

/// Call `eth_getLogs` on the EVM RPC canister.
///
/// # Examples
Expand Down Expand Up @@ -353,7 +416,6 @@ impl<R> EvmRpcClient<R> {
///
/// let result = client
/// .get_logs(vec![address!("0xdac17f958d2ee523a2206206994597c13d831ec7")])
/// .with_cycles(10_000_000_000)
/// .send()
/// .await
/// .expect_consistent();
Expand Down
35 changes: 35 additions & 0 deletions evm_rpc_client/src/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,38 @@ use serde::de::DeserializeOwned;
use std::fmt::{Debug, Formatter};
use strum::EnumIter;

#[derive(Debug, Clone)]
pub struct GetBlockByNumberRequest(BlockTag);

impl GetBlockByNumberRequest {
pub fn new(params: BlockTag) -> Self {
Self(params)
}
}

impl EvmRpcRequest for GetBlockByNumberRequest {
type Config = RpcConfig;
type Params = BlockTag;
type CandidOutput = MultiRpcResult<evm_rpc_types::Block>;
type Output = MultiRpcResult<alloy_rpc_types::Block>;

fn endpoint(&self) -> EvmRpcEndpoint {
EvmRpcEndpoint::GetBlockByNumber
}

fn params(self) -> Self::Params {
self.0
}
}

pub type GetBlockByNumberRequestBuilder<R> = RequestBuilder<
R,
RpcConfig,
BlockTag,
MultiRpcResult<evm_rpc_types::Block>,
MultiRpcResult<alloy_rpc_types::Block>,
>;

#[derive(Debug, Clone)]
pub struct GetLogsRequest(GetLogsArgs);

Expand Down Expand Up @@ -92,6 +124,8 @@ pub trait EvmRpcRequest {
/// Endpoint on the EVM RPC canister triggering a call to EVM providers.
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, EnumIter)]
pub enum EvmRpcEndpoint {
/// `eth_getBlockByNumber` endpoint.
GetBlockByNumber,
/// `eth_getLogs` endpoint.
GetLogs,
}
Expand All @@ -100,6 +134,7 @@ impl EvmRpcEndpoint {
/// Method name on the EVM RPC canister
pub fn rpc_method(&self) -> &'static str {
match &self {
Self::GetBlockByNumber => "eth_getBlockByNumber",
Self::GetLogs => "eth_getLogs",
}
}
Expand Down
8 changes: 6 additions & 2 deletions evm_rpc_types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ repository = "https://github.com/dfinity/evm-rpc-canister"
documentation = "https://docs.rs/evm_rpc_types"

[dependencies]
alloy-consensus = { workspace = true, optional = true }
alloy-primitives = { workspace = true, optional = true }
alloy-rpc-types = { workspace = true, optional = true }
candid = { workspace = true }
Expand All @@ -29,5 +30,8 @@ proptest = { workspace = true }
serde_json = { workspace = true }

[features]
default = ["alloy"]
alloy = ["dep:alloy-primitives", "dep:alloy-rpc-types"]
alloy = [
"dep:alloy-consensus",
"dep:alloy-primitives",
"dep:alloy-rpc-types"
]
41 changes: 40 additions & 1 deletion evm_rpc_types/src/alloy.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{Hex, Hex20, Hex32};
use crate::{Hex, Hex20, Hex256, Hex32, Nat256, RpcError};
use alloy_primitives::ruint::{ToUintError, UintTryFrom};

impl From<Hex20> for alloy_primitives::Address {
fn from(value: Hex20) -> Self {
Expand Down Expand Up @@ -35,3 +36,41 @@ impl From<alloy_primitives::Bytes> for Hex {
Hex(value.to_vec())
}
}

impl From<alloy_primitives::U256> for Nat256 {
fn from(value: alloy_primitives::U256) -> Self {
Nat256::from_be_bytes(value.to_be_bytes())
}
}

impl UintTryFrom<Nat256> for alloy_primitives::U256 {
fn uint_try_from(value: Nat256) -> Result<Self, ToUintError<Self>> {
Ok(alloy_primitives::U256::from_be_bytes(value.into_be_bytes()))
}
}

impl From<Hex256> for alloy_primitives::Bloom {
fn from(value: Hex256) -> Self {
alloy_primitives::Bloom::from(value.0)
}
}

impl From<alloy_primitives::Bloom> for Hex256 {
fn from(value: alloy_primitives::Bloom) -> Self {
Hex256::from(value.into_array())
}
}

impl TryFrom<Nat256> for alloy_primitives::B64 {
type Error = RpcError;

fn try_from(value: Nat256) -> Result<Self, Self::Error> {
Ok(alloy_primitives::B64::from(u64::try_from(value)?))
}
}

impl From<alloy_primitives::B64> for Nat256 {
fn from(value: alloy_primitives::B64) -> Self {
Nat256::from(u64::from(value))
}
}
Loading