From b38c40d4fdd23818e97bbc20163a67ac761f8766 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= <15343819+jmg-duarte@users.noreply.github.com> Date: Fri, 14 Aug 2026 15:14:55 +0100 Subject: [PATCH 1/6] Store trade's gas costs --- crates/autopilot/src/infra/persistence/mod.rs | 11 ++ crates/database/src/trades.rs | 183 ++++++++++++++++-- database/README.md | 3 +- database/sql/V121__trade_gas_cost.sql | 7 + .../V122__trade_gas_cost_covering_index.sql | 6 + 5 files changed, 193 insertions(+), 17 deletions(-) create mode 100644 database/sql/V121__trade_gas_cost.sql create mode 100644 database/sql/V122__trade_gas_cost_covering_index.sql diff --git a/crates/autopilot/src/infra/persistence/mod.rs b/crates/autopilot/src/infra/persistence/mod.rs index ce7c42b0d0..f44221ebed 100644 --- a/crates/autopilot/src/infra/persistence/mod.rs +++ b/crates/autopilot/src/infra/persistence/mod.rs @@ -787,6 +787,17 @@ impl Persistence { ) .await?; + database::trades::attribute_gas_cost( + &mut ex, + EventIndex { + block_number, + log_index, + }, + u256_to_big_decimal(&gas.0), + u256_to_big_decimal(&gas_price.0.0), + ) + .await?; + store_order_events( &mut ex, fee_breakdown.keys().cloned(), diff --git a/crates/database/src/trades.rs b/crates/database/src/trades.rs index 09d6072ae5..52f262e6d4 100644 --- a/crates/database/src/trades.rs +++ b/crates/database/src/trades.rs @@ -126,27 +126,36 @@ pub struct TradeEvent { pub order_uid: OrderUid, } +/// A CTE named `settled` holding the trades one settlement settled. Prefix it +/// to a query that binds the settlement's block number to `$1` and its log +/// index to `$2`. +/// +/// The lower bound is the log index of the previous (lower log index) +/// settlement in the same block, or 0 if there is no previous settlement. +/// `order_uid` is only needed by the read path. +const SETTLED_TRADES_CTE: &str = r#" +WITH previous_settlement AS ( + SELECT COALESCE(MAX(log_index), 0) + FROM settlements + WHERE block_number = $1 AND log_index < $2 +), +settled AS ( + SELECT block_number, log_index, order_uid + FROM trades + WHERE block_number = $1 + AND log_index BETWEEN (SELECT * from previous_settlement) AND $2 +) +"#; + #[instrument(skip_all)] pub async fn get_trades_for_settlement( ex: &mut PgConnection, settlement: EventIndex, ) -> Result, sqlx::Error> { - const QUERY: &str = r#" -WITH - -- The log index in this query is the log index of the settlement event from the previous (lower log index) settlement in the same transaction or 0 if there is no previous settlement. - previous_settlement AS ( - SELECT COALESCE(MAX(log_index), 0) - FROM settlements - WHERE block_number = $1 AND log_index < $2 - ) -SELECT - block_number, - log_index, - order_uid -FROM trades t -WHERE t.block_number = $1 -AND t.log_index BETWEEN (SELECT * from previous_settlement) AND $2 -"#; + const QUERY: &str = const_format::concatcp!( + SETTLED_TRADES_CTE, + "SELECT block_number, log_index, order_uid FROM settled" + ); sqlx::query_as(QUERY) .bind(settlement.block_number) .bind(settlement.log_index) @@ -154,6 +163,39 @@ AND t.log_index BETWEEN (SELECT * from previous_settlement) AND $2 .await } +/// Splits the gas cost of a settlement transaction equally between the trades +/// that settlement settled, storing each trade's share in `trades.gas_cost`. +/// +/// The share is rounded down, so the shares add up to at most the cost +/// attributed to the settlement, short by up to one wei per trade. As with +/// `settlements.gas_used`, a transaction with two settlements attributes its +/// full cost twice, once per settlement. We do not expect this to happen. +#[instrument(skip_all)] +pub async fn attribute_gas_cost( + ex: &mut PgConnection, + settlement: EventIndex, + gas_used: BigDecimal, + effective_gas_price: BigDecimal, +) -> Result<(), sqlx::Error> { + // The divisor is never 0: every row the UPDATE writes comes from `settled`. + const QUERY: &str = const_format::concatcp!( + SETTLED_TRADES_CTE, + "UPDATE trades t + SET gas_cost = FLOOR($3 * $4 / (SELECT COUNT(*) FROM settled)) + FROM settled s + WHERE t.block_number = s.block_number + AND t.log_index = s.log_index" + ); + sqlx::query(QUERY) + .bind(settlement.block_number) + .bind(settlement.log_index) + .bind(gas_used) + .bind(effective_gas_price) + .execute(ex) + .await + .map(|_| ()) +} + #[instrument(skip_all)] pub async fn token_first_trade_block( ex: &mut PgConnection, @@ -550,6 +592,115 @@ mod tests { settlement } + async fn gas_costs(ex: &mut PgConnection) -> Vec<(i64, Option)> { + sqlx::query_as("SELECT log_index, gas_cost FROM trades ORDER BY log_index") + .fetch_all(ex) + .await + .unwrap() + } + + /// A settlement's gas cost is split between the trades it settled, and a + /// second settlement in the same block only takes its own trades. + #[tokio::test] + #[ignore] + async fn postgres_attribute_gas_cost() { + let mut db = PgConnection::connect("postgresql://").await.unwrap(); + let mut db = db.begin().await.unwrap(); + crate::clear_DANGER_(&mut db).await.unwrap(); + + let event = |log_index| EventIndex { + block_number: 0, + log_index, + }; + + // Two settlements in one block: the first settles the trades at log 0 + // and 1, the second those at log 3, 4 and 5. + for log_index in [0, 1, 3, 4, 5] { + let uid = ByteArray([u8::try_from(log_index).unwrap(); 56]); + add_trade( + &mut db, + Default::default(), + uid, + event(log_index), + None, + None, + ) + .await; + } + let first = event(2); + add_settlement(&mut db, first, Default::default(), ByteArray([1; 32]), 1).await; + let second = event(6); + add_settlement(&mut db, second, Default::default(), ByteArray([2; 32]), 2).await; + + // Nothing is attributed until the settlement is observed. + assert!( + gas_costs(&mut db) + .await + .iter() + .all(|(_, cost)| cost.is_none()) + ); + + attribute_gas_cost(&mut db, first, 100.into(), 10.into()) + .await + .unwrap(); + + // 1000 wei split between the first settlement's 2 trades. The second + // settlement's trades are untouched. + assert_eq!( + gas_costs(&mut db).await, + vec![ + (0, Some(500.into())), + (1, Some(500.into())), + (3, None), + (4, None), + (5, None), + ] + ); + + // 700 wei over 3 trades does not divide evenly. The share rounds down, + // so the shares never add up to more than the transaction paid. + attribute_gas_cost(&mut db, second, 70.into(), 10.into()) + .await + .unwrap(); + assert_eq!( + gas_costs(&mut db).await, + vec![ + (0, Some(500.into())), + (1, Some(500.into())), + (3, Some(233.into())), + (4, Some(233.into())), + (5, Some(233.into())), + ] + ); + } + + /// A settlement that settled no trades must not fail on a zero divisor. + #[tokio::test] + #[ignore] + async fn postgres_attribute_gas_cost_without_trades() { + let mut db = PgConnection::connect("postgresql://").await.unwrap(); + let mut db = db.begin().await.unwrap(); + crate::clear_DANGER_(&mut db).await.unwrap(); + + let settlement = EventIndex { + block_number: 0, + log_index: 0, + }; + add_settlement( + &mut db, + settlement, + Default::default(), + Default::default(), + 1, + ) + .await; + + attribute_gas_cost(&mut db, settlement, 100.into(), 10.into()) + .await + .unwrap(); + assert!(gas_costs(&mut db).await.is_empty()); + } + #[tokio::test] #[ignore] async fn postgres_trades_having_same_settlement_with_and_without_orders() { diff --git a/database/README.md b/database/README.md index 70a42c9630..b8f88b8a2d 100644 --- a/database/README.md +++ b/database/README.md @@ -477,11 +477,12 @@ This table contains data of [`Trade`](https://github.com/cowprotocol/contracts/b sell\_amount | numeric | not null | amount of sell\_token that got taken from the order owner buy\_amount | numeric | not null | amount of buy\_token received by the order owner fee\_amount | numeric | not null | fee amount in sell\_token that got taken in this trade. Note that this amount refers to all or a portion of the static fee\_amount the user signed during the order creation. + gas\_cost | numeric | nullable | this trade's share of its settlement's gas cost in wei, rounded down. `NULL` for settlements observed before the migration that added it. Indexes: - PRIMARY KEY: btree(`block_number`, `log_index`) - trade\_order\_uid: btree (`order_uid`, `block_number`, `log_index`) -- trades_covering: btree(`order_uid`) INCLUDE (`buy_amount`, `sell_amount`, `fee_amount`) +- trades\_covering\_with\_gas\_cost: btree(`order_uid`) INCLUDE (`buy_amount`, `sell_amount`, `fee_amount`, `gas_cost`) ### jit\_orders diff --git a/database/sql/V121__trade_gas_cost.sql b/database/sql/V121__trade_gas_cost.sql new file mode 100644 index 0000000000..f98c60bc6c --- /dev/null +++ b/database/sql/V121__trade_gas_cost.sql @@ -0,0 +1,7 @@ +-- Each trade's share of its settlement's gas cost: `gas_used * +-- effective_gas_price` (V116) split equally between the trades that settlement +-- settled. Stored so order and trade lookups don't re-derive it per fill. +-- +-- Nullable: not backfilled, so only settlements observed after this migration. +ALTER TABLE trades + ADD COLUMN gas_cost numeric(78, 0); diff --git a/database/sql/V122__trade_gas_cost_covering_index.sql b/database/sql/V122__trade_gas_cost_covering_index.sql new file mode 100644 index 0000000000..f408ef2456 --- /dev/null +++ b/database/sql/V122__trade_gas_cost_covering_index.sql @@ -0,0 +1,6 @@ +-- An order's gas cost is the sum of `gas_cost` over its fills. Keep that sum an +-- index-only scan by replacing the existing index with one containing the gas_cost. +CREATE INDEX CONCURRENTLY IF NOT EXISTS trades_covering_with_gas_cost ON trades (order_uid) + INCLUDE (buy_amount, sell_amount, fee_amount, gas_cost); + +DROP INDEX CONCURRENTLY IF EXISTS trades_covering; From 81d731b2eff582083997b37d36fbd75e9c1ed3de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= <15343819+jmg-duarte@users.noreply.github.com> Date: Tue, 18 Aug 2026 09:41:12 +0100 Subject: [PATCH 2/6] Handle low hanging fruit --- database/README.md | 4 ++-- database/sql/V122__trade_gas_cost_covering_index.sql | 6 ------ 2 files changed, 2 insertions(+), 8 deletions(-) delete mode 100644 database/sql/V122__trade_gas_cost_covering_index.sql diff --git a/database/README.md b/database/README.md index b8f88b8a2d..1e2e005818 100644 --- a/database/README.md +++ b/database/README.md @@ -477,12 +477,12 @@ This table contains data of [`Trade`](https://github.com/cowprotocol/contracts/b sell\_amount | numeric | not null | amount of sell\_token that got taken from the order owner buy\_amount | numeric | not null | amount of buy\_token received by the order owner fee\_amount | numeric | not null | fee amount in sell\_token that got taken in this trade. Note that this amount refers to all or a portion of the static fee\_amount the user signed during the order creation. - gas\_cost | numeric | nullable | this trade's share of its settlement's gas cost in wei, rounded down. `NULL` for settlements observed before the migration that added it. + gas\_cost | numeric | nullable | this trade's share of its settlement's gas cost in wei (estimated as `gas_used` * `gas_price`), rounded down. `NULL` for settlements observed before the migration that added it. Indexes: - PRIMARY KEY: btree(`block_number`, `log_index`) - trade\_order\_uid: btree (`order_uid`, `block_number`, `log_index`) -- trades\_covering\_with\_gas\_cost: btree(`order_uid`) INCLUDE (`buy_amount`, `sell_amount`, `fee_amount`, `gas_cost`) +- trades_covering: btree(`order_uid`) INCLUDE (`buy_amount`, `sell_amount`, `fee_amount`) ### jit\_orders diff --git a/database/sql/V122__trade_gas_cost_covering_index.sql b/database/sql/V122__trade_gas_cost_covering_index.sql deleted file mode 100644 index f408ef2456..0000000000 --- a/database/sql/V122__trade_gas_cost_covering_index.sql +++ /dev/null @@ -1,6 +0,0 @@ --- An order's gas cost is the sum of `gas_cost` over its fills. Keep that sum an --- index-only scan by replacing the existing index with one containing the gas_cost. -CREATE INDEX CONCURRENTLY IF NOT EXISTS trades_covering_with_gas_cost ON trades (order_uid) - INCLUDE (buy_amount, sell_amount, fee_amount, gas_cost); - -DROP INDEX CONCURRENTLY IF EXISTS trades_covering; From 120b72388df84a6ec298010f68d9f963c9324451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= <15343819+jmg-duarte@users.noreply.github.com> Date: Tue, 18 Aug 2026 11:37:01 +0100 Subject: [PATCH 3/6] Address JIT comments --- crates/autopilot/src/domain/settlement/mod.rs | 6 + crates/autopilot/src/infra/persistence/mod.rs | 5 + crates/database/src/trades.rs | 123 +++++++++++++++--- database/sql/V121__trade_gas_cost.sql | 3 +- 4 files changed, 120 insertions(+), 17 deletions(-) diff --git a/crates/autopilot/src/domain/settlement/mod.rs b/crates/autopilot/src/domain/settlement/mod.rs index bcdc19cde5..39eedaf64a 100644 --- a/crates/autopilot/src/domain/settlement/mod.rs +++ b/crates/autopilot/src/domain/settlement/mod.rs @@ -88,6 +88,12 @@ impl Settlement { self.solution_uid } + /// The owners whose JIT orders the associated auction treats like user + /// orders. + pub fn surplus_capturing_jit_order_owners(&self) -> &HashSet { + &self.auction.surplus_capturing_jit_order_owners + } + /// Summarizes settlement data required by the autopilot, see /// [`SettlementMetrics`] for details. pub(crate) fn summarize(&self) -> SettlementMetrics<'_> { diff --git a/crates/autopilot/src/infra/persistence/mod.rs b/crates/autopilot/src/infra/persistence/mod.rs index f44221ebed..0c33f36e17 100644 --- a/crates/autopilot/src/infra/persistence/mod.rs +++ b/crates/autopilot/src/infra/persistence/mod.rs @@ -795,6 +795,11 @@ impl Persistence { }, u256_to_big_decimal(&gas.0), u256_to_big_decimal(&gas_price.0.0), + &settlement + .surplus_capturing_jit_order_owners() + .iter() + .map(|owner| ByteArray(owner.0.0)) + .collect::>(), ) .await?; diff --git a/crates/database/src/trades.rs b/crates/database/src/trades.rs index 52f262e6d4..c4b32219f2 100644 --- a/crates/database/src/trades.rs +++ b/crates/database/src/trades.rs @@ -163,34 +163,55 @@ pub async fn get_trades_for_settlement( .await } -/// Splits the gas cost of a settlement transaction equally between the trades -/// that settlement settled, storing each trade's share in `trades.gas_cost`. +/// Splits a settlement's gas cost equally between the user trades it settled, +/// storing each share in `trades.gas_cost`. /// -/// The share is rounded down, so the shares add up to at most the cost -/// attributed to the settlement, short by up to one wei per trade. As with -/// `settlements.gas_used`, a transaction with two settlements attributes its -/// full cost twice, once per settlement. We do not expect this to happen. +/// A trade is a user trade if its order is in the `orders` table, or if its +/// owner is in `surplus_capturing_jit_order_owners`. Every other trade settled +/// a JIT order that only provides liquidity for the user trades, so it gets a +/// share of 0 instead of taking one away from them. +/// +/// Shares round down, so they add up to at most the cost attributed to the +/// settlement. As with `settlements.gas_used`, a transaction with two +/// settlements attributes its full cost twice, once per settlement. We do not +/// expect this to happen. #[instrument(skip_all)] pub async fn attribute_gas_cost( ex: &mut PgConnection, settlement: EventIndex, gas_used: BigDecimal, effective_gas_price: BigDecimal, + surplus_capturing_jit_order_owners: &[Address], ) -> Result<(), sqlx::Error> { - // The divisor is never 0: every row the UPDATE writes comes from `settled`. + // The divisor is never 0: only rows that are in `gas_paying` divide by it. + // Bytes 33 to 52 of an order uid are the owner, see the + // `trades_order_uid_owner` index. const QUERY: &str = const_format::concatcp!( SETTLED_TRADES_CTE, - "UPDATE trades t - SET gas_cost = FLOOR($3 * $4 / (SELECT COUNT(*) FROM settled)) - FROM settled s - WHERE t.block_number = s.block_number - AND t.log_index = s.log_index" + ", gas_paying AS ( + SELECT block_number, log_index + FROM settled s + WHERE EXISTS (SELECT 1 FROM orders o WHERE o.uid = s.order_uid) + OR substring(s.order_uid, 33, 20) = ANY($5) + ) + UPDATE trades t SET gas_cost = + CASE + WHEN p.log_index IS NULL THEN 0 + ELSE FLOOR($3 * $4 / (SELECT COUNT(*) FROM gas_paying)) + END + FROM settled s + LEFT JOIN gas_paying p + ON p.block_number = s.block_number + AND p.log_index = s.log_index + WHERE t.block_number = s.block_number + AND t.log_index = s.log_index" ); sqlx::query(QUERY) .bind(settlement.block_number) .bind(settlement.log_index) .bind(gas_used) .bind(effective_gas_price) + .bind(surplus_capturing_jit_order_owners) .execute(ex) .await .map(|_| ()) @@ -617,7 +638,7 @@ mod tests { // and 1, the second those at log 3, 4 and 5. for log_index in [0, 1, 3, 4, 5] { let uid = ByteArray([u8::try_from(log_index).unwrap(); 56]); - add_trade( + add_order_and_trade( &mut db, Default::default(), uid, @@ -640,7 +661,7 @@ mod tests { .all(|(_, cost)| cost.is_none()) ); - attribute_gas_cost(&mut db, first, 100.into(), 10.into()) + attribute_gas_cost(&mut db, first, 100.into(), 10.into(), &[]) .await .unwrap(); @@ -659,7 +680,7 @@ mod tests { // 700 wei over 3 trades does not divide evenly. The share rounds down, // so the shares never add up to more than the transaction paid. - attribute_gas_cost(&mut db, second, 70.into(), 10.into()) + attribute_gas_cost(&mut db, second, 70.into(), 10.into(), &[]) .await .unwrap(); assert_eq!( @@ -674,6 +695,76 @@ mod tests { ); } + /// JIT orders only provide liquidity for the user orders, so they take no + /// share of the gas cost, unless the auction lets their owner capture + /// surplus. + #[tokio::test] + #[ignore] + async fn postgres_attribute_gas_cost_of_jit_orders() { + let mut db = PgConnection::connect("postgresql://").await.unwrap(); + let mut db = db.begin().await.unwrap(); + crate::clear_DANGER_(&mut db).await.unwrap(); + + let event = |log_index| EventIndex { + block_number: 0, + log_index, + }; + let uid = |owner: Address| { + let mut uid = [0u8; 56]; + uid[32..52].copy_from_slice(&owner.0); + ByteArray(uid) + }; + let user = ByteArray([1; 20]); + let market_maker = ByteArray([2; 20]); + let liquidity_provider = ByteArray([3; 20]); + + // A user order, a JIT order of an owner the auction lets capture + // surplus and a plain liquidity JIT order. + add_order_and_trade(&mut db, user, uid(user), event(0), None, None).await; + add_trade( + &mut db, + market_maker, + uid(market_maker), + event(1), + None, + None, + ) + .await; + add_trade( + &mut db, + liquidity_provider, + uid(liquidity_provider), + event(2), + None, + None, + ) + .await; + let settlement = event(3); + add_settlement( + &mut db, + settlement, + Default::default(), + ByteArray([1; 32]), + 1, + ) + .await; + + attribute_gas_cost(&mut db, settlement, 100.into(), 10.into(), &[market_maker]) + .await + .unwrap(); + + // 1000 wei split between the user order and the surplus capturing JIT + // order. The liquidity JIT order paid nothing. + assert_eq!( + gas_costs(&mut db).await, + vec![ + (0, Some(500.into())), + (1, Some(500.into())), + (2, Some(0.into())), + ] + ); + } + /// A settlement that settled no trades must not fail on a zero divisor. #[tokio::test] #[ignore] @@ -695,7 +786,7 @@ mod tests { ) .await; - attribute_gas_cost(&mut db, settlement, 100.into(), 10.into()) + attribute_gas_cost(&mut db, settlement, 100.into(), 10.into(), &[]) .await .unwrap(); assert!(gas_costs(&mut db).await.is_empty()); diff --git a/database/sql/V121__trade_gas_cost.sql b/database/sql/V121__trade_gas_cost.sql index f98c60bc6c..0cf19aa7fb 100644 --- a/database/sql/V121__trade_gas_cost.sql +++ b/database/sql/V121__trade_gas_cost.sql @@ -1,6 +1,7 @@ -- Each trade's share of its settlement's gas cost: `gas_used * -- effective_gas_price` (V116) split equally between the trades that settlement --- settled. Stored so order and trade lookups don't re-derive it per fill. +-- settled for a user. Trades of JIT orders that only provide liquidity get 0. +-- Stored so order and trade lookups don't re-derive it per fill. -- -- Nullable: not backfilled, so only settlements observed after this migration. ALTER TABLE trades From 2b845a10f10475ce40c08680e057656e0ea97160 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= <15343819+jmg-duarte@users.noreply.github.com> Date: Tue, 18 Aug 2026 11:40:35 +0100 Subject: [PATCH 4/6] Address tx comment --- crates/database/src/trades.rs | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/crates/database/src/trades.rs b/crates/database/src/trades.rs index c4b32219f2..5fd0022811 100644 --- a/crates/database/src/trades.rs +++ b/crates/database/src/trades.rs @@ -1,7 +1,14 @@ use { - crate::{Address, OrderUid, TransactionHash, auction::AuctionId, events::EventIndex}, + crate::{ + Address, + OrderUid, + PgTransaction, + TransactionHash, + auction::AuctionId, + events::EventIndex, + }, bigdecimal::BigDecimal, - sqlx::PgConnection, + sqlx::{Executor, PgConnection}, tracing::{Instrument, info_span, instrument}, }; @@ -177,7 +184,7 @@ pub async fn get_trades_for_settlement( /// expect this to happen. #[instrument(skip_all)] pub async fn attribute_gas_cost( - ex: &mut PgConnection, + ex: &mut PgTransaction<'_>, settlement: EventIndex, gas_used: BigDecimal, effective_gas_price: BigDecimal, @@ -206,15 +213,16 @@ pub async fn attribute_gas_cost( WHERE t.block_number = s.block_number AND t.log_index = s.log_index" ); - sqlx::query(QUERY) - .bind(settlement.block_number) - .bind(settlement.log_index) - .bind(gas_used) - .bind(effective_gas_price) - .bind(surplus_capturing_jit_order_owners) - .execute(ex) - .await - .map(|_| ()) + ex.execute( + sqlx::query(QUERY) + .bind(settlement.block_number) + .bind(settlement.log_index) + .bind(gas_used) + .bind(effective_gas_price) + .bind(surplus_capturing_jit_order_owners), + ) + .await + .map(|_| ()) } #[instrument(skip_all)] @@ -248,7 +256,6 @@ mod tests { use { super::*, crate::{ - PgTransaction, byte_array::ByteArray, events::{Event, EventIndex, Settlement, Trade}, onchain_broadcasted_orders::{OnchainOrderPlacement, insert_onchain_order}, From 5b2e4f5030c086078b82cb21866f4df67f4ccde1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= <15343819+jmg-duarte@users.noreply.github.com> Date: Tue, 18 Aug 2026 17:24:58 +0100 Subject: [PATCH 5/6] simplify --- crates/database/src/trades.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/database/src/trades.rs b/crates/database/src/trades.rs index 5fd0022811..bb5f397d01 100644 --- a/crates/database/src/trades.rs +++ b/crates/database/src/trades.rs @@ -9,6 +9,7 @@ use { }, bigdecimal::BigDecimal, sqlx::{Executor, PgConnection}, + std::ops::DerefMut, tracing::{Instrument, info_span, instrument}, }; @@ -213,16 +214,15 @@ pub async fn attribute_gas_cost( WHERE t.block_number = s.block_number AND t.log_index = s.log_index" ); - ex.execute( - sqlx::query(QUERY) - .bind(settlement.block_number) - .bind(settlement.log_index) - .bind(gas_used) - .bind(effective_gas_price) - .bind(surplus_capturing_jit_order_owners), - ) - .await - .map(|_| ()) + sqlx::query(QUERY) + .bind(settlement.block_number) + .bind(settlement.log_index) + .bind(gas_used) + .bind(effective_gas_price) + .bind(surplus_capturing_jit_order_owners) + .execute(ex.deref_mut()) + .await + .map(|_| ()) } #[instrument(skip_all)] From 61fa7274eb948b5a1d0a3fdc9b2f5e9d22ec3c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Duarte?= <15343819+jmg-duarte@users.noreply.github.com> Date: Tue, 18 Aug 2026 17:29:08 +0100 Subject: [PATCH 6/6] fix lint --- crates/database/src/trades.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/database/src/trades.rs b/crates/database/src/trades.rs index bb5f397d01..c354ba079d 100644 --- a/crates/database/src/trades.rs +++ b/crates/database/src/trades.rs @@ -8,7 +8,7 @@ use { events::EventIndex, }, bigdecimal::BigDecimal, - sqlx::{Executor, PgConnection}, + sqlx::PgConnection, std::ops::DerefMut, tracing::{Instrument, info_span, instrument}, };