Skip to content

(fast8) E2E tests for the fast-path settlement flow - #4863

Open
MartinquaXD wants to merge 1 commit into
fast-path-7from
fast-path-8
Open

(fast8) E2E tests for the fast-path settlement flow#4863
MartinquaXD wants to merge 1 commit into
fast-path-7from
fast-path-8

Conversation

@MartinquaXD

Copy link
Copy Markdown
Contributor

Description

Finally adds e2e test coverage of a few different things:

  • orders can be settled via fast path
  • all the data is there so that the autopilot can index the trades correctly and the orderbook returns correct data on API calls
  • volume fees get captured
  • order that does not get settled via fast path fails over to regular auction

How to test

this is it

@MartinquaXD
MartinquaXD requested a review from a team as a code owner September 3, 2026 13:28
@claude

claude Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Claude finished @MartinquaXD's task in 3m 5s —— View job


PR Review — E2E tests for the fast-path settlement flow

  • Read the PR diff against origin/fast-path-7
  • Review the new E2E tests and supporting changes
  • Post inline findings + summary

Nice, thorough coverage — the DB-level assertions on quote promotion, competition-table patching, and the compounded volume-fee capture are exactly the invariants worth pinning down, and the fallback test cleanly isolates the regular-auction path.

Only substantive concern is timing-based flakiness in a couple of the wall-clock assertions on loaded CI runners — left two inline comments:

  • The abs_diff(expected) <= 2 check on valid_from (sampled after create_order + a DB query).
  • The 5s exclusivity window in fast_path_regular_auction_fallback, where the immediate Open / valid_from > now asserts race against order-placement latency.

Both are non-blocking. Everything else (fee-ordering assumption, competition-auction proofs, the quote_fastpath_flags deletion now that the flag is supported) checks out.
· branch fast-path-8

Comment on lines +145 to +149
let expected = model::time::now_in_epoch_seconds() + exclusivity.as_secs() as u32;
assert!(
valid_from.abs_diff(expected) <= 2,
"valid_from {valid_from} should be ~{expected} (now + exclusivity)"
);

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.

expected is sampled here — after create_order (an HTTP round-trip) and a DB acquire+query have elapsed — but valid_from was fixed server-side at order-creation time. The abs_diff <= 2 tolerance is therefore really "≤2s of wall time elapsed between order creation and this line". On a loaded CI runner that gap can plausibly exceed 2s, making this assert flaky.

Consider sampling now before create_order and asserting valid_from falls in [before+excl, after+excl], or widening the tolerance.

Comment on lines +281 to +298
// Held out: not settled early by the fast path.
assert_eq!(
services.get_order(&uid).await.unwrap().metadata.status,
OrderStatus::Open
);
let valid_from = {
let mut db = services.db().acquire().await.unwrap();
sqlx::query_scalar::<_, Option<i64>>("SELECT valid_from FROM orders WHERE uid = $1")
.bind(ByteArray(uid.0))
.fetch_one(db.deref_mut())
.await
.unwrap()
.expect("fast-path order has a valid_from") as u32
};
assert!(
valid_from > model::time::now_in_epoch_seconds(),
"valid_from {valid_from} should be in the future (order held out)"
);

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.

With a 5s exclusivity window, both of these assertions race against wall time. valid_from = creation_now + 5s; if create_order + this first get_order / DB read take longer than 5s (possible on a slow/loaded CI runner), the order can already have passed valid_from and been picked up by the regular auction — flipping status away from Open and failing valid_from > now. A larger window (as used in the other tests) would remove the race at the cost of a slightly longer test.

@MartinquaXD MartinquaXD changed the title E2E tests for the fast-path settlement flow (fast8) E2E tests for the fast-path settlement flow Sep 3, 2026
Adds three ignored E2E tests plus supporting registration:

* `fast_path_quote_promotion` — quoting with `enableFastPath` writes
  synthetic competition rows, placing the order patches them to the real
  `order_uid` (both trait and onchain / ethflow paths).
* `fast_path_settle` — the fast path settles the order out of
  competition within the exclusivity window, and never re-appears in a
  regular auction.
* `fast_path_regular_auction_fallback` — when a fast-path order's
  exclusivity elapses without settlement, the regular auction picks it
  up and settles it.
* `fast_path_volume_fees_captured` — configures a protocol volume fee
  and a partner volume fee, then asserts the `/trades` API reports both,
  with the correct policy factors and the buy amount reduced accordingly.

Also removes the now obsolete `quote_fastpath_flags.rs` (previously
asserted that placing a fast-path order was rejected).

Signed-off-by: MartinquaXD <martin@cow.fi>
// 2) The transient `quotes` row must be tagged with the fast-path
// `auction_id`, and that auction id must be present across all
// competition tables written at quote time.
tracing::info!("Verifying competition tables written at quote time");

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.

All these assertions are quite "white box" (knowing how the implementation works) and not really the spirit of our other e2e tests. I think what we should test is that a fast path order gets settled "correctly" (right amounts, etc) before the next real auction is spawned. For this we should use the externally facing API functions that a user would use to look at their trades.

So I think having one fast_path test module with the three cases

  1. Regular order
  2. Ethflow order
  3. Fallback auction

is all we need here.

Comment on lines +259 to +260
// The order still requests the fast path, so the orderbook holds it out of
// the auction until `valid_from`.

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.

This really tests the validFrom feature (which enables wait for CoW), but not the failover. For failover I'd expect we shut down the quote winning solver (so it doesn't settle) and expect the order to be settled by another solver in the first regular auction after the exclusivity period.

fee.token, buy_token,
"fees on a sell order are taken from the buy token"
);
assert!(!fee.amount.is_zero(), "fee amount should be positive");

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.

Here we should probably assert that the amounts are correct to avoid issues with the fee calculation logic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants