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

Executed total fee token #2966

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
21 changes: 19 additions & 2 deletions crates/autopilot/src/domain/settlement/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,27 @@ impl Settlement {
}

/// Per order fees breakdown. Contains all orders from the settlement
pub fn fee_breakdown(&self) -> HashMap<domain::OrderUid, Option<trade::FeeBreakdown>> {
pub fn fee_breakdown(&self) -> HashMap<domain::OrderUid, trade::FeeBreakdown> {
self.trades
.iter()
.map(|trade| (*trade.uid(), trade.fee_breakdown(&self.auction).ok()))
.map(|trade| {
let fee_breakdown = trade.fee_breakdown(&self.auction).unwrap_or_else(|err| {
tracing::warn!(
?err,
trade = %trade.uid(),
"possible incomplete fee breakdown calculation",
);
trade::FeeBreakdown {
total: eth::Asset {
// TODO surplus token
token: trade.sell_token(),
amount: num::zero(),
},
protocol: vec![],
}
});
(*trade.uid(), fee_breakdown)
})
.collect()
}

Expand Down
14 changes: 10 additions & 4 deletions crates/autopilot/src/domain/settlement/trade/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,9 @@ impl Trade {
pub fn fee_in_ether(&self, prices: &auction::Prices) -> Result<eth::Ether, Error> {
let total_fee = self.fee_in_sell_token()?;
let price = prices
.get(&self.sell.token)
.ok_or(Error::MissingPrice(self.sell.token))?;
Ok(price.in_eth(total_fee.into()))
.get(&total_fee.token)
.ok_or(Error::MissingPrice(total_fee.token))?;
Ok(price.in_eth(total_fee.amount))
}

/// Converts given surplus fee into sell token fee.
Expand All @@ -134,9 +134,15 @@ impl Trade {

/// Total fee (protocol fee + network fee). Equal to a surplus difference
/// before and after applying the fees.
pub fn fee_in_sell_token(&self) -> Result<eth::SellTokenAmount, Error> {
///
/// Denominated in SELL token
Comment on lines +137 to +138
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need this clarification here since the function name is self-explanatory already?

pub fn fee_in_sell_token(&self) -> Result<eth::Asset, Error> {
let fee = self.fee()?;
self.fee_into_sell_token(fee.amount)
.map(|amount| eth::Asset {
token: self.sell.token,
amount: amount.into(),
})
}

/// Total fee (protocol fee + network fee). Equal to a surplus difference
Expand Down
11 changes: 9 additions & 2 deletions crates/autopilot/src/domain/settlement/trade/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ impl Trade {
Ok(FeeBreakdown { total, protocol })
}

pub fn sell_token(&self) -> eth::TokenAddress {
match self {
Self::Fulfillment(trade) => trade.sell.token,
Self::Jit(trade) => trade.sell.token,
}
}

pub fn new(trade: transaction::EncodedTrade, auction: &super::Auction, created: u32) -> Self {
if auction.orders.contains_key(&trade.uid) {
Trade::Fulfillment(Fulfillment {
Expand Down Expand Up @@ -150,8 +157,8 @@ pub struct Jit {
#[derive(Debug, Clone)]
pub struct FeeBreakdown {
/// Total fee the trade was charged (network fee + protocol fee)
// TODO: express in surplus token
pub total: eth::SellTokenAmount,
// TODO surplus token
pub total: eth::Asset,
/// Breakdown of protocol fees.
pub protocol: Vec<ExecutedProtocolFee>,
}
Expand Down
27 changes: 10 additions & 17 deletions crates/autopilot/src/infra/persistence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,28 +645,21 @@ impl Persistence {
.await;

for (order, order_fee) in fee_breakdown {
let total_fee = order_fee
.as_ref()
.map(|fee| u256_to_big_decimal(&fee.total.0))
.unwrap_or_default();
let executed_protocol_fees = order_fee
.map(|fee| {
fee.protocol
.into_iter()
.map(|executed| Asset {
token: ByteArray(executed.fee.token.0 .0),
amount: u256_to_big_decimal(&executed.fee.amount.0),
})
.collect::<Vec<_>>()
})
.unwrap_or_default();
database::order_execution::save(
&mut ex,
&ByteArray(order.0),
auction_id,
block_number,
&total_fee,
&executed_protocol_fees,
&u256_to_big_decimal(&order_fee.total.amount.0),
&ByteArray(order_fee.total.token.0 .0),
&order_fee
.protocol
.into_iter()
.map(|executed| Asset {
token: ByteArray(executed.fee.token.0 .0),
amount: u256_to_big_decimal(&executed.fee.amount.0),
})
.collect::<Vec<_>>(),
)
.await?;
}
Expand Down
1 change: 1 addition & 0 deletions crates/database/src/jit_orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ NULL AS ethflow_data,
NULL AS onchain_user,
NULL AS onchain_placement_error,
COALESCE((SELECT SUM(surplus_fee) FROM order_execution oe WHERE oe.order_uid = o.uid), 0) as executed_surplus_fee,
COALESCE((SELECT surplus_fee_token FROM order_execution oe WHERE oe.order_uid = o.uid), o.sell_token) as executed_surplus_fee_token, -- TODO surplus token
NULL AS full_app_data
"#;

Expand Down
23 changes: 17 additions & 6 deletions crates/database/src/order_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub async fn save(
auction: AuctionId,
block_number: i64,
executed_fee: &BigDecimal,
executed_fee_token: &Address,
executed_protocol_fees: &[Asset],
) -> Result<(), sqlx::Error> {
let (protocol_fee_tokens, protocol_fee_amounts): (Vec<_>, Vec<_>) = executed_protocol_fees
Expand All @@ -27,16 +28,17 @@ pub async fn save(
.unzip();

const QUERY: &str = r#"
INSERT INTO order_execution (order_uid, auction_id, reward, surplus_fee, block_number, protocol_fee_tokens, protocol_fee_amounts)
VALUES ($1, $2, $3, $4, $5, $6, $7)
INSERT INTO order_execution (order_uid, auction_id, reward, surplus_fee, surplus_fee_token, block_number, protocol_fee_tokens, protocol_fee_amounts)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
ON CONFLICT (order_uid, auction_id)
DO UPDATE SET reward = $3, surplus_fee = $4, block_number = $5, protocol_fee_tokens = $6, protocol_fee_amounts = $7
DO UPDATE SET reward = $3, surplus_fee = $4, surplus_fee_token = $5, block_number = $6, protocol_fee_tokens = $7, protocol_fee_amounts = $8
;"#;
sqlx::query(QUERY)
.bind(order)
.bind(auction)
.bind(0.) // reward is deprecated but saved for historical analysis
.bind(Some(executed_fee))
.bind(executed_fee_token)
.bind(block_number)
.bind(protocol_fee_tokens)
.bind(protocol_fee_amounts)
Expand Down Expand Up @@ -124,16 +126,25 @@ mod tests {
1,
0,
&Default::default(),
&Default::default(),
protocol_fees.as_slice(),
)
.await
.unwrap();

// save entry without protocol fees (simulate case when we are still not
sunce86 marked this conversation as resolved.
Show resolved Hide resolved
// calculating them)
save(&mut db, &Default::default(), 2, 0, &Default::default(), &[])
.await
.unwrap();
save(
&mut db,
&Default::default(),
2,
0,
&Default::default(),
&Default::default(),
&[],
)
.await
.unwrap();

let keys: Vec<(AuctionId, OrderUid)> = vec![
(1, Default::default()),
Expand Down
8 changes: 7 additions & 1 deletion crates/database/src/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ pub struct FullOrder {
pub onchain_user: Option<Address>,
pub onchain_placement_error: Option<OnchainOrderPlacementError>,
pub executed_surplus_fee: BigDecimal,
pub executed_surplus_fee_token: Address,
pub full_app_data: Option<Vec<u8>>,
}

Expand Down Expand Up @@ -549,6 +550,7 @@ array(Select (p.target, p.value, p.data) from interactions p where p.order_uid =
(SELECT onchain_o.sender from onchain_placed_orders onchain_o where onchain_o.uid = o.uid limit 1) as onchain_user,
(SELECT onchain_o.placement_error from onchain_placed_orders onchain_o where onchain_o.uid = o.uid limit 1) as onchain_placement_error,
COALESCE((SELECT SUM(surplus_fee) FROM order_execution oe WHERE oe.order_uid = o.uid), 0) as executed_surplus_fee,
COALESCE((SELECT surplus_fee_token FROM order_execution oe WHERE oe.order_uid = o.uid), o.sell_token) as executed_surplus_fee_token, -- TODO surplus token
(SELECT full_app_data FROM app_data ad WHERE o.app_data = ad.contract_app_data LIMIT 1) as full_app_data
"#;

Expand Down Expand Up @@ -1767,7 +1769,7 @@ mod tests {
assert_eq!(order.executed_surplus_fee, fee);

let fee: BigDecimal = 1.into();
crate::order_execution::save(&mut db, &order_uid, 1, 0, &fee, &[])
crate::order_execution::save(&mut db, &order_uid, 1, 0, &fee, &Default::default(), &[])
.await
.unwrap();

Expand Down Expand Up @@ -1890,6 +1892,7 @@ mod tests {
1,
1,
&BigDecimal::from(1),
&Default::default(),
Default::default(),
)
.await
Expand All @@ -1900,6 +1903,7 @@ mod tests {
2,
2,
&BigDecimal::from(2),
&Default::default(),
Default::default(),
)
.await
Expand All @@ -1910,6 +1914,7 @@ mod tests {
3,
0,
&BigDecimal::from(4),
&Default::default(),
Default::default(),
)
.await
Expand All @@ -1920,6 +1925,7 @@ mod tests {
2,
3,
&BigDecimal::from(4),
&Default::default(),
Default::default(),
)
.await
Expand Down
3 changes: 3 additions & 0 deletions crates/model/src/order.rs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ pub struct OrderMetadata {
pub executed_fee_amount: U256,
#[serde_as(as = "HexOrDecimalU256")]
pub executed_surplus_fee: U256,
pub executed_surplus_fee_token: H160,
pub invalidated: bool,
pub status: OrderStatus,
#[serde(flatten)]
Expand Down Expand Up @@ -1061,6 +1062,7 @@ mod tests {
"appData": "0x6000000000000000000000000000000000000000000000000000000000000007",
"feeAmount": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"executedSurplusFee": "1",
"executedSurplusFeeToken": "0x000000000000000000000000000000000000000a",
"fullFeeAmount": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"solverFee": "115792089237316195423570985008687907853269984665640564039457584007913129639935",
"kind": "buy",
Expand Down Expand Up @@ -1092,6 +1094,7 @@ mod tests {
executed_sell_amount_before_fees: 4.into(),
executed_fee_amount: 1.into(),
executed_surplus_fee: 1.into(),
executed_surplus_fee_token: H160::from_low_u64_be(10),
invalidated: true,
status: OrderStatus::Open,
settlement_contract: H160::from_low_u64_be(2),
Expand Down
7 changes: 6 additions & 1 deletion crates/orderbook/openapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -885,7 +885,12 @@ components:
description: Surplus fee that the limit order was executed with.
allOf:
- $ref: "#/components/schemas/BigUint"
nullable: true
nullable: false
executedSurplusFeeToken:
description: Token of the surplus fee.
sunce86 marked this conversation as resolved.
Show resolved Hide resolved
allOf:
- $ref: "#/components/schemas/Address"
nullable: false
fullAppData:
description: |
Full `appData`, which the contract-level `appData` is a hash of. See `OrderCreation`
Expand Down
2 changes: 2 additions & 0 deletions crates/orderbook/src/database/orders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,7 @@ fn full_order_into_model_order(order: FullOrder) -> Result<Order> {
.context("executed fee amount is not a valid u256")?,
executed_surplus_fee: big_decimal_to_u256(&order.executed_surplus_fee)
.context("executed surplus fee is not a valid u256")?,
executed_surplus_fee_token: H160(order.executed_surplus_fee_token.0),
invalidated: order.invalidated,
status,
is_liquidity_order: class == OrderClass::Liquidity,
Expand Down Expand Up @@ -638,6 +639,7 @@ mod tests {
onchain_user: None,
onchain_placement_error: None,
executed_surplus_fee: Default::default(),
executed_surplus_fee_token: ByteArray([1; 20]), // TODO surplus token
full_app_data: Default::default(),
};

Expand Down
1 change: 1 addition & 0 deletions crates/shared/src/db_order_conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ pub fn full_order_into_model_order(order: database::orders::FullOrder) -> Result
.context("executed fee amount is not a valid u256")?,
executed_surplus_fee: big_decimal_to_u256(&order.executed_surplus_fee)
.context("executed surplus fee is not a valid u256")?,
executed_surplus_fee_token: H160(order.executed_surplus_fee_token.0),
invalidated: order.invalidated,
status,
is_liquidity_order: class == OrderClass::Liquidity,
Expand Down
3 changes: 2 additions & 1 deletion database/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ Protocol fee tokens/amounts are stored in the same order as fee policies in fee_
order\_uid | bytea | not null | which order this trade execution is related to
auction\_id | bigint | not null | in which auction this trade was initiated
reward | double | not null | revert adjusted solver rewards, deprecated in favor of [CIP-20](https://snapshot.org/#/cow.eth/proposal/0x2d3f9bd1ea72dca84b03e97dda3efc1f4a42a772c54bd2037e8b62e7d09a491f)
surplus\_fee | numeric | nullable | dynamic fee computed by the protocol that should get taken from the surplus of a trade, this value only applies and is set for fill-or-kill limit orders.
surplus\_fee | numeric | not null | total fee taken for execution of the trade
sunce86 marked this conversation as resolved.
Show resolved Hide resolved
surplus\_fee\_token | bytea | not null | token in which the surplus fee is taken
block\_number | bigint | not null | block in which the order was executed
protocol\_fee\_tokens | bytea[] | not null | tokens in which the protocol fees are taken
protocol\_fee\_amounts | numeric[] | not null | amounts of protocol fees taken, aligned protocol\_fee\_tokens array
Expand Down
21 changes: 21 additions & 0 deletions database/sql/V071__surplus_fee_token.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- Add a new column to the order_execution table to store the surplus fee token
ALTER TABLE order_execution
ADD COLUMN surplus_fee_token bytea NOT NULL DEFAULT '\x0000000000000000000000000000000000000000';

-- Now populate existing rows with the sell token taken from the 'orders' table, or if it doesn't exist, try from 'jit_orders'.
UPDATE order_execution oe
SET surplus_fee_token = COALESCE(
sub.sell_token, '\x0000000000000000000000000000000000000000'
)
FROM (
SELECT o.uid, o.sell_token
FROM orders o
UNION
SELECT j.uid, j.sell_token
FROM jit_orders j
WHERE NOT EXISTS (SELECT 1 FROM orders WHERE orders.uid = j.uid)
) AS sub
WHERE oe.order_uid = sub.uid;

-- Drop the default value for the surplus_fee_token column
ALTER TABLE order_execution ALTER COLUMN surplus_fee_token DROP DEFAULT;
Loading