Skip to content
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

Use external prices for conversion of fees in autopilot #2863

Merged
merged 2 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion crates/autopilot/src/domain/settlement/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl Settlement {
gas_price: self.transaction.effective_gas_price,
surplus: self.solution.native_surplus(&self.auction),
fee: self.solution.native_fee(&self.auction.prices),
order_fees: self.solution.fees(),
order_fees: self.solution.fees(&self.auction.prices),
}
}
}
Expand Down
15 changes: 12 additions & 3 deletions crates/autopilot/src/domain/settlement/solution/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,13 @@ impl Solution {
}

/// Returns fees denominated in sell token for each order in the solution.
pub fn fees(&self) -> HashMap<domain::OrderUid, Option<eth::SellTokenAmount>> {
pub fn fees(
&self,
prices: &auction::Prices,
) -> HashMap<domain::OrderUid, Option<eth::SellTokenAmount>> {
self.trades
.iter()
.map(|trade| (*trade.order_uid(), trade.fee().ok()))
.map(|trade| (*trade.order_uid(), trade.fee_in_sell_token(prices).ok()))
.collect()
}

Expand Down Expand Up @@ -307,9 +310,15 @@ mod tests {
eth::U256::from(52937525819789126u128)
);
// fee read from "executedSurplusFee" https://api.cow.fi/mainnet/api/v1/orders/0x10dab31217bb6cc2ace0fe601c15d342f7626a1ee5ef0495449800e73156998740a50cf069e992aa4536211b23f286ef88752187ffffffff
// "executedSurplusFee" and native fee are equal because the sell token is ETH
assert_eq!(
solution.native_fee(&auction.prices).0,
eth::U256::from(6890975030480504u128)
eth::U256::from(6752697350740628u128)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here we see that for this specific example, difference is ~2% if we use external prices vector for conversion. Seems acceptable.

);
// fee read from "executedSurplusFee" https://api.cow.fi/mainnet/api/v1/orders/0x10dab31217bb6cc2ace0fe601c15d342f7626a1ee5ef0495449800e73156998740a50cf069e992aa4536211b23f286ef88752187ffffffff
assert_eq!(
solution.fees(&auction.prices),
HashMap::from([(domain::OrderUid(hex!("10dab31217bb6cc2ace0fe601c15d342f7626a1ee5ef0495449800e73156998740a50cf069e992aa4536211b23f286ef88752187ffffffff")), Some(eth::SellTokenAmount(eth::U256::from(6752697350740628u128))))])
);
}
}
56 changes: 37 additions & 19 deletions crates/autopilot/src/domain/settlement/solution/trade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,36 +136,54 @@ impl Trade {
pub fn native_fee(&self, prices: &auction::Prices) -> Result<eth::Ether, Error> {
let fee = self.fee()?;
let price = prices
.get(&self.sell.token)
.ok_or(Error::MissingPrice(self.sell.token))?;
Ok(price.in_eth(fee.into()))
.get(&fee.token)
.ok_or(Error::MissingPrice(fee.token))?;
Ok(price.in_eth(fee.amount))
}

/// Total fee (protocol fee + network fee). Equal to a surplus difference
/// before and after applying the fees.
///
/// Denominated in SELL token
pub fn fee(&self) -> Result<eth::SellTokenAmount, Error> {
pub fn fee_in_sell_token(
&self,
prices: &auction::Prices,
) -> Result<eth::SellTokenAmount, Error> {
let fee = self.fee()?;
let fee_in_sell_token = match self.side {
order::Side::Buy => fee.amount,
order::Side::Sell => {
let buy_price = prices
.get(&self.buy.token)
.ok_or(Error::MissingPrice(self.buy.token))?;
let sell_price = prices
.get(&self.sell.token)
.ok_or(Error::MissingPrice(self.sell.token))?;
fee.amount
.checked_mul(&buy_price.get().0.into())
.ok_or(error::Math::Overflow)?
.checked_div(&sell_price.get().0.into())
.ok_or(error::Math::DivisionByZero)?
}
}
.into();
Ok(fee_in_sell_token)
}

/// Total fee (protocol fee + network fee). Equal to a surplus difference
/// before and after applying the fees.
///
/// Denominated in SURPLUS token
fn fee(&self) -> Result<eth::Asset, Error> {
let fee = self
.surplus_over_limit_price_before_fee()?
.amount
.checked_sub(&self.surplus_over_limit_price()?.amount)
.ok_or(error::Math::Negative)?;
// We don't have to convert the fee to the sell token, we can just use the fee
// in surplus token. This is done just because it was done like this in
// the previous implementation
//
// https://github.com/cowprotocol/services/blob/main/crates/autopilot/src/decoded_settlement.rs#L345
let fee_in_sell_token = match self.side {
order::Side::Buy => fee,
order::Side::Sell => fee
.checked_mul(&self.prices.uniform.buy.into())
.ok_or(error::Math::Overflow)?
.checked_div(&self.prices.uniform.sell.into())
.ok_or(error::Math::DivisionByZero)?,
}
.into();
Ok(fee_in_sell_token)
Ok(eth::Asset {
token: self.surplus_token(),
amount: fee,
})
}

/// Protocol fees is defined by fee policies attached to the order.
Expand Down
Loading