Skip to content

refactor quoting interfaces to work with full competition - #4714

Open
MartinquaXD wants to merge 3 commits into
send-auction-id-in-quotesfrom
refactor-quote-interfaces
Open

refactor quoting interfaces to work with full competition#4714
MartinquaXD wants to merge 3 commits into
send-auction-id-in-quotesfrom
refactor-quote-interfaces

Conversation

@MartinquaXD

@MartinquaXD MartinquaXD commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Description

In order to actually store a full quote competition in the DB as if it were a regular auction we need to update the quoting related types and interfaces. Actually writing the competition data to the DB will happen in a follow up PR.

Changes

  • storing function now takes QuoteCompetition which contains all quotes and only returns the new quote id. If a full quote + id is needed the caller can assemble it themselves
  • adjusted quote stream to continuously update the same QuoteCompetition - will become relevant in the follow up PR
  • updates unit tests to new interface

How to test

only an interface change - all tests should still pass

Related Issues

BE-56

@MartinquaXD
MartinquaXD requested a review from a team as a code owner August 6, 2026 21:18
@MartinquaXD

Copy link
Copy Markdown
Contributor Author

@claude

@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

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


PR Review: refactor quoting interfaces to work with full competition

I reviewed the diff against origin/send-auction-id-in-quotes. This is a clean, well-documented refactor — the new QuoteCompetition/QuoteRequest/QuoteResponse/QuoteCompetitionMetadata split reads clearly, and the interface changes are threaded consistently through orderbook, autopilot, and the shared quoting logic.

I verified the two trickiest pieces:

  • Streaming ranking — building RankedEstimates::new(new_best, quotes.iter().rev()) relies on the inner stream only forwarding strictly-improving quotes. I confirmed that contract in CompetitionEstimator::estimate_stream (crates/price-estimation/src/competition/quote.rs), so the best-to-worst ordering holds. ✅
  • to_final_quote equivalence — the extracted fee/scaling logic (additional cost, SellAmount::BeforeFee scaling, SellAmountDoesNotCoverFee) matches the previous inline logic in both calculate_quote and the streaming path. with_additional_cost/with_scaled_sell_amount don't mutate data, so what's persisted is unchanged. ✅

Two minor points posted as inline comments (both non-blocking):

  1. Doc comment referencing a non-existent winning_quote() method.
  2. The .expect() on quotes.first() combined with the public quotes field / placeholder-injecting Default is a latent API foot-gun — a smart constructor would make the non-empty invariant structural.

The DB-side // TODO populate competition_auctions ... and the "later iterations update the DB state" behavior are explicitly deferred to the follow-up PR per the description, so I didn't flag those.

Nothing blocking from my side.
· refactor-quote-interfaces

Comment thread crates/shared/src/order_quoting.rs Outdated
Comment thread crates/shared/src/order_quoting.rs Outdated
@MartinquaXD
MartinquaXD force-pushed the send-auction-id-in-quotes branch from 851e5a7 to 23d1393 Compare August 7, 2026 11:31
@MartinquaXD
MartinquaXD force-pushed the refactor-quote-interfaces branch from 4007722 to 558df31 Compare August 7, 2026 12:06

@squadgazzz squadgazzz left a comment

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.

LGTM! The separation using to_final_quote makes sense to me.

pub auction_id: Option<AuctionId>,
}

/// Collection of data that describes the full quote comptition (request,

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.

Suggested change
/// Collection of data that describes the full quote comptition (request,
/// Collection of data that describes the full quote competition (request,

@AryanGodara AryanGodara left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

again, just some questions/doubts, Otherwise gg 👌🏼

let row = create_quote_row(data)?;
let row = create_quote_row(&data)?;
let id = database::quotes::save(&mut ex, &row).await?;
// TODO populate `competition_auctions`, `proposed_solutions`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

you're already working on this PR right? 👀 (confirming that it's not meant to stay as a TODO for long)

verified: data.verified,
metadata: data.metadata.try_into()?,
auction_id: None,
auction_id: competition.metadata.auction_id,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this is a change to how DB is filled. But yeah, techincally still an interface change, that's in TODO

// Validate the fee doesn't exceed the requested input by deriving the
// final quote once. Callers can re-derive it later via
// `QuoteCompetition::to_final_quote`.
let _ = competition.to_final_quote(&parameters)?;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this function builds the final quote just to surface the fee error and drops it; each caller rebuilds it + sets the id. Could it hand back the assembled Quote to kill the double-compute? (Or is this it trivial to create)

metadata: quote.data.metadata.try_into()?,
auction_id: None,
metadata: quote.data.metadata.clone().try_into()?,
auction_id: quote.data.auction_id,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This propagates auction_id into order_quotes for the onchain orders' path, but fast-path orders come in through the regular API/DB route, (ie, orderbook/database/orders.rs:209), which still sets this to None. And since model::OrderQuote has no auction_id field, it's stuck at None. So the orders that actually get an auction_id won't persist it here. Is wiring that through OrderQuote + the regular path the next PR? (i think this is in line with this comment on #4712)

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.

3 participants