Skip to content
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
76 changes: 75 additions & 1 deletion crates/common/src/local_db/query/fetch_trades/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,21 @@ const CLEAR_EVENTS_ORDERBOOKS_CLAUSE: &str = "/*CLEAR_EVENTS_ORDERBOOKS_CLAUSE*/
const CLEAR_EVENTS_ORDERBOOKS_CLAUSE_BODY: &str = "AND c.orderbook_address IN ({list})";
const CLEAR_EVENTS_TAKERS_CLAUSE: &str = "/*CLEAR_EVENTS_TAKERS_CLAUSE*/";
const CLEAR_EVENTS_TAKERS_CLAUSE_BODY: &str = "AND c.sender IN ({list})";
const CLEAR_EVENTS_ORDER_HASHES_CLAUSE: &str = "/*CLEAR_EVENTS_ORDER_HASHES_CLAUSE*/";
const CLEAR_EVENTS_ORDER_HASHES_CLAUSE_BODY: &str =
"AND (c.alice_order_hash IN ({list}) OR c.bob_order_hash IN ({list}))";
const TAKE_TRADES_ORDER_HASHES_CLAUSE: &str = "/*TAKE_TRADES_ORDER_HASHES_CLAUSE*/";
const TAKE_TRADES_ORDER_HASHES_CLAUSE_BODY: &str = "AND oe.order_hash IN ({list})";
const CLEAR_ALICE_ORDER_HASHES_CLAUSE: &str = "/*CLEAR_ALICE_ORDER_HASHES_CLAUSE*/";
const CLEAR_ALICE_ORDER_HASHES_CLAUSE_BODY: &str = "AND mc.alice_order_hash IN ({list})";
const CLEAR_BOB_ORDER_HASHES_CLAUSE: &str = "/*CLEAR_BOB_ORDER_HASHES_CLAUSE*/";
const CLEAR_BOB_ORDER_HASHES_CLAUSE_BODY: &str = "AND mc.bob_order_hash IN ({list})";
const OWNERS_CLAUSE: &str = "/*OWNERS_CLAUSE*/";
const OWNERS_CLAUSE_BODY: &str = "AND tws.order_owner IN ({list})";
const ORDER_HASH_CLAUSE: &str = "/*ORDER_HASH_CLAUSE*/";
const ORDER_HASH_CLAUSE_BODY: &str = "AND tws.order_hash = {param}";
const ORDER_HASHES_CLAUSE: &str = "/*ORDER_HASHES_CLAUSE*/";
const ORDER_HASHES_CLAUSE_BODY: &str = "AND tws.order_hash IN ({list})";
const START_TS_CLAUSE: &str = "/*START_TS_CLAUSE*/";
const START_TS_BODY: &str = "AND tws.block_timestamp >= {param}";
const END_TS_CLAUSE: &str = "/*END_TS_CLAUSE*/";
Expand All @@ -48,6 +59,7 @@ pub struct FetchTradesArgs {
pub owners: Vec<Address>,
pub takers: Vec<Address>,
pub order_hash: Option<B256>,
pub order_hashes: Vec<B256>,
pub tokens: FetchTradesTokensFilter,
pub time_filter: TimeFilter,
pub pagination: PaginationParams,
Expand Down Expand Up @@ -114,6 +126,35 @@ pub fn build_fetch_trades_stmt(args: &FetchTradesArgs) -> Result<SqlStatement, S
ORDER_HASH_CLAUSE_BODY,
args.order_hash.map(SqlValue::from),
)?;
let mut order_hashes = args.order_hashes.clone();
order_hashes.sort();
order_hashes.dedup();
let order_hashes_iter = || order_hashes.iter().cloned().map(SqlValue::from);
stmt.bind_list_clause(
CLEAR_EVENTS_ORDER_HASHES_CLAUSE,
CLEAR_EVENTS_ORDER_HASHES_CLAUSE_BODY,
order_hashes_iter(),
)?;
stmt.bind_list_clause(
TAKE_TRADES_ORDER_HASHES_CLAUSE,
TAKE_TRADES_ORDER_HASHES_CLAUSE_BODY,
order_hashes_iter(),
)?;
stmt.bind_list_clause(
CLEAR_ALICE_ORDER_HASHES_CLAUSE,
CLEAR_ALICE_ORDER_HASHES_CLAUSE_BODY,
order_hashes_iter(),
)?;
stmt.bind_list_clause(
CLEAR_BOB_ORDER_HASHES_CLAUSE,
CLEAR_BOB_ORDER_HASHES_CLAUSE_BODY,
order_hashes_iter(),
)?;
stmt.bind_list_clause(
ORDER_HASHES_CLAUSE,
ORDER_HASHES_CLAUSE_BODY,
order_hashes_iter(),
)?;

if let (Some(start), Some(end)) = (args.time_filter.start, args.time_filter.end) {
if start > end {
Expand Down Expand Up @@ -240,7 +281,10 @@ fn bind_token_filters(
#[cfg(test)]
mod tests {
use super::*;
use alloy::{hex, primitives::address};
use alloy::{
hex,
primitives::{address, b256},
};

#[test]
fn builds_with_chain_ids() {
Expand Down Expand Up @@ -333,6 +377,36 @@ mod tests {
);
}

#[test]
fn builds_with_batch_order_hash_filters() {
let hash_a = b256!("0x1111111111111111111111111111111111111111111111111111111111111111");
let hash_b = b256!("0x2222222222222222222222222222222222222222222222222222222222222222");
let stmt = build_fetch_trades_stmt(&FetchTradesArgs {
order_hashes: vec![hash_b, hash_a, hash_a],
..Default::default()
})
.unwrap();

assert!(stmt
.sql
.contains("c.alice_order_hash IN (?1, ?2) OR c.bob_order_hash IN (?1, ?2)"));
assert!(stmt.sql.contains("oe.order_hash IN (?3, ?4)"));
assert!(stmt.sql.contains("mc.alice_order_hash IN (?5, ?6)"));
assert!(stmt.sql.contains("mc.bob_order_hash IN (?7, ?8)"));
assert!(stmt.sql.contains("tws.order_hash IN (?9, ?10)"));
assert!(!stmt.sql.contains(ORDER_HASHES_CLAUSE));
assert!(!stmt.sql.contains(TAKE_TRADES_ORDER_HASHES_CLAUSE));
assert!(!stmt.sql.contains(CLEAR_ALICE_ORDER_HASHES_CLAUSE));
assert!(!stmt.sql.contains(CLEAR_BOB_ORDER_HASHES_CLAUSE));
assert!(!stmt.sql.contains(CLEAR_EVENTS_ORDER_HASHES_CLAUSE));
assert_eq!(stmt.params[0], SqlValue::Text(hex::encode_prefixed(hash_a)));
assert_eq!(stmt.params[1], SqlValue::Text(hex::encode_prefixed(hash_b)));
assert_eq!(stmt.params[6], SqlValue::Text(hex::encode_prefixed(hash_a)));
assert_eq!(stmt.params[7], SqlValue::Text(hex::encode_prefixed(hash_b)));
assert_eq!(stmt.params[8], SqlValue::Text(hex::encode_prefixed(hash_a)));
assert_eq!(stmt.params[9], SqlValue::Text(hex::encode_prefixed(hash_b)));
}

#[test]
fn builds_with_same_token_as_either_side_filter() {
let token = address!("0x1111111111111111111111111111111111111111");
Expand Down
5 changes: 5 additions & 0 deletions crates/common/src/local_db/query/fetch_trades/query.sql
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ matching_clears AS (
/*CLEAR_EVENTS_CHAIN_IDS_CLAUSE*/
/*CLEAR_EVENTS_ORDERBOOKS_CLAUSE*/
/*CLEAR_EVENTS_TAKERS_CLAUSE*/
/*CLEAR_EVENTS_ORDER_HASHES_CLAUSE*/
),
take_trades AS (
SELECT
Expand Down Expand Up @@ -77,6 +78,7 @@ take_trades AS (
oe.block_number < mt.block_number
OR (oe.block_number = mt.block_number AND oe.log_index <= mt.log_index)
)
/*TAKE_TRADES_ORDER_HASHES_CLAUSE*/
AND NOT EXISTS (
SELECT 1
FROM order_events newer
Expand Down Expand Up @@ -139,6 +141,7 @@ clear_alice AS (
oe.block_number < mc.block_number
OR (oe.block_number = mc.block_number AND oe.log_index <= mc.log_index)
)
/*CLEAR_ALICE_ORDER_HASHES_CLAUSE*/
AND NOT EXISTS (
SELECT 1
FROM order_events newer
Expand Down Expand Up @@ -212,6 +215,7 @@ clear_bob AS (
oe.block_number < mc.block_number
OR (oe.block_number = mc.block_number AND oe.log_index <= mc.log_index)
)
/*CLEAR_BOB_ORDER_HASHES_CLAUSE*/
AND NOT EXISTS (
SELECT 1
FROM order_events newer
Expand Down Expand Up @@ -374,6 +378,7 @@ LEFT JOIN erc20_tokens tok_out
WHERE 1 = 1
/*OWNERS_CLAUSE*/
/*ORDER_HASH_CLAUSE*/
/*ORDER_HASHES_CLAUSE*/
/*START_TS_CLAUSE*/
/*END_TS_CLAUSE*/
/*INPUT_TOKENS_CLAUSE*/
Expand Down
12 changes: 10 additions & 2 deletions crates/common/src/raindex_client/trades/get_all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ impl From<GetTradesFilters> for SgTradesListQueryFilters {
.map(|owner| SgBytes(owner.to_string()))
.collect(),
order_hash: filters.order_hash.map(|hash| SgBytes(hash.to_string())),
order_hash_in: Vec::new(),
});
}

Expand Down Expand Up @@ -131,15 +132,20 @@ fn local_trades_pagination(
}
}

fn normalize_trade_tokens(mut tokens: SgTradesTokensFilterArgs) -> SgTradesTokensFilterArgs {
pub(super) fn normalize_trade_tokens(
mut tokens: SgTradesTokensFilterArgs,
) -> SgTradesTokensFilterArgs {
tokens.inputs.sort_unstable();
tokens.inputs.dedup();
tokens.outputs.sort_unstable();
tokens.outputs.dedup();
tokens
}

fn sg_trade_matches_token_filter(trade: &SgTrade, tokens: &SgTradesTokensFilterArgs) -> bool {
pub(super) fn sg_trade_matches_token_filter(
trade: &SgTrade,
tokens: &SgTradesTokensFilterArgs,
) -> bool {
let has_inputs = !tokens.inputs.is_empty();
let has_outputs = !tokens.outputs.is_empty();
let input_token = trade
Expand Down Expand Up @@ -246,6 +252,7 @@ impl RaindexClient {
owners: filters.owners.clone(),
takers: filters.takers.clone(),
order_hash: filters.order_hash,
order_hashes: Vec::new(),
tokens: local_tokens.clone(),
time_filter: filters.time_filter.clone().unwrap_or_default(),
pagination: local_pagination,
Expand Down Expand Up @@ -276,6 +283,7 @@ impl RaindexClient {
owners: filters.owners.clone(),
takers: filters.takers.clone(),
order_hash: filters.order_hash,
order_hashes: Vec::new(),
tokens: local_tokens,
time_filter: filters.time_filter.clone().unwrap_or_default(),
pagination: PaginationParams::default(),
Expand Down
Loading
Loading