Skip to content

Implement gas estimation for UserOperations #32

Description

@ch4r10t33r

Title

Implement gas estimation for UserOperations

Labels

enhancement, account-abstraction, gas, estimation

Description

Add accurate gas estimation for UserOperations, accounting for all ERC-4337 components including verification, execution, and paymaster gas.

Requirements

UserOperation Gas Components

  • Estimate callGasLimit:

    • Simulate main execution call
    • Add buffer for safety (10-20%)
  • Estimate verificationGasLimit:

    • Account's validateUserOp gas cost
    • Handle different account implementations
    • Standard accounts: ~100k gas
    • Complex validation: higher limits
  • Calculate preVerificationGas:

    • Fixed overhead for bundler
    • calldata cost calculation
    • Signature length consideration
    • Formula: 21000 + calldataGas + bundlerOverhead
  • Estimate paymaster gas (if used):

    • paymasterVerificationGasLimit
    • paymasterPostOpGasLimit

Estimation Strategies

  • Via Bundler RPC:

    • Use eth_estimateUserOperationGas
    • Parse bundler response
    • Apply safety margins
  • Local Simulation:

    • Fallback if bundler doesn't support estimation
    • Simulate via eth_call to EntryPoint
    • Extract gas usage from trace
  • Heuristic-based:

    • Default values for known account types
    • Simple account: 100k verification, based on call for execution
    • Configurable defaults

Gas Optimization

  • Add optimization helpers:
    • optimizeUserOpGas(userOp: *UserOperation) - Reduce gas where safe
    • Check if init_code is needed
    • Minimize signature size
    • Optimize calldata packing

Estimation Middleware

  • Create UserOpGasMiddleware:
    • Automatic gas estimation before submission
    • Caching of estimation results
    • Dynamic adjustment based on network conditions

Gas Calculation Formulas

// Pre-verification gas
pub fn calculatePreVerificationGas(
    userOp: UserOperation,
    bundler_overhead: u256,
) u256 {
    const calldata_cost = calcdataGasCost(userOp);
    return 21000 + calldata_cost + bundler_overhead;
}

// Calldata gas cost
fn calcdataGasCost(userOp: UserOperation) u256 {
    var cost: u256 = 0;
    const packed = packUserOp(userOp);
    for (packed) |byte| {
        cost += if (byte == 0) 4 else 16;
    }
    return cost;
}

File Structure

src/account_abstraction/
  ├── gas_estimation.zig       # Core gas estimation logic
  └── gas_middleware.zig       # Middleware for auto-estimation

Example Usage

// Automatic estimation
var userOp = try UserOperationBuilder.init(allocator)
    .setSender(account)
    .setCallData(data)
    .estimateGas(provider, entrypoint)  // <-- automatic
    .build();

// Manual estimation
const gas_estimate = try estimateUserOperationGas(
    provider,
    userOp,
    entrypoint_address,
);
userOp.callGasLimit = gas_estimate.callGasLimit;
userOp.verificationGasLimit = gas_estimate.verificationGasLimit;
userOp.preVerificationGas = gas_estimate.preVerificationGas;

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions