From e51c086b61434bc90650ee50b4434b6b95389342 Mon Sep 17 00:00:00 2001 From: Rayyan Alam Date: Fri, 19 Dec 2025 15:37:38 -0500 Subject: [PATCH 1/4] chore: update read me and mempool --- crates/account-abstraction-core-v2/Cargo.toml | 30 -- crates/account-abstraction-core/Cargo.toml | 8 +- .../README.md | 0 .../core/src/account_abstraction_service.rs | 195 -------- .../core/src/entrypoints/mod.rs | 3 - .../core/src/entrypoints/v06.rs | 139 ------ .../core/src/entrypoints/v07.rs | 180 ------- .../core/src/entrypoints/version.rs | 31 -- .../core/src/kafka_mempool_engine.rs | 275 ---------- .../account-abstraction-core/core/src/lib.rs | 7 - .../core/src/mempool.rs | 472 ------------------ .../core/src/types.rs | 230 --------- .../src/domain/entrypoints/mod.rs | 0 .../src/domain/entrypoints/v06.rs | 0 .../src/domain/entrypoints/v07.rs | 0 .../src/domain/entrypoints/version.rs | 0 .../src/domain/events.rs | 0 .../src/domain/mempool.rs | 0 .../src/domain/mod.rs | 0 .../src/domain/reputation.rs | 0 .../src/domain/types.rs | 0 .../src/factories/kafka_engine.rs | 0 .../src/factories/mod.rs | 0 .../src/infrastructure/base_node/mod.rs | 0 .../src/infrastructure/base_node/validator.rs | 0 .../src/infrastructure/in_memory/mempool.rs | 0 .../src/infrastructure/in_memory/mod.rs | 0 .../src/infrastructure/kafka/consumer.rs | 0 .../src/infrastructure/kafka/mod.rs | 0 .../src/infrastructure/mod.rs | 0 .../src/lib.rs | 0 .../src/services/interfaces/event_source.rs | 0 .../src/services/interfaces/mod.rs | 0 .../services/interfaces/user_op_validator.rs | 0 .../src/services/mempool_engine.rs | 0 .../src/services/mod.rs | 0 .../src/services/reputations_service.rs | 0 37 files changed, 3 insertions(+), 1567 deletions(-) delete mode 100644 crates/account-abstraction-core-v2/Cargo.toml rename crates/{account-abstraction-core-v2 => account-abstraction-core}/README.md (100%) delete mode 100644 crates/account-abstraction-core/core/src/account_abstraction_service.rs delete mode 100644 crates/account-abstraction-core/core/src/entrypoints/mod.rs delete mode 100644 crates/account-abstraction-core/core/src/entrypoints/v06.rs delete mode 100644 crates/account-abstraction-core/core/src/entrypoints/v07.rs delete mode 100644 crates/account-abstraction-core/core/src/entrypoints/version.rs delete mode 100644 crates/account-abstraction-core/core/src/kafka_mempool_engine.rs delete mode 100644 crates/account-abstraction-core/core/src/lib.rs delete mode 100644 crates/account-abstraction-core/core/src/mempool.rs delete mode 100644 crates/account-abstraction-core/core/src/types.rs rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/domain/entrypoints/mod.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/domain/entrypoints/v06.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/domain/entrypoints/v07.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/domain/entrypoints/version.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/domain/events.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/domain/mempool.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/domain/mod.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/domain/reputation.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/domain/types.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/factories/kafka_engine.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/factories/mod.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/infrastructure/base_node/mod.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/infrastructure/base_node/validator.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/infrastructure/in_memory/mempool.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/infrastructure/in_memory/mod.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/infrastructure/kafka/consumer.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/infrastructure/kafka/mod.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/infrastructure/mod.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/lib.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/services/interfaces/event_source.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/services/interfaces/mod.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/services/interfaces/user_op_validator.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/services/mempool_engine.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/services/mod.rs (100%) rename crates/{account-abstraction-core-v2 => account-abstraction-core}/src/services/reputations_service.rs (100%) diff --git a/crates/account-abstraction-core-v2/Cargo.toml b/crates/account-abstraction-core-v2/Cargo.toml deleted file mode 100644 index a0560ce..0000000 --- a/crates/account-abstraction-core-v2/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "account-abstraction-core-v2" -version.workspace = true -rust-version.workspace = true -license.workspace = true -homepage.workspace = true -repository.workspace = true -edition.workspace = true - -[dependencies] -alloy-serde = { version = "1.0.41", default-features = false } -serde.workspace = true -alloy-rpc-types.workspace = true -alloy-provider.workspace = true -op-alloy-network.workspace = true -alloy-primitives = { workspace = true } -reth-rpc-eth-types.workspace = true -tokio.workspace = true -jsonrpsee.workspace = true -async-trait = { workspace = true } -alloy-sol-types.workspace = true -anyhow.workspace = true -rdkafka.workspace = true -serde_json.workspace = true -tips-core.workspace = true -tracing.workspace = true - -[dev-dependencies] -alloy-primitives.workspace = true -wiremock.workspace = true diff --git a/crates/account-abstraction-core/Cargo.toml b/crates/account-abstraction-core/Cargo.toml index 39b1591..a0560ce 100644 --- a/crates/account-abstraction-core/Cargo.toml +++ b/crates/account-abstraction-core/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "account-abstraction-core" +name = "account-abstraction-core-v2" version.workspace = true rust-version.workspace = true license.workspace = true @@ -7,8 +7,6 @@ homepage.workspace = true repository.workspace = true edition.workspace = true -[lib] -path = "core/src/lib.rs" [dependencies] alloy-serde = { version = "1.0.41", default-features = false } serde.workspace = true @@ -20,12 +18,12 @@ reth-rpc-eth-types.workspace = true tokio.workspace = true jsonrpsee.workspace = true async-trait = { workspace = true } -alloy-sol-types.workspace= true +alloy-sol-types.workspace = true anyhow.workspace = true rdkafka.workspace = true serde_json.workspace = true tips-core.workspace = true -tracing.workspace=true +tracing.workspace = true [dev-dependencies] alloy-primitives.workspace = true diff --git a/crates/account-abstraction-core-v2/README.md b/crates/account-abstraction-core/README.md similarity index 100% rename from crates/account-abstraction-core-v2/README.md rename to crates/account-abstraction-core/README.md diff --git a/crates/account-abstraction-core/core/src/account_abstraction_service.rs b/crates/account-abstraction-core/core/src/account_abstraction_service.rs deleted file mode 100644 index d6c65a0..0000000 --- a/crates/account-abstraction-core/core/src/account_abstraction_service.rs +++ /dev/null @@ -1,195 +0,0 @@ -use crate::types::{ValidationResult, VersionedUserOperation}; -use alloy_primitives::Address; -use alloy_provider::{Provider, RootProvider}; -use async_trait::async_trait; -use jsonrpsee::core::RpcResult; -use op_alloy_network::Optimism; -use reth_rpc_eth_types::EthApiError; -use std::sync::Arc; -use tokio::time::{Duration, timeout}; -#[async_trait] -pub trait AccountAbstractionService: Send + Sync { - async fn validate_user_operation( - &self, - user_operation: &VersionedUserOperation, - entry_point: &Address, - ) -> RpcResult; -} - -#[derive(Debug, Clone)] -pub struct AccountAbstractionServiceImpl { - simulation_provider: Arc>, - validate_user_operation_timeout: u64, -} - -#[async_trait] -impl AccountAbstractionService for AccountAbstractionServiceImpl { - async fn validate_user_operation( - &self, - user_operation: &VersionedUserOperation, - entry_point: &Address, - ) -> RpcResult { - // Steps: Reputation Service Validate - // Steps: Base Node Validate User Operation - self.base_node_validate_user_operation(user_operation, entry_point) - .await - } -} - -impl AccountAbstractionServiceImpl { - pub fn new( - simulation_provider: Arc>, - validate_user_operation_timeout: u64, - ) -> Self { - Self { - simulation_provider, - validate_user_operation_timeout, - } - } - - pub async fn base_node_validate_user_operation( - &self, - user_operation: &VersionedUserOperation, - entry_point: &Address, - ) -> RpcResult { - let result = timeout( - Duration::from_secs(self.validate_user_operation_timeout), - self.simulation_provider - .client() - .request("base_validateUserOperation", (user_operation, entry_point)), - ) - .await; - - let validation_result: ValidationResult = match result { - Err(_) => { - return Err( - EthApiError::InvalidParams("Timeout on requesting validation".into()) - .into_rpc_err(), - ); - } - Ok(Err(e)) => { - return Err(EthApiError::InvalidParams(e.to_string()).into_rpc_err()); // likewise, map RPC error to your error type - } - Ok(Ok(v)) => v, - }; - - Ok(validation_result) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use alloy_primitives::{Address, Bytes, U256}; - use alloy_rpc_types::erc4337::UserOperation; - use tokio::time::Duration; - use wiremock::{Mock, MockServer, ResponseTemplate, matchers::method}; - - const VALIDATION_TIMEOUT_SECS: u64 = 1; - const LONG_DELAY_SECS: u64 = 3; - - async fn setup_mock_server() -> MockServer { - MockServer::start().await - } - - fn new_test_user_operation_v06() -> VersionedUserOperation { - VersionedUserOperation::UserOperation(UserOperation { - sender: Address::ZERO, - nonce: U256::from(0), - init_code: Bytes::default(), - call_data: Bytes::default(), - call_gas_limit: U256::from(21_000), - verification_gas_limit: U256::from(100_000), - pre_verification_gas: U256::from(21_000), - max_fee_per_gas: U256::from(1_000_000_000), - max_priority_fee_per_gas: U256::from(1_000_000_000), - paymaster_and_data: Bytes::default(), - signature: Bytes::default(), - }) - } - - fn new_service(mock_server: &MockServer) -> AccountAbstractionServiceImpl { - let provider: RootProvider = - RootProvider::new_http(mock_server.uri().parse().unwrap()); - let simulation_provider = Arc::new(provider); - AccountAbstractionServiceImpl::new(simulation_provider, VALIDATION_TIMEOUT_SECS) - } - - #[tokio::test] - async fn base_node_validate_user_operation_times_out() { - let mock_server = setup_mock_server().await; - - Mock::given(method("POST")) - .respond_with( - ResponseTemplate::new(200).set_delay(Duration::from_secs(LONG_DELAY_SECS)), - ) - .mount(&mock_server) - .await; - - let service = new_service(&mock_server); - let user_operation = new_test_user_operation_v06(); - - let result = service - .base_node_validate_user_operation(&user_operation, &Address::ZERO) - .await; - - assert!(result.is_err()); - assert!(result.unwrap_err().to_string().contains("Timeout")); - } - - #[tokio::test] - async fn should_propagate_error_from_base_node() { - let mock_server = setup_mock_server().await; - - Mock::given(method("POST")) - .respond_with(ResponseTemplate::new(500).set_body_json(serde_json::json!({ - "jsonrpc": "2.0", - "id": 1, - "error": { - "code": -32000, - "message": "Internal error" - } - }))) - .mount(&mock_server) - .await; - - let service = new_service(&mock_server); - let user_operation = new_test_user_operation_v06(); - - let result = service - .base_node_validate_user_operation(&user_operation, &Address::ZERO) - .await; - assert!(result.is_err()); - assert!(result.unwrap_err().to_string().contains("Internal error")); - } - #[tokio::test] - async fn base_node_validate_user_operation_succeeds() { - let mock_server = setup_mock_server().await; - - Mock::given(method("POST")) - .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ - "jsonrpc": "2.0", - "id": 1, - "result": { - "valid": true, - "reason": null, - "valid_until": null, - "valid_after": null, - "context": null - } - }))) - .mount(&mock_server) - .await; - - let service = new_service(&mock_server); - let user_operation = new_test_user_operation_v06(); - - let result = service - .base_node_validate_user_operation(&user_operation, &Address::ZERO) - .await - .unwrap(); - - assert_eq!(result.valid, true); - } -} diff --git a/crates/account-abstraction-core/core/src/entrypoints/mod.rs b/crates/account-abstraction-core/core/src/entrypoints/mod.rs deleted file mode 100644 index 4946ba2..0000000 --- a/crates/account-abstraction-core/core/src/entrypoints/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod v06; -pub mod v07; -pub mod version; diff --git a/crates/account-abstraction-core/core/src/entrypoints/v06.rs b/crates/account-abstraction-core/core/src/entrypoints/v06.rs deleted file mode 100644 index 4883305..0000000 --- a/crates/account-abstraction-core/core/src/entrypoints/v06.rs +++ /dev/null @@ -1,139 +0,0 @@ -/* - * ERC-4337 v0.6 UserOperation Hash Calculation - * - * 1. Hash variable-length fields: initCode, callData, paymasterAndData - * 2. Pack all fields into struct (using hashes from step 1, gas values as uint256) - * 3. encodedHash = keccak256(abi.encode(packed struct)) - * 4. final hash = keccak256(abi.encode(encodedHash, entryPoint, chainId)) - * - * Reference: rundler/crates/types/src/user_operation/v0_6.rs:927-934 - */ -use alloy_primitives::{ChainId, U256}; -use alloy_rpc_types::erc4337; -use alloy_sol_types::{SolValue, sol}; -sol! { - #[allow(missing_docs)] - #[derive(Default, Debug, PartialEq, Eq)] - struct UserOperationHashEncoded { - bytes32 encodedHash; - address entryPoint; - uint256 chainId; - } - - #[allow(missing_docs)] - #[derive(Default, Debug, PartialEq, Eq)] - struct UserOperationPackedForHash { - address sender; - uint256 nonce; - bytes32 hashInitCode; - bytes32 hashCallData; - uint256 callGasLimit; - uint256 verificationGasLimit; - uint256 preVerificationGas; - uint256 maxFeePerGas; - uint256 maxPriorityFeePerGas; - bytes32 hashPaymasterAndData; - } -} - -impl From for UserOperationPackedForHash { - fn from(op: erc4337::UserOperation) -> UserOperationPackedForHash { - UserOperationPackedForHash { - sender: op.sender, - nonce: op.nonce, - hashInitCode: alloy_primitives::keccak256(op.init_code), - hashCallData: alloy_primitives::keccak256(op.call_data), - callGasLimit: U256::from(op.call_gas_limit), - verificationGasLimit: U256::from(op.verification_gas_limit), - preVerificationGas: U256::from(op.pre_verification_gas), - maxFeePerGas: U256::from(op.max_fee_per_gas), - maxPriorityFeePerGas: U256::from(op.max_priority_fee_per_gas), - hashPaymasterAndData: alloy_primitives::keccak256(op.paymaster_and_data), - } - } -} - -pub fn hash_user_operation( - user_operation: &erc4337::UserOperation, - entry_point: alloy_primitives::Address, - chain_id: ChainId, -) -> alloy_primitives::B256 { - let packed = UserOperationPackedForHash::from(user_operation.clone()); - let encoded = UserOperationHashEncoded { - encodedHash: alloy_primitives::keccak256(packed.abi_encode()), - entryPoint: entry_point, - chainId: U256::from(chain_id), - }; - alloy_primitives::keccak256(encoded.abi_encode()) -} - -#[cfg(test)] -mod tests { - use super::*; - use alloy_primitives::{Bytes, U256, address, b256, bytes}; - use alloy_rpc_types::erc4337; - - #[test] - fn test_hash_zeroed() { - let entry_point_address_v0_6 = address!("66a15edcc3b50a663e72f1457ffd49b9ae284ddc"); - let chain_id = 1337; - let user_op_with_zeroed_init_code = erc4337::UserOperation { - sender: address!("0x0000000000000000000000000000000000000000"), - nonce: U256::ZERO, - init_code: Bytes::default(), - call_data: Bytes::default(), - call_gas_limit: U256::from(0), - verification_gas_limit: U256::from(0), - pre_verification_gas: U256::from(0), - max_fee_per_gas: U256::from(0), - max_priority_fee_per_gas: U256::from(0), - paymaster_and_data: Bytes::default(), - signature: Bytes::default(), - }; - - let hash = hash_user_operation( - &user_op_with_zeroed_init_code, - entry_point_address_v0_6, - chain_id, - ); - assert_eq!( - hash, - b256!("dca97c3b49558ab360659f6ead939773be8bf26631e61bb17045bb70dc983b2d") - ); - } - - #[test] - fn test_hash_non_zeroed() { - let entry_point_address_v0_6 = address!("66a15edcc3b50a663e72f1457ffd49b9ae284ddc"); - let chain_id = 1337; - let user_op_with_non_zeroed_init_code = erc4337::UserOperation { - sender: address!("0x1306b01bc3e4ad202612d3843387e94737673f53"), - nonce: U256::from(8942), - init_code: "0x6942069420694206942069420694206942069420" - .parse() - .unwrap(), - call_data: "0x0000000000000000000000000000000000000000080085" - .parse() - .unwrap(), - call_gas_limit: U256::from(10_000), - verification_gas_limit: U256::from(100_000), - pre_verification_gas: U256::from(100), - max_fee_per_gas: U256::from(99_999), - max_priority_fee_per_gas: U256::from(9_999_999), - paymaster_and_data: bytes!( - "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" - ), - signature: bytes!("da0929f527cded8d0a1eaf2e8861d7f7e2d8160b7b13942f99dd367df4473a"), - }; - - let hash = hash_user_operation( - &user_op_with_non_zeroed_init_code, - entry_point_address_v0_6, - chain_id, - ); - assert_eq!( - hash, - b256!("484add9e4d8c3172d11b5feb6a3cc712280e176d278027cfa02ee396eb28afa1") - ); - } -} diff --git a/crates/account-abstraction-core/core/src/entrypoints/v07.rs b/crates/account-abstraction-core/core/src/entrypoints/v07.rs deleted file mode 100644 index 60d8fd4..0000000 --- a/crates/account-abstraction-core/core/src/entrypoints/v07.rs +++ /dev/null @@ -1,180 +0,0 @@ -/* - * ERC-4337 v0.7 UserOperation Hash Calculation - * - * 1. Hash variable-length fields: initCode, callData, paymasterAndData - * 2. Pack all fields into struct (using hashes from step 1, gas values as bytes32) - * 3. encodedHash = keccak256(abi.encode(packed struct)) - * 4. final hash = keccak256(abi.encode(encodedHash, entryPoint, chainId)) - * - * Reference: rundler/crates/types/src/user_operation/v0_7.rs:1094-1123 - */ -use alloy_primitives::{Address, ChainId, FixedBytes, U256}; -use alloy_primitives::{Bytes, keccak256}; -use alloy_rpc_types::erc4337; -use alloy_sol_types::{SolValue, sol}; - -sol!( - #[allow(missing_docs)] - #[derive(Default, Debug, PartialEq, Eq)] - struct PackedUserOperation { - address sender; - uint256 nonce; - bytes initCode; - bytes callData; - bytes32 accountGasLimits; - uint256 preVerificationGas; - bytes32 gasFees; - bytes paymasterAndData; - bytes signature; - } - - #[derive(Default, Debug, PartialEq, Eq)] - struct UserOperationHashEncoded { - bytes32 encodedHash; - address entryPoint; - uint256 chainId; - } - - #[derive(Default, Debug, PartialEq, Eq)] - struct UserOperationPackedForHash { - address sender; - uint256 nonce; - bytes32 hashInitCode; - bytes32 hashCallData; - bytes32 accountGasLimits; - uint256 preVerificationGas; - bytes32 gasFees; - bytes32 hashPaymasterAndData; - } -); - -impl From for PackedUserOperation { - fn from(uo: erc4337::PackedUserOperation) -> Self { - let init_code = if let Some(factory) = uo.factory { - let mut init_code = factory.to_vec(); - init_code.extend_from_slice(&uo.factory_data.clone().unwrap_or_default()); - Bytes::from(init_code) - } else { - Bytes::new() - }; - let account_gas_limits = - pack_u256_pair_to_bytes32(uo.verification_gas_limit, uo.call_gas_limit); - let gas_fees = pack_u256_pair_to_bytes32(uo.max_priority_fee_per_gas, uo.max_fee_per_gas); - let pvgl: [u8; 16] = uo - .paymaster_verification_gas_limit - .unwrap_or_default() - .to::() - .to_be_bytes(); - let pogl: [u8; 16] = uo - .paymaster_post_op_gas_limit - .unwrap_or_default() - .to::() - .to_be_bytes(); - let paymaster_and_data = if let Some(paymaster) = uo.paymaster { - let mut paymaster_and_data = paymaster.to_vec(); - paymaster_and_data.extend_from_slice(&pvgl); - paymaster_and_data.extend_from_slice(&pogl); - paymaster_and_data.extend_from_slice(&uo.paymaster_data.unwrap()); - Bytes::from(paymaster_and_data) - } else { - Bytes::new() - }; - PackedUserOperation { - sender: uo.sender, - nonce: uo.nonce, - initCode: init_code, - callData: uo.call_data.clone(), - accountGasLimits: account_gas_limits, - preVerificationGas: U256::from(uo.pre_verification_gas), - gasFees: gas_fees, - paymasterAndData: paymaster_and_data, - signature: uo.signature.clone(), - } - } -} -fn pack_u256_pair_to_bytes32(high: U256, low: U256) -> FixedBytes<32> { - let mask = (U256::from(1u64) << 128) - U256::from(1u64); - let hi = high & mask; - let lo = low & mask; - let combined: U256 = (hi << 128) | lo; - FixedBytes::from(combined.to_be_bytes::<32>()) -} - -fn hash_packed_user_operation( - puo: &PackedUserOperation, - entry_point: Address, - chain_id: u64, -) -> FixedBytes<32> { - let hash_init_code = alloy_primitives::keccak256(&puo.initCode); - let hash_call_data = alloy_primitives::keccak256(&puo.callData); - let hash_paymaster_and_data = alloy_primitives::keccak256(&puo.paymasterAndData); - - let packed_for_hash = UserOperationPackedForHash { - sender: puo.sender, - nonce: puo.nonce, - hashInitCode: hash_init_code, - hashCallData: hash_call_data, - accountGasLimits: puo.accountGasLimits, - preVerificationGas: puo.preVerificationGas, - gasFees: puo.gasFees, - hashPaymasterAndData: hash_paymaster_and_data, - }; - - let hashed = alloy_primitives::keccak256(packed_for_hash.abi_encode()); - - let encoded = UserOperationHashEncoded { - encodedHash: hashed, - entryPoint: entry_point, - chainId: U256::from(chain_id), - }; - - keccak256(encoded.abi_encode()) -} - -pub fn hash_user_operation( - user_operation: &erc4337::PackedUserOperation, - entry_point: Address, - chain_id: ChainId, -) -> FixedBytes<32> { - let packed = PackedUserOperation::from(user_operation.clone()); - hash_packed_user_operation(&packed, entry_point, chain_id) -} - -#[cfg(test)] -mod test { - use super::*; - use alloy_primitives::{Bytes, U256}; - use alloy_primitives::{address, b256, bytes, uint}; - - #[test] - fn test_hash() { - let puo = PackedUserOperation { - sender: address!("b292Cf4a8E1fF21Ac27C4f94071Cd02C022C414b"), - nonce: uint!(0xF83D07238A7C8814A48535035602123AD6DBFA63000000000000000000000001_U256), - initCode: Bytes::default(), // Empty - callData: - bytes!("e9ae5c53000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000 - 0000000000000000000000000000000000001d8b292cf4a8e1ff21ac27c4f94071cd02c022c414b00000000000000000000000000000000000000000000000000000000000000009517e29f000000000000000000 - 0000000000000000000000000000000000000000000002000000000000000000000000ad6330089d9a1fe89f4020292e1afe9969a5a2fc00000000000000000000000000000000000000000000000000000000000 - 0006000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000 - 00000000000000000000000000000000000000000000000000000000000000000000000000000000018e2fbe898000000000000000000000000000000000000000000000000000000000000000800000000000000 - 0000000000000000000000000000000000000000000000000800000000000000000000000002372912728f93ab3daaaebea4f87e6e28476d987000000000000000000000000000000000000000000000000002386 - f26fc10000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000"), - accountGasLimits: b256!("000000000000000000000000000114fc0000000000000000000000000012c9b5"), - preVerificationGas: U256::from(48916), - gasFees: b256!("000000000000000000000000524121000000000000000000000000109a4a441a"), - paymasterAndData: Bytes::default(), // Empty - signature: bytes!("3c7bfe22c9c2ef8994a9637bcc4df1741c5dc0c25b209545a7aeb20f7770f351479b683bd17c4d55bc32e2a649c8d2dff49dcfcc1f3fd837bcd88d1e69a434cf1c"), - }; - - let expected_hash = - b256!("e486401370d145766c3cf7ba089553214a1230d38662ae532c9b62eb6dadcf7e"); - let uo = hash_packed_user_operation( - &puo, - address!("0x0000000071727De22E5E9d8BAf0edAc6f37da032"), - 11155111, - ); - - assert_eq!(uo, expected_hash); - } -} diff --git a/crates/account-abstraction-core/core/src/entrypoints/version.rs b/crates/account-abstraction-core/core/src/entrypoints/version.rs deleted file mode 100644 index ae37e5d..0000000 --- a/crates/account-abstraction-core/core/src/entrypoints/version.rs +++ /dev/null @@ -1,31 +0,0 @@ -use alloy_primitives::{Address, address}; - -#[derive(Debug, Clone)] -pub enum EntryPointVersion { - V06, - V07, -} - -impl EntryPointVersion { - pub const V06_ADDRESS: Address = address!("0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789"); - pub const V07_ADDRESS: Address = address!("0x0000000071727De22E5E9d8BAf0edAc6f37da032"); -} - -#[derive(Debug)] -pub struct UnknownEntryPointAddress { - pub address: Address, -} - -impl TryFrom
for EntryPointVersion { - type Error = UnknownEntryPointAddress; - - fn try_from(addr: Address) -> Result { - if addr == Self::V06_ADDRESS { - Ok(EntryPointVersion::V06) - } else if addr == Self::V07_ADDRESS { - Ok(EntryPointVersion::V07) - } else { - Err(UnknownEntryPointAddress { address: addr }) - } - } -} diff --git a/crates/account-abstraction-core/core/src/kafka_mempool_engine.rs b/crates/account-abstraction-core/core/src/kafka_mempool_engine.rs deleted file mode 100644 index c843a08..0000000 --- a/crates/account-abstraction-core/core/src/kafka_mempool_engine.rs +++ /dev/null @@ -1,275 +0,0 @@ -use crate::mempool::PoolConfig; -use crate::mempool::{self, Mempool}; -use crate::types::WrappedUserOperation; -use async_trait::async_trait; -use rdkafka::{ - ClientConfig, Message, - consumer::{Consumer, StreamConsumer}, - message::OwnedMessage, -}; -use serde::{Deserialize, Serialize}; -use serde_json; -use std::sync::Arc; -use tips_core::kafka::load_kafka_config_from_file; -use tokio::sync::RwLock; -use tracing::{info, warn}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "event", content = "data")] -pub enum KafkaEvent { - UserOpAdded { - user_op: WrappedUserOperation, - }, - UserOpIncluded { - user_op: WrappedUserOperation, - }, - UserOpDropped { - user_op: WrappedUserOperation, - reason: String, - }, -} - -#[async_trait] -pub trait KafkaConsumer: Send + Sync { - async fn recv_msg(&self) -> anyhow::Result; -} - -#[async_trait] -impl KafkaConsumer for StreamConsumer { - async fn recv_msg(&self) -> anyhow::Result { - Ok(self.recv().await?.detach()) - } -} - -pub struct KafkaMempoolEngine { - mempool: Arc>, - kafka_consumer: Arc, -} - -impl KafkaMempoolEngine { - pub fn new( - mempool: Arc>, - kafka_consumer: Arc, - ) -> Self { - Self { - mempool, - kafka_consumer, - } - } - - pub fn with_kafka_consumer( - kafka_consumer: Arc, - pool_config: Option, - ) -> Self { - let pool_config = pool_config.unwrap_or_default(); - let mempool = Arc::new(RwLock::new(mempool::MempoolImpl::new(pool_config))); - Self { - mempool, - kafka_consumer, - } - } - - pub fn get_mempool(&self) -> Arc> { - self.mempool.clone() - } - - pub async fn run(&self) { - loop { - if let Err(err) = self.process_next().await { - warn!(error = %err, "Kafka mempool engine error, continuing"); - } - } - } - - /// Process a single Kafka message (useful for tests and controlled loops) - pub async fn process_next(&self) -> anyhow::Result<()> { - let msg = self.kafka_consumer.recv_msg().await?; - let payload = msg - .payload() - .ok_or_else(|| anyhow::anyhow!("Kafka message missing payload"))?; - let event: KafkaEvent = serde_json::from_slice(payload) - .map_err(|e| anyhow::anyhow!("Failed to parse Kafka event: {e}"))?; - - self.handle_event(event).await - } - - async fn handle_event(&self, event: KafkaEvent) -> anyhow::Result<()> { - info!( - event = ?event, - "Kafka mempool engine handling event" - ); - match event { - KafkaEvent::UserOpAdded { user_op } => { - self.mempool.write().await.add_operation(&user_op)?; - } - KafkaEvent::UserOpIncluded { user_op } => { - self.mempool.write().await.remove_operation(&user_op.hash)?; - } - KafkaEvent::UserOpDropped { user_op, reason: _ } => { - self.mempool.write().await.remove_operation(&user_op.hash)?; - } - } - Ok(()) - } -} - -fn create_user_operation_consumer( - properties_file: &str, - topic: &str, - consumer_group_id: &str, -) -> anyhow::Result { - let mut client_config = ClientConfig::from_iter(load_kafka_config_from_file(properties_file)?); - - client_config.set("group.id", consumer_group_id); - client_config.set("enable.auto.commit", "true"); - - let consumer: StreamConsumer = client_config.create()?; - consumer.subscribe(&[topic])?; - - Ok(consumer) -} - -pub fn create_mempool_engine( - properties_file: &str, - topic: &str, - consumer_group_id: &str, - pool_config: Option, -) -> anyhow::Result> { - let consumer: StreamConsumer = - create_user_operation_consumer(properties_file, topic, consumer_group_id)?; - Ok(Arc::new(KafkaMempoolEngine::with_kafka_consumer( - Arc::new(consumer), - pool_config, - ))) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::mempool::PoolConfig; - use crate::types::VersionedUserOperation; - use alloy_primitives::{Address, FixedBytes, Uint}; - use alloy_rpc_types::erc4337; - use rdkafka::Timestamp; - use tokio::sync::Mutex; - - fn make_wrapped_op(max_fee: u128, hash: [u8; 32]) -> WrappedUserOperation { - let op = VersionedUserOperation::UserOperation(erc4337::UserOperation { - sender: Address::ZERO, - nonce: Uint::from(0u64), - init_code: Default::default(), - call_data: Default::default(), - call_gas_limit: Uint::from(100_000u64), - verification_gas_limit: Uint::from(100_000u64), - pre_verification_gas: Uint::from(21_000u64), - max_fee_per_gas: Uint::from(max_fee), - max_priority_fee_per_gas: Uint::from(max_fee), - paymaster_and_data: Default::default(), - signature: Default::default(), - }); - - WrappedUserOperation { - operation: op, - hash: FixedBytes::from(hash), - } - } - - #[tokio::test] - async fn handle_add_operation() { - let mempool = Arc::new(RwLock::new( - mempool::MempoolImpl::new(PoolConfig::default()), - )); - - let op_hash = [1u8; 32]; - let wrapped = make_wrapped_op(1_000, op_hash); - - let add_event = KafkaEvent::UserOpAdded { - user_op: wrapped.clone(), - }; - let mock_consumer = Arc::new(MockConsumer::new(vec![OwnedMessage::new( - Some(serde_json::to_vec(&add_event).unwrap()), - None, - "topic".to_string(), - Timestamp::NotAvailable, - 0, - 0, - None, - )])); - - let engine = KafkaMempoolEngine::new(mempool.clone(), mock_consumer); - - // Process add then remove deterministically - engine.process_next().await.unwrap(); - let items: Vec<_> = mempool.read().await.get_top_operations(10).collect(); - assert_eq!(items.len(), 1); - assert_eq!(items[0].hash, FixedBytes::from(op_hash)); - } - - #[tokio::test] - async fn remove_opperation_should_remove_from_mempool() { - let mempool = Arc::new(RwLock::new( - mempool::MempoolImpl::new(PoolConfig::default()), - )); - let op_hash = [1u8; 32]; - let wrapped = make_wrapped_op(1_000, op_hash); - let add_mempool = KafkaEvent::UserOpAdded { - user_op: wrapped.clone(), - }; - let remove_mempool = KafkaEvent::UserOpDropped { - user_op: wrapped.clone(), - reason: "test".to_string(), - }; - let mock_consumer = Arc::new(MockConsumer::new(vec![ - OwnedMessage::new( - Some(serde_json::to_vec(&add_mempool).unwrap()), - None, - "topic".to_string(), - Timestamp::NotAvailable, - 0, - 0, - None, - ), - OwnedMessage::new( - Some(serde_json::to_vec(&remove_mempool).unwrap()), - None, - "topic".to_string(), - Timestamp::NotAvailable, - 0, - 0, - None, - ), - ])); - - let engine = KafkaMempoolEngine::new(mempool.clone(), mock_consumer); - engine.process_next().await.unwrap(); - let items: Vec<_> = mempool.read().await.get_top_operations(10).collect(); - assert_eq!(items.len(), 1); - assert_eq!(items[0].hash, FixedBytes::from(op_hash)); - engine.process_next().await.unwrap(); - let items: Vec<_> = mempool.read().await.get_top_operations(10).collect(); - assert_eq!(items.len(), 0); - } - struct MockConsumer { - msgs: Mutex>, - } - - impl MockConsumer { - fn new(msgs: Vec) -> Self { - Self { - msgs: Mutex::new(msgs), - } - } - } - - #[async_trait] - impl KafkaConsumer for MockConsumer { - async fn recv_msg(&self) -> anyhow::Result { - let mut guard = self.msgs.lock().await; - if guard.is_empty() { - Err(anyhow::anyhow!("no more messages")) - } else { - Ok(guard.remove(0)) - } - } - } -} diff --git a/crates/account-abstraction-core/core/src/lib.rs b/crates/account-abstraction-core/core/src/lib.rs deleted file mode 100644 index e6f0ffb..0000000 --- a/crates/account-abstraction-core/core/src/lib.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod account_abstraction_service; -pub mod entrypoints; -pub mod types; -pub use account_abstraction_service::{AccountAbstractionService, AccountAbstractionServiceImpl}; -pub use types::{SendUserOperationResponse, VersionedUserOperation}; -pub mod kafka_mempool_engine; -pub mod mempool; diff --git a/crates/account-abstraction-core/core/src/mempool.rs b/crates/account-abstraction-core/core/src/mempool.rs deleted file mode 100644 index d5eccc7..0000000 --- a/crates/account-abstraction-core/core/src/mempool.rs +++ /dev/null @@ -1,472 +0,0 @@ -use crate::types::{UserOpHash, WrappedUserOperation}; -use alloy_primitives::Address; -use std::cmp::Ordering; -use std::collections::{BTreeSet, HashMap}; -use std::sync::Arc; -use std::sync::atomic::{AtomicU64, Ordering as AtomicOrdering}; - -#[derive(Default)] -pub struct PoolConfig { - minimum_max_fee_per_gas: u128, -} - -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct OrderedPoolOperation { - pub pool_operation: WrappedUserOperation, - pub submission_id: u64, -} - -impl OrderedPoolOperation { - pub fn from_wrapped(operation: &WrappedUserOperation, submission_id: u64) -> Self { - Self { - pool_operation: operation.clone(), - submission_id, - } - } - - pub fn sender(&self) -> Address { - self.pool_operation.operation.sender() - } -} - -/// Ordering by max priority fee (desc) then submission id, then hash to ensure total order -#[derive(Clone, Debug)] -pub struct ByMaxFeeAndSubmissionId(pub OrderedPoolOperation); - -impl PartialEq for ByMaxFeeAndSubmissionId { - fn eq(&self, other: &Self) -> bool { - self.0.pool_operation.hash == other.0.pool_operation.hash - } -} -impl Eq for ByMaxFeeAndSubmissionId {} - -impl PartialOrd for ByMaxFeeAndSubmissionId { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for ByMaxFeeAndSubmissionId { - fn cmp(&self, other: &Self) -> Ordering { - other - .0 - .pool_operation - .operation - .max_priority_fee_per_gas() - .cmp(&self.0.pool_operation.operation.max_priority_fee_per_gas()) - .then_with(|| self.0.submission_id.cmp(&other.0.submission_id)) - .then_with(|| self.0.pool_operation.hash.cmp(&other.0.pool_operation.hash)) - } -} - -/// Ordering by nonce (asc), then submission id, then hash to ensure total order -#[derive(Clone, Debug)] -pub struct ByNonce(pub OrderedPoolOperation); - -impl PartialEq for ByNonce { - fn eq(&self, other: &Self) -> bool { - self.0.pool_operation.hash == other.0.pool_operation.hash - } -} -impl Eq for ByNonce {} - -impl PartialOrd for ByNonce { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for ByNonce { - /// TODO: There can be invalid opperations, where base fee, + expected gas price - /// is greater that the maximum gas, in that case we don't include it in the mempool as such mempool changes. - fn cmp(&self, other: &Self) -> Ordering { - self.0 - .pool_operation - .operation - .nonce() - .cmp(&other.0.pool_operation.operation.nonce()) - .then_with(|| self.0.submission_id.cmp(&other.0.submission_id)) - } -} - -pub trait Mempool { - fn add_operation( - &mut self, - operation: &WrappedUserOperation, - ) -> Result, anyhow::Error>; - fn get_top_operations(&self, n: usize) -> impl Iterator>; - fn remove_operation( - &mut self, - operation_hash: &UserOpHash, - ) -> Result, anyhow::Error>; -} - -pub struct MempoolImpl { - config: PoolConfig, - best: BTreeSet, - hash_to_operation: HashMap, - operations_by_account: HashMap>, - submission_id_counter: AtomicU64, -} - -impl Mempool for MempoolImpl { - fn add_operation( - &mut self, - operation: &WrappedUserOperation, - ) -> Result, anyhow::Error> { - if operation.operation.max_fee_per_gas() < self.config.minimum_max_fee_per_gas { - return Err(anyhow::anyhow!( - "Gas price is below the minimum required PVG gas" - )); - } - let ordered_operation_result = self.handle_add_operation(operation)?; - Ok(ordered_operation_result) - } - - fn get_top_operations(&self, n: usize) -> impl Iterator> { - // TODO: There is a case where we skip operations that are not the lowest nonce for an account. - // But we still have not given the N number of operations, meaning we don't return those operations. - - self.best - .iter() - .filter_map(|op_by_fee| { - let lowest = self - .operations_by_account - .get(&op_by_fee.0.sender()) - .and_then(|set| set.first()); - - match lowest { - Some(lowest) - if lowest.0.pool_operation.hash == op_by_fee.0.pool_operation.hash => - { - Some(Arc::new(op_by_fee.0.pool_operation.clone())) - } - Some(_) => None, - None => { - println!( - "No operations found for account: {} but one was found in the best set", - op_by_fee.0.sender() - ); - None - } - } - }) - .take(n) - } - - fn remove_operation( - &mut self, - operation_hash: &UserOpHash, - ) -> Result, anyhow::Error> { - if let Some(ordered_operation) = self.hash_to_operation.remove(operation_hash) { - self.best - .remove(&ByMaxFeeAndSubmissionId(ordered_operation.clone())); - self.operations_by_account - .get_mut(&ordered_operation.sender()) - .map(|set| set.remove(&ByNonce(ordered_operation.clone()))); - Ok(Some(ordered_operation.pool_operation)) - } else { - Ok(None) - } - } -} - -// When user opperation is added to the mempool we need to check - -impl MempoolImpl { - fn handle_add_operation( - &mut self, - operation: &WrappedUserOperation, - ) -> Result, anyhow::Error> { - // Account - if self.hash_to_operation.contains_key(&operation.hash) { - return Ok(None); - } - - let order = self.get_next_order_id(); - let ordered_operation = OrderedPoolOperation::from_wrapped(operation, order); - - self.best - .insert(ByMaxFeeAndSubmissionId(ordered_operation.clone())); - self.operations_by_account - .entry(ordered_operation.sender()) - .or_default() - .insert(ByNonce(ordered_operation.clone())); - self.hash_to_operation - .insert(operation.hash, ordered_operation.clone()); - Ok(Some(ordered_operation)) - } - - fn get_next_order_id(&self) -> u64 { - self.submission_id_counter - .fetch_add(1, AtomicOrdering::SeqCst) - } - - pub fn new(config: PoolConfig) -> Self { - Self { - config, - best: BTreeSet::new(), - hash_to_operation: HashMap::new(), - operations_by_account: HashMap::new(), - submission_id_counter: AtomicU64::new(0), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::types::VersionedUserOperation; - use alloy_primitives::{Address, FixedBytes, Uint}; - use alloy_rpc_types::erc4337; - fn create_test_user_operation(max_priority_fee_per_gas: u128) -> VersionedUserOperation { - VersionedUserOperation::UserOperation(erc4337::UserOperation { - sender: Address::random(), - nonce: Uint::from(0), - init_code: Default::default(), - call_data: Default::default(), - call_gas_limit: Uint::from(100000), - verification_gas_limit: Uint::from(100000), - pre_verification_gas: Uint::from(21000), - max_fee_per_gas: Uint::from(max_priority_fee_per_gas), - max_priority_fee_per_gas: Uint::from(max_priority_fee_per_gas), - paymaster_and_data: Default::default(), - signature: Default::default(), - }) - } - - fn create_wrapped_operation( - max_priority_fee_per_gas: u128, - hash: UserOpHash, - ) -> WrappedUserOperation { - WrappedUserOperation { - operation: create_test_user_operation(max_priority_fee_per_gas), - hash, - } - } - - fn create_test_mempool(minimum_required_pvg_gas: u128) -> MempoolImpl { - MempoolImpl::new(PoolConfig { - minimum_max_fee_per_gas: minimum_required_pvg_gas, - }) - } - - // Tests successfully adding a valid operation to the mempool - #[test] - fn test_add_operation_success() { - let mut mempool = create_test_mempool(1000); - let hash = FixedBytes::from([1u8; 32]); - let operation = create_wrapped_operation(2000, hash); - - let result = mempool.add_operation(&operation); - - assert!(result.is_ok()); - let ordered_op = result.unwrap(); - assert!(ordered_op.is_some()); - let ordered_op = ordered_op.unwrap(); - assert_eq!(ordered_op.pool_operation.hash, hash); - assert_eq!( - ordered_op.pool_operation.operation.max_fee_per_gas(), - Uint::from(2000) - ); - } - - // Tests adding an operation with a gas price below the minimum required PVG gas - #[test] - fn test_add_operation_below_minimum_gas() { - let mut mempool = create_test_mempool(2000); - let hash = FixedBytes::from([1u8; 32]); - let operation = create_wrapped_operation(1000, hash); - - let result = mempool.add_operation(&operation); - - assert!(result.is_err()); - assert!( - result - .unwrap_err() - .to_string() - .contains("Gas price is below the minimum required PVG gas") - ); - } - - // Tests adding multiple operations with different hashes - #[test] - fn test_add_multiple_operations() { - let mut mempool = create_test_mempool(1000); - - let hash1 = FixedBytes::from([1u8; 32]); - let operation1 = create_wrapped_operation(2000, hash1); - let result1 = mempool.add_operation(&operation1); - assert!(result1.is_ok()); - assert!(result1.unwrap().is_some()); - - let hash2 = FixedBytes::from([2u8; 32]); - let operation2 = create_wrapped_operation(3000, hash2); - let result2 = mempool.add_operation(&operation2); - assert!(result2.is_ok()); - assert!(result2.unwrap().is_some()); - - let hash3 = FixedBytes::from([3u8; 32]); - let operation3 = create_wrapped_operation(1500, hash3); - let result3 = mempool.add_operation(&operation3); - assert!(result3.is_ok()); - assert!(result3.unwrap().is_some()); - - assert_eq!(mempool.hash_to_operation.len(), 3); - assert_eq!(mempool.best.len(), 3); - } - - // Tests removing an operation that is not in the mempool - #[test] - fn test_remove_operation_not_in_mempool() { - let mut mempool = create_test_mempool(1000); - let hash = FixedBytes::from([1u8; 32]); - - let result = mempool.remove_operation(&hash); - assert!(result.is_ok()); - assert!(result.unwrap().is_none()); - } - - // Tests removing an operation that exists in the mempool - #[test] - fn test_remove_operation_exists() { - let mut mempool = create_test_mempool(1000); - let hash = FixedBytes::from([1u8; 32]); - let operation = create_wrapped_operation(2000, hash); - - mempool.add_operation(&operation).unwrap(); - - let result = mempool.remove_operation(&hash); - assert!(result.is_ok()); - let removed = result.unwrap(); - assert!(removed.is_some()); - let removed_op = removed.unwrap(); - assert_eq!(removed_op.hash, hash); - assert_eq!(removed_op.operation.max_fee_per_gas(), Uint::from(2000)); - } - - // Tests removing an operation and checking the best operations - #[test] - fn test_remove_operation_and_check_best() { - let mut mempool = create_test_mempool(1000); - let hash = FixedBytes::from([1u8; 32]); - let operation = create_wrapped_operation(2000, hash); - - mempool.add_operation(&operation).unwrap(); - - let best_before: Vec<_> = mempool.get_top_operations(10).collect(); - assert_eq!(best_before.len(), 1); - assert_eq!(best_before[0].hash, hash); - - let result = mempool.remove_operation(&hash); - assert!(result.is_ok()); - assert!(result.unwrap().is_some()); - - let best_after: Vec<_> = mempool.get_top_operations(10).collect(); - assert_eq!(best_after.len(), 0); - } - - // Tests getting the top operations with ordering - #[test] - fn test_get_top_operations_ordering() { - let mut mempool = create_test_mempool(1000); - - let hash1 = FixedBytes::from([1u8; 32]); - let operation1 = create_wrapped_operation(2000, hash1); - mempool.add_operation(&operation1).unwrap(); - - let hash2 = FixedBytes::from([2u8; 32]); - let operation2 = create_wrapped_operation(3000, hash2); - mempool.add_operation(&operation2).unwrap(); - - let hash3 = FixedBytes::from([3u8; 32]); - let operation3 = create_wrapped_operation(1500, hash3); - mempool.add_operation(&operation3).unwrap(); - - let best: Vec<_> = mempool.get_top_operations(10).collect(); - assert_eq!(best.len(), 3); - assert_eq!(best[0].operation.max_fee_per_gas(), Uint::from(3000)); - assert_eq!(best[1].operation.max_fee_per_gas(), Uint::from(2000)); - assert_eq!(best[2].operation.max_fee_per_gas(), Uint::from(1500)); - } - - // Tests getting the top operations with a limit - #[test] - fn test_get_top_operations_limit() { - let mut mempool = create_test_mempool(1000); - - let hash1 = FixedBytes::from([1u8; 32]); - let operation1 = create_wrapped_operation(2000, hash1); - mempool.add_operation(&operation1).unwrap(); - - let hash2 = FixedBytes::from([2u8; 32]); - let operation2 = create_wrapped_operation(3000, hash2); - mempool.add_operation(&operation2).unwrap(); - - let hash3 = FixedBytes::from([3u8; 32]); - let operation3 = create_wrapped_operation(1500, hash3); - mempool.add_operation(&operation3).unwrap(); - - let best: Vec<_> = mempool.get_top_operations(2).collect(); - assert_eq!(best.len(), 2); - assert_eq!(best[0].operation.max_fee_per_gas(), Uint::from(3000)); - assert_eq!(best[1].operation.max_fee_per_gas(), Uint::from(2000)); - } - - // Tests top opperations tie breaker with submission id - #[test] - fn test_get_top_operations_submission_id_tie_breaker() { - let mut mempool = create_test_mempool(1000); - - let hash1 = FixedBytes::from([1u8; 32]); - let operation1 = create_wrapped_operation(2000, hash1); - mempool.add_operation(&operation1).unwrap().unwrap(); - - let hash2 = FixedBytes::from([2u8; 32]); - let operation2 = create_wrapped_operation(2000, hash2); - mempool.add_operation(&operation2).unwrap().unwrap(); - - let best: Vec<_> = mempool.get_top_operations(2).collect(); - assert_eq!(best.len(), 2); - assert_eq!(best[0].hash, hash1); - assert_eq!(best[1].hash, hash2); - } - - #[test] - fn test_get_top_operations_should_return_the_lowest_nonce_operation_for_each_account() { - let mut mempool = create_test_mempool(1000); - let hash1 = FixedBytes::from([1u8; 32]); - let test_user_operation = create_test_user_operation(2000); - - // Destructure to the inner struct, then update nonce - let base_op = match test_user_operation.clone() { - VersionedUserOperation::UserOperation(op) => op, - _ => panic!("expected UserOperation variant"), - }; - - let operation1 = WrappedUserOperation { - operation: VersionedUserOperation::UserOperation(erc4337::UserOperation { - nonce: Uint::from(0), - max_fee_per_gas: Uint::from(2000), - ..base_op.clone() - }), - hash: hash1, - }; - - mempool.add_operation(&operation1).unwrap().unwrap(); - let hash2 = FixedBytes::from([2u8; 32]); - let operation2 = WrappedUserOperation { - operation: VersionedUserOperation::UserOperation(erc4337::UserOperation { - nonce: Uint::from(1), - max_fee_per_gas: Uint::from(10_000), - ..base_op.clone() - }), - hash: hash2, - }; - mempool.add_operation(&operation2).unwrap().unwrap(); - - let best: Vec<_> = mempool.get_top_operations(2).collect(); - assert_eq!(best.len(), 1); - assert_eq!(best[0].operation.nonce(), Uint::from(0)); - } -} diff --git a/crates/account-abstraction-core/core/src/types.rs b/crates/account-abstraction-core/core/src/types.rs deleted file mode 100644 index 3d79564..0000000 --- a/crates/account-abstraction-core/core/src/types.rs +++ /dev/null @@ -1,230 +0,0 @@ -use crate::entrypoints::{v06, v07, version::EntryPointVersion}; -use alloy_primitives::{Address, B256, ChainId, FixedBytes, U256}; -use alloy_rpc_types::erc4337; -pub use alloy_rpc_types::erc4337::SendUserOperationResponse; -use anyhow::Result; -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -#[serde(untagged)] -pub enum VersionedUserOperation { - UserOperation(erc4337::UserOperation), - PackedUserOperation(erc4337::PackedUserOperation), -} - -impl VersionedUserOperation { - pub fn max_fee_per_gas(&self) -> U256 { - match self { - VersionedUserOperation::UserOperation(op) => op.max_fee_per_gas, - VersionedUserOperation::PackedUserOperation(op) => op.max_fee_per_gas, - } - } - - pub fn max_priority_fee_per_gas(&self) -> U256 { - match self { - VersionedUserOperation::UserOperation(op) => op.max_priority_fee_per_gas, - VersionedUserOperation::PackedUserOperation(op) => op.max_priority_fee_per_gas, - } - } - pub fn nonce(&self) -> U256 { - match self { - VersionedUserOperation::UserOperation(op) => op.nonce, - VersionedUserOperation::PackedUserOperation(op) => op.nonce, - } - } - - pub fn sender(&self) -> Address { - match self { - VersionedUserOperation::UserOperation(op) => op.sender, - VersionedUserOperation::PackedUserOperation(op) => op.sender, - } - } -} -#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] -pub struct UserOperationRequest { - pub user_operation: VersionedUserOperation, - pub entry_point: Address, - pub chain_id: ChainId, -} - -impl UserOperationRequest { - pub fn hash(&self) -> Result { - let entry_point_version = EntryPointVersion::try_from(self.entry_point) - .map_err(|_| anyhow::anyhow!("Unknown entry point version: {:#x}", self.entry_point))?; - - match (&self.user_operation, entry_point_version) { - (VersionedUserOperation::UserOperation(op), EntryPointVersion::V06) => Ok( - v06::hash_user_operation(op, self.entry_point, self.chain_id), - ), - (VersionedUserOperation::PackedUserOperation(op), EntryPointVersion::V07) => Ok( - v07::hash_user_operation(op, self.entry_point, self.chain_id), - ), - _ => Err(anyhow::anyhow!( - "Mismatched operation type and entry point version" - )), - } - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct UserOperationRequestValidationResult { - pub expiration_timestamp: u64, - pub gas_used: U256, -} - -/// Validation result for User Operations -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ValidationResult { - /// Whether the UserOp is valid - pub valid: bool, - /// Error message if not valid - #[serde(skip_serializing_if = "Option::is_none")] - pub reason: Option, - /// Timestamp until the UserOp is valid (0 = no expiry) - #[serde(skip_serializing_if = "Option::is_none")] - pub valid_until: Option, - /// Timestamp after which the UserOp is valid (0 = immediately) - #[serde(skip_serializing_if = "Option::is_none")] - pub valid_after: Option, - /// Entity stake/deposit context - #[serde(skip_serializing_if = "Option::is_none")] - pub context: Option, -} - -/// Entity stake/deposit information context -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct ValidationContext { - /// Sender (account) stake info - pub sender_info: EntityStakeInfo, - /// Factory stake info (if present) - #[serde(skip_serializing_if = "Option::is_none")] - pub factory_info: Option, - /// Paymaster stake info (if present) - #[serde(skip_serializing_if = "Option::is_none")] - pub paymaster_info: Option, - /// Aggregator stake info (if present) - #[serde(skip_serializing_if = "Option::is_none")] - pub aggregator_info: Option, -} - -/// Stake info for an entity (used in RPC response) -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct EntityStakeInfo { - /// Entity address - pub address: Address, - /// Amount staked - pub stake: U256, - /// Unstake delay in seconds - pub unstake_delay_sec: u64, - /// Amount deposited for gas - pub deposit: U256, - /// Whether entity meets staking requirements - pub is_staked: bool, -} - -/// Aggregator stake info (used in RPC response) -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct AggregatorInfo { - /// Aggregator address - pub aggregator: Address, - /// Stake info - pub stake_info: EntityStakeInfo, -} - -pub type UserOpHash = FixedBytes<32>; - -#[derive(Eq, PartialEq, Clone, Debug, Serialize, Deserialize)] -pub struct WrappedUserOperation { - pub operation: VersionedUserOperation, - pub hash: UserOpHash, -} - -impl WrappedUserOperation { - pub fn has_higher_max_fee(&self, other: &WrappedUserOperation) -> bool { - self.operation.max_fee_per_gas() > other.operation.max_fee_per_gas() - } -} - -// Tests -#[cfg(test)] -mod tests { - use std::str::FromStr; - - use super::*; - use alloy_primitives::{Address, Uint}; - - #[test] - fn deser_untagged_user_operation_without_type_field() { - // v0.6 shape, no "type" key - let json = r#" - { - "sender": "0x1111111111111111111111111111111111111111", - "nonce": "0x0", - "initCode": "0x", - "callData": "0x", - "callGasLimit": "0x5208", - "verificationGasLimit": "0x100000", - "preVerificationGas": "0x10000", - "maxFeePerGas": "0x59682f10", - "maxPriorityFeePerGas": "0x3b9aca00", - "paymasterAndData": "0x", - "signature": "0x01" - } - "#; - - let parsed: VersionedUserOperation = - serde_json::from_str(json).expect("should deserialize as v0.6"); - match parsed { - VersionedUserOperation::UserOperation(op) => { - assert_eq!( - op.sender, - Address::from_str("0x1111111111111111111111111111111111111111").unwrap() - ); - assert_eq!(op.nonce, Uint::from(0)); - } - other => panic!("expected UserOperation, got {:?}", other), - } - } - - #[test] - fn deser_untagged_packed_user_operation_without_type_field() { - // v0.7 shape, no "type" key - let json = r#" - { - "sender": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", - "nonce": "0x1", - "factory": "0x2222222222222222222222222222222222222222", - "factoryData": "0xabcdef1234560000000000000000000000000000000000000000000000000000", - "callData": "0xb61d27f600000000000000000000000000000000000000000000000000000000000000c8", - "callGasLimit": "0x2dc6c0", - "verificationGasLimit": "0x1e8480", - "preVerificationGas": "0x186a0", - "maxFeePerGas": "0x77359400", - "maxPriorityFeePerGas": "0x3b9aca00", - "paymaster": "0x3333333333333333333333333333333333333333", - "paymasterVerificationGasLimit": "0x186a0", - "paymasterPostOpGasLimit": "0x27100", - "paymasterData": "0xfafb00000000000000000000000000000000000000000000000000000000000064", - "signature": "0xa3c5f1b90014e68abbbdc42e4b77b9accc0b7e1c5d0b5bcde1a47ba8faba00ff55c9a7de12e98b731766e35f6c51ab25c9b58cc0e7c4a33f25e75c51c6ad3c3a" - } - "#; - - let parsed: VersionedUserOperation = - serde_json::from_str(json).expect("should deserialize as v0.7 packed"); - match parsed { - VersionedUserOperation::PackedUserOperation(op) => { - assert_eq!( - op.sender, - Address::from_str("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48").unwrap() - ); - assert_eq!(op.nonce, Uint::from(1)); - } - other => panic!("expected PackedUserOperation, got {:?}", other), - } - } -} diff --git a/crates/account-abstraction-core-v2/src/domain/entrypoints/mod.rs b/crates/account-abstraction-core/src/domain/entrypoints/mod.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/domain/entrypoints/mod.rs rename to crates/account-abstraction-core/src/domain/entrypoints/mod.rs diff --git a/crates/account-abstraction-core-v2/src/domain/entrypoints/v06.rs b/crates/account-abstraction-core/src/domain/entrypoints/v06.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/domain/entrypoints/v06.rs rename to crates/account-abstraction-core/src/domain/entrypoints/v06.rs diff --git a/crates/account-abstraction-core-v2/src/domain/entrypoints/v07.rs b/crates/account-abstraction-core/src/domain/entrypoints/v07.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/domain/entrypoints/v07.rs rename to crates/account-abstraction-core/src/domain/entrypoints/v07.rs diff --git a/crates/account-abstraction-core-v2/src/domain/entrypoints/version.rs b/crates/account-abstraction-core/src/domain/entrypoints/version.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/domain/entrypoints/version.rs rename to crates/account-abstraction-core/src/domain/entrypoints/version.rs diff --git a/crates/account-abstraction-core-v2/src/domain/events.rs b/crates/account-abstraction-core/src/domain/events.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/domain/events.rs rename to crates/account-abstraction-core/src/domain/events.rs diff --git a/crates/account-abstraction-core-v2/src/domain/mempool.rs b/crates/account-abstraction-core/src/domain/mempool.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/domain/mempool.rs rename to crates/account-abstraction-core/src/domain/mempool.rs diff --git a/crates/account-abstraction-core-v2/src/domain/mod.rs b/crates/account-abstraction-core/src/domain/mod.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/domain/mod.rs rename to crates/account-abstraction-core/src/domain/mod.rs diff --git a/crates/account-abstraction-core-v2/src/domain/reputation.rs b/crates/account-abstraction-core/src/domain/reputation.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/domain/reputation.rs rename to crates/account-abstraction-core/src/domain/reputation.rs diff --git a/crates/account-abstraction-core-v2/src/domain/types.rs b/crates/account-abstraction-core/src/domain/types.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/domain/types.rs rename to crates/account-abstraction-core/src/domain/types.rs diff --git a/crates/account-abstraction-core-v2/src/factories/kafka_engine.rs b/crates/account-abstraction-core/src/factories/kafka_engine.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/factories/kafka_engine.rs rename to crates/account-abstraction-core/src/factories/kafka_engine.rs diff --git a/crates/account-abstraction-core-v2/src/factories/mod.rs b/crates/account-abstraction-core/src/factories/mod.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/factories/mod.rs rename to crates/account-abstraction-core/src/factories/mod.rs diff --git a/crates/account-abstraction-core-v2/src/infrastructure/base_node/mod.rs b/crates/account-abstraction-core/src/infrastructure/base_node/mod.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/infrastructure/base_node/mod.rs rename to crates/account-abstraction-core/src/infrastructure/base_node/mod.rs diff --git a/crates/account-abstraction-core-v2/src/infrastructure/base_node/validator.rs b/crates/account-abstraction-core/src/infrastructure/base_node/validator.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/infrastructure/base_node/validator.rs rename to crates/account-abstraction-core/src/infrastructure/base_node/validator.rs diff --git a/crates/account-abstraction-core-v2/src/infrastructure/in_memory/mempool.rs b/crates/account-abstraction-core/src/infrastructure/in_memory/mempool.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/infrastructure/in_memory/mempool.rs rename to crates/account-abstraction-core/src/infrastructure/in_memory/mempool.rs diff --git a/crates/account-abstraction-core-v2/src/infrastructure/in_memory/mod.rs b/crates/account-abstraction-core/src/infrastructure/in_memory/mod.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/infrastructure/in_memory/mod.rs rename to crates/account-abstraction-core/src/infrastructure/in_memory/mod.rs diff --git a/crates/account-abstraction-core-v2/src/infrastructure/kafka/consumer.rs b/crates/account-abstraction-core/src/infrastructure/kafka/consumer.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/infrastructure/kafka/consumer.rs rename to crates/account-abstraction-core/src/infrastructure/kafka/consumer.rs diff --git a/crates/account-abstraction-core-v2/src/infrastructure/kafka/mod.rs b/crates/account-abstraction-core/src/infrastructure/kafka/mod.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/infrastructure/kafka/mod.rs rename to crates/account-abstraction-core/src/infrastructure/kafka/mod.rs diff --git a/crates/account-abstraction-core-v2/src/infrastructure/mod.rs b/crates/account-abstraction-core/src/infrastructure/mod.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/infrastructure/mod.rs rename to crates/account-abstraction-core/src/infrastructure/mod.rs diff --git a/crates/account-abstraction-core-v2/src/lib.rs b/crates/account-abstraction-core/src/lib.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/lib.rs rename to crates/account-abstraction-core/src/lib.rs diff --git a/crates/account-abstraction-core-v2/src/services/interfaces/event_source.rs b/crates/account-abstraction-core/src/services/interfaces/event_source.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/services/interfaces/event_source.rs rename to crates/account-abstraction-core/src/services/interfaces/event_source.rs diff --git a/crates/account-abstraction-core-v2/src/services/interfaces/mod.rs b/crates/account-abstraction-core/src/services/interfaces/mod.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/services/interfaces/mod.rs rename to crates/account-abstraction-core/src/services/interfaces/mod.rs diff --git a/crates/account-abstraction-core-v2/src/services/interfaces/user_op_validator.rs b/crates/account-abstraction-core/src/services/interfaces/user_op_validator.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/services/interfaces/user_op_validator.rs rename to crates/account-abstraction-core/src/services/interfaces/user_op_validator.rs diff --git a/crates/account-abstraction-core-v2/src/services/mempool_engine.rs b/crates/account-abstraction-core/src/services/mempool_engine.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/services/mempool_engine.rs rename to crates/account-abstraction-core/src/services/mempool_engine.rs diff --git a/crates/account-abstraction-core-v2/src/services/mod.rs b/crates/account-abstraction-core/src/services/mod.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/services/mod.rs rename to crates/account-abstraction-core/src/services/mod.rs diff --git a/crates/account-abstraction-core-v2/src/services/reputations_service.rs b/crates/account-abstraction-core/src/services/reputations_service.rs similarity index 100% rename from crates/account-abstraction-core-v2/src/services/reputations_service.rs rename to crates/account-abstraction-core/src/services/reputations_service.rs From b8ae2c65624fc145e4e841db3e1389f42b0391b1 Mon Sep 17 00:00:00 2001 From: Rayyan Alam Date: Fri, 19 Dec 2025 15:38:34 -0500 Subject: [PATCH 2/4] chore: create abstraction core --- crates/account-abstraction-core/README.md | 10 +++++----- crates/ingress-rpc/src/bin/main.rs | 2 +- crates/ingress-rpc/src/queue.rs | 2 +- crates/ingress-rpc/src/service.rs | 24 +++++++++++------------ 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/crates/account-abstraction-core/README.md b/crates/account-abstraction-core/README.md index d391854..f72faa5 100644 --- a/crates/account-abstraction-core/README.md +++ b/crates/account-abstraction-core/README.md @@ -228,10 +228,10 @@ pub fn create_mempool_engine( 3. **Reusability**: Services can be used in multiple binaries ```rust // ingress-rpc binary - use account_abstraction_core_v2::MempoolEngine; + use account_abstraction_core::MempoolEngine; // batch-processor binary - use account_abstraction_core_v2::MempoolEngine; + use account_abstraction_core::MempoolEngine; // Same code, different contexts! ``` @@ -252,7 +252,7 @@ pub fn create_mempool_engine( ### Basic Usage (with Factory) ```rust -use account_abstraction_core_v2::create_mempool_engine; +use account_abstraction_core::create_mempool_engine; let engine = create_mempool_engine( "kafka.properties", @@ -269,7 +269,7 @@ tokio::spawn(async move { ### Custom Setup (without Factory) ```rust -use account_abstraction_core_v2::{ +use account_abstraction_core::{ MempoolEngine, infrastructure::kafka::consumer::KafkaEventSource, }; @@ -282,7 +282,7 @@ let engine = MempoolEngine::with_event_source(event_source, Some(custom_config)) ### Testing ```rust -use account_abstraction_core_v2::{ +use account_abstraction_core::{ MempoolEngine, MempoolEvent, services::interfaces::event_source::EventSource, }; diff --git a/crates/ingress-rpc/src/bin/main.rs b/crates/ingress-rpc/src/bin/main.rs index c886edb..28bcfe3 100644 --- a/crates/ingress-rpc/src/bin/main.rs +++ b/crates/ingress-rpc/src/bin/main.rs @@ -1,4 +1,4 @@ -use account_abstraction_core_v2::create_mempool_engine; +use account_abstraction_core::create_mempool_engine; use alloy_provider::ProviderBuilder; use clap::Parser; use jsonrpsee::server::Server; diff --git a/crates/ingress-rpc/src/queue.rs b/crates/ingress-rpc/src/queue.rs index d360930..cd227a0 100644 --- a/crates/ingress-rpc/src/queue.rs +++ b/crates/ingress-rpc/src/queue.rs @@ -1,4 +1,4 @@ -use account_abstraction_core_v2::{ +use account_abstraction_core::{ MempoolEvent, domain::types::{VersionedUserOperation, WrappedUserOperation}, }; diff --git a/crates/ingress-rpc/src/service.rs b/crates/ingress-rpc/src/service.rs index e03686f..7b2ad79 100644 --- a/crates/ingress-rpc/src/service.rs +++ b/crates/ingress-rpc/src/service.rs @@ -1,8 +1,8 @@ -use account_abstraction_core_v2::domain::ReputationService; -use account_abstraction_core_v2::infrastructure::base_node::validator::BaseNodeValidator; -use account_abstraction_core_v2::services::ReputationServiceImpl; -use account_abstraction_core_v2::services::interfaces::user_op_validator::UserOperationValidator; -use account_abstraction_core_v2::{Mempool, MempoolEngine}; +use account_abstraction_core::domain::ReputationService; +use account_abstraction_core::infrastructure::base_node::validator::BaseNodeValidator; +use account_abstraction_core::services::ReputationServiceImpl; +use account_abstraction_core::services::interfaces::user_op_validator::UserOperationValidator; +use account_abstraction_core::{Mempool, MempoolEngine}; use alloy_consensus::transaction::Recovered; use alloy_consensus::{Transaction, transaction::SignerRecoverable}; use alloy_primitives::{Address, B256, Bytes, FixedBytes}; @@ -28,8 +28,8 @@ use crate::metrics::{Metrics, record_histogram}; use crate::queue::{BundleQueuePublisher, MessageQueue, UserOpQueuePublisher}; use crate::validation::validate_bundle; use crate::{Config, TxSubmissionMethod}; -use account_abstraction_core_v2::domain::entrypoints::version::EntryPointVersion; -use account_abstraction_core_v2::domain::types::{UserOperationRequest, VersionedUserOperation}; +use account_abstraction_core::domain::entrypoints::version::EntryPointVersion; +use account_abstraction_core::domain::types::{UserOperationRequest, VersionedUserOperation}; use std::sync::Arc; /// RPC providers for different endpoints @@ -514,10 +514,10 @@ impl IngressService { mod tests { use super::*; use crate::{Config, TxSubmissionMethod, queue::MessageQueue}; - use account_abstraction_core_v2::MempoolEvent; - use account_abstraction_core_v2::domain::PoolConfig; - use account_abstraction_core_v2::infrastructure::in_memory::mempool::InMemoryMempool; - use account_abstraction_core_v2::services::interfaces::event_source::EventSource; + use account_abstraction_core::MempoolEvent; + use account_abstraction_core::domain::PoolConfig; + use account_abstraction_core::infrastructure::in_memory::mempool::InMemoryMempool; + use account_abstraction_core::services::interfaces::event_source::EventSource; use alloy_provider::RootProvider; use anyhow::Result; use async_trait::async_trait; @@ -811,7 +811,7 @@ mod tests { let user_op = sample_user_operation_v06(); let entry_point = - account_abstraction_core_v2::domain::entrypoints::version::EntryPointVersion::V06_ADDRESS; + account_abstraction_core::domain::entrypoints::version::EntryPointVersion::V06_ADDRESS; let result: Result, _> = client .request("eth_sendUserOperation", (user_op, entry_point)) From dc4b915dfaffb9de0cb09ef9d5c8f4401e3cf5b1 Mon Sep 17 00:00:00 2001 From: Rayyan Alam Date: Fri, 19 Dec 2025 15:42:01 -0500 Subject: [PATCH 3/4] chore: update cargo --- Cargo.lock | 25 +--------------------- Cargo.toml | 3 +-- crates/account-abstraction-core/Cargo.toml | 2 +- crates/account-abstraction-core/README.md | 2 +- crates/ingress-rpc/Cargo.toml | 2 +- 5 files changed, 5 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d33b32c..158faae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,29 +25,6 @@ dependencies = [ "wiremock", ] -[[package]] -name = "account-abstraction-core-v2" -version = "0.1.0" -dependencies = [ - "alloy-primitives", - "alloy-provider", - "alloy-rpc-types", - "alloy-serde", - "alloy-sol-types", - "anyhow", - "async-trait", - "jsonrpsee", - "op-alloy-network", - "rdkafka", - "reth-rpc-eth-types", - "serde", - "serde_json", - "tips-core", - "tokio", - "tracing", - "wiremock", -] - [[package]] name = "adler2" version = "2.0.1" @@ -7298,7 +7275,7 @@ dependencies = [ name = "tips-ingress-rpc" version = "0.1.0" dependencies = [ - "account-abstraction-core-v2", + "account-abstraction-core", "alloy-consensus", "alloy-primitives", "alloy-provider", diff --git a/Cargo.toml b/Cargo.toml index 80a6631..f05aed7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,14 +7,13 @@ homepage = "https://github.com/base/tips" repository = "https://github.com/base/tips" [workspace] -members = ["crates/audit", "crates/ingress-rpc", "crates/core", "crates/account-abstraction-core", "crates/account-abstraction-core-v2"] +members = ["crates/audit", "crates/ingress-rpc", "crates/core", "crates/account-abstraction-core"] resolver = "2" [workspace.dependencies] tips-audit = { path = "crates/audit" } tips-core = { path = "crates/core" } account-abstraction-core = { path = "crates/account-abstraction-core" } -account-abstraction-core-v2 = { path = "crates/account-abstraction-core-v2" } # Reth reth = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3" } diff --git a/crates/account-abstraction-core/Cargo.toml b/crates/account-abstraction-core/Cargo.toml index a0560ce..132e374 100644 --- a/crates/account-abstraction-core/Cargo.toml +++ b/crates/account-abstraction-core/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "account-abstraction-core-v2" +name = "account-abstraction-core" version.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/account-abstraction-core/README.md b/crates/account-abstraction-core/README.md index f72faa5..0abcaba 100644 --- a/crates/account-abstraction-core/README.md +++ b/crates/account-abstraction-core/README.md @@ -1,4 +1,4 @@ -# account-abstraction-core-v2 +# account-abstraction-core Clean architecture implementation for ERC-4337 account abstraction mempool and validation. diff --git a/crates/ingress-rpc/Cargo.toml b/crates/ingress-rpc/Cargo.toml index d0957e0..813754b 100644 --- a/crates/ingress-rpc/Cargo.toml +++ b/crates/ingress-rpc/Cargo.toml @@ -14,7 +14,7 @@ path = "src/bin/main.rs" [dependencies] tips-core.workspace = true tips-audit.workspace = true -account-abstraction-core-v2.workspace = true +account-abstraction-core.workspace = true jsonrpsee.workspace = true alloy-primitives.workspace = true op-alloy-network.workspace = true From bfc3d9deaf51c9943b489b682dbf426d6f09eabf Mon Sep 17 00:00:00 2001 From: Rayyan Alam Date: Fri, 19 Dec 2025 15:46:13 -0500 Subject: [PATCH 4/4] chore: update lock --- Cargo.lock | 123 ----------------------------------------------------- 1 file changed, 123 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c20aed0..7d6bca7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2578,15 +2578,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - [[package]] name = "enr" version = "0.13.0" @@ -3332,11 +3323,9 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2 0.6.1", - "system-configuration", "tokio", "tower-service", "tracing", - "windows-registry", ] [[package]] @@ -5122,9 +5111,7 @@ checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f" dependencies = [ "base64 0.22.1", "bytes", - "encoding_rs", "futures-core", - "h2 0.4.12", "http 1.4.0", "http-body 1.0.1", "http-body-util", @@ -5134,7 +5121,6 @@ dependencies = [ "hyper-util", "js-sys", "log", - "mime", "native-tls", "percent-encoding", "pin-project-lite", @@ -6417,15 +6403,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "scc" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc" -dependencies = [ - "sdd", -] - [[package]] name = "schannel" version = "0.1.28" @@ -6486,12 +6463,6 @@ dependencies = [ "untrusted", ] -[[package]] -name = "sdd" -version = "3.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca" - [[package]] name = "sec1" version = "0.3.0" @@ -6741,31 +6712,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serial_test" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" -dependencies = [ - "futures", - "log", - "once_cell", - "parking_lot", - "scc", - "serial_test_derive", -] - -[[package]] -name = "serial_test_derive" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - [[package]] name = "sha1" version = "0.10.6" @@ -7075,27 +7021,6 @@ dependencies = [ "syn 2.0.111", ] -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tap" version = "1.0.1" @@ -7367,43 +7292,6 @@ dependencies = [ "wiremock", ] -[[package]] -name = "tips-system-tests" -version = "0.1.0" -dependencies = [ - "alloy-consensus", - "alloy-network", - "alloy-primitives", - "alloy-provider", - "alloy-signer-local", - "anyhow", - "async-trait", - "aws-config", - "aws-credential-types", - "aws-sdk-s3", - "bytes", - "hex", - "jsonrpsee", - "op-alloy-consensus", - "op-alloy-network", - "op-revm", - "rdkafka", - "reqwest", - "serde", - "serde_json", - "serial_test", - "testcontainers", - "testcontainers-modules", - "tips-audit", - "tips-core", - "tips-ingress-rpc", - "tokio", - "tracing", - "tracing-subscriber 0.3.22", - "url", - "uuid", -] - [[package]] name = "tokio" version = "1.48.0" @@ -8024,17 +7912,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" -dependencies = [ - "windows-link", - "windows-result", - "windows-strings", -] - [[package]] name = "windows-result" version = "0.4.1"