-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[ON HOLD] Build domain::Settlement
based on /solve
response
#2730
Changes from all commits
33a1e57
c43192d
c7bf825
b31c69b
535d713
f7700f2
72d7d25
3400293
4354517
219a1e3
4afdda3
aba9925
e1bb5da
02ed7ba
74aee00
8f6b35f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
use { | ||
self::trade::Trade, | ||
crate::domain::{ | ||
auction::{self}, | ||
auction::{self, order}, | ||
competition, | ||
eth, | ||
fee, | ||
|
@@ -125,6 +125,71 @@ impl Solution { | |
|
||
Ok(Self { trades, auction_id }) | ||
} | ||
|
||
/// Build a `settlement::Solution` from a `competition::Solution`. | ||
/// | ||
/// Since `competition::Solution` does not contain JIT orders, the resulting | ||
/// `settlement::Solution` might be a subset of it's onchain observable | ||
/// twin. | ||
pub fn from_competition_solution( | ||
solution: &competition::Solution, | ||
auction: &auction::Auction, | ||
auction_id: auction::Id, | ||
) -> Result<Self, error::Solution> { | ||
let auction_orders = auction | ||
.orders | ||
.iter() | ||
.map(|o| (o.uid, o)) | ||
.collect::<HashMap<_, _>>(); | ||
|
||
let mut trades = Vec::with_capacity(solution.orders().len()); | ||
for (order_uid, traded) in solution.orders().iter() { | ||
let order = auction_orders | ||
.get(order_uid) | ||
.ok_or(error::Solution::MissingOrder(*order_uid))?; | ||
trades.push(trade::Trade::new( | ||
order.uid, | ||
order.sell, | ||
order.buy, | ||
order.side, | ||
match order.side { | ||
order::Side::Sell => traded.sell.0.into(), | ||
order::Side::Buy => traded.buy.0.into(), | ||
}, | ||
trade::Prices { | ||
uniform: trade::ClearingPrices { | ||
sell: solution | ||
.prices() | ||
.get(&order.sell.token) | ||
.ok_or(error::Solution::MissingClearingPrice(order.sell.token))? | ||
.get() | ||
.into(), | ||
buy: solution | ||
.prices() | ||
.get(&order.buy.token) | ||
.ok_or(error::Solution::MissingClearingPrice(order.buy.token))? | ||
.get() | ||
.into(), | ||
}, | ||
custom: trade::ClearingPrices { | ||
// settlement contract uses this formula to convert executed amounts: | ||
// SELL order: executedBuyAmount = executed * sellPrice / buyPrice; | ||
// BUY order: executedSellAmount = executed * buyPrice / sellPrice; | ||
// | ||
// With an example of converting 1 GNO for 100 DAI: | ||
// SELL order: executedBuyAmount = 1 * 100 / 1 = 100 => | ||
// (sellPrice = 100, buyPrice = 1) | ||
// BUY order: executedSellAmount = 100 * 1 / 100 = 1 => | ||
// (sellPrice = 100, buyPrice = 1) | ||
Comment on lines
+175
to
+183
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nanonit: if it was for me you could remove this comment (I think it's quite clear that the exchange rate can be represented with the effective buy/sell amounts) |
||
sell: traded.buy.into(), | ||
buy: traded.sell.into(), | ||
}, | ||
}, | ||
)); | ||
} | ||
|
||
Ok(Self { trades, auction_id }) | ||
} | ||
} | ||
|
||
pub mod error { | ||
|
@@ -159,6 +224,14 @@ pub mod error { | |
} | ||
} | ||
} | ||
|
||
#[derive(Debug, thiserror::Error)] | ||
pub enum Solution { | ||
#[error("order not found in the auction for uid {0:?}")] | ||
MissingOrder(OrderUid), | ||
#[error("referenced clearing price missing for token {0:?}")] | ||
MissingClearingPrice(eth::TokenAddress), | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -146,6 +146,33 @@ impl RunLoop { | |
} | ||
}; | ||
|
||
{ | ||
// Also calculate the score from the solution itself | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a temporary code that will be replaced when we switch to using autopilot calculated score. So did not spend too much time polishing it. It's used to detect differences in driver/autopilot score calculations. |
||
// For now, don't actually use it for ranking, instead log differences to solver | ||
// provided score for debugging purposes. | ||
let policies = auction | ||
.orders | ||
.iter() | ||
.map(|order| (order.uid, order.protocol_fees.clone())) | ||
.collect(); | ||
let settlement_solution = domain::settlement::Solution::from_competition_solution( | ||
solution, &auction, auction_id, | ||
) | ||
.map(|s| s.score(&auction.prices, &policies)); | ||
|
||
if let Ok(Ok(score)) = settlement_solution { | ||
if score != solution.score() { | ||
tracing::warn!( | ||
"score mismatch: solver provided score: {:?}, calculated score: {:?}", | ||
solution.score(), | ||
score | ||
); | ||
} | ||
} else { | ||
tracing::warn!(?settlement_solution, "failed to calculate score"); | ||
} | ||
} | ||
|
||
let order_uids = solution.order_ids().copied().collect(); | ||
self.persistence | ||
.store_order_events(order_uids, OrderEventLabel::Considered); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: