Skip to content

# Sequence diagram for simulateMulticall3CombinedGas flow #25

Description

@Dargon789

Reviewer's Guide

Adds multicall3-based simulation support to the Simulator, introduces an IMulticall3 interface and mock implementation, and extends tests to cover multicall-based gas estimation, payment handling, and key-hash context propagation, along with some minor formatting / style tweaks.

Sequence diagram for simulateMulticall3CombinedGas flow

sequenceDiagram
    actor ExternalCaller
    participant Simulator
    participant Multicall3
    participant Orchestrator

    ExternalCaller->>Simulator: simulateMulticall3CombinedGas(multicall3, calls, oc, paymentPerGasPrecision, paymentPerGas, combinedGasIncrement, encodedIntent)
    Simulator->>Simulator: decode encodedIntent into Intent u

    loop Primary simulation run
        Simulator->>Simulator: _callMulticall3(multicall3, calls, oc, isStateOverride=false, combinedGasOverride=type(uint256).max, u)
        Simulator->>Multicall3: aggregate3(allCalls)
        Multicall3->>Orchestrator: simulateExecute(isStateOverride, combinedGasOverride, abi.encode(u))
        Orchestrator-->>Multicall3: revert SimulationPassed or return state override data
        Multicall3-->>Simulator: Result[] results
        Simulator->>Simulator: parse last Result, extract gasUsed or errorData
    end

    alt primary run failed (gasUsed == 0)
        Simulator->>Simulator: _bubbleUpMulticall3Error(errorData)
        Simulator-->>ExternalCaller: revert with orchestrator error
    else primary run succeeded
        Simulator->>Simulator: u.combinedGas += gasUsed
        Simulator->>Simulator: _updatePaymentAmounts(u, u.combinedGas, paymentPerGasPrecision, paymentPerGas)
    end

    loop Search for passing combinedGas
        Simulator->>Simulator: _callMulticall3(multicall3, calls, oc, isStateOverride=false, combinedGasOverride=0, u)
        Simulator->>Multicall3: aggregate3(allCalls)
        Multicall3->>Orchestrator: simulateExecute(false, 0, abi.encode(u))
        Orchestrator-->>Multicall3: revert SimulationPassed or error
        Multicall3-->>Simulator: Result[] results
        Simulator->>Simulator: parse gasUsed or errorData

        alt gasUsed == 0 and errorSelector == PaymentError
            Simulator-->>ExternalCaller: revert PaymentError
        else gasUsed == 0 (other error)
            Simulator->>Simulator: gasIncrement = mulDiv(u.combinedGas, combinedGasIncrement, 10000)
            Simulator->>Simulator: _updatePaymentAmounts(u, gasIncrement, paymentPerGasPrecision, paymentPerGas)
            Simulator->>Simulator: u.combinedGas += gasIncrement
        else gasUsed != 0
            Simulator-->>ExternalCaller: return gasUsed, multicall3Gas, u.combinedGas
        end
    end
Loading

File-Level Changes

Change Details Files
Add multicall3 support to Simulator for pre-call execution and gas estimation, including error bubbling and V1-logs compatible flows.
  • Import IMulticall3 and wire it into the Simulator contract
  • Implement internal _callMulticall3 to build Call3 arrays, invoke aggregate3, and parse orchestrator gas usage from results / revert data, including state-override vs non-override handling
  • Implement _bubbleUpMulticall3Error to rethrow orchestrator errors returned via multicall3
  • Add simulateMulticall3CombinedGas to iteratively search for a passing combinedGas using multicall3, updating payment amounts and handling PaymentError specially
  • Add simulateMulticall3V1Logs wrapper that uses simulateMulticall3CombinedGas, applies a verification offset, recomputes payments, and performs a final state-override run to generate logs
src/Simulator.sol
Introduce Multicall3 interface and a mock implementation for tests.
  • Define IMulticall3 interface with Call, Call3, Call3Value, Result structs and aggregate/aggregate3 signatures
  • Add MockMulticall3 contract that implements aggregate and aggregate3 by sequentially calling targets and enforcing allowFailure semantics
src/interfaces/IMulticall3.sol
test/SimulateExecute.t.sol
Extend simulator tests to cover multicall3-based simulations with various pre-call scenarios and to compare simulated vs actual gas.
  • Instantiate MockMulticall3 in SimulateExecuteTest and thread IMulticall3.Call3[] through temporary state
  • Add tests for simulateMulticall3V1Logs under max-balance / InsufficientGas conditions
  • Add tests ensuring simulateMulticall3* revert on underfunded payments via PaymentError
  • Add tests for multicall3 simulation with EOA key and PassKey, including verification offset behavior and storage side effects
  • Add tests for empty and multiple preCalls arrays to validate behavior parity with non-multicall simulateExecute
  • Add test that compares simulateMulticall3CombinedGas output to real gas usage when executing via multicall3.aggregate3
test/SimulateExecute.t.sol
Expose and test context key-hash retrieval on accounts during execution flows.
  • Add contextKeyHash state variable and targetFunctionContextKeyHash helper to BaseTest, which calls IthacaAccount(msg.sender).getContextKeyHash()
  • Add AccountTest.testContextKeyHash to validate context key hash in three flows: orchestrator workflow, workflow with opData (nonce+signature), and self-execution without opData
test/Base.t.sol
test/Account.t.sol
Minor formatting and style adjustments in tests and LayerZeroSettler.
  • Reformat chained calls to setCanExecute and setSpendLimit in Benchmark and GuardedExecutor tests for readability
  • Reformat LayerZeroSettler._getPeerOrRevert signature over multiple lines without changing logic
test/Benchmark.t.sol
test/GuardedExecutor.t.sol
src/LayerZeroSettler.sol

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Originally posted by @sourcery-ai[bot] in #24 (comment)

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdocumentationImprovements or additions to documentationduplicateThis issue or pull request already existsenhancementNew feature or requestgood first issueGood for newcomershelp wantedExtra attention is neededinvalidThis doesn't seem rightquestionFurther information is requestedwontfixThis will not be worked on

Projects

Status
In Review
Status
Todo

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions