Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add erc4337 endpoint methods to provider #1176

Merged
merged 21 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
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
1 change: 1 addition & 0 deletions crates/provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ anvil-node = [
"dep:alloy-signer-local",
]
debug-api = ["dep:alloy-rpc-types-trace"]
erc4337-api = []
engine-api = ["dep:alloy-rpc-types-engine"]
net-api = []
trace-api = ["dep:alloy-rpc-types-trace"]
Expand Down
76 changes: 76 additions & 0 deletions crates/provider/src/ext/erc4337.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use crate::Provider;
use alloy_network::Network;
use alloy_primitives::Address;
use alloy_rpc_types_eth::erc4337::{SendUserOperationResponse, UserOperation};
use alloy_transport::{Transport, TransportResult};

/// ERC-4337 Account Abstraction API
///
/// This module provides support for the `eth_sendUserOperation` RPC method
/// as defined in ERC-4337.
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
pub trait Erc4337Api<N, T>: Send + Sync {
/// Sends a [`UserOperation`] to the bundler.
async fn eth_send_user_operation(
royvardhan marked this conversation as resolved.
Show resolved Hide resolved
&self,
user_op: UserOperation,
entry_point: Address,
) -> TransportResult<SendUserOperationResponse>;
}

#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
impl<N, T, P> Erc4337Api<N, T> for P
where
N: Network,
T: Transport + Clone,
P: Provider<T, N>,
{
async fn eth_send_user_operation(
&self,
user_op: UserOperation,
entry_point: Address,
) -> TransportResult<SendUserOperationResponse> {
self.client().request("eth_sendUserOperation", (user_op, entry_point)).await
}
}

#[cfg(test)]
mod tests {
royvardhan marked this conversation as resolved.
Show resolved Hide resolved
use super::*;
use crate::ProviderBuilder;
use alloy_node_bindings::Geth;
use alloy_primitives::{Address, Bytes, U256};

#[tokio::test]
async fn test_eth_send_user_operation() {
let temp_dir = tempfile::TempDir::with_prefix("geth-test-").unwrap();
let geth = Geth::new().disable_discovery().data_dir(temp_dir.path()).spawn();
let provider = ProviderBuilder::new().on_http(geth.endpoint_url());

let user_op = UserOperation {
sender: Address::random(),
nonce: U256::from(0),
factory: Address::random(),
factory_data: Bytes::default(),
call_data: Bytes::default(),
call_gas_limit: U256::from(1000000),
verification_gas_limit: U256::from(1000000),
pre_verification_gas: U256::from(1000000),
max_fee_per_gas: U256::from(1000000000),
max_priority_fee_per_gas: U256::from(1000000000),
paymaster: Address::random(),
paymaster_verification_gas_limit: U256::from(1000000),
paymaster_post_op_gas_limit: U256::from(1000000),
paymaster_data: Bytes::default(),
signature: Bytes::default(),
};

let entry_point: Address = "0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789".parse().unwrap();
royvardhan marked this conversation as resolved.
Show resolved Hide resolved

let result = provider.eth_send_user_operation(user_op, entry_point).await;

assert!(result.is_ok());
}
}
5 changes: 5 additions & 0 deletions crates/provider/src/ext/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,8 @@ pub use rpc::RpcApi;
mod txpool;
#[cfg(feature = "txpool-api")]
pub use txpool::TxPoolApi;

#[cfg(feature = "erc4337-api")]
mod erc4337;
#[cfg(feature = "erc4337-api")]
pub use erc4337::Erc4337Api;
6 changes: 3 additions & 3 deletions crates/rpc-types-eth/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Eth_simulateV1 Request / Response types ([#1042](https://github.com/alloy-rs/alloy/issues/1042))
- Feat(rpc-type-eth) convert vec TxReq to bundle ([#1091](https://github.com/alloy-rs/alloy/issues/1091))
- Feat(provider) : introduction to eth_sendRawTransactionConditional RPC endpoint type ([#1009](https://github.com/alloy-rs/alloy/issues/1009))
- Feat(provider) : introduction to eth_sendRawTransactionConditional RPC endpoint type ([#1009](https://github.com/alloy-rs/alloy/issues/1009))
- [rpc-types-eth] Serde flatten `BlobTransactionSidecar` in tx req ([#1054](https://github.com/alloy-rs/alloy/issues/1054))
- Add authorization list to rpc transaction and tx receipt types ([#1051](https://github.com/alloy-rs/alloy/issues/1051))

Expand All @@ -40,7 +40,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Refactor

- Add network-primitives ([#1101](https://github.com/alloy-rs/alloy/issues/1101))
- Replace `U64` with `u64` ([#1057](https://github.com/alloy-rs/alloy/issues/1057))
- Replace `U64` with `u64` ([#1057](https://github.com/alloy-rs/alloy/issues/1057))

### Styling

Expand Down Expand Up @@ -112,7 +112,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Miscellaneous Tasks

- Rm unused txtype mod ([#879](https://github.com/alloy-rs/alloy/issues/879))
- [other] Use type aliases where possible to improve clarity ([#859](https://github.com/alloy-rs/alloy/issues/859))
- [other] Use type aliases where possible to improve clarity ([#859](https://github.com/alloy-rs/alloy/issues/859))
- [docs] Crate completeness and fix typos ([#861](https://github.com/alloy-rs/alloy/issues/861))

### Other
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use alloy_primitives::{Address, BlockNumber, B256, U256};
use alloy_primitives::{Address, BlockNumber, Bytes, B256, U256};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

Expand Down Expand Up @@ -39,3 +39,52 @@ pub enum AccountStorage {
/// Explicit storage slots and their expected values.
Slots(HashMap<U256, B256>),
}

/// ERC-4337: User Operation
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserOperation {
/// The account making the operation.
royvardhan marked this conversation as resolved.
Show resolved Hide resolved
pub sender: Address,
/// Prevents message replay attacks and serves as a randomizing element for initial user
/// registration.
pub nonce: U256,
/// Deployer contract address: Required exclusively for deploying new accounts that don't yet
/// exist on the blockchain.
pub factory: Address,
/// Factory data for the account creation process, applicable only when using a deployer
/// contract.
pub factory_data: Bytes,
/// The call data.
pub call_data: Bytes,
/// The gas limit for the call.
pub call_gas_limit: U256,
/// The gas limit for the verification.
pub verification_gas_limit: U256,
/// Prepaid gas fee: Covers the bundler's costs for initial transaction validation and data
/// transmission.
pub pre_verification_gas: U256,
/// The maximum fee per gas.
pub max_fee_per_gas: U256,
/// The maximum priority fee per gas.
pub max_priority_fee_per_gas: U256,
/// Paymaster contract address: Needed if a third party is covering transaction costs; left
/// blank for self-funded accounts.
pub paymaster: Address,
/// The gas limit for the paymaster verification.
pub paymaster_verification_gas_limit: U256,
/// The gas limit for the paymaster post-operation.
pub paymaster_post_op_gas_limit: U256,
/// The paymaster data.
pub paymaster_data: Bytes,
/// The signature of the transaction.
pub signature: Bytes,
}

/// Response to sending a user operation.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SendUserOperationResponse {
/// The hash of the user operation.
pub hash: Bytes,
}
3 changes: 2 additions & 1 deletion crates/rpc-types-eth/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ mod work;
pub use work::Work;

/// This module provides implementations for EIP-4337.
pub mod eip4337;
pub mod erc4337;
pub use erc4337::{SendUserOperationResponse, UserOperation};

pub mod simulate;
Loading