Skip to content

Commit 00832c3

Browse files
authored
Enhance transaction handling and EIP-7702 support (#13)
- Added `call_gas_limit` to `UserOpBuilderConfig` for better gas management. - Introduced `AuthorizationSchema` and `SignedAuthorizationSchema` for EIP-7702 authorization handling. - Updated transaction structures to accommodate new gas limit and authorization features. - Refactored execution options to streamline transaction type data handling. - Improved error handling and logging in transaction processing. These changes aim to enhance the flexibility and efficiency of transaction execution, particularly for EIP-7702 compliant operations.
1 parent 4c480bd commit 00832c3

File tree

11 files changed

+182
-163
lines changed

11 files changed

+182
-163
lines changed

aa-core/src/userop/builder.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub struct UserOpBuilderConfig<'a, C: Chain> {
1818
pub account_address: Address,
1919
pub signer_address: Address,
2020
pub entrypoint_and_factory: EntrypointAndFactoryDetails,
21+
pub call_gas_limit: Option<U256>,
2122
pub call_data: Bytes,
2223
pub init_call_data: Vec<u8>,
2324
pub is_deployed: bool,
@@ -101,7 +102,7 @@ impl<'a, C: Chain> UserOpBuilderV0_6<'a, C> {
101102
nonce: config.nonce,
102103
init_code: initcode,
103104
call_data: config.call_data.clone(),
104-
call_gas_limit: U256::ZERO,
105+
call_gas_limit: config.call_gas_limit.unwrap_or(U256::ZERO),
105106
verification_gas_limit: U256::ZERO,
106107
pre_verification_gas: U256::ZERO,
107108
max_fee_per_gas: U256::ZERO,
@@ -211,7 +212,7 @@ impl<'a, C: Chain> UserOpBuilderV0_7<'a, C> {
211212
factory,
212213
factory_data,
213214
call_data: config.call_data.clone(),
214-
call_gas_limit: U256::ZERO,
215+
call_gas_limit: config.call_gas_limit.unwrap_or(U256::ZERO),
215216
verification_gas_limit: U256::ZERO,
216217
pre_verification_gas: U256::ZERO,
217218
max_fee_per_gas: U256::ZERO,

core/src/defs.rs

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,83 @@
1+
use alloy::primitives::{Address, U256};
12
use schemars::JsonSchema;
23
use serde::{Deserialize, Serialize};
34

45
#[derive(JsonSchema, Serialize, Deserialize, Clone, utoipa::ToSchema)]
56
#[schema(title = "EVM Address")]
6-
/// ### Address
77
/// Used to represent an EVM address. This is a string of length 42 with a `0x` prefix. Non-checksummed addresses are also supported, but will be converted to checksummed.
88
pub struct AddressDef(pub String);
99

1010
#[derive(JsonSchema, Serialize, Deserialize, Clone, utoipa::ToSchema)]
1111
#[schema(title = "Bytes")]
12-
/// # Bytes
1312
/// Used to represent "bytes". This is a 0x prefixed hex string.
1413
pub struct BytesDef(pub String);
1514

1615
#[derive(JsonSchema, Serialize, Deserialize, Clone, utoipa::ToSchema)]
1716
#[schema(title = "U256")]
18-
/// # U256
1917
/// Used to represent a 256-bit unsigned integer. Engine can parse these from any valid encoding of the Ethereum "quantity" format.
2018
pub struct U256Def(pub String);
19+
20+
/// EIP-7702 Authorization structure for OpenAPI schema
21+
/// Represents an unsigned authorization that allows an EOA to delegate to a smart contract
22+
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, utoipa::ToSchema)]
23+
#[serde(rename_all = "camelCase")]
24+
pub struct AuthorizationSchema {
25+
/// The chain ID of the authorization
26+
/// Must match the chain where the transaction will be executed
27+
#[schemars(with = "String")]
28+
#[schema(value_type = String, example = "1")]
29+
pub chain_id: U256,
30+
31+
/// The smart contract address to delegate to
32+
/// This contract will be able to execute logic on behalf of the EOA
33+
#[schemars(with = "AddressDef")]
34+
#[schema(value_type = AddressDef)]
35+
pub address: Address,
36+
37+
/// The nonce for the authorization
38+
/// Must be the current nonce of the authorizing account
39+
#[schema(example = 42)]
40+
pub nonce: u64,
41+
}
42+
43+
/// EIP-7702 Signed Authorization structure for OpenAPI schema
44+
/// Contains an authorization plus the cryptographic signature
45+
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, utoipa::ToSchema)]
46+
#[serde(rename_all = "camelCase")]
47+
#[schema(title = "EIP-7702 Signed Authorization")]
48+
pub struct SignedAuthorizationSchema {
49+
/// The chain ID of the authorization
50+
/// Must match the chain where the transaction will be executed
51+
#[schemars(with = "String")]
52+
#[schema(value_type = U256Def, example = "1")]
53+
pub chain_id: U256,
54+
55+
/// The smart contract address to delegate to
56+
/// This contract will be able to execute logic on behalf of the EOA
57+
#[schemars(with = "AddressDef")]
58+
#[schema(value_type = AddressDef)]
59+
pub address: Address,
60+
61+
/// The nonce for the authorization
62+
/// Must be the current nonce of the authorizing account
63+
#[schema(example = 42)]
64+
pub nonce: u64,
65+
66+
/// Signature parity value (0 or 1)
67+
/// Used for ECDSA signature recovery
68+
#[serde(rename = "yParity", alias = "v")]
69+
#[schema(example = 0)]
70+
pub y_parity: u8,
71+
72+
/// Signature r value
73+
/// First component of the ECDSA signature
74+
#[schemars(with = "String")]
75+
#[schema(value_type = U256Def, example = "0x1234567890abcdef...")]
76+
pub r: U256,
77+
78+
/// Signature s value
79+
/// Second component of the ECDSA signature
80+
#[schemars(with = "String")]
81+
#[schema(value_type = U256Def, example = "0xfedcba0987654321...")]
82+
pub s: U256,
83+
}

core/src/execution_options/eoa.rs

Lines changed: 1 addition & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use crate::defs::AddressDef;
2-
use alloy::eips::eip7702::SignedAuthorization;
3-
use alloy::primitives::{Address, U256};
2+
use alloy::primitives::Address;
43
use schemars::JsonSchema;
54
use serde::{Deserialize, Serialize};
65

@@ -33,13 +32,6 @@ pub struct EoaExecutionOptions {
3332
#[schemars(with = "AddressDef")]
3433
#[schema(value_type = AddressDef)]
3534
pub from: Address,
36-
37-
/// The gas limit to use for the transaction
38-
/// If not provided, the system will auto-detect the best gas limit
39-
#[schemars(with = "Option<u64>")]
40-
#[schema(value_type = Option<u64>)]
41-
pub gas_limit: Option<u64>,
42-
4335
// /// Maximum number of in-flight transactions for this EOA
4436
// /// Controls how many transactions can be pending confirmation at once
4537
// /// Defaults to 100 if not specified
@@ -51,136 +43,4 @@ pub struct EoaExecutionOptions {
5143
// /// Defaults to 50 if not specified
5244
// #[serde(default = "default_max_recycled_nonces")]
5345
// pub max_recycled_nonces: u64,
54-
/// Transaction type-specific data for gas configuration
55-
/// If not provided, the system will auto-detect the best transaction type
56-
#[serde(flatten)]
57-
pub transaction_type_data: Option<EoaTransactionTypeData>,
58-
}
59-
60-
/// EOA Transaction type-specific data for different EIP standards
61-
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, utoipa::ToSchema)]
62-
#[serde(untagged)]
63-
pub enum EoaTransactionTypeData {
64-
/// EIP-7702 transaction with authorization list and EIP-1559 gas pricing
65-
Eip7702(EoaSend7702JobData),
66-
/// EIP-1559 transaction with priority fee and max fee per gas
67-
Eip1559(EoaSend1559JobData),
68-
/// Legacy transaction with simple gas price
69-
Legacy(EoaSendLegacyJobData),
70-
}
71-
72-
/// EIP-7702 transaction configuration
73-
/// Allows delegation of EOA to smart contract logic temporarily
74-
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, utoipa::ToSchema)]
75-
#[serde(rename_all = "camelCase")]
76-
pub struct EoaSend7702JobData {
77-
/// List of signed authorizations for contract delegation
78-
/// Each authorization allows the EOA to temporarily delegate to a smart contract
79-
#[schemars(with = "Option<Vec<SignedAuthorizationSchema>>")]
80-
#[schema(value_type = Option<Vec<SignedAuthorizationSchema>>)]
81-
pub authorization_list: Option<Vec<SignedAuthorization>>,
82-
83-
/// Maximum fee per gas willing to pay (in wei)
84-
/// This is the total fee cap including base fee and priority fee
85-
pub max_fee_per_gas: Option<u128>,
86-
87-
/// Maximum priority fee per gas willing to pay (in wei)
88-
/// This is the tip paid to validators for transaction inclusion
89-
pub max_priority_fee_per_gas: Option<u128>,
90-
}
91-
92-
/// EIP-1559 transaction configuration
93-
/// Uses base fee + priority fee model for more predictable gas pricing
94-
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, utoipa::ToSchema)]
95-
#[serde(rename_all = "camelCase")]
96-
pub struct EoaSend1559JobData {
97-
/// Maximum fee per gas willing to pay (in wei)
98-
/// This is the total fee cap including base fee and priority fee
99-
pub max_fee_per_gas: Option<u128>,
100-
101-
/// Maximum priority fee per gas willing to pay (in wei)
102-
/// This is the tip paid to validators for transaction inclusion
103-
pub max_priority_fee_per_gas: Option<u128>,
104-
}
105-
106-
/// Legacy transaction configuration
107-
/// Uses simple gas price model (pre-EIP-1559)
108-
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, utoipa::ToSchema)]
109-
#[serde(rename_all = "camelCase")]
110-
pub struct EoaSendLegacyJobData {
111-
/// Gas price willing to pay (in wei)
112-
/// This is the total price per unit of gas for legacy transactions
113-
pub gas_price: Option<u128>,
114-
}
115-
116-
/// EIP-7702 Authorization structure for OpenAPI schema
117-
/// Represents an unsigned authorization that allows an EOA to delegate to a smart contract
118-
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, utoipa::ToSchema)]
119-
#[serde(rename_all = "camelCase")]
120-
pub struct AuthorizationSchema {
121-
/// The chain ID of the authorization
122-
/// Must match the chain where the transaction will be executed
123-
#[schemars(with = "String")]
124-
#[schema(value_type = String, example = "1")]
125-
pub chain_id: U256,
126-
127-
/// The smart contract address to delegate to
128-
/// This contract will be able to execute logic on behalf of the EOA
129-
#[schemars(with = "AddressDef")]
130-
#[schema(value_type = AddressDef)]
131-
pub address: Address,
132-
133-
/// The nonce for the authorization
134-
/// Must be the current nonce of the authorizing account
135-
#[schema(example = 42)]
136-
pub nonce: u64,
137-
}
138-
139-
/// EIP-7702 Signed Authorization structure for OpenAPI schema
140-
/// Contains an authorization plus the cryptographic signature
141-
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema, utoipa::ToSchema)]
142-
#[serde(rename_all = "camelCase")]
143-
pub struct SignedAuthorizationSchema {
144-
/// The chain ID of the authorization
145-
/// Must match the chain where the transaction will be executed
146-
#[schemars(with = "String")]
147-
#[schema(value_type = String, example = "1")]
148-
pub chain_id: U256,
149-
150-
/// The smart contract address to delegate to
151-
/// This contract will be able to execute logic on behalf of the EOA
152-
#[schemars(with = "AddressDef")]
153-
#[schema(value_type = AddressDef)]
154-
pub address: Address,
155-
156-
/// The nonce for the authorization
157-
/// Must be the current nonce of the authorizing account
158-
#[schema(example = 42)]
159-
pub nonce: u64,
160-
161-
/// Signature parity value (0 or 1)
162-
/// Used for ECDSA signature recovery
163-
#[serde(rename = "yParity", alias = "v")]
164-
#[schema(example = 0)]
165-
pub y_parity: u8,
166-
167-
/// Signature r value
168-
/// First component of the ECDSA signature
169-
#[schemars(with = "String")]
170-
#[schema(value_type = String, example = "0x1234567890abcdef...")]
171-
pub r: U256,
172-
173-
/// Signature s value
174-
/// Second component of the ECDSA signature
175-
#[schemars(with = "String")]
176-
#[schema(value_type = String, example = "0xfedcba0987654321...")]
177-
pub s: U256,
178-
}
179-
180-
fn default_max_inflight() -> u64 {
181-
100
182-
}
183-
184-
fn default_max_recycled_nonces() -> u64 {
185-
50
18646
}

core/src/execution_options/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ use std::collections::HashMap;
77
use crate::transaction::InnerTransaction;
88
pub mod aa;
99
pub mod auto;
10-
pub mod eoa;
1110
pub mod eip7702;
11+
pub mod eoa;
1212

1313
// Base execution options for all transactions
1414
// All specific execution options share this
@@ -32,7 +32,7 @@ fn default_idempotency_key() -> String {
3232
#[schema(title = "Execution Option Variants")]
3333
pub enum SpecificExecutionOptions {
3434
#[serde(rename = "auto")]
35-
#[schema(title = "Auto Determine Execution")]
35+
#[schema(title = "Auto Determine Execution", default)]
3636
Auto(auto::AutoExecutionOptions),
3737

3838
#[schema(title = "ERC-4337 Execution Options")]

core/src/transaction.rs

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
use crate::defs::{AddressDef, BytesDef, U256Def};
2-
use alloy::primitives::{Address, Bytes, U256};
1+
use crate::defs::{AddressDef, BytesDef, SignedAuthorizationSchema, U256Def};
2+
use alloy::{
3+
eips::eip7702::SignedAuthorization,
4+
primitives::{Address, Bytes, U256},
5+
};
36
use serde::{Deserialize, Serialize};
47

5-
/// # InnerTransaction
8+
/// ### InnerTransaction
69
/// This is the actual encoded inner transaction data that will be sent to the blockchain.
710
#[derive(Deserialize, Serialize, Debug, Clone, utoipa::ToSchema)]
811
pub struct InnerTransaction {
@@ -16,4 +19,78 @@ pub struct InnerTransaction {
1619
#[schema(value_type = U256Def)]
1720
#[serde(default)]
1821
pub value: U256,
22+
23+
/// Gas limit for the transaction
24+
/// If not provided, engine will estimate the gas limit
25+
#[schema(value_type = Option<u64>)]
26+
#[serde(default, rename = "gasLimit")]
27+
pub gas_limit: Option<u64>,
28+
29+
/// Transaction type-specific data for different EIP standards
30+
///
31+
/// This is the actual encoded inner transaction data that will be sent to the blockchain.
32+
///
33+
/// Depending on the execution mode chosen, these might be ignored:
34+
///
35+
/// - For ERC4337 execution, all gas fee related fields are ignored. Sending signed authorizations is also not supported.
36+
#[serde(flatten)]
37+
pub transaction_type_data: Option<TransactionTypeData>,
38+
}
39+
40+
#[derive(Serialize, Deserialize, Debug, Clone, utoipa::ToSchema)]
41+
#[serde(untagged)]
42+
#[schema(title = "Transaction Type Specific Data")]
43+
pub enum TransactionTypeData {
44+
/// EIP-7702 transaction with authorization list and EIP-1559 gas pricing
45+
Eip7702(Transaction7702Data),
46+
/// EIP-1559 transaction with priority fee and max fee per gas
47+
Eip1559(Transaction1559Data),
48+
/// Legacy transaction with simple gas price
49+
Legacy(TransactionLegacyData),
50+
}
51+
52+
/// EIP-7702 transaction configuration
53+
/// Allows delegation of EOA to smart contract logic temporarily
54+
#[derive(Serialize, Deserialize, Debug, Clone, utoipa::ToSchema)]
55+
#[serde(rename_all = "camelCase")]
56+
#[schema(title = "EIP-7702 Specific Transaction Data")]
57+
pub struct Transaction7702Data {
58+
/// List of signed authorizations for contract delegation
59+
/// Each authorization allows the EOA to temporarily delegate to a smart contract
60+
#[schema(value_type = Option<Vec<SignedAuthorizationSchema>>)]
61+
pub authorization_list: Option<Vec<SignedAuthorization>>,
62+
63+
/// Maximum fee per gas willing to pay (in wei)
64+
/// This is the total fee cap including base fee and priority fee
65+
pub max_fee_per_gas: Option<u128>,
66+
67+
/// Maximum priority fee per gas willing to pay (in wei)
68+
/// This is the tip paid to validators for transaction inclusion
69+
pub max_priority_fee_per_gas: Option<u128>,
70+
}
71+
72+
/// EIP-1559 transaction configuration
73+
/// Uses base fee + priority fee model for more predictable gas pricing
74+
#[derive(Serialize, Deserialize, Debug, Clone, utoipa::ToSchema)]
75+
#[serde(rename_all = "camelCase")]
76+
#[schema(title = "EIP-1559 Specific Transaction Data")]
77+
pub struct Transaction1559Data {
78+
/// Maximum fee per gas willing to pay (in wei)
79+
/// This is the total fee cap including base fee and priority fee
80+
pub max_fee_per_gas: Option<u128>,
81+
82+
/// Maximum priority fee per gas willing to pay (in wei)
83+
/// This is the tip paid to validators for transaction inclusion
84+
pub max_priority_fee_per_gas: Option<u128>,
85+
}
86+
87+
/// Legacy transaction configuration
88+
/// Uses simple gas price model (pre-EIP-1559)
89+
#[derive(Serialize, Deserialize, Debug, Clone, utoipa::ToSchema)]
90+
#[serde(rename_all = "camelCase")]
91+
#[schema(title = "Legacy Specific Transaction Data")]
92+
pub struct TransactionLegacyData {
93+
/// Gas price willing to pay (in wei)
94+
/// This is the total price per unit of gas for legacy transactions
95+
pub gas_price: Option<u128>,
1996
}

0 commit comments

Comments
 (0)