| 78 | /// Fetch protocol fees for all keys in the filter |
| 79 | #[instrument(skip_all)] |
| 80 | pub async fn executed_protocol_fees( |
| 81 | ex: &mut PgConnection, |
| 82 | keys_filter: &[Execution], |
| 83 | ) -> Result<HashMap<Execution, Vec<Asset>>, sqlx::Error> { |
| 84 | if keys_filter.is_empty() { |
| 85 | return Ok(HashMap::new()); |
| 86 | } |
| 87 | |
| 88 | let mut query_builder = QueryBuilder::new( |
| 89 | "SELECT oe.order_uid, oe.auction_id, oe.protocol_fee_tokens, oe.protocol_fee_amounts FROM \ |
| 90 | order_execution oe INNER JOIN (VALUES ", |
| 91 | ); |
| 92 | |
| 93 | for (i, (auction_id, order_uid)) in keys_filter.iter().enumerate() { |
| 94 | if i > 0 { |
| 95 | query_builder.push(", "); |
| 96 | } |
| 97 | query_builder |
| 98 | .push("(") |
| 99 | .push_bind(order_uid) |
| 100 | .push(", ") |
| 101 | .push_bind(auction_id) |
| 102 | .push(")"); |
| 103 | } |
| 104 | |
| 105 | query_builder.push(") AS vals(order_uid, auction_id) "); |
| 106 | query_builder.push("ON (oe.order_uid, oe.auction_id) = (vals.order_uid, vals.auction_id)"); |
| 107 | |
| 108 | #[derive(Clone, Debug, Eq, PartialEq, sqlx::Type, sqlx::FromRow)] |
| 109 | struct ProtocolFees { |
| 110 | pub order_uid: OrderUid, |
| 111 | pub auction_id: AuctionId, |
| 112 | pub protocol_fee_tokens: Vec<Address>, |
| 113 | pub protocol_fee_amounts: Vec<BigDecimal>, |
| 114 | } |
| 115 | let query = query_builder.build_query_as::<ProtocolFees>(); |
| 116 | let rows: Vec<ProtocolFees> = query.fetch_all(ex).await?; |
| 117 | |
| 118 | let mut fees = HashMap::new(); |
| 119 | for row in rows { |
| 120 | fees.insert( |
| 121 | (row.auction_id, row.order_uid), |
| 122 | row.protocol_fee_tokens |
| 123 | .into_iter() |
| 124 | .zip(row.protocol_fee_amounts) |
| 125 | .map(|(token, amount)| Asset { token, amount }) |
| 126 | .collect(), |
| 127 | ); |
| 128 | } |
| 129 | |
| 130 | Ok(fees) |
| 131 | } |
| 132 | |
| 133 | #[cfg(test)] |
| 134 | mod tests { |