Skip to content

Commit

Permalink
Add more notify call for scoring (#2612)
Browse files Browse the repository at this point in the history
# Description
Add more notify call for scoring

# Changes
Add notify calls for the following score errors:
- `InvalidExecutedAmount`
- `MissingPrice(TokenAddress)`
- `CustomPrice(String)`

## How to test
1. e2e
2. unit test

## Related Issues
Fixes #2597
  • Loading branch information
m-lord-renkse authored Apr 22, 2024
1 parent 478b26d commit 03748ae
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 50 deletions.
5 changes: 3 additions & 2 deletions crates/driver/src/domain/competition/solution/fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
use {
super::{
error::Math,
trade::{self, ClearingPrices, Fee, Fulfillment},
trade::{ClearingPrices, Fee, Fulfillment},
},
crate::domain::{
competition::{
order,
order::{FeePolicy, Side},
solution::error::Trade,
PriceLimits,
},
eth::{self},
Expand Down Expand Up @@ -288,7 +289,7 @@ pub enum Error {
#[error(transparent)]
Math(#[from] Math),
#[error(transparent)]
Fulfillment(#[from] trade::Error),
Fulfillment(#[from] Trade),
}

// todo: should be removed once integration tests are implemented
Expand Down
30 changes: 27 additions & 3 deletions crates/driver/src/domain/competition/solution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,9 @@ impl Solution {
.get(&trade.order().buy.token.wrap(self.weth))
.ok_or(error::Scoring::InvalidClearingPrices)?,
};
let custom_prices = trade.calculate_custom_prices(&uniform_prices)?;
let custom_prices = trade
.calculate_custom_prices(&uniform_prices)
.map_err(error::Scoring::CalculateCustomPrices)?;
trades.push(scoring::Trade::new(
trade.order().sell,
trade.order().buy,
Expand All @@ -163,7 +165,7 @@ impl Solution {
}

let scoring = scoring::Scoring::new(trades);
Ok(scoring.score(prices)?)
scoring.score(prices).map_err(error::Scoring::from)
}

/// Approval interactions necessary for encoding the settlement.
Expand Down Expand Up @@ -499,7 +501,29 @@ pub mod error {
InvalidClearingPrices,
#[error(transparent)]
Math(#[from] Math),
#[error("failed to calculate custom prices")]
CalculateCustomPrices(#[source] Trade),
#[error("missing native price for token {0:?}")]
MissingPrice(TokenAddress),
}

impl From<scoring::Error> for Scoring {
fn from(value: scoring::Error) -> Self {
match value {
scoring::Error::MissingPrice(e) => Self::MissingPrice(e),
scoring::Error::Math(e) => Self::Math(e),
scoring::Error::Scoring(e) => e,
}
}
}

#[derive(Debug, thiserror::Error)]
pub enum Trade {
#[error("orders with non solver determined gas cost fees are not supported")]
ProtocolFeeOnStaticOrder,
#[error("invalid executed amount")]
InvalidExecutedAmount,
#[error(transparent)]
Score(#[from] scoring::Error),
Math(#[from] Math),
}
}
6 changes: 3 additions & 3 deletions crates/driver/src/domain/competition/solution/scoring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ impl Trade {
if !i.is_zero() {
current_trade.custom_price = self
.calculate_custom_prices(amount)
.map_err(|e| Error::CustomPrice(e.to_string()))?;
.map_err(Error::Scoring)?;
}
}

Expand Down Expand Up @@ -419,6 +419,6 @@ pub enum Error {
MissingPrice(eth::TokenAddress),
#[error(transparent)]
Math(#[from] Math),
#[error("failed to calculate custom price {0:?}")]
CustomPrice(String),
#[error("scoring: failed to calculate custom price for the applied fee policy {0:?}")]
Scoring(#[source] error::Scoring),
}
30 changes: 10 additions & 20 deletions crates/driver/src/domain/competition/solution/trade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl Fulfillment {
order: competition::Order,
executed: order::TargetAmount,
fee: Fee,
) -> Result<Self, Error> {
) -> Result<Self, error::Trade> {
// If the order is partial, the total executed amount can be smaller than
// the target amount. Otherwise, the executed amount must be equal to the target
// amount.
Expand All @@ -54,7 +54,7 @@ impl Fulfillment {
executed
.0
.checked_add(fee.0)
.ok_or(Error::InvalidExecutedAmount)?,
.ok_or(error::Trade::InvalidExecutedAmount)?,
);
match order.partial {
order::Partial::Yes { available } => executed_with_fee <= available,
Expand All @@ -76,7 +76,7 @@ impl Fulfillment {
fee,
})
} else {
Err(Error::InvalidExecutedAmount)
Err(error::Trade::InvalidExecutedAmount)
}
}

Expand All @@ -86,7 +86,7 @@ impl Fulfillment {
pub fn calculate_custom_prices(
&self,
uniform_prices: &ClearingPrices,
) -> Result<scoring::CustomClearingPrices, error::Scoring> {
) -> Result<scoring::CustomClearingPrices, error::Trade> {
Ok(scoring::CustomClearingPrices {
sell: match self.order().side {
Side::Sell => self
Expand Down Expand Up @@ -147,7 +147,7 @@ impl Fulfillment {
}

/// The effective amount that left the user's wallet including all fees.
pub fn sell_amount(&self, prices: &ClearingPrices) -> Result<eth::TokenAmount, Error> {
pub fn sell_amount(&self, prices: &ClearingPrices) -> Result<eth::TokenAmount, error::Trade> {
let before_fee = match self.order.side {
order::Side::Sell => self.executed.0,
order::Side::Buy => self
Expand All @@ -164,7 +164,7 @@ impl Fulfillment {
}

/// The effective amount the user received after all fees.
pub fn buy_amount(&self, prices: &ClearingPrices) -> Result<eth::TokenAmount, Error> {
pub fn buy_amount(&self, prices: &ClearingPrices) -> Result<eth::TokenAmount, error::Trade> {
let amount = match self.order.side {
order::Side::Buy => self.executed.0,
order::Side::Sell => self
Expand All @@ -187,7 +187,7 @@ impl Fulfillment {
limit_sell: eth::U256,
limit_buy: eth::U256,
prices: ClearingPrices,
) -> Result<eth::TokenAmount, Error> {
) -> Result<eth::TokenAmount, error::Trade> {
let executed = self.executed().0;
let executed_sell_amount = match self.order().side {
Side::Buy => {
Expand All @@ -206,7 +206,7 @@ impl Fulfillment {
// surplus_fee is always expressed in sell token
self.surplus_fee()
.map(|fee| fee.0)
.ok_or(Error::ProtocolFeeOnStaticOrder)?,
.ok_or(error::Trade::ProtocolFeeOnStaticOrder)?,
)
.ok_or(Math::Overflow)?;
let surplus = match self.order().side {
Expand Down Expand Up @@ -279,7 +279,7 @@ pub struct Jit {
}

impl Jit {
pub fn new(order: order::Jit, executed: order::TargetAmount) -> Result<Self, Error> {
pub fn new(order: order::Jit, executed: order::TargetAmount) -> Result<Self, error::Trade> {
// If the order is partially fillable, the executed amount can be smaller than
// the target amount. Otherwise, the executed amount must be equal to the target
// amount.
Expand All @@ -291,7 +291,7 @@ impl Jit {
if is_valid {
Ok(Self { order, executed })
} else {
Err(Error::InvalidExecutedAmount)
Err(error::Trade::InvalidExecutedAmount)
}
}

Expand All @@ -312,13 +312,3 @@ pub struct Execution {
/// The total amount being bought.
pub buy: eth::Asset,
}

#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("orders with non solver determined gas cost fees are not supported")]
ProtocolFeeOnStaticOrder,
#[error("invalid executed amount")]
InvalidExecutedAmount,
#[error(transparent)]
Math(#[from] Math),
}
11 changes: 10 additions & 1 deletion crates/driver/src/infra/notify/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,16 @@ pub fn scoring_failed(
solution::error::Scoring::InvalidClearingPrices => {
notification::Kind::ScoringFailed(ScoreKind::InvalidClearingPrices)
}
solution::error::Scoring::Math(_) | solution::error::Scoring::Score(_) => return,
solution::error::Scoring::Math(_)
| solution::error::Scoring::CalculateCustomPrices(
solution::error::Trade::Math(_) | solution::error::Trade::ProtocolFeeOnStaticOrder,
) => return,
solution::error::Scoring::CalculateCustomPrices(
solution::error::Trade::InvalidExecutedAmount,
) => notification::Kind::ScoringFailed(ScoreKind::InvalidExecutedAmount),
solution::error::Scoring::MissingPrice(token) => {
notification::Kind::ScoringFailed(ScoreKind::MissingPrice(*token))
}
};

solver.notify(auction_id, Some(solution_id.clone()), notification);
Expand Down
5 changes: 5 additions & 0 deletions crates/driver/src/infra/notify/notification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ pub enum Kind {
pub enum ScoreKind {
/// No clearing prices are present for all trades.
InvalidClearingPrices,
/// The amount executed is invalid: out of range or the fee doesn't match
/// its execution with fee
InvalidExecutedAmount,
/// missing native price for the surplus token
MissingPrice(TokenAddress),
}

#[derive(Debug)]
Expand Down
23 changes: 19 additions & 4 deletions crates/driver/src/infra/solver/dto/notification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
crate::{
domain::{
competition::{auction, solution},
eth,
eth::{self},
},
infra::notify,
util::serialize,
Expand Down Expand Up @@ -38,9 +38,7 @@ impl Notification {
succeeded_once,
}
}
notify::Kind::ScoringFailed(notify::ScoreKind::InvalidClearingPrices) => {
Kind::InvalidClearingPrices
}
notify::Kind::ScoringFailed(scoring) => scoring.into(),
notify::Kind::NonBufferableTokensUsed(tokens) => Kind::NonBufferableTokensUsed {
tokens: tokens.into_iter().map(|token| token.0 .0).collect(),
},
Expand All @@ -67,6 +65,18 @@ impl Notification {
}
}

impl From<notify::ScoreKind> for Kind {
fn from(value: notify::ScoreKind) -> Self {
match value {
notify::ScoreKind::InvalidClearingPrices => Kind::InvalidClearingPrices,
notify::ScoreKind::InvalidExecutedAmount => Kind::InvalidExecutedAmount,
notify::ScoreKind::MissingPrice(token_address) => Kind::MissingPrice {
token_address: token_address.into(),
},
}
}
}

#[serde_as]
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -108,6 +118,11 @@ pub enum Kind {
succeeded_once: bool,
},
InvalidClearingPrices,
#[serde(rename_all = "camelCase")]
MissingPrice {
token_address: eth::H160,
},
InvalidExecutedAmount,
NonBufferableTokensUsed {
tokens: BTreeSet<eth::H160>,
},
Expand Down
6 changes: 6 additions & 0 deletions crates/shared/src/http_solver/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,12 @@ pub enum SolverRejectionReason {
/// Not all trades have clearing prices
InvalidClearingPrices,

/// Invalid executed amount
InvalidExecutedAmount,

/// Missing price for the token address
MissingPrice(H160),

/// Solver balance too low to cover the execution costs.
SolverAccountInsufficientBalance(U256),

Expand Down
5 changes: 5 additions & 0 deletions crates/solvers-dto/src/notification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ pub enum Kind {
succeeded_once: bool,
},
InvalidClearingPrices,
#[serde(rename_all = "camelCase")]
MissingPrice {
token_address: H160,
},
InvalidExecutedAmount,
NonBufferableTokensUsed {
tokens: BTreeSet<H160>,
},
Expand Down
Loading

0 comments on commit 03748ae

Please sign in to comment.