Skip to content

Simulation endpoint#4275

Merged
m-sz merged 94 commits intomainfrom
simulation-endpoint
Apr 1, 2026
Merged

Simulation endpoint#4275
m-sz merged 94 commits intomainfrom
simulation-endpoint

Conversation

@m-sz
Copy link
Copy Markdown
Contributor

@m-sz m-sz commented Mar 18, 2026

Description

Based on #4265

Adds a /api/v1/debug/simulation/{uid} endpoint to the orderbook that lets you simulate an order's execution via Tenderly.

Changes

  • debug_simulation.rs — new API handler that accepts an order UID and returns the Tenderly simulation request + any error
  • Orderbook::simulate_order() — fetches the order, encodes it as a swap, simulates it, and returns the Tenderly request payload
  • OrderSimulator struct — wraps SwapSimulator with chain ID context; handles encoding orders into EncodedSwap and running simulations

Notice

Simulation runs against the current block (not a historical replay at the block the order was filled), and that it uses the original order amounts — so for partially filled orders, the full amount is simulated against the trader's current balance.

Follow-up PR

Encoding improvements in simulator:

  • InteractionEncoding trait extracted so both Interaction and InteractionData (from model crate) can be encoded — this allows order pre/post interactions to be encoded directly without manual conversion
  • WrapperCall struct + encode_wrapper_settlement() function added to handle settlements that go through wrapper contracts
  • SwapSimulator::fake_swap() extended to support wrapper contracts in the query

Supporting changes:

  • app-data: added wrappers() accessor to expose wrapper calls from app data
  • configs/orderbook: added config for the new simulator (optional — order_simulation_gas_limit: None keeps existing behavior)
  • price-estimation: refactored to use the new InteractionEncoding trait
  • driver/encoding: cleanup — moved some encoding logic to the simulator crate

The OpenAPI spec has been updated with:

Path /api/v1/debug/simulation/{uid} — GET endpoint that takes an order UID and returns 200 (OrderSimulation), 404 (not found), 501 (not enabled), or 500 (internal error).

New schemas:

  • OrderSimulation — top-level response with tenderly_request and optional error
  • TenderlyRequest — the full Tenderly simulation request structure
  • SimulationType — enum full | quick | abi:
    • full (default): Detailed decoded output — call trace, function, inputs/outputs, state diffs, and logs with Solidity types.
    • quick: Raw, minimal output only. Fastest option; no decoding.
    • abi: Decoded function inputs/outputs and logs, but no state diffs. Middle ground between quick and full.
      AccessListItem — address + storage_keys
      StateObject — balance/code/storage overrides

How to test

Create order in local playground, query for its simulation. Verify on tenderly.

Example output:

{
    "tenderly_request": {
        "network_id": "1",
        "from": "0xfcc789354262dd9c2f2ff1b0a5f9067b55af1bfa",
        "to": "0xa513e6e4b8f2a923d98304ec87f64353c4d5c853",
        "input": "0x13d79a0b000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000032000000000000000000000000000000000000000000000000000000000000000020000000000000000000000005fbdb2315678afecb367f032d93f642f64180aa300000000000000000000000068b1d87f95878fe05b998f19b66f4baba5de1aed00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000001bc16d674ec8000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000009315fc8ffae493123b9b6b1c93d50c9b9eef03440000000000000000000000000000000000000000000000001bc16d674ec800000000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000ffffffff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000de0b6b3a7640000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000149315fc8ffae493123b9b6b1c93d50c9b9eef03440000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
        "gas": 16777215,
        "simulation_type": "full",
        "save": true,
        "save_if_fails": true,
        "state_objects": {
            "0x68b1d87f95878fe05b998f19b66f4baba5de1aed": {
                "storage": {
                    "0xd7a1f0b46140686e5b4c405dcbec93c326c8c0e52cb615e05dcf53ad4119c720": "0x0000000000000000000000000000000000000000000000000de0b6b3a7640000"
                }
            },
            "0x9315fc8ffae493123b9b6b1c93d50c9b9eef0344": {
                "code": "0x608060405260043610610037575f3560e01c80631626ba7e1461008d578063542eb77d14610104578063eb5625d9146101255761003e565b3661003e57005b5f6100835f368080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525062010000939250506101449050565b9050805160208201f35b348015610098575f5ffd5b506100cf6100a7366004610b01565b7f1626ba7e000000000000000000000000000000000000000000000000000000009392505050565b6040517fffffffff00000000000000000000000000000000000000000000000000000000909116815260200160405180910390f35b34801561010f575f5ffd5b5061012361011e366004610b9c565b6101c2565b005b348015610130575f5ffd5b5061012361013f366004610c00565b610916565b60605f8373ffffffffffffffffffffffffffffffffffffffff168360405161016c9190610c3e565b5f60405180830381855af49150503d805f81146101a4576040519150601f19603f3d011682016040523d82523d5f602084013e6101a9565b606091505b5092509050806101bb57815160208301fd5b5092915050565b7f02565dba7d68dcbed629110024b7b5e785bfc1a484602045eea513de8a2dcf99805460017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0082161790915560ff16156102a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f70726570617265537761702063616e206f6e6c792062652063616c6c6564206f60448201527f6e6365000000000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16036103e4576040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8616906370a0823190602401602060405180830381865afa158015610340573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906103649190610c6a565b9050838110156103e2575f6103798286610c81565b90508047106103e0578373ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004015f604051808303818588803b1580156103c8575f5ffd5b505af11580156103da573d5f5f3e3d5ffd5b50505050505b505b505b5f8573ffffffffffffffffffffffffffffffffffffffff16639b552cc26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561042e573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104529190610cb9565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff80831660248301529192505f9187169063dd62ed3e90604401602060405180830381865afa1580156104c7573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906104eb9190610c6a565b905084811015610748576040517feb5625d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8088166004830152831660248201525f6044820152309063eb5625d9906064015f604051808303815f87803b158015610567575f5ffd5b505af1925050508015610578575060015b506040517feb5625d900000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8088166004830152831660248201527fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6044820152309063eb5625d9906064015f604051808303815f87803b15801561060b575f5ffd5b505af192505050801561061c575060015b506040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff83811660248301525f919088169063dd62ed3e90604401602060405180830381865afa158015610690573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906106b49190610c6a565b905085811015610746576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f74726164657220646964206e6f7420676976652074686520726571756972656460448201527f20617070726f76616c7300000000000000000000000000000000000000000000606482015260840161029a565b505b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201525f9073ffffffffffffffffffffffffffffffffffffffff8816906370a0823190602401602060405180830381865afa1580156107b2573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906107d69190610c6a565b90508581101561090c5773ffffffffffffffffffffffffffffffffffffffff841663494666b688610807848a610c81565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff909216600483015260248201526044015f604051808303815f87803b15801561086f575f5ffd5b505af1925050508015610880575060015b61090c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f74726164657220646f6573206e6f74206861766520656e6f7567682073656c6c60448201527f20746f6b656e0000000000000000000000000000000000000000000000000000606482015260840161029a565b5050505050505050565b61093773ffffffffffffffffffffffffffffffffffffffff8416838361093c565b505050565b6040805173ffffffffffffffffffffffffffffffffffffffff848116602483015260448083018590528351808403909101815260649092019092526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f095ea7b300000000000000000000000000000000000000000000000000000000179052905f906109ce90861683610a46565b90506109d981610a5a565b610a3f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f5361666545524332303a20617070726f76616c206661696c6564000000000000604482015260640161029a565b5050505050565b6060610a53835f84610a7f565b9392505050565b5f81515f1480610a79575081806020019051810190610a799190610cd4565b92915050565b60605f8473ffffffffffffffffffffffffffffffffffffffff168484604051610aa89190610c3e565b5f6040518083038185875af1925050503d805f8114610ae2576040519150601f19603f3d011682016040523d82523d5f602084013e610ae7565b606091505b509250905080610af957815160208301fd5b509392505050565b5f5f5f60408486031215610b13575f5ffd5b83359250602084013567ffffffffffffffff811115610b30575f5ffd5b8401601f81018613610b40575f5ffd5b803567ffffffffffffffff811115610b56575f5ffd5b866020828401011115610b67575f5ffd5b939660209190910195509293505050565b73ffffffffffffffffffffffffffffffffffffffff81168114610b99575f5ffd5b50565b5f5f5f5f5f60a08688031215610bb0575f5ffd5b8535610bbb81610b78565b94506020860135610bcb81610b78565b9350604086013592506060860135610be281610b78565b91506080860135610bf281610b78565b809150509295509295909350565b5f5f5f60608486031215610c12575f5ffd5b8335610c1d81610b78565b92506020840135610c2d81610b78565b929592945050506040919091013590565b5f82515f5b81811015610c5d5760208186018101518583015201610c43565b505f920191825250919050565b5f60208284031215610c7a575f5ffd5b5051919050565b81810381811115610a79577f4e487b71000000000000000000000000000000000000000000000000000000005f52601160045260245ffd5b5f60208284031215610cc9575f5ffd5b8151610a5381610b78565b5f60208284031215610ce4575f5ffd5b81518015158114610a53575f5ffdfea164736f6c634300081e000a"
            },
            "0xfcc789354262dd9c2f2ff1b0a5f9067b55af1bfa": {
                "balance": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
            },
            "0x5fc8d32690cc91d4c39d9d3abcbd16989f875707": {
                "code": "0x6080604052348015600e575f5ffd5b50600436106026575f3560e01c806302cc250d14602a575b5f5ffd5b603b6035366004604f565b50600190565b604051901515815260200160405180910390f35b5f60208284031215605e575f5ffd5b813573ffffffffffffffffffffffffffffffffffffffff811681146080575f5ffd5b939250505056fea164736f6c634300081e000a"
            }
        }
    },
    "error": null
}

Migration Guide: simulation-endpoint branch

New field: order-simulation-gas-limit
A new optional top-level field has been added to the orderbook TOML configuration.

Type: string (decimal integer, interpreted as U256)
Default: omitted / disabled

Enable the order simulation debug endpoint

order-simulation-gas-limit = "16777215"
Effect:

When absent (default): the GET /api/v1/debug/simulation/{uid} endpoint is disabled. Requests return a 501 Not Implemented response.
When present: the endpoint is enabled. The value sets the gas limit used when simulating the order's settlement call via Tenderly (through the price estimation driver's balance-override infrastructure).
Recommended value: "16777215" (0xFFFFFF — same as the E2E test default). Adjust downward if you want to cap simulation gas usage.

No action required if you do not want to expose the simulation endpoint — omitting the field is the safe default.

m-sz added 28 commits March 12, 2026 18:02
Contact and Token addresses now are private structs containing Address.
Implemented Deref for them and updated usages.
Contact and Token addresses now are private structs containing Address.
Implemented Deref for them and updated usages.
Adds dependency on simulator for solver
These can be added as post-processing step at the callsite.

Reverted invalid contracts changes
Addressed comments
@m-sz m-sz requested a review from a team as a code owner March 18, 2026 18:56
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new simulation endpoint and refactors simulation logic into a dedicated simulator crate. The changes are extensive and touch many parts of the codebase. My review focuses on the correctness of the new simulation logic. I've identified a critical issue in how simulations for orders with wrappers are handled, a high-severity issue with buy order simulation logic, and a couple of medium-severity issues related to API error handling and logging. Overall, the refactoring is a good step towards modularity, but the identified issues need to be addressed to ensure the new functionality is correct.

@m-sz
Copy link
Copy Markdown
Contributor Author

m-sz commented Mar 31, 2026

Added the example output

@squadgazzz
Copy link
Copy Markdown
Contributor

squadgazzz commented Mar 31, 2026

Nit on the PR description: it would help to clarify that the simulation runs against the current block (not a historical replay at the block the order was filled), and that it uses the original order amounts — so for partially filled orders, the full amount is simulated against the trader's current balance.

Is it expected to simulate only expired/unfilled orders?

@m-sz
Copy link
Copy Markdown
Contributor Author

m-sz commented Mar 31, 2026

Nit on the PR description: it would help to clarify that the simulation runs against the current block (not a historical replay at the block the order was filled), and that it uses the original order amounts — so for partially filled orders, the full amount is simulated against the trader's current balance.

Is it expected to simulate only expired/unfilled orders?

I haven't though about it, I can add a query parameter to specify simulation's block number

@squadgazzz
Copy link
Copy Markdown
Contributor

I haven't though about it, I can add a query parameter to specify simulation's block number

Feel free to do that in a follow-up PR, since this PR is already huge. Just update the PR description please.

@m-sz
Copy link
Copy Markdown
Contributor Author

m-sz commented Apr 1, 2026

I haven't though about it, I can add a query parameter to specify simulation's block number

Feel free to do that in a follow-up PR, since this PR is already huge. Just update the PR description please.

Thanks, will do a follow up then. The description was updated per Your previous comment. Added larger heading to make it stand out :)

Copy link
Copy Markdown
Contributor

@squadgazzz squadgazzz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing the comments! LGTM.
Please update the PR description by listing the follow-up items we've discussed in the comments. If it is not expected to be addressed soon, create relevant GH issues.

Co-authored-by: ilya <ilya@cow.fi>
@jmg-duarte jmg-duarte dismissed their stale review April 1, 2026 10:56

I've found some more issues I'd like to see addressed or at least discussed

m-sz and others added 7 commits April 1, 2026 13:00
Co-authored-by: José Duarte <duarte.gmj@gmail.com>
Co-authored-by: José Duarte <duarte.gmj@gmail.com>
Co-authored-by: José Duarte <duarte.gmj@gmail.com>
Co-authored-by: José Duarte <duarte.gmj@gmail.com>
Co-authored-by: José Duarte <duarte.gmj@gmail.com>
@m-sz m-sz added this pull request to the merge queue Apr 1, 2026
Merged via the queue into main with commit 5b22ece Apr 1, 2026
20 checks passed
@m-sz m-sz deleted the simulation-endpoint branch April 1, 2026 17:12
@github-actions github-actions bot locked and limited conversation to collaborators Apr 1, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants