Skip to content

Commit

Permalink
fix(7702): add max_fill, random_fill, and use for gas estimation
Browse files Browse the repository at this point in the history
  • Loading branch information
andysim3d committed Feb 4, 2025
1 parent 2c64f9f commit 4bc5f50
Show file tree
Hide file tree
Showing 13 changed files with 131 additions and 19 deletions.
6 changes: 6 additions & 0 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ alloy-sol-types = "0.8.15"
# alloy
alloy-consensus = "0.7.3"
alloy-contract = "0.7.3"
alloy-eips = "0.7.3"
alloy-eips = { version = "0.7.3", features = ["k256","serde", "std", ] }
alloy-json-rpc = "0.7.3"
alloy-provider = { version = "0.7.3", default-features = false, features = ["reqwest", "reqwest-rustls-tls"] }
alloy-rpc-client = "0.7.3"
alloy-rpc-types-eth = "0.7.3"
alloy-rpc-types-trace = "0.7.3"
alloy-signer = "0.7.3"
alloy-signer-aws = "0.7.3"
alloy-signer-local = "0.7.3"
alloy-signer-local = { version = "0.7.3" }
alloy-transport = "0.7.3"
alloy-transport-http = { version = "0.7.3", default-features = false, features = ["reqwest", "reqwest-rustls-tls"] }
alloy-network = { version = "0.7.3" }
Expand Down
1 change: 1 addition & 0 deletions bin/rundler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ rundler-types.workspace = true
rundler-utils.workspace = true

alloy-primitives.workspace = true
alloy-signer-local.workspace = true

anyhow.workspace = true
aws-config.workspace = true
Expand Down
3 changes: 3 additions & 0 deletions crates/pool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ url.workspace = true
mockall = { workspace = true, optional = true }

[dev-dependencies]
alloy-eips.workspace = true
alloy-signer.workspace = true
alloy-signer-local.workspace = true
mockall.workspace = true
reth-tasks.workspace = true
rundler-provider = { workspace = true, features = ["test-utils"] }
Expand Down
3 changes: 2 additions & 1 deletion crates/pool/src/mempool/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,9 @@ where
}

pub(crate) fn check_eip7702(&self, uo: &UserOperationVariant) -> MempoolResult<()> {
if uo.authorization_tuple().is_some() {
if let Some(auth) = uo.authorization_tuple() {
if self.config.support_7702 {
auth.validate()?;
Ok(())
} else {
Err(MempoolError::EIPNotSupported(
Expand Down
39 changes: 37 additions & 2 deletions crates/pool/src/mempool/uo_pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -942,9 +942,11 @@ struct UoPoolMetrics {

#[cfg(test)]
mod tests {
use std::{collections::HashMap, vec};
use std::{collections::HashMap, str::FromStr, vec};

use alloy_primitives::{uint, Bytes};
use alloy_signer::SignerSync;
use alloy_signer_local::PrivateKeySigner;
use mockall::Sequence;
use rundler_provider::{
DepositInfo, ExecutionResult, MockDAGasOracleSync, MockEntryPointV0_6, MockEvmProvider,
Expand All @@ -969,7 +971,6 @@ mod tests {
chain::{BalanceUpdate, MinedOp},
mempool::{PaymasterConfig, ReputationParams},
};

const THROTTLE_SLACK: u64 = 5;
const BAN_SLACK: u64 = 10;

Expand Down Expand Up @@ -1882,6 +1883,40 @@ mod tests {
assert!(pool
.add_operation(OperationOrigin::Local, op.clone().op)
.await
.is_err());
}
{
config.support_7702 = true;
let private_key = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80";
let signer: PrivateKeySigner = PrivateKeySigner::from_str(private_key).unwrap();
let authorization = alloy_eips::eip7702::Authorization {
chain_id: 11011,
address: Address::from_str("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266").unwrap(),
nonce: 1,
};
let signature = signer
.sign_hash_sync(&authorization.signature_hash())
.unwrap();
let signed_authorization = authorization.into_signed(signature);
let signed_op = create_op_from_op_v0_6(UserOperation {
call_gas_limit: 50_000,
max_fee_per_gas: 0,
max_priority_fee_per_gas: 0,
authorization_tuple: Some(Eip7702Auth {
address: signed_authorization.address,
chain_id: signed_authorization.chain_id,
nonce: signed_authorization.nonce,
y_parity: signed_authorization.y_parity(),
r: signed_authorization.r(),
s: signed_authorization.s(),
}),
..Default::default()
});

let pool = create_pool_with_config(config.clone(), vec![signed_op.clone()]);
assert!(pool
.add_operation(OperationOrigin::Local, signed_op.clone().op)
.await
.is_ok());
}
}
Expand Down
11 changes: 10 additions & 1 deletion crates/pool/src/server/remote/protos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,16 @@ impl From<&v0_7::UserOperation> for UserOperation {
factory_data: op.factory_data.to_proto_bytes(),
entry_point: op.entry_point.to_proto_bytes(),
chain_id: op.chain_id,
authorization_tuple: None,
authorization_tuple: op.authorization_tuple.as_ref().map(|authorization| {
AuthorizationTuple {
chain_id: authorization.chain_id,
address: authorization.address.to_proto_bytes(),
nonce: authorization.nonce,
y_parity: authorization.y_parity.into(),
r: authorization.r.to_proto_bytes(),
s: authorization.s.to_proto_bytes(),
}
}),
};
UserOperation {
uo: Some(user_operation::Uo::V07(op)),
Expand Down
6 changes: 4 additions & 2 deletions crates/provider/src/alloy/entry_point/v0_6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use rundler_contracts::v0_6::{
UserOperation as ContractUserOperation, UserOpsPerAggregator as UserOpsPerAggregatorV0_6,
};
use rundler_types::{
authorization::Eip7702Auth,
chain::ChainSpec,
da::{DAGasBlockData, DAGasUOData},
v0_6::UserOperation,
Expand Down Expand Up @@ -330,8 +331,9 @@ where
.i_entry_point
.handleOps(vec![user_op.into()], Address::random())
.into_transaction_request();
if let Some(authorization) = au {
txn_request = txn_request.with_authorization_list(vec![authorization.into()]);
if au.is_some() {
txn_request =
txn_request.with_authorization_list(vec![Eip7702Auth::random_fill().into()]);
}

let data = txn_request.input.into_input().unwrap();
Expand Down
4 changes: 2 additions & 2 deletions crates/provider/src/alloy/entry_point/v0_7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,8 @@ where
.i_entry_point
.handleOps(vec![user_op.pack()], Address::random())
.into_transaction_request();
if let Some(authorization_tuple) = au {
txn_req = txn_req.with_authorization_list(vec![authorization_tuple.into()]);
if au.is_some() {
txn_req = txn_req.with_authorization_list(vec![Eip7702Auth::random_fill().into()]);
}

let data = txn_req.input.into_input().unwrap();
Expand Down
1 change: 1 addition & 0 deletions crates/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ http.workspace = true
jsonrpsee = { workspace = true, features = ["client", "macros", "server"] }
metrics.workspace = true
metrics-derive.workspace = true
rand.workspace = true
serde.workspace = true
strum.workspace = true
thiserror.workspace = true
Expand Down
48 changes: 48 additions & 0 deletions crates/types/src/authorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use alloy_eips::eip7702::SignedAuthorization;
use alloy_primitives::{Address, U256};
use rand::{self, RngCore};
use serde::{Deserialize, Serialize};

/// authorization tuple for 7702 txn support
Expand Down Expand Up @@ -45,3 +46,50 @@ impl From<Eip7702Auth> for alloy_eips::eip7702::SignedAuthorization {
SignedAuthorization::new_unchecked(authorization, value.y_parity, value.r, value.s)
}
}

pub(crate) fn random_bytes_array<const ARR_SIZE: usize, const FILL_SIZE: usize>() -> [u8; ARR_SIZE]
{
let mut bytes = [0_u8; ARR_SIZE];
rand::thread_rng().fill_bytes(&mut bytes[..FILL_SIZE]);
bytes
}

impl Eip7702Auth {
/// Genreate a random filled Eip7702Auth entity.
pub fn random_fill() -> Eip7702Auth {
Self {
chain_id: u64::from_le_bytes(random_bytes_array::<8, 4>()),
address: Address::random(),
nonce: u64::from_le_bytes(random_bytes_array::<8, 4>()),
y_parity: 27,
r: U256::from_le_bytes(random_bytes_array::<64, 32>()),
s: U256::from_le_bytes(random_bytes_array::<64, 32>()),
}
}
/// Generate a maxfilled Eip7702Auth entity.
pub fn max_fill() -> Eip7702Auth {
Self {
chain_id: u64::MAX,
address: Address::repeat_byte(0xf),
nonce: u64::MAX,
y_parity: 27,
r: U256::MAX,
s: U256::MAX,
}
}

/// validate a Eip7702Auth's signature.
pub fn validate(&self) -> anyhow::Result<()> {
let signed_auth = SignedAuthorization::from(self.clone());
match signed_auth.recover_authority() {
Ok(address) => {
if address == self.address {
Ok(())
} else {
Err(anyhow::anyhow!("Invalid Signature"))
}
}
Err(e) => Err(anyhow::anyhow!(e.to_string())),
}
}
}
12 changes: 10 additions & 2 deletions crates/types/src/user_operation/v0_6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,11 @@ impl UserOperationOptionalGas {
max_fee_per_gas: max_8,
},
ExtendedUserOperation {
authorization_tuple: None,
authorization_tuple: if self.eip7702_auth_address.is_some() {
Some(Eip7702Auth::max_fill())
} else {
None
},
},
);

Expand Down Expand Up @@ -461,7 +465,11 @@ impl UserOperationOptionalGas {
max_priority_fee_per_gas: u128::from_le_bytes(random_bytes_array::<16, 8>()), // 2^64 max
},
ExtendedUserOperation {
authorization_tuple: None,
authorization_tuple: if self.eip7702_auth_address.is_some() {
Some(Eip7702Auth::random_fill())
} else {
None
},
},
);

Expand Down
12 changes: 5 additions & 7 deletions crates/types/src/user_operation/v0_7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,13 +373,8 @@ impl UserOperationOptionalGas {
vec![255_u8; self.paymaster_data.len()].into(),
);
}
if let Some(eip_7702_auth_address) = self.eip7702_auth_address {
builder = builder.authorization_tuple(Some(Eip7702Auth {
address: eip_7702_auth_address,
chain_id: chain_spec.id,
// fake value for gas estimation.
..Default::default()
}));
if self.eip7702_auth_address.is_some() {
builder = builder.authorization_tuple(Some(Eip7702Auth::max_fill()));
}
if self.factory.is_some() {
builder = builder.factory(
Expand Down Expand Up @@ -427,6 +422,9 @@ impl UserOperationOptionalGas {
if self.factory.is_some() {
builder = builder.factory(self.factory.unwrap(), random_bytes(self.factory_data.len()))
}
if self.eip7702_auth_address.is_some() {
builder = builder.authorization_tuple(Some(Eip7702Auth::random_fill()));
}

builder.build()
}
Expand Down

0 comments on commit 4bc5f50

Please sign in to comment.