Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
ab8357b
initial commit
MartinquaXD Apr 22, 2026
76b12c6
fixup
MartinquaXD Apr 22, 2026
d410031
fixup
MartinquaXD Apr 22, 2026
417c9a0
introduce Solver enum
MartinquaXD Apr 22, 2026
19926d9
factory
MartinquaXD Apr 22, 2026
9731a30
Only allow list specific solver address
MartinquaXD Apr 22, 2026
0f03c74
add function for funding settlement contract
MartinquaXD Apr 22, 2026
afedc26
add executed amounts
MartinquaXD Apr 22, 2026
db932ac
Move flashloan router address into simulator thingy
MartinquaXD Apr 22, 2026
258539b
fixup
MartinquaXD Apr 22, 2026
969ffee
simulate(), handle fillable amounts
MartinquaXD Apr 24, 2026
ae91cf6
Better handling of block target and executed amount
MartinquaXD Apr 27, 2026
2ccedbb
Move encoding logic into separate file
MartinquaXD Apr 27, 2026
c1a0fe2
move code around
MartinquaXD Apr 27, 2026
36d46aa
store chain_id and convert to tenderly request
MartinquaXD Apr 27, 2026
9259b06
current block watcher in simulator
MartinquaXD Apr 27, 2026
fb58a25
more fixes
MartinquaXD Apr 28, 2026
8a0cd78
fmt
MartinquaXD Apr 28, 2026
dcdd986
more fixes
MartinquaXD Apr 28, 2026
6ecd600
correct tenderly block
MartinquaXD Apr 29, 2026
93a8dda
comment for idea
MartinquaXD Apr 29, 2026
5c1f7c3
extract wrappers from appdata
MartinquaXD Apr 29, 2026
3f33170
Populate properties from appdata
MartinquaXD Apr 29, 2026
7d0253a
.context() instead of unwrap()
MartinquaXD Apr 29, 2026
764d3e7
fix tests
MartinquaXD Apr 29, 2026
934da39
remove test log
MartinquaXD Apr 29, 2026
67d7a8a
Merge branch 'main' into new-api-simulator-crate
squadgazzz Apr 29, 2026
c1aabeb
more functionality needed for trade verification
MartinquaXD Apr 30, 2026
29c2254
remove need for native token address in trade verification
MartinquaXD Apr 30, 2026
9aec495
Nicer API for handling state overrides
MartinquaXD Apr 30, 2026
0a092dc
build final state overrides in separate function
MartinquaXD Apr 30, 2026
ba042f0
claude suggested changes
MartinquaXD Apr 30, 2026
bfc5627
use `SettlementSimulator` in trade verification
MartinquaXD Apr 30, 2026
ff58e63
Remove old code
MartinquaXD Apr 30, 2026
104b759
assemble state overrides via simulator crate
MartinquaXD Apr 30, 2026
12dead3
best effort override resolution
MartinquaXD Apr 30, 2026
aad3997
Remove customize functionality
MartinquaXD Apr 30, 2026
56b020b
Support multiple orders
MartinquaXD Apr 30, 2026
4dd3628
nicer API
MartinquaXD Apr 30, 2026
a0c3bcc
nits
MartinquaXD Apr 30, 2026
1de44d9
api improvements
MartinquaXD Apr 30, 2026
2afaf88
2 price vector entries per order
MartinquaXD Apr 30, 2026
439d719
move gas_limit into settlement simulator
MartinquaXD Apr 30, 2026
0929b38
Merge branch 'main' into new-api-simulator-crate
MartinquaXD Apr 30, 2026
29ed574
sort dependencies
MartinquaXD Apr 30, 2026
543d466
fix lints
MartinquaXD Apr 30, 2026
e24104d
Keep error reporting consistent
MartinquaXD May 5, 2026
6ff31cb
fix other failing e2e test
MartinquaXD May 5, 2026
42be284
Merge remote-tracking branch 'origin/main' into new-api-simulator-crate
MartinquaXD May 5, 2026
bd726e5
Pipe contract addresses around
MartinquaXD May 5, 2026
2b87af2
add link for storage slot encoding
MartinquaXD May 5, 2026
bf12ca8
`.unwrap()` -> `.expect()`
MartinquaXD May 5, 2026
2010b59
replace unreachable with error log
MartinquaXD May 5, 2026
68bdd8d
Move new encoding logic into existing file
MartinquaXD May 5, 2026
4e2ef55
Merge branch 'main' into new-api-simulator-crate
MartinquaXD May 5, 2026
6d87308
delete unused file
MartinquaXD May 5, 2026
7ab386a
Make tenderly URL optional
MartinquaXD May 5, 2026
b0348df
consistent naming
MartinquaXD May 5, 2026
d299a38
Replace awkward BuyTokensForBuffers variant
MartinquaXD May 5, 2026
7d4c4aa
Stricter error handling
MartinquaXD May 5, 2026
ea48bce
move code around + comments
MartinquaXD May 5, 2026
a4aa3bf
Revert native token handling change to shrink diff
MartinquaXD May 5, 2026
70885e8
group errors together
MartinquaXD May 6, 2026
7192c76
doc comments
MartinquaXD May 6, 2026
8ccf915
drop comment on tenderly gas price - should not be needed
MartinquaXD May 6, 2026
f7be2aa
import `tenderly` instead of using fully qualified paths
MartinquaXD May 6, 2026
ed7ef9a
cleaner error conversion
MartinquaXD May 6, 2026
7c0521f
doc comments
MartinquaXD May 6, 2026
3098ef2
move struct + impl together
MartinquaXD May 6, 2026
c74823f
move ethcallinputs to simulationbuilder
MartinquaXD May 6, 2026
036ed92
fixup
MartinquaXD May 6, 2026
a37050b
move struct + impl together
MartinquaXD May 6, 2026
f07d4d1
Function for wrapping hooks in trampoline call
MartinquaXD May 6, 2026
2ef69f7
match instead of ifs
MartinquaXD May 6, 2026
667a4c7
doc comment
MartinquaXD May 6, 2026
4a7f75e
use `vec![]` instead of pushing into empty vector
MartinquaXD May 6, 2026
16cd8f3
use iterators intead of eagerly collecting into vectors
MartinquaXD May 6, 2026
e16f2da
Use `#[from]` over `#[source]`
MartinquaXD May 6, 2026
88b8e73
better errors
MartinquaXD May 6, 2026
65a4f0f
prepare jit orders in separate function
MartinquaXD May 6, 2026
c05d82c
Merge branch 'main' into new-api-simulator-crate
MartinquaXD May 6, 2026
5b0499c
better error
MartinquaXD May 6, 2026
4698b86
mark fields as required in openapi spec
MartinquaXD May 6, 2026
a6ab2f5
don't override interactions, remove from order, drop functions
MartinquaXD May 6, 2026
121fbbc
drop unnecessary dependency
MartinquaXD May 6, 2026
573ae5e
fix comment
MartinquaXD May 6, 2026
bd8be29
mark appdata as required as well
MartinquaXD May 6, 2026
14e0f06
comment
MartinquaXD May 6, 2026
010b1a1
Merge branch 'main' into new-api-simulator-crate
MartinquaXD May 6, 2026
edf7993
extend instead over overwrite appdata interactions
MartinquaXD May 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

13 changes: 13 additions & 0 deletions crates/autopilot/src/infra/blockchain/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use {
chain::Chain,
contracts::{
ChainalysisOracle,
FlashLoanRouter,
GPv2AllowListAuthentication,
GPv2Settlement,
HooksTrampoline,
Expand All @@ -21,6 +22,7 @@ pub struct Contracts {
balances: Balances::Instance,
chainalysis_oracle: Option<ChainalysisOracle::Instance>,
trampoline: HooksTrampoline::Instance,
flashloan_router: Address,

/// The authenticator contract that decides which solver is allowed to
/// submit settlements.
Expand All @@ -36,6 +38,7 @@ pub struct Addresses {
pub weth: Option<Address>,
pub balances: Option<Address>,
pub trampoline: Option<Address>,
pub flashloan_router: Option<Address>,
}

impl Contracts {
Expand Down Expand Up @@ -80,6 +83,11 @@ impl Contracts {
web3.provider.clone(),
);

let flashloan_router = addresses
.flashloan_router
.or_else(|| FlashLoanRouter::deployment_address(&chain.id()))
.unwrap();

let chainalysis_oracle = ChainalysisOracle::Instance::deployed(&web3.provider)
.await
.ok();
Expand Down Expand Up @@ -111,6 +119,7 @@ impl Contracts {
settlement_domain_separator,
authenticator,
trampoline,
flashloan_router,
}
}

Expand Down Expand Up @@ -151,4 +160,8 @@ impl Contracts {
pub fn authenticator(&self) -> &GPv2AllowListAuthentication::Instance {
&self.authenticator
}

pub fn flashloan_router(&self) -> Address {
self.flashloan_router
}
}
3 changes: 3 additions & 0 deletions crates/autopilot/src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ pub async fn run(config: Configuration, shutdown_controller: ShutdownController)
weth: config.shared.contracts.native_token,
balances: config.shared.contracts.balances,
trampoline: config.shared.contracts.hooks,
flashloan_router: config.shared.contracts.flashloan_router,
};
let current_block_args = shared::current_block::Arguments::from(&config.shared.current_block);
let eth = ethereum(
Expand Down Expand Up @@ -314,6 +315,8 @@ pub async fn run(config: Configuration, shutdown_controller: ShutdownController)
.await
.expect("failed to query solver authenticator address"),
block_stream: eth.current_block().clone(),
flash_loan_router: eth.contracts().flashloan_router(),
hooks_trampoline: *eth.contracts().trampoline().address(),
},
factory::Components {
http_factory: http_client::HttpClientFactory::new(&configs::http_client::HttpClient {
Expand Down
3 changes: 3 additions & 0 deletions crates/configs/src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ pub struct ContractAddresses {

/// The Balancer V2 Vault contract used for liquidity sourcing.
pub balancer_v2_vault: Option<Address>,

/// The flashloan router contract.
pub flashloan_router: Option<Address>,
}

/// Logging configuration (log filter, output format).
Expand Down
5 changes: 5 additions & 0 deletions crates/e2e/src/setup/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ impl<'a> Services<'a> {
native_token: Some(*self.contracts.weth.address()),
hooks: Some(*self.contracts.hooks.address()),
balancer_v2_vault: Some(*self.contracts.balancer_vault.address()),
flashloan_router: self
.contracts
.flashloan_router
.as_ref()
.map(|c| *c.address()),
},
..Default::default()
}
Expand Down
17 changes: 16 additions & 1 deletion crates/e2e/tests/e2e/malformed_requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ async fn http_validation(web3: Web3) {
"zero sellAmount should return 422"
);

// Invalid kind enum value → 422
// some fields missing → 422
let response = client
.post(format!("{API_HOST}/restricted/api/v1/debug/simulation"))
.json(&json!({
Expand Down Expand Up @@ -492,6 +492,13 @@ async fn http_validation(web3: Web3) {
"kind": "sell",
"owner": VALID_ADDRESS,
"appData": bad_app_data,
"sellTokenBalance": "erc20",
"buyTokenBalance": "erc20",
"signingScheme": "eip1271",
"signature": "0x000000",
"feeAmount": "0",
"validTo": 12341234,
"partiallyFillable": false,
}))
.send()
.await
Expand Down Expand Up @@ -563,6 +570,14 @@ async fn simulation_not_enabled(web3: Web3) {
"buyAmount": "1000000000000000000",
"kind": "sell",
"owner": VALID_ADDRESS,
"appData": "{}",
"sellTokenBalance": "erc20",
"buyTokenBalance": "erc20",
"signingScheme": "eip1271",
"signature": "0x000000",
"feeAmount": "0",
"validTo": 12341234,
"partiallyFillable": false,
}))
.send()
.await
Expand Down
57 changes: 52 additions & 5 deletions crates/e2e/tests/e2e/order_simulation.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
use {
alloy::{primitives::Address, providers::Provider},
alloy::{
primitives::{Address, ruint::aliases::U256},
providers::Provider,
},
configs::test_util::TestDefault,
e2e::setup::{API_HOST, OnchainComponents, Services, TIMEOUT, run_test, wait_for_condition},
ethrpc::{Web3, alloy::CallBuilderExt},
model::{
order::{OrderCreation, OrderKind},
order::{
BuyTokenDestination,
OrderCreation,
OrderCreationAppData,
OrderKind,
SellTokenSource,
},
signature::EcdsaSigningScheme,
},
number::units::EthUnit,
Expand Down Expand Up @@ -50,15 +59,53 @@ async fn custom_order_simulation(web3: Web3) {
.await;

let client = services.client();
let valid_to = model::time::now_in_epoch_seconds() + 100;

let sell_amount = 1u64.eth();
let request = orderbook::dto::OrderSimulationRequest {
let app_data = "{}";

// Sign an OrderCreation with the same fields the simulation will encode.
// simulate_custom_order hashes `app_data` with keccak256; OrderCreation::Full
// does the same, so the signature covers exactly the same OrderData hash.
let signed = OrderCreation {
sell_token: *token.address(),
buy_token: *onchain.contracts().weth.address(),
sell_amount: sell_amount.try_into().expect("Sell amount is non zero"),
sell_amount,
buy_amount: 1u64.eth(),
kind: OrderKind::Sell,
owner: trader.address(),
receiver: Some(Address::default()),
sell_token_balance: SellTokenSource::Erc20,
buy_token_balance: BuyTokenDestination::Erc20,
fee_amount: U256::ZERO,
valid_to,
app_data: OrderCreationAppData::Full {
full: app_data.to_string(),
},
partially_fillable: false,
..Default::default()
}
.sign(
EcdsaSigningScheme::Eip712,
&onchain.contracts().domain_separator,
&trader.signer,
);

let request = orderbook::dto::OrderSimulationRequest {
sell_token: signed.sell_token,
buy_token: signed.buy_token,
sell_amount: signed.sell_amount.try_into().unwrap(),
buy_amount: signed.buy_amount,
kind: signed.kind,
owner: trader.address(),
receiver: signed.receiver,
sell_token_balance: signed.sell_token_balance,
buy_token_balance: signed.buy_token_balance,
app_data: app_data.to_string(),
block_number: None,
signature: signed.signature,
fee_amount: signed.fee_amount,
valid_to: signed.valid_to,
partially_fillable: signed.partially_fillable,
};

// Trader has no sell tokens — simulation should revert.
Expand Down
29 changes: 15 additions & 14 deletions crates/e2e/tests/e2e/quote_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use {
price_estimation::BalanceOverridesConfig,
test_util::TestDefault,
},
contracts::ERC20,
contracts::{ERC20, GPv2Settlement},
e2e::setup::*,
ethrpc::{Web3, alloy::CallBuilderExt},
model::{
Expand All @@ -28,7 +28,7 @@ use {
trade_verifier::{PriceQuery, TradeVerifier, TradeVerifying},
},
serde_json::json,
simulator::swap_simulator::SwapSimulator,
simulator::simulation_builder::SettlementSimulator,
std::{collections::HashMap, sync::Arc},
};

Expand Down Expand Up @@ -189,32 +189,33 @@ async fn test_bypass_verification_for_rfq_quotes(web3: Web3) {
.unwrap();
let onchain = OnchainComponents::deployed(web3.clone()).await;
let balance_overrides = Arc::new(BalanceOverrides::default());
let gas_limit = 12_000_000;
let simulator = SwapSimulator::new(
balance_overrides.clone(),
let gas_limit = 12_000_000u64;
let settlement_contract = GPv2Settlement::GPv2Settlement::new(
*onchain.contracts().gp_settlement.address(),
web3.provider.clone(),
);
let simulator = SettlementSimulator::new(
settlement_contract,
Default::default(),
Default::default(),
*onchain.contracts().weth.address(),
block_stream.clone(),
web3.clone(),
gas_limit,
balance_overrides,
block_stream.clone(),
None,
)
.await
.unwrap();

let verifier = TradeVerifier::new(
web3.clone(),
None,
simulator,
None,
Arc::new(web3.clone()),
balance_overrides,
*onchain.contracts().gp_settlement.address(),
BigDecimal::zero(),
Default::default(),
0,
u32::MAX,
)
.await
.unwrap();
);

let verify_trade = |tx_origin| {
let verifier = verifier.clone();
Expand Down
29 changes: 24 additions & 5 deletions crates/orderbook/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2731,31 +2731,50 @@ components:
if omitted.
allOf:
- $ref: "#/components/schemas/Address"
nullable: true
sellTokenBalance:
description: Where the sell token should be drawn from.
allOf:
- $ref: "#/components/schemas/SellTokenSource"
default: erc20
buyTokenBalance:
description: Where the buy token should be transferred to.
allOf:
- $ref: "#/components/schemas/BuyTokenDestination"
default: erc20
appData:
description: >
Full app data JSON string. Defaults to `"{}"` if omitted.
Full app data JSON string.
type: string
nullable: true
blockNumber:
type: integer
nullable: true
signingScheme:
$ref: "#/components/schemas/SigningScheme"
signature:
$ref: "#/components/schemas/Signature"
feeAmount:
description: >
The fee amount in sell token atoms. Expected to be 0; only present
because it must be part of the signed order data.
allOf:
- $ref: "#/components/schemas/TokenAmount"
validTo:
description: Unix timestamp (`uint32`) until which the order is valid.
type: integer
partiallyFillable:
description: Whether the order can be partially filled or must be filled all at once.
type: boolean
required:
- sellToken
- buyToken
- sellAmount
- buyAmount
- kind
- owner
- signingScheme
- signature
Comment on lines +2772 to +2773
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

OrderSimulationRequest in crates/orderbook/src/dto/mod.rs declares app_data: String, fee_amount: U256, valid_to: u32, partially_fillable: bool - none Option, none #[serde(default)]. Serde will 422 when any is missing.

Suggested change
- signingScheme
- signature
- signingScheme
- signature
- feeAmount
- validTo
- partiallyFillable

- feeAmount
- validTo
- partiallyFillable
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

appData is missing.

- appData
OrderSimulation:
description: >
The Tenderly simulation request for an order, along with any
Expand Down
23 changes: 18 additions & 5 deletions crates/orderbook/src/dto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ pub mod order;
use {
alloy::primitives::U256,
eth_domain_types::{Address, NonZeroU256},
model::order::{BuyTokenDestination, OrderKind, SellTokenSource},
model::{
order::{BuyTokenDestination, OrderKind, SellTokenSource},
signature::Signature,
},
number::serialization::HexOrDecimalU256,
serde::{Deserialize, Serialize},
serde_with::serde_as,
Expand Down Expand Up @@ -45,12 +48,22 @@ pub struct OrderSimulationRequest {
/// token transfer or internal Balancer Vault transfer.
#[serde(default)]
pub buy_token_balance: BuyTokenDestination,
/// Full app data JSON. Defaults to `"{}"` if omitted.
#[serde(default)]
pub app_data: Option<String>,
/// Full app data JSON.
pub app_data: String,
/// The block number at which the simulation should happen
#[serde(default)]
pub block_number: Option<u64>,
/// The order signature (signing scheme + bytes). Required to pass
/// signature verification in the settlement contract during simulation.
#[serde(flatten)]
pub signature: Signature,
/// The fee amount signed by the user. This field is expected to be 0 and
/// only still there because it needs to be signed by the user.
pub fee_amount: U256,
/// UNIX timestamp when the order will expire.
pub valid_to: u32,
/// Whether the order needs to be filled all at once or allows to be filled
/// over multiple partial executions.
pub partially_fillable: bool,
}

/// The result of Order simulation, contains the error (if any)
Expand Down
1 change: 0 additions & 1 deletion crates/orderbook/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ pub mod database;
pub mod dto;
mod ipfs;
mod ipfs_app_data;
pub mod order_simulator;
pub mod orderbook;
mod quoter;
pub mod run;
Expand Down
Loading
Loading