From a1df7ac48107a59778eb375bd4e567bd42d0a679 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Wed, 19 Nov 2025 21:39:44 -0500 Subject: [PATCH 01/52] update tables names for breaking changes --- src/sql/balances_for_account/svm.sql | 4 ++-- src/sql/holders_for_contract/svm.sql | 2 +- src/sql/ohlcv_prices_for_pool/svm.sql | 6 +++--- src/sql/owner_for_account/svm.sql | 4 ++-- src/sql/tokens_for_contract/svm.sql | 4 ++-- src/sql/transfers/svm.sql | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/sql/balances_for_account/svm.sql b/src/sql/balances_for_account/svm.sql index 3b084747..b7cc570c 100644 --- a/src/sql/balances_for_account/svm.sql +++ b/src/sql/balances_for_account/svm.sql @@ -2,7 +2,7 @@ WITH accounts AS ( SELECT DISTINCT owner, argMax(account, o.block_num) AS account - FROM owner_state_latest AS o + FROM owner_state AS o WHERE ({token_account:Array(String)} = [''] or o.account IN {token_account:Array(String)}) AND owner IN {owner:Array(String)} GROUP BY owner, o.account @@ -39,7 +39,7 @@ metadata AS FROM metadata_view WHERE metadata IN ( SELECT metadata - FROM metadata_mint_state_latest + FROM metadata_mint_state WHERE mint IN (SELECT mint FROM filtered_balances) GROUP BY metadata ) diff --git a/src/sql/holders_for_contract/svm.sql b/src/sql/holders_for_contract/svm.sql index 98c7d825..0c686263 100644 --- a/src/sql/holders_for_contract/svm.sql +++ b/src/sql/holders_for_contract/svm.sql @@ -26,7 +26,7 @@ metadata AS ( WHERE {mint:String} NOT IN ('So11111111111111111111111111111111111111111', 'So11111111111111111111111111111111111111112') AND metadata IN ( SELECT metadata - FROM metadata_mint_state_latest + FROM metadata_mint_state WHERE mint = {mint:String} GROUP BY metadata ) diff --git a/src/sql/ohlcv_prices_for_pool/svm.sql b/src/sql/ohlcv_prices_for_pool/svm.sql index 71b87dd4..e6d7f1d7 100644 --- a/src/sql/ohlcv_prices_for_pool/svm.sql +++ b/src/sql/ohlcv_prices_for_pool/svm.sql @@ -30,12 +30,12 @@ SELECT amm_pool, token0, coalesce( - (SELECT decimals FROM {db_svm_tokens:Identifier}.mints WHERE mint IN (SELECT token0 FROM ohlc) AND decimals != 0), + (SELECT decimals FROM {db_svm_tokens:Identifier}.mints_view WHERE mint IN (SELECT token0 FROM ohlc) AND decimals != 0), 9 ) AS token0_decimals, token1, coalesce( - (SELECT decimals FROM {db_svm_tokens:Identifier}.mints WHERE mint IN (SELECT token1 FROM ohlc) AND decimals != 0), + (SELECT decimals FROM {db_svm_tokens:Identifier}.mints_view WHERE mint IN (SELECT token1 FROM ohlc) AND decimals != 0), 9 ) AS token1_decimals, pow(10, -(token1_decimals - token0_decimals)) * if(is_stablecoin, 1/open_raw, open_raw) AS open, @@ -46,4 +46,4 @@ SELECT uaw, transactions FROM ohlc AS o -ORDER BY datetime DESC; \ No newline at end of file +ORDER BY datetime DESC; diff --git a/src/sql/owner_for_account/svm.sql b/src/sql/owner_for_account/svm.sql index 847c5f7f..6fd98515 100644 --- a/src/sql/owner_for_account/svm.sql +++ b/src/sql/owner_for_account/svm.sql @@ -4,7 +4,7 @@ WITH owners AS ( max(block_num) AS last_update_block_num, account, argMax(owner, o.block_num) AS owner - FROM owner_state_latest AS o + FROM owner_state AS o WHERE account IN {account:Array(String)} GROUP BY o.owner, account ) @@ -20,4 +20,4 @@ FROM owners WHERE owner != '' ORDER BY last_update DESC, account LIMIT {limit:UInt64} -OFFSET {offset:UInt64} \ No newline at end of file +OFFSET {offset:UInt64} diff --git a/src/sql/tokens_for_contract/svm.sql b/src/sql/tokens_for_contract/svm.sql index 5c052ba7..ea60a82f 100644 --- a/src/sql/tokens_for_contract/svm.sql +++ b/src/sql/tokens_for_contract/svm.sql @@ -19,7 +19,7 @@ metadata AS FROM metadata_view WHERE metadata IN ( SELECT metadata - FROM metadata_mint_state_latest + FROM metadata_mint_state WHERE mint = {mint:String} GROUP BY metadata ) @@ -36,4 +36,4 @@ SELECT uri, {network:String} AS network FROM filtered_balances -LEFT JOIN metadata USING mint \ No newline at end of file +LEFT JOIN metadata USING mint diff --git a/src/sql/transfers/svm.sql b/src/sql/transfers/svm.sql index 24eeb021..4d8d76b5 100644 --- a/src/sql/transfers/svm.sql +++ b/src/sql/transfers/svm.sql @@ -131,7 +131,7 @@ spl_metadata AS FROM metadata_view WHERE metadata IN ( SELECT metadata - FROM metadata_mint_state_latest + FROM metadata_mint_state WHERE mint IN (SELECT mint FROM spl_mints) GROUP BY metadata ) From b619cfb9614275ce8c22160a15fe90e23464adfa Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Wed, 19 Nov 2025 21:52:40 -0500 Subject: [PATCH 02/52] fix decimals table --- src/sql/ohlcv_prices_for_pool/svm.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sql/ohlcv_prices_for_pool/svm.sql b/src/sql/ohlcv_prices_for_pool/svm.sql index e6d7f1d7..d98d59e1 100644 --- a/src/sql/ohlcv_prices_for_pool/svm.sql +++ b/src/sql/ohlcv_prices_for_pool/svm.sql @@ -30,12 +30,12 @@ SELECT amm_pool, token0, coalesce( - (SELECT decimals FROM {db_svm_tokens:Identifier}.mints_view WHERE mint IN (SELECT token0 FROM ohlc) AND decimals != 0), + (SELECT decimals FROM {db_svm_tokens:Identifier}.decimals_state WHERE mint IN (SELECT token0 FROM ohlc) AND decimals != 0), 9 ) AS token0_decimals, token1, coalesce( - (SELECT decimals FROM {db_svm_tokens:Identifier}.mints_view WHERE mint IN (SELECT token1 FROM ohlc) AND decimals != 0), + (SELECT decimals FROM {db_svm_tokens:Identifier}.decimals_state WHERE mint IN (SELECT token1 FROM ohlc) AND decimals != 0), 9 ) AS token1_decimals, pow(10, -(token1_decimals - token0_decimals)) * if(is_stablecoin, 1/open_raw, open_raw) AS open, From 50ead74cace6f9669e96ab927930bf4fe96c36cd Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Tue, 25 Nov 2025 23:02:53 -0500 Subject: [PATCH 03/52] tvm-tokens v0.2.0 changes --- src/sql/transfers/tvm.sql | 152 +++++++++++++++---------------- src/sql/transfers_native/tvm.sql | 89 +++++++++++------- 2 files changed, 132 insertions(+), 109 deletions(-) diff --git a/src/sql/transfers/tvm.sql b/src/sql/transfers/tvm.sql index b029dcdb..15c5297a 100644 --- a/src/sql/transfers/tvm.sql +++ b/src/sql/transfers/tvm.sql @@ -1,90 +1,89 @@ + WITH -/* 1) Count how many filters are active */ -active_filters AS -( - SELECT - toUInt8({transaction_id:Array(String)} != ['']) + - toUInt8({from_address:Array(String)} != ['']) + - toUInt8({to_address:Array(String)} != ['']) + - toUInt8({contract:Array(String)} != ['']) - AS n -), -/* 2) Union minutes from only active filters */ -minutes_union AS -( - SELECT toRelativeMinuteNum(timestamp) AS minute - FROM trc20_transfer - WHERE ({transaction_id:Array(String)} != [''] AND tx_hash IN {transaction_id:Array(String)}) - GROUP BY tx_hash, minute - UNION ALL +arrayFilter(x -> x != '', {transaction_id:Array(String)}) AS tx_ids, +arrayFilter(x -> x != '', {from_address:Array(String)}) AS from_addresses, +arrayFilter(x -> x != '', {to_address:Array(String)}) AS to_addresses, +arrayFilter(x -> x != '', {contract:Array(String)}) AS contracts, - SELECT toRelativeMinuteNum(timestamp) AS minute - FROM trc20_transfer - WHERE ({from_address:Array(String)} != [''] AND `from` IN {from_address:Array(String)}) - GROUP BY `from`, minute +(length(tx_ids) > 0) AS has_tx_hash, +(length(from_addresses) > 0) AS has_from, +(length(to_addresses) > 0) AS has_to, +(length(contracts) > 0) AS has_contract, +has_contract AND (NOT has_from) AND (NOT has_to) AS has_only_contract, - UNION ALL +toRelativeMinuteNum(toDateTime({start_time:UInt64})) AS start_minute, +toRelativeMinuteNum(toDateTime({end_time:UInt64})) AS end_minute, +{start_time:UInt64} = 1420070400 AS no_start_time, +{end_time:UInt64} = 2524608000 AS no_end_time, +{start_block:UInt64} = 0 AS no_start_block, +{end_block:UInt64} = 9999999999 AS no_end_block, - SELECT toRelativeMinuteNum(timestamp) AS minute +tx_hash_timestamps AS ( + SELECT (minute, timestamp) FROM trc20_transfer - WHERE ({to_address:Array(String)} != [''] AND `to` IN {to_address:Array(String)}) - GROUP BY `to`, minute - - UNION ALL - - SELECT toRelativeMinuteNum(timestamp) AS minute + WHERE has_tx_hash AND tx_hash IN {transaction_id:Array(String)} + GROUP BY minute, timestamp +), +/* minute filters */ +from_minutes AS ( + SELECT minute FROM trc20_transfer - WHERE ({contract:Array(String)} != [''] AND log_address IN {contract:Array(String)}) - GROUP BY log_address, minute + WHERE has_from AND `from` IN {from_address:Array(String)} + GROUP BY minute ), -filtered_minutes AS ( - SELECT minute FROM minutes_union - WHERE minute BETWEEN toRelativeMinuteNum(toDateTime({start_time:UInt64})) AND toRelativeMinuteNum(toDateTime({end_time:UInt64})) +to_minutes AS ( + SELECT minute + FROM trc20_transfer + WHERE has_to AND `to` IN {to_address:Array(String)} GROUP BY minute - HAVING count() >= (SELECT n FROM active_filters) - ORDER BY minute DESC - LIMIT 1 BY minute - LIMIT if( - (SELECT n FROM active_filters) <= 1, - {limit:UInt64} + {offset:UInt64}, /* safe to limit if there is 1 active filter */ - ({limit:UInt64} + {offset:UInt64}) * 10 /* unsafe limit with a multiplier - usually safe but find a way to early return */ - ) ), -/* Latest ingested timestamp in source table */ -latest_ts AS -( - SELECT max(timestamp) AS ts FROM trc20_transfer +/* USDT has very high volume, so we need to limit the number of minutes we scan */ +contract_minutes AS ( + SELECT minute + FROM trc20_transfer + WHERE has_only_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND log_address IN {contract:Array(String)} + GROUP BY minute + ORDER BY minute DESC + LIMIT 100000 ), transfers AS ( - SELECT * FROM trc20_transfer - PREWHERE - timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} - AND block_num BETWEEN {start_block: UInt64} AND {end_block: UInt64} - AND ( - ( - /* if no filters are active search only the last 10 minutes */ - (SELECT n FROM active_filters) = 0 - AND timestamp BETWEEN - greatest( toDateTime({start_time:UInt64}), least(toDateTime({end_time:UInt64}), (SELECT ts FROM latest_ts)) - (INTERVAL 1 HOUR + INTERVAL 1 * {offset:UInt64} MINUTE)) - AND least(toDateTime({end_time:UInt64}), (SELECT ts FROM latest_ts)) - ) - /* if filters are active, search through the intersecting minute ranges */ - OR toRelativeMinuteNum(timestamp) IN (SELECT minute FROM filtered_minutes) - ) + SELECT * + FROM trc20_transfer WHERE - /* filter by active filters if any */ - ({transaction_id:Array(String)} = [''] OR tx_hash IN {transaction_id:Array(String)}) - AND ({from_address:Array(String)} = [''] OR `from` IN {from_address:Array(String)}) - AND ({to_address:Array(String)} = [''] OR `to` IN {to_address:Array(String)}) - AND ({contract:Array(String)} = [''] OR log_address IN {contract:Array(String)}) - ORDER BY timestamp DESC, block_num DESC, block_hash DESC, tx_index DESC, log_index DESC + /* direct minutes */ + (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + + /* transaction ID filter */ + AND ( NOT has_tx_hash OR (minute, timestamp) IN tx_hash_timestamps AND tx_hash IN {transaction_id:Array(String)} ) + + /* minute filters */ + AND ( NOT has_from OR minute IN from_minutes ) + AND ( NOT has_to OR minute IN to_minutes ) + AND ( NOT has_only_contract OR minute IN contract_minutes ) + + /* direct filters */ + AND ( NOT has_from OR `from` IN {from_address:Array(String)} ) + AND ( NOT has_to OR `to` IN {to_address:Array(String)} ) + AND ( NOT has_contract OR log_address IN {contract:Array(String)} ) + + /* timestamp and block_num filters */ + AND (no_start_block OR block_num >= {start_block:UInt64}) + AND (no_end_block OR block_num <= {end_block:UInt64}) + AND (no_start_time OR timestamp >= toDateTime({start_time:UInt64})) + AND (no_end_time OR timestamp <= toDateTime({end_time:UInt64})) + + ORDER BY minute DESC, timestamp DESC, block_num DESC, tx_index DESC, log_index DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} ) SELECT /* block */ - t.block_num as block_num, + block_num, t.timestamp as datetime, toUnixTimestamp(t.timestamp) as timestamp, @@ -101,14 +100,15 @@ SELECT `from`, `to`, toString(t.amount) AS amount, - t.amount / pow(10, decimals) AS value, /* token metadata */ - abi_hex_to_string(m.name_hex) AS name, - abi_hex_to_string(m.symbol_hex) AS symbol, - abi_hex_to_uint8(m.decimals_hex) AS decimals, + t.amount / pow(10, decimals) AS value, + name, + symbol, + decimals, + + /* network */ {network:String} AS network FROM transfers AS t -/* Get token metadata (name, symbol, decimals) */ -JOIN metadata_rpc AS m ON t.log_address = m.contract -ORDER BY timestamp DESC, block_num DESC, tx_index DESC, log_index DESC; +LEFT JOIN metadata m ON t.log_address = m.contract +ORDER BY minute DESC, timestamp DESC, block_num DESC, tx_index DESC, log_index DESC; diff --git a/src/sql/transfers_native/tvm.sql b/src/sql/transfers_native/tvm.sql index 8954259a..17776587 100644 --- a/src/sql/transfers_native/tvm.sql +++ b/src/sql/transfers_native/tvm.sql @@ -1,43 +1,39 @@ WITH -tx_hash_minutes AS ( - SELECT toRelativeMinuteNum(timestamp) AS minute + +arrayFilter(x -> x != '', {transaction_id:Array(String)}) AS tx_ids, +arrayFilter(x -> x != '', {from_address:Array(String)}) AS from_addresses, +arrayFilter(x -> x != '', {to_address:Array(String)}) AS to_addresses, + +(length(tx_ids) > 0) AS has_tx_hash, +(length(from_addresses) > 0) AS has_from, +(length(to_addresses) > 0) AS has_to, + +toRelativeMinuteNum(toDateTime({start_time:UInt64})) AS start_minute, +toRelativeMinuteNum(toDateTime({end_time:UInt64})) AS end_minute, +{start_time:UInt64} = 1420070400 AS no_start_time, +{end_time:UInt64} = 2524608000 AS no_end_time, +{start_block:UInt64} = 0 AS no_start_block, +{end_block:UInt64} = 9999999999 AS no_end_block, + + +tx_hash_timestamps AS ( + SELECT (minute, timestamp) FROM native_transfer - WHERE ({transaction_id:Array(String)} != [''] AND tx_hash IN {transaction_id:Array(String)}) - GROUP BY tx_hash, minute + WHERE has_tx_hash AND tx_hash IN {transaction_id:Array(String)} + GROUP BY minute, timestamp ), +/* minute filters */ from_minutes AS ( - SELECT toRelativeMinuteNum(timestamp) AS minute + SELECT minute FROM native_transfer - WHERE ({from_address:Array(String)} != [''] AND `from` IN {from_address:Array(String)}) - GROUP BY `from`, minute + WHERE has_from AND `from` IN {from_address:Array(String)} + GROUP BY minute ), to_minutes AS ( - SELECT toRelativeMinuteNum(timestamp) AS minute + SELECT minute FROM native_transfer - WHERE ({to_address:Array(String)} != [''] AND `to` IN {to_address:Array(String)}) - GROUP BY `to`, minute -), -transfers AS ( - SELECT * FROM native_transfer - WHERE - /* filter by timestamp and block_num early to reduce data scanned */ - ({start_time:UInt64} = 1420070400 OR timestamp >= toDateTime({start_time:UInt64})) - AND ({end_time:UInt64} = 2524608000 OR timestamp <= toDateTime({end_time:UInt64})) - AND ({start_block:UInt64} = 0 OR block_num >= {start_block:UInt64}) - AND ({end_block:UInt64} = 9999999999 OR block_num <= {end_block:UInt64}) - - /* filter by minute ranges if any filters are active */ - AND ({transaction_id:Array(String)} = [''] OR toRelativeMinuteNum(timestamp) IN tx_hash_minutes) - AND ({from_address:Array(String)} = [''] OR toRelativeMinuteNum(timestamp) IN from_minutes) - AND ({to_address:Array(String)} = [''] OR toRelativeMinuteNum(timestamp) IN to_minutes) - - /* filter by active filters if any */ - AND ({transaction_id:Array(String)} = [''] OR tx_hash IN {transaction_id:Array(String)}) - AND ({from_address:Array(String)} = [''] OR `from` IN {from_address:Array(String)}) - AND ({to_address:Array(String)} = [''] OR `to` IN {to_address:Array(String)}) - ORDER BY timestamp DESC, block_num DESC, block_hash DESC, tx_index DESC - LIMIT {limit:UInt64} - OFFSET {offset:UInt64} + WHERE has_to AND `to` IN {to_address:Array(String)} + GROUP BY minute ) SELECT /* block */ @@ -59,5 +55,32 @@ SELECT 'Tron' AS name, 'TRX' AS symbol, 6 AS decimals, + + /* network */ {network:String} AS network -FROM transfers AS t; \ No newline at end of file +FROM native_transfer AS t +WHERE + /* direct minutes */ + (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + + /* transaction ID filter */ + AND ( NOT has_tx_hash OR (minute, timestamp) IN tx_hash_timestamps AND tx_hash IN {transaction_id:Array(String)} ) + + /* minute filters */ + AND (NOT has_from OR minute IN from_minutes) + AND (NOT has_to OR minute IN to_minutes) + + /* direct filters */ + AND (NOT has_from OR `from` IN {from_address:Array(String)}) + AND (NOT has_to OR `to` IN {to_address:Array(String)}) + + /* timestamp and block_num filters */ + AND (no_start_block OR block_num >= {start_block:UInt64}) + AND (no_end_block OR block_num <= {end_block:UInt64}) + AND (no_start_time OR timestamp >= toDateTime({start_time:UInt64})) + AND (no_end_time OR timestamp <= toDateTime({end_time:UInt64})) + +ORDER BY minute DESC, timestamp DESC, block_num DESC, tx_index DESC +LIMIT {limit:UInt64} +OFFSET {offset:UInt64} From b2619645129a28709006e52e350b1b8a2757218c Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Tue, 25 Nov 2025 23:17:17 -0500 Subject: [PATCH 04/52] handle duplicate metadata --- src/sql/transfers/tvm.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sql/transfers/tvm.sql b/src/sql/transfers/tvm.sql index 15c5297a..03ea1cdb 100644 --- a/src/sql/transfers/tvm.sql +++ b/src/sql/transfers/tvm.sql @@ -110,5 +110,5 @@ SELECT /* network */ {network:String} AS network FROM transfers AS t -LEFT JOIN metadata m ON t.log_address = m.contract +ANY LEFT JOIN metadata m ON t.log_address = m.contract ORDER BY minute DESC, timestamp DESC, block_num DESC, tx_index DESC, log_index DESC; From 15eb1a5c42fd4f8a7d54af96517991521880116c Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Wed, 26 Nov 2025 00:04:36 -0500 Subject: [PATCH 05/52] changeset --- .changeset/floppy-feet-send.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/floppy-feet-send.md diff --git a/.changeset/floppy-feet-send.md b/.changeset/floppy-feet-send.md new file mode 100644 index 00000000..a195fcfa --- /dev/null +++ b/.changeset/floppy-feet-send.md @@ -0,0 +1,5 @@ +--- +"token-api": minor +--- + +Updated SQL queries for svm-tokens@v0.2.8, svm-dex@v0.3.1, tvm-tokens@v0.2.0 From 02d79edb184bea541fbefb058282009e712dd120 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Wed, 26 Nov 2025 09:26:58 -0500 Subject: [PATCH 06/52] preview bump From 2a943eb9d5bf49e35a14d3d0df345f1ad6705180 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Wed, 26 Nov 2025 12:28:30 -0500 Subject: [PATCH 07/52] fix tvm/tokens --- src/sql/tokens_for_contract/tvm.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sql/tokens_for_contract/tvm.sql b/src/sql/tokens_for_contract/tvm.sql index b417190b..8e5c9a1a 100644 --- a/src/sql/tokens_for_contract/tvm.sql +++ b/src/sql/tokens_for_contract/tvm.sql @@ -5,7 +5,7 @@ WITH filtered_contract AS ( log_address AS contract FROM trc20_transfer WHERE log_address = {contract:String} - ORDER BY timestamp DESC + ORDER BY minute DESC LIMIT 1 ), metadata AS From 42adc83dc79aa0209f2836b2ac3e336db70e6b1d Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Wed, 26 Nov 2025 13:17:27 -0500 Subject: [PATCH 08/52] clean up sql query --- src/sql/tokens_for_contract/evm.sql | 33 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/sql/tokens_for_contract/evm.sql b/src/sql/tokens_for_contract/evm.sql index ac01f5a4..48a321d8 100644 --- a/src/sql/tokens_for_contract/evm.sql +++ b/src/sql/tokens_for_contract/evm.sql @@ -1,19 +1,21 @@ -WITH m AS ( +WITH metadata AS ( SELECT symbol, name, decimals FROM metadata_view WHERE contract = {contract: String} -), s AS ( +), +total_supply AS ( SELECT argMax(total_supply, block_num) AS total_supply FROM total_supply WHERE contract = {contract: String} GROUP BY contract -), b AS ( +), +circulating AS ( SELECT - count(address) AS holders, + count() AS holders, sum(balance) AS raw_circulating_supply, max(block_num) AS block_num, max(timestamp) AS timestamp @@ -26,25 +28,22 @@ WITH m AS ( argMax(balance, t.block_num) AS balance FROM balances AS t WHERE contract = {contract: String} - GROUP BY - contract, - address + GROUP BY contract, address HAVING balance > 0 ) - GROUP BY contract ) SELECT - b.timestamp AS last_update, - b.block_num AS last_update_block_num, - toUnixTimestamp(b.timestamp) AS last_update_timestamp, + circulating.timestamp AS last_update, + circulating.block_num AS last_update_block_num, + toUnixTimestamp(circulating.timestamp) AS last_update_timestamp, {contract: String} AS contract, name, symbol, decimals, - b.raw_circulating_supply / pow(10, decimals) AS circulating_supply, - s.total_supply / pow(10, decimals) AS total_supply, - b.holders AS holders, + circulating.raw_circulating_supply / pow(10, decimals) AS circulating_supply, + total_supply.total_supply / pow(10, decimals) AS total_supply, + circulating.holders AS holders, {network: String} AS network -FROM b -LEFT JOIN m ON 1 = 1 -LEFT JOIN s ON 1 = 1 \ No newline at end of file +FROM circulating +LEFT JOIN metadata ON 1 = 1 +LEFT JOIN total_supply ON 1 = 1 From e0d7c999daed346bceaa0f4397cb367315b0e3e3 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 1 Dec 2025 16:33:29 -0500 Subject: [PATCH 09/52] fix tvm endpoints --- src/sql/swaps/tvm.sql | 2 +- src/sql/transfers/tvm.sql | 75 ++++++++++++++++++++++++++++++++------- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/src/sql/swaps/tvm.sql b/src/sql/swaps/tvm.sql index 0a7b8e61..fd5c821d 100644 --- a/src/sql/swaps/tvm.sql +++ b/src/sql/swaps/tvm.sql @@ -90,7 +90,7 @@ filtered_swaps AS ( /* if no filters are active search only the last 10 minutes */ (SELECT n FROM active_filters) = 0 AND timestamp BETWEEN - greatest( toDateTime({start_time:UInt64}), least(toDateTime({end_time:UInt64}), (SELECT ts FROM latest_ts)) - (INTERVAL 1 HOUR + INTERVAL 10 * {offset:UInt64} SECOND)) + greatest( toDateTime({start_time:UInt64}), least(toDateTime({end_time:UInt64}), (SELECT ts FROM latest_ts)) - (INTERVAL 10 MINUTE + INTERVAL 10 * {offset:UInt64} SECOND)) AND least(toDateTime({end_time:UInt64}), (SELECT ts FROM latest_ts)) ) /* if filters are active, search through the intersecting minute ranges */ diff --git a/src/sql/transfers/tvm.sql b/src/sql/transfers/tvm.sql index 03ea1cdb..1f39c557 100644 --- a/src/sql/transfers/tvm.sql +++ b/src/sql/transfers/tvm.sql @@ -1,4 +1,4 @@ - +/* Clean up transaction_id param: drop the sentinel '' if present */ WITH arrayFilter(x -> x != '', {transaction_id:Array(String)}) AS tx_ids, @@ -10,7 +10,6 @@ arrayFilter(x -> x != '', {contract:Array(String)}) AS contracts, (length(from_addresses) > 0) AS has_from, (length(to_addresses) > 0) AS has_to, (length(contracts) > 0) AS has_contract, -has_contract AND (NOT has_from) AND (NOT has_to) AS has_only_contract, toRelativeMinuteNum(toDateTime({start_time:UInt64})) AS start_minute, toRelativeMinuteNum(toDateTime({end_time:UInt64})) AS end_minute, @@ -29,26 +28,76 @@ tx_hash_timestamps AS ( from_minutes AS ( SELECT minute FROM trc20_transfer - WHERE has_from AND `from` IN {from_address:Array(String)} + WHERE has_from AND NOT has_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND `from` IN {from_address:Array(String)} GROUP BY minute + LIMIT {limit:UInt64} + {offset:UInt64} ), to_minutes AS ( SELECT minute FROM trc20_transfer - WHERE has_to AND `to` IN {to_address:Array(String)} + WHERE has_to AND NOT has_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND `to` IN {to_address:Array(String)} GROUP BY minute + LIMIT {limit:UInt64} + {offset:UInt64} ), -/* USDT has very high volume, so we need to limit the number of minutes we scan */ contract_minutes AS ( SELECT minute FROM trc20_transfer - WHERE has_only_contract + WHERE has_contract AND NOT has_from AND NOT has_to AND (no_start_time OR minute >= start_minute) AND (no_end_time OR minute <= end_minute) AND log_address IN {contract:Array(String)} GROUP BY minute - ORDER BY minute DESC - LIMIT 100000 + LIMIT {limit:UInt64} + {offset:UInt64} +), +contract_from_minutes AS ( + SELECT * FROM ( + SELECT minute + FROM trc20_transfer + WHERE has_contract AND has_from + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND log_address IN {contract:Array(String)} + GROUP BY minute + + INTERSECT ALL + + SELECT minute + FROM trc20_transfer + WHERE has_contract AND has_from + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND `from` IN {from_address:Array(String)} + GROUP BY minute + /* higher multiplication factor to account for double filtering */ + ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 +), +contract_to_minutes AS ( + SELECT * FROM ( + SELECT minute + FROM trc20_transfer + WHERE has_contract AND has_to + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND log_address IN {contract:Array(String)} + GROUP BY minute + + INTERSECT ALL + + SELECT minute + FROM trc20_transfer + WHERE has_contract AND has_to + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND `to` IN {to_address:Array(String)} + GROUP BY minute + /* higher multiplication factor to account for double filtering */ + ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 ), transfers AS ( SELECT * @@ -62,9 +111,11 @@ transfers AS ( AND ( NOT has_tx_hash OR (minute, timestamp) IN tx_hash_timestamps AND tx_hash IN {transaction_id:Array(String)} ) /* minute filters */ - AND ( NOT has_from OR minute IN from_minutes ) - AND ( NOT has_to OR minute IN to_minutes ) - AND ( NOT has_only_contract OR minute IN contract_minutes ) + AND ( NOT (has_from AND NOT has_contract) OR minute IN from_minutes ) + AND ( NOT (has_to AND NOT has_contract) OR minute IN to_minutes ) + AND ( NOT (has_contract AND NOT has_from AND NOT has_to) OR minute IN contract_minutes ) + AND ( NOT (has_contract AND has_from) OR minute IN contract_from_minutes ) + AND ( NOT (has_contract AND has_to) OR minute IN contract_to_minutes ) /* direct filters */ AND ( NOT has_from OR `from` IN {from_address:Array(String)} ) @@ -110,5 +161,5 @@ SELECT /* network */ {network:String} AS network FROM transfers AS t -ANY LEFT JOIN metadata m ON t.log_address = m.contract +LEFT JOIN metadata m ON t.log_address = m.contract ORDER BY minute DESC, timestamp DESC, block_num DESC, tx_index DESC, log_index DESC; From 1476bd3147a8f68c6da83c856ec40b0274264ae2 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 1 Dec 2025 18:23:58 -0500 Subject: [PATCH 10/52] first stab --- src/sql/swaps/evm.sql | 264 ++++++++++-------------------------------- 1 file changed, 61 insertions(+), 203 deletions(-) diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index 02c65547..afbba00d 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -1,218 +1,76 @@ WITH -/* 1) Count how many filters are active */ -active_filters AS -( - SELECT - toUInt8({transaction_id:Array(String)} != ['']) + - toUInt8({pool:Array(String)} != ['']) + - toUInt8({caller:Array(String)} != ['']) + - toUInt8({sender:Array(String)} != ['']) + - toUInt8({recipient:Array(String)} != ['']) - AS n -), -/* 2) Union buckets from only active filters */ -minutes_union AS -( - SELECT minute - FROM swaps_by_tx_hash - WHERE ({transaction_id:Array(String)} != [''] AND tx_hash IN {transaction_id:Array(String)}) - ORDER BY minute DESC - - UNION ALL - SELECT minute - FROM swaps_by_pool - WHERE ({pool:Array(String)} != [''] AND pool IN {pool:Array(String)}) - ORDER BY minute DESC - - UNION ALL +arrayFilter(x -> x != '', {transaction_id:Array(String)}) AS tx_ids, +arrayFilter(x -> x != '', {pool:Array(String)}) AS pools, - SELECT minute - FROM swaps_by_caller - WHERE ({caller:Array(String)} != [''] AND caller IN {caller:Array(String)}) - ORDER BY minute DESC +(length(tx_ids) > 0) AS has_tx_hash, +(length(pools) > 0) AS has_pool, - UNION ALL +toRelativeMinuteNum(toDateTime({start_time:UInt64})) AS start_minute, +toRelativeMinuteNum(toDateTime({end_time:UInt64})) AS end_minute, +{start_time:UInt64} = 1420070400 AS no_start_time, +{end_time:UInt64} = 2524608000 AS no_end_time, +{start_block:UInt64} = 0 AS no_start_block, +{end_block:UInt64} = 9999999999 AS no_end_block, - SELECT minute - FROM swaps_by_sender - WHERE ({sender:Array(String)} != [''] AND sender IN {sender:Array(String)}) - ORDER BY minute DESC - - UNION ALL +tx_hash_timestamps AS ( + SELECT (minute, timestamp) + FROM swaps + WHERE has_tx_hash AND tx_hash IN {transaction_id:Array(String)} + GROUP BY minute, timestamp +), +pool_minutes AS ( SELECT minute - FROM swaps_by_recipient - WHERE ({recipient:Array(String)} != [''] AND recipient IN {recipient:Array(String)}) - ORDER BY minute DESC -), -/* 3) Intersect: keep only buckets present in ALL active filters */ -filtered_minutes AS -( - SELECT minute FROM minutes_union - WHERE minute BETWEEN toRelativeMinuteNum(toDateTime({start_time: UInt64})) AND toRelativeMinuteNum(toDateTime({end_time: UInt64})) + FROM swaps + WHERE has_pool AND pool IN {pool:Array(String)} GROUP BY minute - HAVING count() >= (SELECT n FROM active_filters) - ORDER BY minute DESC - LIMIT 1 BY minute - LIMIT if( - (SELECT n FROM active_filters) <= 1, - toUInt64({limit:UInt64}) + toUInt64({offset:UInt64}), /* safe to limit if there is 1 active filter */ - (toUInt64({limit:UInt64}) + toUInt64({offset:UInt64})) * 10 /* unsafe limit with a multiplier - usually safe but find a way to early return */ - ) -), -/* Latest ingested timestamp in source table */ -latest_ts AS -( - SELECT max(timestamp) AS ts FROM swaps + LIMIT {limit:UInt64} + {offset:UInt64} ), -s AS ( - SELECT - block_num, - timestamp, - tx_hash, - pool, - toString(caller) AS caller, - toString(sender) AS sender, - toString(recipient) AS recipient, - abs(amount0) AS amount0, - abs(amount1) AS amount1, - price, - protocol, - s.amount0 < 0 AS invert_tokens - FROM swaps AS s - PREWHERE - timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} - AND block_num BETWEEN {start_block: UInt64} AND {end_block: UInt64} - AND ( - ( - /* if no filters are active, search through the last hour only */ - (SELECT n FROM active_filters) = 0 - AND timestamp BETWEEN - greatest( toDateTime({start_time:UInt64}), least(toDateTime({end_time:UInt64}), (SELECT ts FROM latest_ts)) - (INTERVAL 1 HOUR + INTERVAL 1 * {offset:UInt64} SECOND)) - AND least(toDateTime({end_time:UInt64}), (SELECT ts FROM latest_ts)) - ) - /* if filters are active, search through the intersecting minute ranges */ - OR toRelativeMinuteNum(timestamp) IN (SELECT minute FROM filtered_minutes) - ) + +filtered_swaps AS ( + SELECT * + FROM swaps WHERE - /* filter the trimmed down minute ranges by the active filters */ - ({transaction_id:Array(String)} = [''] OR tx_hash IN {transaction_id:Array(String)}) - AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) - AND ({caller:Array(String)} = [''] OR caller IN {caller:Array(String)}) - AND ({sender:Array(String)} = [''] OR sender IN {sender:Array(String)}) - AND ({recipient:Array(String)} = [''] OR recipient IN {recipient:Array(String)}) - AND ({protocol:String} = '' OR protocol = {protocol:String}) - ORDER BY timestamp DESC, tx_hash + /* direct minutes */ + (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + + /* transaction ID filter */ + AND ( NOT has_tx_hash OR (minute, timestamp) IN tx_hash_timestamps AND tx_hash IN {transaction_id:Array(String)} ) + + /* minute filters */ + AND ( NOT has_pool OR minute IN pool_minutes ) + + /* direct filters */ + AND ( NOT has_pool OR pool IN {pool:Array(String)} ) + + /* timestamp and block_num filters */ + AND (no_start_block OR block_num >= {start_block:UInt64}) + AND (no_end_block OR block_num <= {end_block:UInt64}) + AND (no_start_time OR timestamp >= toDateTime({start_time:UInt64})) + AND (no_end_time OR timestamp <= toDateTime({end_time:UInt64})) + + ORDER BY minute DESC, timestamp DESC, block_num DESC, tx_index DESC, log_index DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} -), -filtered_pools AS ( - SELECT - pool, - factory, - protocol, - token0, - token1 - FROM pools - WHERE pool IN (SELECT DISTINCT pool FROM s) -), -unique_tokens AS ( - SELECT DISTINCT token0 AS address FROM filtered_pools - UNION DISTINCT - SELECT DISTINCT token1 AS address FROM filtered_pools -), -filtered_tokens AS ( - SELECT - t.address, - if(isNull(t.symbol), '', t.symbol) AS symbol, - coalesce(t.decimals, 0) AS decimals - FROM erc20_metadata_initialize t - WHERE t.address IN (SELECT address FROM unique_tokens) -), -p AS ( - SELECT - pool, - protocol, - factory, - c0.decimals AS decimals0, - c1.decimals AS decimals1, - CAST(( - toString(p.token0), - trim(coalesce( - multiIf( - p.token0 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'mainnet', 'ETH', - p.token0 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'arbitrum-one', 'ETH', - p.token0 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'avalanche', 'AVAX', - p.token0 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'base', 'ETH', - p.token0 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'bsc', 'BNB', - p.token0 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'polygon', 'POL', - p.token0 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'optimism', 'ETH', - p.token0 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'unichain', 'ETH', - c0.symbol - ), '')), - coalesce( - if(p.token0 = '0x0000000000000000000000000000000000000000', 18, c0.decimals), 0 - ) - ) - AS Tuple(address String, symbol String, decimals UInt8) - ) AS input_token, - CAST( - ( - toString(p.token1), - trim(coalesce( - multiIf( - p.token1 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'mainnet', 'ETH', - p.token1 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'arbitrum-one', 'ETH', - p.token1 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'avalanche', 'AVAX', - p.token1 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'base', 'ETH', - p.token1 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'bsc', 'BNB', - p.token1 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'polygon', 'POL', - p.token1 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'optimism', 'ETH', - p.token1 = '0x0000000000000000000000000000000000000000' AND {network:String} = 'unichain', 'ETH', - c1.symbol - ), '')), - coalesce( - if(p.token1 = '0x0000000000000000000000000000000000000000', 18, c1.decimals), 0 - ) - ) - AS Tuple(address String, symbol String, decimals UInt8) - ) AS output_token - FROM filtered_pools AS p - JOIN filtered_tokens c0 ON c0.address = p.token0 - JOIN filtered_tokens c1 ON c1.address = p.token1 ) + SELECT - s.block_num AS block_num, - s.timestamp AS datetime, - toUnixTimestamp(s.timestamp) AS timestamp, - s.tx_hash AS transaction_id, - toString(p.factory) AS factory, - s.pool AS pool, - if(invert_tokens, p.output_token, p.input_token) AS input_token, - if(invert_tokens, p.input_token, p.output_token) AS output_token, - s.caller AS caller, - s.sender, - s.recipient, - if(invert_tokens, toString(s.amount1), toString(s.amount0)) AS input_amount, - if(invert_tokens, s.amount1 / pow(10, decimals1), s.amount0 / pow(10, decimals0)) AS input_value, - if(invert_tokens, toString(s.amount0), toString(s.amount1)) AS output_amount, - if(invert_tokens, s.amount0 / pow(10, decimals0), s.amount1 / pow(10, decimals1)) AS output_value, - s.price AS price, - 1 / s.price AS price_inv, - s.protocol AS protocol, - format('Swap {} {} for {} {} on {}', - if(input_value > 1000, formatReadableQuantity(input_value), toString(round(input_value, input_token.decimals))), - input_token.symbol, - if(output_value > 1000, formatReadableQuantity(output_value), toString(round(output_value, output_token.decimals))), - output_token.symbol, - arrayStringConcat( - arrayMap(x -> concat(upper(substring(x, 1, 1)), substring(x, 2)), - splitByChar('_', protocol)), - ' ' - ) - ) AS summary, + block_num, + timestamp AS datetime, + toUnixTimestamp(timestamp) AS timestamp, + tx_hash AS transaction_id, + toString(factory) AS factory, + pool, + input_contract AS input_token, + output_contract AS output_token, + user AS caller, + user AS sender, + user AS recipient, + input_amount, + output_amount, + protocol, {network:String} AS network -FROM s -LEFT JOIN p USING (pool, protocol) -ORDER BY timestamp DESC, transaction_id +FROM filtered_swaps +ORDER BY timestamp DESC, tx_hash From 39495db62c85727f00ac14e6209d86d3d00157fb Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 1 Dec 2025 23:48:20 -0500 Subject: [PATCH 11/52] add meta --- src/routes/v1/evm/swaps/evm.ts | 11 ++++- src/sql/swaps/evm.sql | 83 +++++++++++++++++++++++++++------- 2 files changed, 75 insertions(+), 19 deletions(-) diff --git a/src/routes/v1/evm/swaps/evm.ts b/src/routes/v1/evm/swaps/evm.ts index d2aeae58..4c233df3 100644 --- a/src/routes/v1/evm/swaps/evm.ts +++ b/src/routes/v1/evm/swaps/evm.ts @@ -147,13 +147,20 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const params = c.req.valid('query'); const dbConfig = config.uniswapDatabases[params.network]; - if (!dbConfig) { + const db_evm_tokens = config.tokenDatabases[params.network]; + + if (!dbConfig || !db_evm_tokens) { return c.json({ error: `Network not found: ${params.network}` }, 400); } const query = sqlQueries.swaps?.[dbConfig.type]; if (!query) return c.json({ error: 'Query for swaps could not be loaded' }, 500); - const response = await makeUsageQueryJson(c, [query], params, { database: dbConfig.database }); + const response = await makeUsageQueryJson( + c, + [query], + { ...params, db_evm_tokens: db_evm_tokens.database }, + { database: dbConfig.database } + ); return handleUsageQueryError(c, response); }); diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index afbba00d..6b74418f 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -29,7 +29,21 @@ pool_minutes AS ( ), filtered_swaps AS ( - SELECT * + SELECT + block_num, + timestamp, + minute, + tx_hash, + tx_index, + log_index, + factory, + pool, + protocol, + user, + input_contract, + output_contract, + input_amount, + output_amount FROM swaps WHERE /* direct minutes */ @@ -54,23 +68,58 @@ filtered_swaps AS ( ORDER BY minute DESC, timestamp DESC, block_num DESC, tx_index DESC, log_index DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} +), + +unique_contracts AS ( + SELECT input_contract AS contract FROM filtered_swaps + UNION DISTINCT + SELECT output_contract AS contract FROM filtered_swaps +), + +metadata AS ( + SELECT + m.contract AS contract, + any(m.name) AS name, + any(m.symbol) AS symbol, + any(m.decimals) AS decimals, + CAST((m.contract, any(m.symbol), any(m.name), any(m.decimals)) AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8))) AS token_info + FROM {db_evm_tokens:Identifier}.metadata_view AS m + INNER JOIN unique_contracts AS u ON m.contract = u.contract + GROUP BY m.contract ) SELECT - block_num, - timestamp AS datetime, - toUnixTimestamp(timestamp) AS timestamp, - tx_hash AS transaction_id, - toString(factory) AS factory, - pool, - input_contract AS input_token, - output_contract AS output_token, - user AS caller, - user AS sender, - user AS recipient, - input_amount, - output_amount, - protocol, + s.block_num AS block_num, + s.timestamp AS datetime, + toUnixTimestamp(s.timestamp) AS timestamp, + s.tx_hash AS transaction_id, + toString(s.factory) AS factory, + s.pool AS pool, + s.user AS caller, + s.user AS sender, + s.user AS recipient, + toString(s.input_amount) AS input_amount, + s.input_amount / pow(10, m1.decimals) AS input_value, + m1.token_info AS input_token, + toString(s.output_amount) AS output_amount, + s.output_amount / pow(10, m2.decimals) AS output_value, + m2.token_info AS output_token, + if(s.input_amount > 0, (s.output_amount / pow(10, m2.decimals)) / (s.input_amount / pow(10, m1.decimals)), 0) AS price, + if(s.output_amount > 0, (s.input_amount / pow(10, m1.decimals)) / (s.output_amount / pow(10, m2.decimals)), 0) AS price_inv, + s.protocol AS protocol, + format('Swap {} {} for {} {} on {}', + if(s.input_amount / pow(10, m1.decimals) > 1000, formatReadableQuantity(s.input_amount / pow(10, m1.decimals)), toString(s.input_amount / pow(10, m1.decimals))), + m1.symbol, + if(s.output_amount / pow(10, m2.decimals) > 1000, formatReadableQuantity(s.output_amount / pow(10, m2.decimals)), toString(s.output_amount / pow(10, m2.decimals))), + m2.symbol, + arrayStringConcat( + arrayMap(x -> concat(upper(substring(x, 1, 1)), substring(x, 2)), + splitByChar('_', s.protocol)), + ' ' + ) + ) AS summary, {network:String} AS network -FROM filtered_swaps -ORDER BY timestamp DESC, tx_hash +FROM filtered_swaps AS s +LEFT JOIN metadata AS m1 ON s.input_contract = m1.contract +LEFT JOIN metadata AS m2 ON s.output_contract = m2.contract +ORDER BY s.timestamp DESC, s.tx_hash From c2ac08e282f94f4caeceab673c484b60ea6d9bf3 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Tue, 2 Dec 2025 01:07:30 -0500 Subject: [PATCH 12/52] fix lazy materializtion error --- src/sql/swaps/evm.sql | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index 6b74418f..b81c31ff 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -70,22 +70,21 @@ filtered_swaps AS ( OFFSET {offset:UInt64} ), -unique_contracts AS ( - SELECT input_contract AS contract FROM filtered_swaps - UNION DISTINCT - SELECT output_contract AS contract FROM filtered_swaps -), - metadata AS ( SELECT - m.contract AS contract, - any(m.name) AS name, - any(m.symbol) AS symbol, - any(m.decimals) AS decimals, - CAST((m.contract, any(m.symbol), any(m.name), any(m.decimals)) AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8))) AS token_info - FROM {db_evm_tokens:Identifier}.metadata_view AS m - INNER JOIN unique_contracts AS u ON m.contract = u.contract - GROUP BY m.contract + contract, + CAST( + (contract, symbol, name, decimals) + AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8)) + ) AS token, + symbol, + decimals + FROM {db_evm_tokens:Identifier}.metadata_view + WHERE contract IN ( + SELECT input_contract FROM filtered_swaps + UNION DISTINCT + SELECT output_contract FROM filtered_swaps + ) ) SELECT @@ -98,12 +97,12 @@ SELECT s.user AS caller, s.user AS sender, s.user AS recipient, + m1.token AS input_token, + m2.token AS output_token, toString(s.input_amount) AS input_amount, s.input_amount / pow(10, m1.decimals) AS input_value, - m1.token_info AS input_token, toString(s.output_amount) AS output_amount, s.output_amount / pow(10, m2.decimals) AS output_value, - m2.token_info AS output_token, if(s.input_amount > 0, (s.output_amount / pow(10, m2.decimals)) / (s.input_amount / pow(10, m1.decimals)), 0) AS price, if(s.output_amount > 0, (s.input_amount / pow(10, m1.decimals)) / (s.output_amount / pow(10, m2.decimals)), 0) AS price_inv, s.protocol AS protocol, @@ -123,3 +122,4 @@ FROM filtered_swaps AS s LEFT JOIN metadata AS m1 ON s.input_contract = m1.contract LEFT JOIN metadata AS m2 ON s.output_contract = m2.contract ORDER BY s.timestamp DESC, s.tx_hash +SETTINGS query_plan_optimize_lazy_materialization = false From 2c341ae9525ecddbb1f3e4e2fe158ab32cbdedc5 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Wed, 3 Dec 2025 17:33:56 -0500 Subject: [PATCH 13/52] add other filters --- src/routes/v1/evm/swaps/evm.ts | 24 +++++++++++++------ src/sql/swaps/evm.sql | 42 ++++++++++++++++++++++++++++++---- src/types/zod.ts | 4 ++-- 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/routes/v1/evm/swaps/evm.ts b/src/routes/v1/evm/swaps/evm.ts index 4c233df3..b11ef1b9 100644 --- a/src/routes/v1/evm/swaps/evm.ts +++ b/src/routes/v1/evm/swaps/evm.ts @@ -7,6 +7,8 @@ import { handleUsageQueryError, makeUsageQueryJson } from '../../../../handleQue import { sqlQueries } from '../../../../sql/index.js'; import { EVM_ADDRESS_SWAP_EXAMPLE, + EVM_CONTRACT_USDC_EXAMPLE, + EVM_CONTRACT_WETH_EXAMPLE, EVM_POOL_USDC_WETH_EXAMPLE, EVM_TRANSACTION_SWAP_EXAMPLE, } from '../../../../types/examples.js'; @@ -16,6 +18,7 @@ import { createQuerySchema, dateTimeSchema, evmAddressSchema, + evmContractSchema, evmFactorySchema, evmNetworkIdSchema, evmPoolSchema, @@ -36,10 +39,19 @@ const querySchema = createQuerySchema({ meta: { example: EVM_TRANSACTION_SWAP_EXAMPLE }, }, pool: { schema: evmPoolSchema, batched: true, default: '', meta: { example: EVM_POOL_USDC_WETH_EXAMPLE } }, - caller: { schema: evmAddressSchema, batched: true, default: '', meta: { example: EVM_ADDRESS_SWAP_EXAMPLE } }, - sender: { schema: evmAddressSchema, batched: true, default: '', meta: { example: EVM_ADDRESS_SWAP_EXAMPLE } }, - recipient: { schema: evmAddressSchema, batched: true, default: '', meta: { example: EVM_ADDRESS_SWAP_EXAMPLE } }, - protocol: { schema: evmProtocolSchema, default: '' }, + user: { schema: evmAddressSchema, batched: true, default: '', meta: { example: EVM_ADDRESS_SWAP_EXAMPLE } }, + input_contract: { + schema: evmContractSchema, + batched: true, + default: '', + meta: { example: EVM_CONTRACT_USDC_EXAMPLE }, + }, + output_contract: { + schema: evmContractSchema, + batched: true, + default: '', + meta: { example: EVM_CONTRACT_WETH_EXAMPLE }, + }, start_time: { schema: timestampSchema, prefault: '2015-01-01' }, end_time: { schema: timestampSchema, prefault: '2050-01-01' }, @@ -62,9 +74,7 @@ const responseSchema = apiUsageResponseSchema.extend({ input_token: evmTokenResponseSchema, output_token: evmTokenResponseSchema, - caller: evmAddressSchema, - sender: evmAddressSchema, - recipient: evmAddressSchema, + user: evmAddressSchema, input_amount: z.string(), input_value: z.number(), diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index b81c31ff..9ace638e 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -2,9 +2,15 @@ WITH arrayFilter(x -> x != '', {transaction_id:Array(String)}) AS tx_ids, arrayFilter(x -> x != '', {pool:Array(String)}) AS pools, +arrayFilter(x -> x != '', {user:Array(String)}) AS users, +arrayFilter(x -> x != '', {input_contract:Array(String)}) AS input_contracts, +arrayFilter(x -> x != '', {output_contract:Array(String)}) AS output_contracts, (length(tx_ids) > 0) AS has_tx_hash, (length(pools) > 0) AS has_pool, +(length(users) > 0) AS has_user, +(length(input_contracts) > 0) AS has_input_contract, +(length(output_contracts) > 0) AS has_output_contract, toRelativeMinuteNum(toDateTime({start_time:UInt64})) AS start_minute, toRelativeMinuteNum(toDateTime({end_time:UInt64})) AS end_minute, @@ -28,6 +34,30 @@ pool_minutes AS ( LIMIT {limit:UInt64} + {offset:UInt64} ), +user_minutes AS ( + SELECT minute + FROM swaps + WHERE has_user AND user IN {user:Array(String)} + GROUP BY minute + LIMIT {limit:UInt64} + {offset:UInt64} +), + +input_contract_minutes AS ( + SELECT minute + FROM swaps + WHERE has_input_contract AND input_contract IN {input_contract:Array(String)} + GROUP BY minute + LIMIT {limit:UInt64} + {offset:UInt64} +), + +output_contract_minutes AS ( + SELECT minute + FROM swaps + WHERE has_output_contract AND output_contract IN {output_contract:Array(String)} + GROUP BY minute + LIMIT {limit:UInt64} + {offset:UInt64} +), + filtered_swaps AS ( SELECT block_num, @@ -55,9 +85,15 @@ filtered_swaps AS ( /* minute filters */ AND ( NOT has_pool OR minute IN pool_minutes ) + AND ( NOT has_user OR minute IN user_minutes ) + AND ( NOT has_input_contract OR minute IN input_contract_minutes ) + AND ( NOT has_output_contract OR minute IN output_contract_minutes ) /* direct filters */ AND ( NOT has_pool OR pool IN {pool:Array(String)} ) + AND ( NOT has_user OR user IN {user:Array(String)} ) + AND ( NOT has_input_contract OR input_contract IN {input_contract:Array(String)} ) + AND ( NOT has_output_contract OR output_contract IN {output_contract:Array(String)} ) /* timestamp and block_num filters */ AND (no_start_block OR block_num >= {start_block:UInt64}) @@ -94,9 +130,7 @@ SELECT s.tx_hash AS transaction_id, toString(s.factory) AS factory, s.pool AS pool, - s.user AS caller, - s.user AS sender, - s.user AS recipient, + s.user AS user, m1.token AS input_token, m2.token AS output_token, toString(s.input_amount) AS input_amount, @@ -113,7 +147,7 @@ SELECT m2.symbol, arrayStringConcat( arrayMap(x -> concat(upper(substring(x, 1, 1)), substring(x, 2)), - splitByChar('_', s.protocol)), + splitByChar('-', s.protocol)), ' ' ) ) AS summary, diff --git a/src/types/zod.ts b/src/types/zod.ts index b9464574..d96d8507 100644 --- a/src/types/zod.ts +++ b/src/types/zod.ts @@ -129,8 +129,8 @@ export const tvmNetworkIdSchema = z // ---------------------- export const evmProtocolSchema = z - .enum(['uniswap_v2', 'uniswap_v3', 'uniswap_v4']) - .meta({ description: 'Protocol name', example: 'uniswap_v3' }); + .enum(['uniswap-v2', 'uniswap-v3', 'uniswap-v4']) + .meta({ description: 'Protocol name', example: 'uniswap-v3' }); export const svmProtocolSchema = z .enum(['raydium_amm_v4']) From 2ab772c4d764969f1d90bc0a0c43e0da72e9aa7b Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Fri, 5 Dec 2025 10:16:48 -0500 Subject: [PATCH 14/52] add 3 filters --- src/sql/swaps/evm.sql | 149 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 144 insertions(+), 5 deletions(-) diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index 9ace638e..f6d79ef4 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -58,6 +58,126 @@ output_contract_minutes AS ( LIMIT {limit:UInt64} + {offset:UInt64} ), +user_pool_minutes AS ( + SELECT * FROM ( + SELECT minute + FROM swaps + WHERE has_user AND has_pool + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND user IN {user:Array(String)} + GROUP BY minute + + INTERSECT ALL + + SELECT minute + FROM swaps + WHERE has_user AND has_pool + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND pool IN {pool:Array(String)} + GROUP BY minute + ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 +), + +user_input_contract_minutes AS ( + SELECT * FROM ( + SELECT minute + FROM swaps + WHERE has_user AND has_input_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND user IN {user:Array(String)} + GROUP BY minute + + INTERSECT ALL + + SELECT minute + FROM swaps + WHERE has_user AND has_input_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND input_contract IN {input_contract:Array(String)} + GROUP BY minute + ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 +), + +user_output_contract_minutes AS ( + SELECT * FROM ( + SELECT minute + FROM swaps + WHERE has_user AND has_output_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND user IN {user:Array(String)} + GROUP BY minute + + INTERSECT ALL + + SELECT minute + FROM swaps + WHERE has_user AND has_output_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND output_contract IN {output_contract:Array(String)} + GROUP BY minute + ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 +), + +input_output_contract_minutes AS ( + SELECT * FROM ( + SELECT minute + FROM swaps + WHERE has_input_contract AND has_output_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND input_contract IN {input_contract:Array(String)} + GROUP BY minute + + INTERSECT ALL + + SELECT minute + FROM swaps + WHERE has_input_contract AND has_output_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND output_contract IN {output_contract:Array(String)} + GROUP BY minute + ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 +), + +user_input_output_contract_minutes AS ( + SELECT * FROM ( + SELECT minute + FROM swaps + WHERE has_user AND has_input_contract AND has_output_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND user IN {user:Array(String)} + GROUP BY minute + + INTERSECT ALL + + SELECT minute + FROM swaps + WHERE has_user AND has_input_contract AND has_output_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND input_contract IN {input_contract:Array(String)} + GROUP BY minute + + INTERSECT ALL + + SELECT minute + FROM swaps + WHERE has_user AND has_input_contract AND has_output_contract + AND (no_start_time OR minute >= start_minute) + AND (no_end_time OR minute <= end_minute) + AND output_contract IN {output_contract:Array(String)} + GROUP BY minute + ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 +), + filtered_swaps AS ( SELECT block_num, @@ -83,11 +203,30 @@ filtered_swaps AS ( /* transaction ID filter */ AND ( NOT has_tx_hash OR (minute, timestamp) IN tx_hash_timestamps AND tx_hash IN {transaction_id:Array(String)} ) - /* minute filters */ - AND ( NOT has_pool OR minute IN pool_minutes ) - AND ( NOT has_user OR minute IN user_minutes ) - AND ( NOT has_input_contract OR minute IN input_contract_minutes ) - AND ( NOT has_output_contract OR minute IN output_contract_minutes ) + /* minute filters - use INTERSECT CTEs when 2+ filters present */ + AND ( NOT has_pool OR + (has_user AND minute IN user_pool_minutes) OR + (NOT has_user AND minute IN pool_minutes) + ) + AND ( NOT has_user OR ( + (has_pool AND minute IN user_pool_minutes) OR + (has_input_contract AND has_output_contract AND minute IN user_input_output_contract_minutes) OR + (has_input_contract AND NOT has_output_contract AND minute IN user_input_contract_minutes) OR + (has_output_contract AND NOT has_input_contract AND minute IN user_output_contract_minutes) OR + (NOT has_pool AND NOT has_input_contract AND NOT has_output_contract AND minute IN user_minutes) + ) ) + AND ( NOT has_input_contract OR ( + (has_user AND has_output_contract AND minute IN user_input_output_contract_minutes) OR + (has_user AND NOT has_output_contract AND minute IN user_input_contract_minutes) OR + (has_output_contract AND NOT has_user AND minute IN input_output_contract_minutes) OR + (NOT has_user AND NOT has_output_contract AND minute IN input_contract_minutes) + ) ) + AND ( NOT has_output_contract OR ( + (has_user AND has_input_contract AND minute IN user_input_output_contract_minutes) OR + (has_user AND NOT has_input_contract AND minute IN user_output_contract_minutes) OR + (has_input_contract AND NOT has_user AND minute IN input_output_contract_minutes) OR + (NOT has_user AND NOT has_input_contract AND minute IN output_contract_minutes) + ) ) /* direct filters */ AND ( NOT has_pool OR pool IN {pool:Array(String)} ) From 3aca780b1725435cefb5bd02666a947da8d48f07 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 8 Dec 2025 17:33:52 -0500 Subject: [PATCH 15/52] refactor swaps sql logic --- src/sql/swaps/evm.sql | 277 +++++++++++------------------------------- 1 file changed, 73 insertions(+), 204 deletions(-) diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index f6d79ef4..3150545f 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -1,188 +1,82 @@ WITH - -arrayFilter(x -> x != '', {transaction_id:Array(String)}) AS tx_ids, -arrayFilter(x -> x != '', {pool:Array(String)}) AS pools, -arrayFilter(x -> x != '', {user:Array(String)}) AS users, -arrayFilter(x -> x != '', {input_contract:Array(String)}) AS input_contracts, -arrayFilter(x -> x != '', {output_contract:Array(String)}) AS output_contracts, - -(length(tx_ids) > 0) AS has_tx_hash, -(length(pools) > 0) AS has_pool, -(length(users) > 0) AS has_user, -(length(input_contracts) > 0) AS has_input_contract, -(length(output_contracts) > 0) AS has_output_contract, - -toRelativeMinuteNum(toDateTime({start_time:UInt64})) AS start_minute, -toRelativeMinuteNum(toDateTime({end_time:UInt64})) AS end_minute, -{start_time:UInt64} = 1420070400 AS no_start_time, -{end_time:UInt64} = 2524608000 AS no_end_time, -{start_block:UInt64} = 0 AS no_start_block, -{end_block:UInt64} = 9999999999 AS no_end_block, - -tx_hash_timestamps AS ( - SELECT (minute, timestamp) - FROM swaps - WHERE has_tx_hash AND tx_hash IN {transaction_id:Array(String)} - GROUP BY minute, timestamp +/* 1) Count how many filters are active */ +active_filters AS +( + SELECT + toUInt8({transaction_id:Array(String)} != ['']) + + toUInt8({pool:Array(String)} != ['']) + + toUInt8({user:Array(String)} != ['']) + + toUInt8({input_contract:Array(String)} != ['']) + + toUInt8({output_contract:Array(String)} != ['']) + AS n ), - -pool_minutes AS ( +/* 2) Union minutes from only active filters */ +minutes_union AS +( SELECT minute FROM swaps - WHERE has_pool AND pool IN {pool:Array(String)} + WHERE ({transaction_id:Array(String)} != [''] AND tx_hash IN {transaction_id:Array(String)}) GROUP BY minute - LIMIT {limit:UInt64} + {offset:UInt64} -), + ORDER BY minute DESC + + UNION ALL -user_minutes AS ( SELECT minute FROM swaps - WHERE has_user AND user IN {user:Array(String)} + WHERE ({pool:Array(String)} != [''] AND pool IN {pool:Array(String)}) GROUP BY minute - LIMIT {limit:UInt64} + {offset:UInt64} -), + ORDER BY minute DESC + + UNION ALL -input_contract_minutes AS ( SELECT minute FROM swaps - WHERE has_input_contract AND input_contract IN {input_contract:Array(String)} + WHERE ({user:Array(String)} != [''] AND user IN {user:Array(String)}) GROUP BY minute - LIMIT {limit:UInt64} + {offset:UInt64} -), + ORDER BY minute DESC + + UNION ALL -output_contract_minutes AS ( SELECT minute FROM swaps - WHERE has_output_contract AND output_contract IN {output_contract:Array(String)} + WHERE ({input_contract:Array(String)} != [''] AND input_contract IN {input_contract:Array(String)}) GROUP BY minute - LIMIT {limit:UInt64} + {offset:UInt64} -), - -user_pool_minutes AS ( - SELECT * FROM ( - SELECT minute - FROM swaps - WHERE has_user AND has_pool - AND (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - AND user IN {user:Array(String)} - GROUP BY minute - - INTERSECT ALL - - SELECT minute - FROM swaps - WHERE has_user AND has_pool - AND (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - AND pool IN {pool:Array(String)} - GROUP BY minute - ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 -), - -user_input_contract_minutes AS ( - SELECT * FROM ( - SELECT minute - FROM swaps - WHERE has_user AND has_input_contract - AND (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - AND user IN {user:Array(String)} - GROUP BY minute - - INTERSECT ALL - - SELECT minute - FROM swaps - WHERE has_user AND has_input_contract - AND (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - AND input_contract IN {input_contract:Array(String)} - GROUP BY minute - ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 -), + ORDER BY minute DESC -user_output_contract_minutes AS ( - SELECT * FROM ( - SELECT minute - FROM swaps - WHERE has_user AND has_output_contract - AND (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - AND user IN {user:Array(String)} - GROUP BY minute + UNION ALL - INTERSECT ALL - - SELECT minute - FROM swaps - WHERE has_user AND has_output_contract - AND (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - AND output_contract IN {output_contract:Array(String)} - GROUP BY minute - ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 + SELECT minute + FROM swaps + WHERE ({output_contract:Array(String)} != [''] AND output_contract IN {output_contract:Array(String)}) + GROUP BY minute + ORDER BY minute DESC ), - -input_output_contract_minutes AS ( - SELECT * FROM ( - SELECT minute - FROM swaps - WHERE has_input_contract AND has_output_contract - AND (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - AND input_contract IN {input_contract:Array(String)} - GROUP BY minute - - INTERSECT ALL - - SELECT minute - FROM swaps - WHERE has_input_contract AND has_output_contract - AND (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - AND output_contract IN {output_contract:Array(String)} - GROUP BY minute - ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 +/* 3) Intersect: keep only buckets present in ALL active filters, bounded by requested time window */ +filtered_minutes AS +( + SELECT minute FROM minutes_union + WHERE minute BETWEEN toRelativeMinuteNum(toDateTime({start_time: UInt64})) AND toRelativeMinuteNum(toDateTime({end_time: UInt64})) + GROUP BY minute + HAVING count() >= (SELECT n FROM active_filters) + ORDER BY minute DESC + LIMIT 1 BY minute + LIMIT if( + (SELECT n FROM active_filters) <= 1, + toUInt64({limit:UInt64}) + toUInt64({offset:UInt64}), /* safe to limit if there is 1 active filter */ + (toUInt64({limit:UInt64}) + toUInt64({offset:UInt64})) * 10 /* unsafe limit with a multiplier - usually safe but find a way to early return */ + ) ), - -user_input_output_contract_minutes AS ( - SELECT * FROM ( - SELECT minute - FROM swaps - WHERE has_user AND has_input_contract AND has_output_contract - AND (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - AND user IN {user:Array(String)} - GROUP BY minute - - INTERSECT ALL - - SELECT minute - FROM swaps - WHERE has_user AND has_input_contract AND has_output_contract - AND (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - AND input_contract IN {input_contract:Array(String)} - GROUP BY minute - - INTERSECT ALL - - SELECT minute - FROM swaps - WHERE has_user AND has_input_contract AND has_output_contract - AND (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - AND output_contract IN {output_contract:Array(String)} - GROUP BY minute - ) LIMIT ({limit:UInt64} + {offset:UInt64}) * 10 +/* Latest ingested timestamp in source table */ +latest_minute AS +( + SELECT max(minute) AS minute FROM swaps ), -filtered_swaps AS ( +filtered_swaps AS +( SELECT block_num, timestamp, - minute, tx_hash, tx_index, log_index, @@ -195,52 +89,27 @@ filtered_swaps AS ( input_amount, output_amount FROM swaps - WHERE - /* direct minutes */ - (no_start_time OR minute >= start_minute) - AND (no_end_time OR minute <= end_minute) - - /* transaction ID filter */ - AND ( NOT has_tx_hash OR (minute, timestamp) IN tx_hash_timestamps AND tx_hash IN {transaction_id:Array(String)} ) - - /* minute filters - use INTERSECT CTEs when 2+ filters present */ - AND ( NOT has_pool OR - (has_user AND minute IN user_pool_minutes) OR - (NOT has_user AND minute IN pool_minutes) + PREWHERE + timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} + AND block_num BETWEEN {start_block: UInt64} AND {end_block: UInt64} + AND ( + ( + /* if no filters are active search only the last minute */ + (SELECT n FROM active_filters) = 0 + AND minute BETWEEN + greatest( toRelativeMinuteNum(toDateTime({start_time:UInt64})), least(toRelativeMinuteNum(toDateTime({end_time:UInt64})), (SELECT minute FROM latest_minute)) - (1 + 1 * {offset:UInt64})) + AND least(toRelativeMinuteNum(toDateTime({end_time:UInt64})), (SELECT minute FROM latest_minute)) + ) + /* if filters are active, search through the intersecting minute ranges */ + OR minute IN (SELECT minute FROM filtered_minutes) ) - AND ( NOT has_user OR ( - (has_pool AND minute IN user_pool_minutes) OR - (has_input_contract AND has_output_contract AND minute IN user_input_output_contract_minutes) OR - (has_input_contract AND NOT has_output_contract AND minute IN user_input_contract_minutes) OR - (has_output_contract AND NOT has_input_contract AND minute IN user_output_contract_minutes) OR - (NOT has_pool AND NOT has_input_contract AND NOT has_output_contract AND minute IN user_minutes) - ) ) - AND ( NOT has_input_contract OR ( - (has_user AND has_output_contract AND minute IN user_input_output_contract_minutes) OR - (has_user AND NOT has_output_contract AND minute IN user_input_contract_minutes) OR - (has_output_contract AND NOT has_user AND minute IN input_output_contract_minutes) OR - (NOT has_user AND NOT has_output_contract AND minute IN input_contract_minutes) - ) ) - AND ( NOT has_output_contract OR ( - (has_user AND has_input_contract AND minute IN user_input_output_contract_minutes) OR - (has_user AND NOT has_input_contract AND minute IN user_output_contract_minutes) OR - (has_input_contract AND NOT has_user AND minute IN input_output_contract_minutes) OR - (NOT has_user AND NOT has_input_contract AND minute IN output_contract_minutes) - ) ) - - /* direct filters */ - AND ( NOT has_pool OR pool IN {pool:Array(String)} ) - AND ( NOT has_user OR user IN {user:Array(String)} ) - AND ( NOT has_input_contract OR input_contract IN {input_contract:Array(String)} ) - AND ( NOT has_output_contract OR output_contract IN {output_contract:Array(String)} ) - - /* timestamp and block_num filters */ - AND (no_start_block OR block_num >= {start_block:UInt64}) - AND (no_end_block OR block_num <= {end_block:UInt64}) - AND (no_start_time OR timestamp >= toDateTime({start_time:UInt64})) - AND (no_end_time OR timestamp <= toDateTime({end_time:UInt64})) - - ORDER BY minute DESC, timestamp DESC, block_num DESC, tx_index DESC, log_index DESC + WHERE + ({transaction_id:Array(String)} = [''] OR tx_hash IN {transaction_id:Array(String)}) + AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) + AND ({user:Array(String)} = [''] OR user IN {user:Array(String)}) + AND ({input_contract:Array(String)} = [''] OR input_contract IN {input_contract:Array(String)}) + AND ({output_contract:Array(String)} = [''] OR output_contract IN {output_contract:Array(String)}) + ORDER BY timestamp DESC, tx_hash, log_index LIMIT {limit:UInt64} OFFSET {offset:UInt64} ), From c20f58f817941dc5d65f730eb7d44d2040357f94 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 8 Dec 2025 17:46:07 -0500 Subject: [PATCH 16/52] add native tokens to query --- src/sql/swaps/evm.sql | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index 3150545f..a52fff8d 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -129,6 +129,38 @@ metadata AS ( UNION DISTINCT SELECT output_contract FROM filtered_swaps ) + AND contract != '0x0000000000000000000000000000000000000000' + + UNION ALL + + SELECT + contract, + CAST( + (contract, native_symbol, 'Native', 18) + AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8)) + ) AS token, + native_symbol AS symbol, + 18 AS decimals + FROM ( + SELECT + '0x0000000000000000000000000000000000000000' AS contract, + multiIf( + {network:String} = 'mainnet', 'ETH', + {network:String} = 'arbitrum-one', 'ETH', + {network:String} = 'avalanche', 'AVAX', + {network:String} = 'base', 'ETH', + {network:String} = 'bsc', 'BNB', + {network:String} = 'polygon', 'POL', + {network:String} = 'optimism', 'ETH', + {network:String} = 'unichain', 'ETH', + 'ETH' + ) AS native_symbol + ) + WHERE contract IN ( + SELECT input_contract FROM filtered_swaps + UNION DISTINCT + SELECT output_contract FROM filtered_swaps + ) ) SELECT From b7a11644d2e015a71635278d38de0615b8994fbe Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 8 Dec 2025 17:58:58 -0500 Subject: [PATCH 17/52] add factory filter --- src/routes/v1/evm/swaps/evm.ts | 7 +++++++ src/sql/swaps/evm.sql | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/routes/v1/evm/swaps/evm.ts b/src/routes/v1/evm/swaps/evm.ts index b11ef1b9..ab352d80 100644 --- a/src/routes/v1/evm/swaps/evm.ts +++ b/src/routes/v1/evm/swaps/evm.ts @@ -9,6 +9,7 @@ import { EVM_ADDRESS_SWAP_EXAMPLE, EVM_CONTRACT_USDC_EXAMPLE, EVM_CONTRACT_WETH_EXAMPLE, + EVM_FACTORY_UNISWAP_V2_EXAMPLE, EVM_POOL_USDC_WETH_EXAMPLE, EVM_TRANSACTION_SWAP_EXAMPLE, } from '../../../../types/examples.js'; @@ -38,6 +39,12 @@ const querySchema = createQuerySchema({ default: '', meta: { example: EVM_TRANSACTION_SWAP_EXAMPLE }, }, + factory: { + schema: evmFactorySchema, + batched: true, + default: '', + meta: { example: EVM_FACTORY_UNISWAP_V2_EXAMPLE }, + }, pool: { schema: evmPoolSchema, batched: true, default: '', meta: { example: EVM_POOL_USDC_WETH_EXAMPLE } }, user: { schema: evmAddressSchema, batched: true, default: '', meta: { example: EVM_ADDRESS_SWAP_EXAMPLE } }, input_contract: { diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index a52fff8d..d3dc6893 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -4,6 +4,7 @@ active_filters AS ( SELECT toUInt8({transaction_id:Array(String)} != ['']) + + toUInt8({factory:Array(String)} != ['']) + toUInt8({pool:Array(String)} != ['']) + toUInt8({user:Array(String)} != ['']) + toUInt8({input_contract:Array(String)} != ['']) + @@ -21,6 +22,14 @@ minutes_union AS UNION ALL + SELECT minute + FROM swaps + WHERE ({factory:Array(String)} != [''] AND factory IN {factory:Array(String)}) + GROUP BY minute + ORDER BY minute DESC + + UNION ALL + SELECT minute FROM swaps WHERE ({pool:Array(String)} != [''] AND pool IN {pool:Array(String)}) @@ -105,6 +114,7 @@ filtered_swaps AS ) WHERE ({transaction_id:Array(String)} = [''] OR tx_hash IN {transaction_id:Array(String)}) + AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) AND ({user:Array(String)} = [''] OR user IN {user:Array(String)}) AND ({input_contract:Array(String)} = [''] OR input_contract IN {input_contract:Array(String)}) From c28356a4d25c6354866ecbcb3933c7a4e3712773 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 8 Dec 2025 18:09:54 -0500 Subject: [PATCH 18/52] add 0xeee contract --- src/sql/swaps/evm.sql | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index d3dc6893..fab37b51 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -139,7 +139,7 @@ metadata AS ( UNION DISTINCT SELECT output_contract FROM filtered_swaps ) - AND contract != '0x0000000000000000000000000000000000000000' + AND contract NOT IN ('0x0000000000000000000000000000000000000000', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') UNION ALL @@ -153,7 +153,7 @@ metadata AS ( 18 AS decimals FROM ( SELECT - '0x0000000000000000000000000000000000000000' AS contract, + contract, multiIf( {network:String} = 'mainnet', 'ETH', {network:String} = 'arbitrum-one', 'ETH', @@ -165,6 +165,11 @@ metadata AS ( {network:String} = 'unichain', 'ETH', 'ETH' ) AS native_symbol + FROM ( + SELECT '0x0000000000000000000000000000000000000000' AS contract + UNION ALL + SELECT '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' AS contract + ) ) WHERE contract IN ( SELECT input_contract FROM filtered_swaps @@ -206,4 +211,3 @@ FROM filtered_swaps AS s LEFT JOIN metadata AS m1 ON s.input_contract = m1.contract LEFT JOIN metadata AS m2 ON s.output_contract = m2.contract ORDER BY s.timestamp DESC, s.tx_hash -SETTINGS query_plan_optimize_lazy_materialization = false From 8b498bc48ee270635bc36e659e6619cff8cd5756 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 8 Dec 2025 18:16:39 -0500 Subject: [PATCH 19/52] refactor metadata query to use unique_contracts CTE --- src/sql/swaps/evm.sql | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index fab37b51..f05c1fa3 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -124,6 +124,12 @@ filtered_swaps AS OFFSET {offset:UInt64} ), +unique_contracts AS ( + SELECT input_contract AS contract FROM filtered_swaps + UNION DISTINCT + SELECT output_contract AS contract FROM filtered_swaps +), + metadata AS ( SELECT contract, @@ -134,11 +140,7 @@ metadata AS ( symbol, decimals FROM {db_evm_tokens:Identifier}.metadata_view - WHERE contract IN ( - SELECT input_contract FROM filtered_swaps - UNION DISTINCT - SELECT output_contract FROM filtered_swaps - ) + WHERE contract IN (SELECT contract FROM unique_contracts) AND contract NOT IN ('0x0000000000000000000000000000000000000000', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') UNION ALL @@ -171,11 +173,7 @@ metadata AS ( SELECT '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' AS contract ) ) - WHERE contract IN ( - SELECT input_contract FROM filtered_swaps - UNION DISTINCT - SELECT output_contract FROM filtered_swaps - ) + WHERE contract IN (SELECT contract FROM unique_contracts) ) SELECT From fc020e1507f35dfe5e39d32e83c8b4bde927c96d Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 8 Dec 2025 21:10:04 -0500 Subject: [PATCH 20/52] refactor /evm/pools --- src/routes/v1/evm/pools/evm.ts | 11 ++- src/sql/pools/evm.sql | 140 ++++++++++++++++++--------------- 2 files changed, 85 insertions(+), 66 deletions(-) diff --git a/src/routes/v1/evm/pools/evm.ts b/src/routes/v1/evm/pools/evm.ts index 3cbf6758..5d9c91d7 100644 --- a/src/routes/v1/evm/pools/evm.ts +++ b/src/routes/v1/evm/pools/evm.ts @@ -123,13 +123,20 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const params = c.req.valid('query'); const dbConfig = config.uniswapDatabases[params.network]; - if (!dbConfig) { + const db_evm_tokens = config.tokenDatabases[params.network]; + + if (!dbConfig || !db_evm_tokens) { return c.json({ error: `Network not found: ${params.network}` }, 400); } const query = sqlQueries.pools?.[dbConfig.type]; if (!query) return c.json({ error: 'Query for pools could not be loaded' }, 500); - const response = await makeUsageQueryJson(c, [query], params, { database: dbConfig.database }); + const response = await makeUsageQueryJson( + c, + [query], + { ...params, db_evm_tokens: db_evm_tokens.database }, + { database: dbConfig.database } + ); return handleUsageQueryError(c, response); }); diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index 6b172301..ca4ee843 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -11,77 +11,89 @@ WITH filtered_pools AS ( protocol FROM pools WHERE - if ({pool:Array(String)} == [''], true, pool IN {pool:Array(String)}) AND - if ({factory:Array(String)} == [''], true, factory IN {factory:Array(String)}) AND - if ({input_token:Array(String)} == [''], true, token0 IN {input_token:Array(String)}) AND - if ({output_token:Array(String)} == [''], true, token1 IN {output_token:Array(String)}) AND - if ({protocol:String} == '', true, protocol = {protocol:String}) + ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) + AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) + AND ({input_token:Array(String)} = [''] OR token0 IN {input_token:Array(String)}) + AND ({output_token:Array(String)} = [''] OR token1 IN {output_token:Array(String)}) + AND ({protocol:String} = '' OR protocol = {protocol:String}) ORDER BY datetime DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} ), + unique_tokens AS ( - SELECT DISTINCT token0 AS address FROM filtered_pools + SELECT token0 AS contract FROM filtered_pools UNION DISTINCT - SELECT DISTINCT token1 AS address FROM filtered_pools + SELECT token1 AS contract FROM filtered_pools ), -filtered_tokens AS ( + +metadata AS ( SELECT - t.address, - if(isNull(t.symbol), '', t.symbol) AS symbol, - coalesce(t.decimals, 0) AS decimals - FROM erc20_metadata_initialize t - WHERE t.address IN (SELECT address FROM unique_tokens) + contract, + CAST( + (contract, symbol, decimals) + AS Tuple(address String, symbol String, decimals UInt8) + ) AS token, + symbol, + decimals + FROM {db_evm_tokens:Identifier}.metadata_view + WHERE contract IN (SELECT contract FROM unique_tokens) + AND contract NOT IN ('0x0000000000000000000000000000000000000000', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') + + UNION ALL + + SELECT + contract, + CAST( + (contract, native_symbol, 18) + AS Tuple(address String, symbol String, decimals UInt8) + ) AS token, + native_symbol AS symbol, + 18 AS decimals + FROM ( + SELECT + '0x0000000000000000000000000000000000000000' AS contract, + multiIf( + {network:String} = 'mainnet', 'ETH', + {network:String} = 'arbitrum-one', 'ETH', + {network:String} = 'avalanche', 'AVAX', + {network:String} = 'base', 'ETH', + {network:String} = 'bsc', 'BNB', + {network:String} = 'polygon', 'POL', + {network:String} = 'optimism', 'ETH', + {network:String} = 'unichain', 'ETH', + 'ETH' + ) AS native_symbol + WHERE '0x0000000000000000000000000000000000000000' IN (SELECT contract FROM unique_tokens) + + UNION ALL + + SELECT + '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' AS contract, + multiIf( + {network:String} = 'mainnet', 'ETH', + {network:String} = 'arbitrum-one', 'ETH', + {network:String} = 'avalanche', 'AVAX', + {network:String} = 'base', 'ETH', + {network:String} = 'bsc', 'BNB', + {network:String} = 'polygon', 'POL', + {network:String} = 'optimism', 'ETH', + {network:String} = 'unichain', 'ETH', + 'ETH' + ) AS native_symbol + WHERE '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' IN (SELECT contract FROM unique_tokens) + ) ) + SELECT - pools.factory AS factory, - pools.pool AS pool, - CAST( - ( - toString(pools.token0), - trim(coalesce( - multiIf( - (pools.token0 = '0x0000000000000000000000000000000000000000' OR pools.token0 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'mainnet', 'ETH', - (pools.token0 = '0x0000000000000000000000000000000000000000' OR pools.token0 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'arbitrum-one', 'ETH', - (pools.token0 = '0x0000000000000000000000000000000000000000' OR pools.token0 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'avalanche', 'AVAX', - (pools.token0 = '0x0000000000000000000000000000000000000000' OR pools.token0 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'base', 'ETH', - (pools.token0 = '0x0000000000000000000000000000000000000000' OR pools.token0 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'bsc', 'BNB', - (pools.token0 = '0x0000000000000000000000000000000000000000' OR pools.token0 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'polygon', 'POL', - (pools.token0 = '0x0000000000000000000000000000000000000000' OR pools.token0 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'optimism', 'ETH', - (pools.token0 = '0x0000000000000000000000000000000000000000' OR pools.token0 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'unichain', 'ETH', - t0.symbol - ), '')), - coalesce( - if((pools.token0 = '0x0000000000000000000000000000000000000000' OR pools.token0 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'), 18, t0.decimals), 0 - ) - ) - AS Tuple(address String, symbol String, decimals UInt8) - ) AS input_token, - CAST( - ( - toString(pools.token1), - trim(coalesce( - multiIf( - (pools.token1 = '0x0000000000000000000000000000000000000000' OR pools.token1 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'mainnet', 'ETH', - (pools.token1 = '0x0000000000000000000000000000000000000000' OR pools.token1 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'arbitrum-one', 'ETH', - (pools.token1 = '0x0000000000000000000000000000000000000000' OR pools.token1 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'avalanche', 'AVAX', - (pools.token1 = '0x0000000000000000000000000000000000000000' OR pools.token1 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'base', 'ETH', - (pools.token1 = '0x0000000000000000000000000000000000000000' OR pools.token1 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'bsc', 'BNB', - (pools.token1 = '0x0000000000000000000000000000000000000000' OR pools.token1 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'polygon', 'POL', - (pools.token1 = '0x0000000000000000000000000000000000000000' OR pools.token1 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'optimism', 'ETH', - (pools.token1 = '0x0000000000000000000000000000000000000000' OR pools.token1 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') AND {network:String} = 'unichain', 'ETH', - t1.symbol - ), '')), - coalesce( - if((pools.token1 = '0x0000000000000000000000000000000000000000' OR pools.token1 = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee'), 18, t1.decimals), 0 - ) - ) - AS Tuple(address String, symbol String, decimals UInt8) - ) AS output_token, - pools.fee AS fee, - pools.protocol AS protocol, - {network:String} as network -FROM filtered_pools AS pools -LEFT JOIN filtered_tokens t0 ON pools.token0 = t0.address -LEFT JOIN filtered_tokens t1 ON pools.token1 = t1.address -ORDER BY datetime DESC, protocol + p.factory AS factory, + p.pool AS pool, + m1.token AS input_token, + m2.token AS output_token, + p.fee AS fee, + p.protocol AS protocol, + {network:String} AS network +FROM filtered_pools AS p +LEFT JOIN metadata AS m1 ON p.token0 = m1.contract +LEFT JOIN metadata AS m2 ON p.token1 = m2.contract +ORDER BY p.datetime DESC, p.protocol From df46bcbff56f7ce6f224fcc31d6267389d5534c2 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 8 Dec 2025 21:32:31 -0500 Subject: [PATCH 21/52] remap protocol names --- src/sql/pools/evm.sql | 4 ++-- src/sql/swaps/evm.sql | 4 ++-- src/types/zod.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index ca4ee843..9e325574 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -15,7 +15,7 @@ WITH filtered_pools AS ( AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) AND ({input_token:Array(String)} = [''] OR token0 IN {input_token:Array(String)}) AND ({output_token:Array(String)} = [''] OR token1 IN {output_token:Array(String)}) - AND ({protocol:String} = '' OR protocol = {protocol:String}) + AND ({protocol:String} = '' OR protocol = replaceAll({protocol:String}, '_', '-')) ORDER BY datetime DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} @@ -91,7 +91,7 @@ SELECT m1.token AS input_token, m2.token AS output_token, p.fee AS fee, - p.protocol AS protocol, + replaceAll(p.protocol, '-', '_') AS protocol, {network:String} AS network FROM filtered_pools AS p LEFT JOIN metadata AS m1 ON p.token0 = m1.contract diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index f05c1fa3..c9b27b04 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -192,7 +192,7 @@ SELECT s.output_amount / pow(10, m2.decimals) AS output_value, if(s.input_amount > 0, (s.output_amount / pow(10, m2.decimals)) / (s.input_amount / pow(10, m1.decimals)), 0) AS price, if(s.output_amount > 0, (s.input_amount / pow(10, m1.decimals)) / (s.output_amount / pow(10, m2.decimals)), 0) AS price_inv, - s.protocol AS protocol, + replaceAll(s.protocol, '-', '_') AS protocol, format('Swap {} {} for {} {} on {}', if(s.input_amount / pow(10, m1.decimals) > 1000, formatReadableQuantity(s.input_amount / pow(10, m1.decimals)), toString(s.input_amount / pow(10, m1.decimals))), m1.symbol, @@ -200,7 +200,7 @@ SELECT m2.symbol, arrayStringConcat( arrayMap(x -> concat(upper(substring(x, 1, 1)), substring(x, 2)), - splitByChar('-', s.protocol)), + splitByChar('_', replaceAll(s.protocol, '-', '_'))), ' ' ) ) AS summary, diff --git a/src/types/zod.ts b/src/types/zod.ts index d96d8507..b9464574 100644 --- a/src/types/zod.ts +++ b/src/types/zod.ts @@ -129,8 +129,8 @@ export const tvmNetworkIdSchema = z // ---------------------- export const evmProtocolSchema = z - .enum(['uniswap-v2', 'uniswap-v3', 'uniswap-v4']) - .meta({ description: 'Protocol name', example: 'uniswap-v3' }); + .enum(['uniswap_v2', 'uniswap_v3', 'uniswap_v4']) + .meta({ description: 'Protocol name', example: 'uniswap_v3' }); export const svmProtocolSchema = z .enum(['raydium_amm_v4']) From 5ea36a86da5d1f47f8b83477b20d2ebdba371db9 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Mon, 8 Dec 2025 21:46:29 -0500 Subject: [PATCH 22/52] add protocol filter to /evm/swaps endpoint --- src/routes/v1/evm/swaps/evm.ts | 1 + src/sql/swaps/evm.sql | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/routes/v1/evm/swaps/evm.ts b/src/routes/v1/evm/swaps/evm.ts index ab352d80..08354368 100644 --- a/src/routes/v1/evm/swaps/evm.ts +++ b/src/routes/v1/evm/swaps/evm.ts @@ -59,6 +59,7 @@ const querySchema = createQuerySchema({ default: '', meta: { example: EVM_CONTRACT_WETH_EXAMPLE }, }, + protocol: { schema: evmProtocolSchema, default: '' }, start_time: { schema: timestampSchema, prefault: '2015-01-01' }, end_time: { schema: timestampSchema, prefault: '2050-01-01' }, diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index c9b27b04..cb711457 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -8,7 +8,8 @@ active_filters AS toUInt8({pool:Array(String)} != ['']) + toUInt8({user:Array(String)} != ['']) + toUInt8({input_contract:Array(String)} != ['']) + - toUInt8({output_contract:Array(String)} != ['']) + toUInt8({output_contract:Array(String)} != ['']) + + toUInt8({protocol:String} != '') AS n ), /* 2) Union minutes from only active filters */ @@ -59,6 +60,14 @@ minutes_union AS WHERE ({output_contract:Array(String)} != [''] AND output_contract IN {output_contract:Array(String)}) GROUP BY minute ORDER BY minute DESC + + UNION ALL + + SELECT minute + FROM swaps + WHERE ({protocol:String} != '' AND protocol = replaceAll({protocol:String}, '_', '-')) + GROUP BY minute + ORDER BY minute DESC ), /* 3) Intersect: keep only buckets present in ALL active filters, bounded by requested time window */ filtered_minutes AS @@ -119,6 +128,7 @@ filtered_swaps AS AND ({user:Array(String)} = [''] OR user IN {user:Array(String)}) AND ({input_contract:Array(String)} = [''] OR input_contract IN {input_contract:Array(String)}) AND ({output_contract:Array(String)} = [''] OR output_contract IN {output_contract:Array(String)}) + AND ({protocol:String} = '' OR protocol = replaceAll({protocol:String}, '_', '-')) ORDER BY timestamp DESC, tx_hash, log_index LIMIT {limit:UInt64} OFFSET {offset:UInt64} From bf5de96810e31ce1706de5ab32470c9f203a54b3 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Thu, 11 Dec 2025 17:56:28 -0500 Subject: [PATCH 23/52] refactor pools query to use initialize fields and improve token metadata handling --- src/sql/pools/evm.sql | 59 ++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 35 deletions(-) diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index 9e325574..c0af5319 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -1,27 +1,27 @@ WITH filtered_pools AS ( SELECT - block_num, - timestamp as datetime, - tx_hash AS transaction_id, + initialize_block_num AS block_num, + initialize_timestamp AS datetime, + initialize_tx_hash AS transaction_id, toString(factory) AS factory, pool, - token0, - token1, + arrayElement(tokens, 1) AS token0, + arrayElement(tokens, 2) AS token1, fee, protocol FROM pools WHERE ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) - AND ({input_token:Array(String)} = [''] OR token0 IN {input_token:Array(String)}) - AND ({output_token:Array(String)} = [''] OR token1 IN {output_token:Array(String)}) - AND ({protocol:String} = '' OR protocol = replaceAll({protocol:String}, '_', '-')) + AND ({input_token:Array(String)} = [''] OR hasAny(tokens, {input_token:Array(String)})) + AND ({output_token:Array(String)} = [''] OR hasAny(tokens, {output_token:Array(String)})) + AND ({protocol:String} = '' OR CAST(protocol AS String) = replaceAll({protocol:String}, '_', '-')) ORDER BY datetime DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} ), -unique_tokens AS ( +unique_contracts AS ( SELECT token0 AS contract FROM filtered_pools UNION DISTINCT SELECT token1 AS contract FROM filtered_pools @@ -31,28 +31,28 @@ metadata AS ( SELECT contract, CAST( - (contract, symbol, decimals) - AS Tuple(address String, symbol String, decimals UInt8) + (contract, symbol, name, decimals) + AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8)) ) AS token, symbol, decimals FROM {db_evm_tokens:Identifier}.metadata_view - WHERE contract IN (SELECT contract FROM unique_tokens) - AND contract NOT IN ('0x0000000000000000000000000000000000000000', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') + WHERE contract NOT IN ('0x0000000000000000000000000000000000000000', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') + AND contract IN (SELECT contract FROM unique_contracts) UNION ALL SELECT contract, CAST( - (contract, native_symbol, 18) - AS Tuple(address String, symbol String, decimals UInt8) + (contract, native_symbol, 'Native', 18) + AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8)) ) AS token, native_symbol AS symbol, 18 AS decimals FROM ( SELECT - '0x0000000000000000000000000000000000000000' AS contract, + contract, multiIf( {network:String} = 'mainnet', 'ETH', {network:String} = 'arbitrum-one', 'ETH', @@ -64,25 +64,14 @@ metadata AS ( {network:String} = 'unichain', 'ETH', 'ETH' ) AS native_symbol - WHERE '0x0000000000000000000000000000000000000000' IN (SELECT contract FROM unique_tokens) - - UNION ALL - - SELECT - '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' AS contract, - multiIf( - {network:String} = 'mainnet', 'ETH', - {network:String} = 'arbitrum-one', 'ETH', - {network:String} = 'avalanche', 'AVAX', - {network:String} = 'base', 'ETH', - {network:String} = 'bsc', 'BNB', - {network:String} = 'polygon', 'POL', - {network:String} = 'optimism', 'ETH', - {network:String} = 'unichain', 'ETH', - 'ETH' - ) AS native_symbol - WHERE '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' IN (SELECT contract FROM unique_tokens) + FROM ( + SELECT '0x0000000000000000000000000000000000000000' AS contract + UNION ALL + SELECT '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' AS contract + ) ) + WHERE contract IN ('0x0000000000000000000000000000000000000000', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') + AND contract IN (SELECT contract FROM unique_contracts) ) SELECT @@ -91,7 +80,7 @@ SELECT m1.token AS input_token, m2.token AS output_token, p.fee AS fee, - replaceAll(p.protocol, '-', '_') AS protocol, + replaceAll(CAST(p.protocol AS String), '-', '_') AS protocol, {network:String} AS network FROM filtered_pools AS p LEFT JOIN metadata AS m1 ON p.token0 = m1.contract From 26b347ce4cb626a6bd46f1cf807c1277a47a1426 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Thu, 11 Dec 2025 22:51:30 -0500 Subject: [PATCH 24/52] replace user filter with separate caller, sender, and recipient filters --- src/routes/v1/evm/swaps/evm.ts | 8 +++++-- src/sql/swaps/evm.sql | 40 +++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 8 deletions(-) diff --git a/src/routes/v1/evm/swaps/evm.ts b/src/routes/v1/evm/swaps/evm.ts index 08354368..e411e918 100644 --- a/src/routes/v1/evm/swaps/evm.ts +++ b/src/routes/v1/evm/swaps/evm.ts @@ -46,7 +46,9 @@ const querySchema = createQuerySchema({ meta: { example: EVM_FACTORY_UNISWAP_V2_EXAMPLE }, }, pool: { schema: evmPoolSchema, batched: true, default: '', meta: { example: EVM_POOL_USDC_WETH_EXAMPLE } }, - user: { schema: evmAddressSchema, batched: true, default: '', meta: { example: EVM_ADDRESS_SWAP_EXAMPLE } }, + caller: { schema: evmAddressSchema, batched: true, default: '', meta: { example: EVM_ADDRESS_SWAP_EXAMPLE } }, + sender: { schema: evmAddressSchema, batched: true, default: '', meta: { example: EVM_ADDRESS_SWAP_EXAMPLE } }, + recipient: { schema: evmAddressSchema, batched: true, default: '', meta: { example: EVM_ADDRESS_SWAP_EXAMPLE } }, input_contract: { schema: evmContractSchema, batched: true, @@ -82,7 +84,9 @@ const responseSchema = apiUsageResponseSchema.extend({ input_token: evmTokenResponseSchema, output_token: evmTokenResponseSchema, - user: evmAddressSchema, + caller: evmAddressSchema, + sender: evmAddressSchema, + recipient: evmAddressSchema, input_amount: z.string(), input_value: z.number(), diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index cb711457..abbadc3d 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -6,7 +6,9 @@ active_filters AS toUInt8({transaction_id:Array(String)} != ['']) + toUInt8({factory:Array(String)} != ['']) + toUInt8({pool:Array(String)} != ['']) + - toUInt8({user:Array(String)} != ['']) + + toUInt8({recipient:Array(String)} != ['']) + + toUInt8({sender:Array(String)} != ['']) + + toUInt8({caller:Array(String)} != ['']) + toUInt8({input_contract:Array(String)} != ['']) + toUInt8({output_contract:Array(String)} != ['']) + toUInt8({protocol:String} != '') @@ -41,7 +43,23 @@ minutes_union AS SELECT minute FROM swaps - WHERE ({user:Array(String)} != [''] AND user IN {user:Array(String)}) + WHERE ({recipient:Array(String)} != [''] AND user IN {recipient:Array(String)}) + GROUP BY minute + ORDER BY minute DESC + + UNION ALL + + SELECT minute + FROM swaps + WHERE ({sender:Array(String)} != [''] AND user IN {sender:Array(String)}) + GROUP BY minute + ORDER BY minute DESC + + UNION ALL + + SELECT minute + FROM swaps + WHERE ({caller:Array(String)} != [''] AND user IN {caller:Array(String)}) GROUP BY minute ORDER BY minute DESC @@ -125,7 +143,15 @@ filtered_swaps AS ({transaction_id:Array(String)} = [''] OR tx_hash IN {transaction_id:Array(String)}) AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) - AND ({user:Array(String)} = [''] OR user IN {user:Array(String)}) + AND ( + ({recipient:Array(String)} == [''] AND {sender:Array(String)} == [''] AND {caller:Array(String)} == ['']) + OR + ({recipient:Array(String)} != [''] AND user IN {recipient:Array(String)}) + OR + ({sender:Array(String)} != [''] AND user IN {sender:Array(String)}) + OR + ({caller:Array(String)} != [''] AND user IN {caller:Array(String)}) + ) AND ({input_contract:Array(String)} = [''] OR input_contract IN {input_contract:Array(String)}) AND ({output_contract:Array(String)} = [''] OR output_contract IN {output_contract:Array(String)}) AND ({protocol:String} = '' OR protocol = replaceAll({protocol:String}, '_', '-')) @@ -193,7 +219,9 @@ SELECT s.tx_hash AS transaction_id, toString(s.factory) AS factory, s.pool AS pool, - s.user AS user, + s.user AS caller, + s.user AS sender, + s.user AS recipient, m1.token AS input_token, m2.token AS output_token, toString(s.input_amount) AS input_amount, @@ -202,7 +230,7 @@ SELECT s.output_amount / pow(10, m2.decimals) AS output_value, if(s.input_amount > 0, (s.output_amount / pow(10, m2.decimals)) / (s.input_amount / pow(10, m1.decimals)), 0) AS price, if(s.output_amount > 0, (s.input_amount / pow(10, m1.decimals)) / (s.output_amount / pow(10, m2.decimals)), 0) AS price_inv, - replaceAll(s.protocol, '-', '_') AS protocol, + replaceAll(CAST(s.protocol AS String), '-', '_') AS protocol, format('Swap {} {} for {} {} on {}', if(s.input_amount / pow(10, m1.decimals) > 1000, formatReadableQuantity(s.input_amount / pow(10, m1.decimals)), toString(s.input_amount / pow(10, m1.decimals))), m1.symbol, @@ -210,7 +238,7 @@ SELECT m2.symbol, arrayStringConcat( arrayMap(x -> concat(upper(substring(x, 1, 1)), substring(x, 2)), - splitByChar('_', replaceAll(s.protocol, '-', '_'))), + splitByChar('_', replaceAll(CAST(s.protocol AS String), '-', '_'))), ' ' ) ) AS summary, From 49120fa6334f0cf17d7ca3150690d5d64479d542 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Thu, 11 Dec 2025 23:04:58 -0500 Subject: [PATCH 25/52] refactor supported_dexes queries to use ohlc_prices table and add result limits --- src/sql/supported_dexes/evm.sql | 37 ++++++++++++++++++++++++--------- src/sql/supported_dexes/svm.sql | 3 ++- src/sql/supported_dexes/tvm.sql | 3 ++- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/sql/supported_dexes/evm.sql b/src/sql/supported_dexes/evm.sql index 8b7391e6..23d52ff4 100644 --- a/src/sql/supported_dexes/evm.sql +++ b/src/sql/supported_dexes/evm.sql @@ -1,10 +1,27 @@ -SELECT - toString(factory) AS factory, - protocol, - sum(uaw) AS uaw, - sum(transactions) AS transactions, - max(timestamp) as last_activity -FROM pool_activity_summary -GROUP BY - factory, protocol -ORDER BY transactions DESC, uaw DESC, protocol, factory \ No newline at end of file +WITH all_dexes AS ( + SELECT + replaceAll(CAST(protocol AS String), '-', '_') AS protocol, + factory, + sum(transactions) as transactions, + uniqMerge(uaw) as uaw, + max(timestamp) as last_activity + FROM ohlc_prices + WHERE interval_min = 10080 + GROUP BY + protocol, + factory +) +SELECT * FROM all_dexes +ORDER BY transactions DESC +LIMIT 100 + +-- SELECT +-- toString(factory) AS factory, +-- protocol, +-- sum(uaw) AS uaw, +-- sum(transactions) AS transactions, +-- max(timestamp) as last_activity +-- FROM pool_activity_summary +-- GROUP BY +-- factory, protocol +-- ORDER BY transactions DESC, uaw DESC, protocol, factory diff --git a/src/sql/supported_dexes/svm.sql b/src/sql/supported_dexes/svm.sql index 5767cd46..04a0b8a4 100644 --- a/src/sql/supported_dexes/svm.sql +++ b/src/sql/supported_dexes/svm.sql @@ -9,4 +9,5 @@ FROM pool_activity_summary AS p GROUP BY p.program_id, p.amm -ORDER BY transactions DESC, program_id, amm \ No newline at end of file +ORDER BY transactions DESC, program_id, amm +LIMIT 100 diff --git a/src/sql/supported_dexes/tvm.sql b/src/sql/supported_dexes/tvm.sql index 84a04576..c3f82ba6 100644 --- a/src/sql/supported_dexes/tvm.sql +++ b/src/sql/supported_dexes/tvm.sql @@ -12,4 +12,5 @@ WITH all_dexes AS ( factory ) SELECT * FROM all_dexes -ORDER BY transactions DESC, uaw DESC, protocol, factory \ No newline at end of file +ORDER BY transactions DESC, uaw DESC, protocol, factory +LIMIT 100 From f0670838b691caad789469685bf6fac869c906e8 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Thu, 11 Dec 2025 23:23:01 -0500 Subject: [PATCH 26/52] refactor ohlc_prices_for_pool query to use token metadata and interval_min filter --- src/routes/v1/evm/pools/ohlc/evm.ts | 5 +- src/sql/ohlcv_prices_for_pool/evm.sql | 91 ++++++++++++++++++++++----- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/src/routes/v1/evm/pools/ohlc/evm.ts b/src/routes/v1/evm/pools/ohlc/evm.ts index 6c75e535..dbd9746c 100644 --- a/src/routes/v1/evm/pools/ohlc/evm.ts +++ b/src/routes/v1/evm/pools/ohlc/evm.ts @@ -90,7 +90,9 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const params = c.req.valid('query'); const dbConfig = config.uniswapDatabases[params.network]; - if (!dbConfig) { + const dbEvmTokens = config.tokenDatabases[params.network]; + + if (!dbConfig || !dbEvmTokens) { return c.json({ error: `Network not found: ${params.network}` }, 400); } const query = sqlQueries.ohlcv_prices_for_pool?.[dbConfig.type]; @@ -101,6 +103,7 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat [query], { ...params, + db_evm_tokens: dbEvmTokens.database, high_quantile: 1 - config.ohlcQuantile, low_quantile: config.ohlcQuantile, stablecoin_contracts: [...stables], diff --git a/src/sql/ohlcv_prices_for_pool/evm.sql b/src/sql/ohlcv_prices_for_pool/evm.sql index 63f82db5..eee8c514 100644 --- a/src/sql/ohlcv_prices_for_pool/evm.sql +++ b/src/sql/ohlcv_prices_for_pool/evm.sql @@ -1,23 +1,47 @@ -WITH ohlc AS ( +WITH token_metadata AS ( SELECT - if( - toTime(toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE)) = toDateTime('1970-01-02 00:00:00'), - toDate(toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE)), - toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE) - ) AS datetime, - CONCAT(symbol0, symbol1) AS ticker, + t0.contract AS token0, + t0.symbol AS symbol0, + t1.contract AS token1, + t1.symbol AS symbol1 + FROM ( + SELECT DISTINCT token0, token1 + FROM ohlc_prices + WHERE pool = {pool: String} + AND interval_min = {interval: UInt64} + AND timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} + ) AS p + LEFT JOIN {db_evm_tokens:Identifier}.metadata_view AS t0 ON p.token0 = t0.contract + LEFT JOIN {db_evm_tokens:Identifier}.metadata_view AS t1 ON p.token1 = t1.contract +), + +ohlc AS ( + SELECT + timestamp AS datetime, + CONCAT(m.symbol0, m.symbol1) AS ticker, pool, argMinMerge(open0) AS open_raw, - greatest(quantileDeterministicMerge({high_quantile: Float32})(quantile0), open_raw, close_raw) AS high_raw, - least(quantileDeterministicMerge({low_quantile: Float32})(quantile0), open_raw, close_raw) AS low_raw, + greatest( + quantileDeterministicMerge({high_quantile: Float32})(quantile0), + argMinMerge(open0), + argMaxMerge(close0) + ) AS high_raw, + least( + quantileDeterministicMerge({low_quantile: Float32})(quantile0), + argMinMerge(open0), + argMaxMerge(close0) + ) AS low_raw, argMaxMerge(close0) AS close_raw, sum(gross_volume0) AS volume, uniqMerge(uaw) AS uaw, sum(transactions) AS transactions, - toString(token0) IN {stablecoin_contracts: Array(String)} AS is_stablecoin - FROM ohlc_prices - WHERE pool = {pool: String} AND timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} - GROUP BY datetime, pool, symbol0, symbol1, token0 + p.token0 IN {stablecoin_contracts: Array(String)} AS is_stablecoin + FROM ohlc_prices p + JOIN token_metadata m ON p.token0 = m.token0 AND p.token1 = m.token1 + WHERE p.pool = {pool: String} + AND p.interval_min = {interval: UInt64} + AND p.timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} + GROUP BY datetime, pool, m.symbol0, m.symbol1, p.token0, p.token1, ticker ORDER BY datetime DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} @@ -33,4 +57,43 @@ SELECT volume, uaw, transactions -FROM ohlc \ No newline at end of file +FROM ohlc + + +-- old schema +-- WITH ohlc AS ( +-- SELECT +-- if( +-- toTime(toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE)) = toDateTime('1970-01-02 00:00:00'), +-- toDate(toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE)), +-- toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE) +-- ) AS datetime, +-- CONCAT(symbol0, symbol1) AS ticker, +-- pool, +-- argMinMerge(open0) AS open_raw, +-- greatest(quantileDeterministicMerge({high_quantile: Float32})(quantile0), open_raw, close_raw) AS high_raw, +-- least(quantileDeterministicMerge({low_quantile: Float32})(quantile0), open_raw, close_raw) AS low_raw, +-- argMaxMerge(close0) AS close_raw, +-- sum(gross_volume0) AS volume, +-- uniqMerge(uaw) AS uaw, +-- sum(transactions) AS transactions, +-- toString(token0) IN {stablecoin_contracts: Array(String)} AS is_stablecoin +-- FROM ohlc_prices +-- WHERE pool = {pool: String} AND timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} +-- GROUP BY datetime, pool, symbol0, symbol1, token0 +-- ORDER BY datetime DESC +-- LIMIT {limit:UInt64} +-- OFFSET {offset:UInt64} +-- ) +-- SELECT +-- datetime, +-- ticker, +-- pool, +-- if(is_stablecoin, 1/open_raw, open_raw) AS open, +-- if(is_stablecoin, 1/low_raw, high_raw) AS high, +-- if(is_stablecoin, 1/high_raw, low_raw) AS low, +-- if(is_stablecoin, 1/close_raw, close_raw) AS close, +-- volume, +-- uaw, +-- transactions +-- FROM ohlc From e4cdaa6f5a2c7a88dd76d2e89cb539e03d302435 Mon Sep 17 00:00:00 2001 From: YaroShkvorets Date: Thu, 11 Dec 2025 23:48:52 -0500 Subject: [PATCH 27/52] udpate changeset --- .changeset/floppy-feet-send.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/floppy-feet-send.md b/.changeset/floppy-feet-send.md index a195fcfa..dc4ba192 100644 --- a/.changeset/floppy-feet-send.md +++ b/.changeset/floppy-feet-send.md @@ -2,4 +2,4 @@ "token-api": minor --- -Updated SQL queries for svm-tokens@v0.2.8, svm-dex@v0.3.1, tvm-tokens@v0.2.0 +Updated SQL queries for svm-tokens@v0.2.8, svm-dex@v0.3.1, tvm-tokens@v0.2.0, evm-dex@v0.2.5, evm-tokens@v1.17.4 From 4a0eef32bd3e11e2ba29d5a2b97b4c183eac7551 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sat, 13 Dec 2025 15:17:45 -0500 Subject: [PATCH 28/52] Update EVM Swaps --- src/sql/swaps/evm.sql | 165 +++++++++++++----------------------------- src/types/zod.ts | 6 +- 2 files changed, 53 insertions(+), 118 deletions(-) diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index abbadc3d..4f4eb32a 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -3,15 +3,15 @@ WITH active_filters AS ( SELECT - toUInt8({transaction_id:Array(String)} != ['']) + - toUInt8({factory:Array(String)} != ['']) + - toUInt8({pool:Array(String)} != ['']) + - toUInt8({recipient:Array(String)} != ['']) + - toUInt8({sender:Array(String)} != ['']) + - toUInt8({caller:Array(String)} != ['']) + - toUInt8({input_contract:Array(String)} != ['']) + + toUInt8({transaction_id:Array(String)} != ['']) + + toUInt8({factory:Array(String)} != ['']) + + toUInt8({pool:Array(String)} != ['']) + + toUInt8({recipient:Array(String)} != ['']) + + toUInt8({sender:Array(String)} != ['']) + + toUInt8({caller:Array(String)} != ['']) + + toUInt8({input_contract:Array(String)} != ['']) + toUInt8({output_contract:Array(String)} != ['']) + - toUInt8({protocol:String} != '') + toUInt8({protocol:String} != '') AS n ), /* 2) Union minutes from only active filters */ @@ -102,135 +102,68 @@ filtered_minutes AS (toUInt64({limit:UInt64}) + toUInt64({offset:UInt64})) * 10 /* unsafe limit with a multiplier - usually safe but find a way to early return */ ) ), -/* Latest ingested timestamp in source table */ -latest_minute AS -( - SELECT max(minute) AS minute FROM swaps -), - filtered_swaps AS ( - SELECT - block_num, - timestamp, - tx_hash, - tx_index, - log_index, - factory, - pool, - protocol, - user, - input_contract, - output_contract, - input_amount, - output_amount + SELECT * FROM swaps PREWHERE - timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} + minute BETWEEN toRelativeMinuteNum(toDateTime({start_time: UInt64})) AND toRelativeMinuteNum(toDateTime({end_time: UInt64})) + AND ((SELECT n FROM active_filters) = 0 OR minute IN filtered_minutes) + AND timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} AND block_num BETWEEN {start_block: UInt64} AND {end_block: UInt64} - AND ( - ( - /* if no filters are active search only the last minute */ - (SELECT n FROM active_filters) = 0 - AND minute BETWEEN - greatest( toRelativeMinuteNum(toDateTime({start_time:UInt64})), least(toRelativeMinuteNum(toDateTime({end_time:UInt64})), (SELECT minute FROM latest_minute)) - (1 + 1 * {offset:UInt64})) - AND least(toRelativeMinuteNum(toDateTime({end_time:UInt64})), (SELECT minute FROM latest_minute)) - ) - /* if filters are active, search through the intersecting minute ranges */ - OR minute IN (SELECT minute FROM filtered_minutes) - ) WHERE - ({transaction_id:Array(String)} = [''] OR tx_hash IN {transaction_id:Array(String)}) - AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) - AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) - AND ( - ({recipient:Array(String)} == [''] AND {sender:Array(String)} == [''] AND {caller:Array(String)} == ['']) - OR - ({recipient:Array(String)} != [''] AND user IN {recipient:Array(String)}) - OR - ({sender:Array(String)} != [''] AND user IN {sender:Array(String)}) - OR - ({caller:Array(String)} != [''] AND user IN {caller:Array(String)}) - ) - AND ({input_contract:Array(String)} = [''] OR input_contract IN {input_contract:Array(String)}) - AND ({output_contract:Array(String)} = [''] OR output_contract IN {output_contract:Array(String)}) - AND ({protocol:String} = '' OR protocol = replaceAll({protocol:String}, '_', '-')) - ORDER BY timestamp DESC, tx_hash, log_index + ({transaction_id:Array(String)} = [''] OR tx_hash IN {transaction_id:Array(String)}) + AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) + AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) + AND ({recipient:Array(String)} = [''] OR user IN {recipient:Array(String)}) + AND ({sender:Array(String)} = [''] OR user IN {sender:Array(String)}) + AND ({caller:Array(String)} = [''] OR user IN {caller:Array(String)}) + AND ({input_contract:Array(String)} = [''] OR input_contract IN {input_contract:Array(String)}) + AND ({output_contract:Array(String)} = [''] OR output_contract IN {output_contract:Array(String)}) + AND ({protocol:String} = '' OR protocol = {protocol:String}) + ORDER BY minute DESC, timestamp DESC, block_num DESC, log_ordinal DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} -), - -unique_contracts AS ( - SELECT input_contract AS contract FROM filtered_swaps - UNION DISTINCT - SELECT output_contract AS contract FROM filtered_swaps -), - -metadata AS ( - SELECT - contract, - CAST( - (contract, symbol, name, decimals) - AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8)) - ) AS token, - symbol, - decimals - FROM {db_evm_tokens:Identifier}.metadata_view - WHERE contract IN (SELECT contract FROM unique_contracts) - AND contract NOT IN ('0x0000000000000000000000000000000000000000', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') - - UNION ALL - - SELECT - contract, - CAST( - (contract, native_symbol, 'Native', 18) - AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8)) - ) AS token, - native_symbol AS symbol, - 18 AS decimals - FROM ( - SELECT - contract, - multiIf( - {network:String} = 'mainnet', 'ETH', - {network:String} = 'arbitrum-one', 'ETH', - {network:String} = 'avalanche', 'AVAX', - {network:String} = 'base', 'ETH', - {network:String} = 'bsc', 'BNB', - {network:String} = 'polygon', 'POL', - {network:String} = 'optimism', 'ETH', - {network:String} = 'unichain', 'ETH', - 'ETH' - ) AS native_symbol - FROM ( - SELECT '0x0000000000000000000000000000000000000000' AS contract - UNION ALL - SELECT '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' AS contract - ) - ) - WHERE contract IN (SELECT contract FROM unique_contracts) ) - SELECT + /* block */ s.block_num AS block_num, s.timestamp AS datetime, toUnixTimestamp(s.timestamp) AS timestamp, + + /* transaction */ s.tx_hash AS transaction_id, + s.log_ordinal AS ordinal, + + /* swap */ toString(s.factory) AS factory, s.pool AS pool, - s.user AS caller, + s.user AS caller, /* rename to `s.tx_from` once v0.2.6 is deployed */ s.user AS sender, s.user AS recipient, - m1.token AS input_token, - m2.token AS output_token, + + /* tokens */ + CAST (( + s.input_contract, + m1.symbol, + m1.decimals + ) AS Tuple(address String, symbol String, decimals UInt8)) AS input_token, + CAST (( + s.output_contract, + m2.symbol, + m2.decimals + ) AS Tuple(address String, symbol String, decimals UInt8)) AS output_token, + + /* amounts and prices */ toString(s.input_amount) AS input_amount, s.input_amount / pow(10, m1.decimals) AS input_value, toString(s.output_amount) AS output_amount, s.output_amount / pow(10, m2.decimals) AS output_value, if(s.input_amount > 0, (s.output_amount / pow(10, m2.decimals)) / (s.input_amount / pow(10, m1.decimals)), 0) AS price, if(s.output_amount > 0, (s.input_amount / pow(10, m1.decimals)) / (s.output_amount / pow(10, m2.decimals)), 0) AS price_inv, - replaceAll(CAST(s.protocol AS String), '-', '_') AS protocol, + s.protocol AS protocol, + + /* summary */ format('Swap {} {} for {} {} on {}', if(s.input_amount / pow(10, m1.decimals) > 1000, formatReadableQuantity(s.input_amount / pow(10, m1.decimals)), toString(s.input_amount / pow(10, m1.decimals))), m1.symbol, @@ -238,12 +171,14 @@ SELECT m2.symbol, arrayStringConcat( arrayMap(x -> concat(upper(substring(x, 1, 1)), substring(x, 2)), - splitByChar('_', replaceAll(CAST(s.protocol AS String), '-', '_'))), + splitByChar('_', toString(s.protocol))), ' ' ) ) AS summary, + + /* network */ {network:String} AS network FROM filtered_swaps AS s LEFT JOIN metadata AS m1 ON s.input_contract = m1.contract LEFT JOIN metadata AS m2 ON s.output_contract = m2.contract -ORDER BY s.timestamp DESC, s.tx_hash +ORDER BY minute DESC, timestamp DESC, block_num DESC, log_ordinal DESC diff --git a/src/types/zod.ts b/src/types/zod.ts index b9464574..10fb34d2 100644 --- a/src/types/zod.ts +++ b/src/types/zod.ts @@ -129,7 +129,7 @@ export const tvmNetworkIdSchema = z // ---------------------- export const evmProtocolSchema = z - .enum(['uniswap_v2', 'uniswap_v3', 'uniswap_v4']) + .enum(['uniswap_v1', 'uniswap_v2', 'uniswap_v3', 'uniswap_v4', 'bancor', 'curvefi', 'balancer']) .meta({ description: 'Protocol name', example: 'uniswap_v3' }); export const svmProtocolSchema = z @@ -137,8 +137,8 @@ export const svmProtocolSchema = z .meta({ description: 'Protocol name', example: 'raydium_amm_v4' }); export const tvmProtocolSchema = z - .enum(['justswap', 'sunswap', 'sunpump']) - .meta({ description: 'Protocol name', example: 'sunswap' }); + .enum(['uniswap_v1', 'uniswap_v2', 'uniswap_v3', 'uniswap_v4', 'sunpump']) + .meta({ description: 'Protocol name', example: 'uniswap_v2' }); // ---------------------- // Common Query Parameter Schemas From bbff390e9cf1956277ffb87605751796941a3638 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sat, 13 Dec 2025 15:26:53 -0500 Subject: [PATCH 29/52] update tests --- src/types/zod.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/types/zod.spec.ts b/src/types/zod.spec.ts index ce8d58da..b530ad12 100644 --- a/src/types/zod.spec.ts +++ b/src/types/zod.spec.ts @@ -257,8 +257,8 @@ describe('Protocol Schemas', () => { describe('tvmProtocolSchema', () => { it('should accept valid protocols', () => { - expect(tvmProtocolSchema.parse('justswap')).toBe('justswap'); - expect(tvmProtocolSchema.parse('sunswap')).toBe('sunswap'); + expect(tvmProtocolSchema.parse('uniswap_v2')).toBe('uniswap_v2'); + expect(tvmProtocolSchema.parse('uniswap_v1')).toBe('uniswap_v1'); expect(tvmProtocolSchema.parse('sunpump')).toBe('sunpump'); }); From 688f962572040611284d2ac6d99907e0451a9869 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Sun, 14 Dec 2025 21:36:16 -0500 Subject: [PATCH 30/52] Update pools (NOT FINISHED) --- src/sql/pools/evm.sql | 126 +++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 82 deletions(-) diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index c0af5319..4a7d1442 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -1,88 +1,50 @@ -WITH filtered_pools AS ( - SELECT - initialize_block_num AS block_num, - initialize_timestamp AS datetime, - initialize_tx_hash AS transaction_id, - toString(factory) AS factory, - pool, - arrayElement(tokens, 1) AS token0, - arrayElement(tokens, 2) AS token1, - fee, - protocol - FROM pools +WITH has_pools AS ( + SELECT DISTINCT pool + FROM state_pools_aggregating_by_token WHERE - ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) - AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) - AND ({input_token:Array(String)} = [''] OR hasAny(tokens, {input_token:Array(String)})) - AND ({output_token:Array(String)} = [''] OR hasAny(tokens, {output_token:Array(String)})) - AND ({protocol:String} = '' OR CAST(protocol AS String) = replaceAll({protocol:String}, '_', '-')) - ORDER BY datetime DESC - LIMIT {limit:UInt64} - OFFSET {offset:UInt64} -), - -unique_contracts AS ( - SELECT token0 AS contract FROM filtered_pools - UNION DISTINCT - SELECT token1 AS contract FROM filtered_pools -), - -metadata AS ( - SELECT - contract, - CAST( - (contract, symbol, name, decimals) - AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8)) - ) AS token, - symbol, - decimals - FROM {db_evm_tokens:Identifier}.metadata_view - WHERE contract NOT IN ('0x0000000000000000000000000000000000000000', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') - AND contract IN (SELECT contract FROM unique_contracts) - - UNION ALL - - SELECT - contract, - CAST( - (contract, native_symbol, 'Native', 18) - AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8)) - ) AS token, - native_symbol AS symbol, - 18 AS decimals - FROM ( - SELECT - contract, - multiIf( - {network:String} = 'mainnet', 'ETH', - {network:String} = 'arbitrum-one', 'ETH', - {network:String} = 'avalanche', 'AVAX', - {network:String} = 'base', 'ETH', - {network:String} = 'bsc', 'BNB', - {network:String} = 'polygon', 'POL', - {network:String} = 'optimism', 'ETH', - {network:String} = 'unichain', 'ETH', - 'ETH' - ) AS native_symbol - FROM ( - SELECT '0x0000000000000000000000000000000000000000' AS contract - UNION ALL - SELECT '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' AS contract - ) - ) - WHERE contract IN ('0x0000000000000000000000000000000000000000', '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee') - AND contract IN (SELECT contract FROM unique_contracts) + token IN {input_token:Array(String)} OR + token IN {output_token:Array(String)} ) - SELECT + /* DEX identity */ p.factory AS factory, p.pool AS pool, - m1.token AS input_token, - m2.token AS output_token, - p.fee AS fee, - replaceAll(CAST(p.protocol AS String), '-', '_') AS protocol, + + /* initialize */ + initialize_block_num AS block_num, + initialize_timestamp AS datetime, + initialize_tx_hash AS transaction_id, + + /* tokens */ + CAST (( + arrayElement(pt.tokens, 1), + m1.symbol, + m1.decimals + ) AS Tuple(address String, symbol String, decimals UInt8)) AS input_token, + CAST (( + arrayElement(pt.tokens, 2), + m2.symbol, + m2.decimals + ) AS Tuple(address String, symbol String, decimals UInt8)) AS output_token, + + fee, + toString(protocol) AS protocol, {network:String} AS network -FROM filtered_pools AS p -LEFT JOIN metadata AS m1 ON p.token0 = m1.contract -LEFT JOIN metadata AS m2 ON p.token1 = m2.contract -ORDER BY p.datetime DESC, p.protocol + +FROM pools AS p +WHERE + ({input_token:Array(String)} = [''] OR p.pool IN has_pools) +AND ({output_token:Array(String)} = [''] OR p.pool IN has_pools) +AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) +AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) +AND ({protocol:String} = '' OR toString(protocol) = {protocol:String}) +AND ({input_token:Array(String)} = [''] OR arrayElement(pt.tokens, 1) IN {input_token:Array(String)}) +AND ({output_token:Array(String)} = [''] OR arrayElement(pt.tokens, 2) IN {output_token:Array(String)}) + +LEFT JOIN pools_tokens AS pt ON pt.pool = p.pool +LEFT JOIN metadata AS m1 ON arrayElement(pt.tokens, 1) = m1.contract +LEFT JOIN metadata AS m2 ON arrayElement(pt.tokens, 2) = m2.contract + +ORDER BY p.transactions DESC +LIMIT {limit:UInt64} +OFFSET {offset:UInt64} From 60d45e42ea878e2982b3bfadb30a2e69615e8009 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Mon, 15 Dec 2025 14:53:54 -0500 Subject: [PATCH 31/52] Update OHLC --- src/routes/v1/svm/pools/ohlc/svm.ts | 2 - src/sql/ohlcv_prices_for_pool/evm.sql | 110 ++++++++------------------ 2 files changed, 33 insertions(+), 79 deletions(-) diff --git a/src/routes/v1/svm/pools/ohlc/svm.ts b/src/routes/v1/svm/pools/ohlc/svm.ts index 71fb636d..18331eb8 100644 --- a/src/routes/v1/svm/pools/ohlc/svm.ts +++ b/src/routes/v1/svm/pools/ohlc/svm.ts @@ -113,8 +113,6 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat [query], { ...params, - high_quantile: 0.95, - low_quantile: 0.05, stablecoin_contracts: [...stables], db_svm_tokens: db_svm_tokens.database, }, diff --git a/src/sql/ohlcv_prices_for_pool/evm.sql b/src/sql/ohlcv_prices_for_pool/evm.sql index eee8c514..b5df0993 100644 --- a/src/sql/ohlcv_prices_for_pool/evm.sql +++ b/src/sql/ohlcv_prices_for_pool/evm.sql @@ -1,47 +1,42 @@ -WITH token_metadata AS ( - SELECT - t0.contract AS token0, - t0.symbol AS symbol0, - t1.contract AS token1, - t1.symbol AS symbol1 - FROM ( - SELECT DISTINCT token0, token1 - FROM ohlc_prices - WHERE pool = {pool: String} - AND interval_min = {interval: UInt64} - AND timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} - ) AS p - LEFT JOIN {db_evm_tokens:Identifier}.metadata_view AS t0 ON p.token0 = t0.contract - LEFT JOIN {db_evm_tokens:Identifier}.metadata_view AS t1 ON p.token1 = t1.contract -), - -ohlc AS ( +WITH ohlc AS ( SELECT timestamp AS datetime, - CONCAT(m.symbol0, m.symbol1) AS ticker, + CONCAT(m0.symbol, m1.symbol) AS ticker, + + /* DEX identity */ pool, - argMinMerge(open0) AS open_raw, + + /* OHLC */ + pow(10, m1.decimals - m0.decimals) AS price_multiplier, + open0 / price_multiplier AS open_raw, greatest( - quantileDeterministicMerge({high_quantile: Float32})(quantile0), - argMinMerge(open0), - argMaxMerge(close0) - ) AS high_raw, + high_quantile0, + open0, + close0 + ) / price_multiplier AS high_raw, least( - quantileDeterministicMerge({low_quantile: Float32})(quantile0), - argMinMerge(open0), - argMaxMerge(close0) - ) AS low_raw, - argMaxMerge(close0) AS close_raw, - sum(gross_volume0) AS volume, - uniqMerge(uaw) AS uaw, - sum(transactions) AS transactions, + low_quantile0, + open0, + close0 + ) / price_multiplier AS low_raw, + close0 / price_multiplier AS close_raw, + + /* Volume */ + gross_volume0 / pow(10, m0.decimals) AS volume, + + /* Universal */ + uniq_tx_from AS uaw, + transactions, + + /* extra fields */ p.token0 IN {stablecoin_contracts: Array(String)} AS is_stablecoin FROM ohlc_prices p - JOIN token_metadata m ON p.token0 = m.token0 AND p.token1 = m.token1 - WHERE p.pool = {pool: String} - AND p.interval_min = {interval: UInt64} - AND p.timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} - GROUP BY datetime, pool, m.symbol0, m.symbol1, p.token0, p.token1, ticker + JOIN metadata m0 ON p.token0 = m0.contract + JOIN metadata m1 ON p.token1 = m1.contract + WHERE + p.interval_min = {interval: UInt64} + AND p.pool = {pool: String} + AND p.timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} ORDER BY datetime DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} @@ -57,43 +52,4 @@ SELECT volume, uaw, transactions -FROM ohlc - - --- old schema --- WITH ohlc AS ( --- SELECT --- if( --- toTime(toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE)) = toDateTime('1970-01-02 00:00:00'), --- toDate(toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE)), --- toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE) --- ) AS datetime, --- CONCAT(symbol0, symbol1) AS ticker, --- pool, --- argMinMerge(open0) AS open_raw, --- greatest(quantileDeterministicMerge({high_quantile: Float32})(quantile0), open_raw, close_raw) AS high_raw, --- least(quantileDeterministicMerge({low_quantile: Float32})(quantile0), open_raw, close_raw) AS low_raw, --- argMaxMerge(close0) AS close_raw, --- sum(gross_volume0) AS volume, --- uniqMerge(uaw) AS uaw, --- sum(transactions) AS transactions, --- toString(token0) IN {stablecoin_contracts: Array(String)} AS is_stablecoin --- FROM ohlc_prices --- WHERE pool = {pool: String} AND timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} --- GROUP BY datetime, pool, symbol0, symbol1, token0 --- ORDER BY datetime DESC --- LIMIT {limit:UInt64} --- OFFSET {offset:UInt64} --- ) --- SELECT --- datetime, --- ticker, --- pool, --- if(is_stablecoin, 1/open_raw, open_raw) AS open, --- if(is_stablecoin, 1/low_raw, high_raw) AS high, --- if(is_stablecoin, 1/high_raw, low_raw) AS low, --- if(is_stablecoin, 1/close_raw, close_raw) AS close, --- volume, --- uaw, --- transactions --- FROM ohlc +FROM ohlc \ No newline at end of file From 9757205e5fd4f01fa43fafdb59fbbc3e5e9bbc9c Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Mon, 15 Dec 2025 14:57:09 -0500 Subject: [PATCH 32/52] Remove evm/prices --- src/routes/v1/evm/prices/evm.ts | 105 ------------------ src/routes/v1/evm/prices/index.ts | 8 -- src/sql/ohlcv_prices_usd_for_contract/evm.sql | 61 ---------- 3 files changed, 174 deletions(-) delete mode 100644 src/routes/v1/evm/prices/evm.ts delete mode 100644 src/routes/v1/evm/prices/index.ts delete mode 100644 src/sql/ohlcv_prices_usd_for_contract/evm.sql diff --git a/src/routes/v1/evm/prices/evm.ts b/src/routes/v1/evm/prices/evm.ts deleted file mode 100644 index d2bb147f..00000000 --- a/src/routes/v1/evm/prices/evm.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { zValidator } from '@hono/zod-validator'; -import { Hono } from 'hono'; -import { describeRoute, resolver, validator } from 'hono-openapi'; -import { z } from 'zod'; -import { config } from '../../../../config.js'; -import { handleUsageQueryError, makeUsageQueryJson } from '../../../../handleQuery.js'; -import { stables } from '../../../../inject/prices.tokens.js'; -import { sqlQueries } from '../../../../sql/index.js'; -import { - apiUsageResponseSchema, - createQuerySchema, - dateTimeSchema, - evmContractSchema, - evmNetworkIdSchema, - intervalSchema, - timestampSchema, -} from '../../../../types/zod.js'; -import { validatorHook, withErrorResponses } from '../../../../utils.js'; - -const querySchema = createQuerySchema({ - network: { schema: evmNetworkIdSchema }, - - contract: { schema: evmContractSchema }, - interval: { schema: intervalSchema, prefault: '1d' }, - start_time: { schema: timestampSchema, prefault: '2025-01-01' }, - end_time: { schema: timestampSchema, prefault: '2050-01-01' }, -}); - -const responseSchema = apiUsageResponseSchema.extend({ - data: z.array( - z.object({ - datetime: dateTimeSchema, - ticker: z.string(), - open: z.number(), - high: z.number(), - low: z.number(), - close: z.number(), - volume: z.number(), - uaw: z.number(), - transactions: z.number(), - }) - ), -}); - -const openapi = describeRoute( - withErrorResponses({ - summary: 'Token Prices (USD)', - description: - 'Returns OHLCV price data in USD for tokens.\n\nOHLCV historical depth is subject to plan restrictions.', - tags: ['EVM DEXs'], - security: [{ bearerAuth: [] }], - responses: { - 200: { - description: 'Successful Response', - content: { - 'application/json': { - schema: resolver(responseSchema), - examples: { - example: { - value: { - data: [ - { - datetime: '2025-05-29 15:00:00', - ticker: 'WETHUSD', - open: 2669.130852861705, - high: 2669.130852861705, - low: 2669.130852861705, - close: 2669.130852861705, - volume: 184897.1695477702, - uaw: 31, - transactions: 35, - }, - ], - }, - }, - }, - }, - }, - }, - }, - }) -); - -const route = new Hono<{ Variables: { validatedData: z.infer } }>(); - -route.get('/', openapi, zValidator('query', querySchema, validatorHook), validator('query', querySchema), async (c) => { - const params = c.req.valid('query'); - - const dbConfig = config.uniswapDatabases[params.network]; - if (!dbConfig) { - return c.json({ error: `Network not found: ${params.network}` }, 400); - } - const query = sqlQueries.ohlcv_prices_usd_for_contract?.[dbConfig.type]; - if (!query) return c.json({ error: 'Query for OHLC price data could not be loaded' }, 500); - - const response = await makeUsageQueryJson( - c, - [query], - { ...params, stablecoin_contracts: [...stables] }, - { database: dbConfig.database } - ); - return handleUsageQueryError(c, response); -}); - -export default route; diff --git a/src/routes/v1/evm/prices/index.ts b/src/routes/v1/evm/prices/index.ts deleted file mode 100644 index e39a3004..00000000 --- a/src/routes/v1/evm/prices/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Hono } from 'hono'; -import evm from './evm.js'; - -const router = new Hono(); - -router.route('/ohlc', evm); - -export default router; diff --git a/src/sql/ohlcv_prices_usd_for_contract/evm.sql b/src/sql/ohlcv_prices_usd_for_contract/evm.sql deleted file mode 100644 index df3cfce3..00000000 --- a/src/sql/ohlcv_prices_usd_for_contract/evm.sql +++ /dev/null @@ -1,61 +0,0 @@ -WITH -metadata AS ( - SELECT - address, - name, - symbol, - decimals - FROM erc20_metadata_initialize - WHERE toString(address) IN {stablecoin_contracts: Array(String)} -), -filtered_pools AS ( - SELECT - pool, - decimals AS stable_decimals, - ( - SELECT decimals - FROM erc20_metadata_initialize - WHERE address = {contract: String} - ) AS token_decimals, - pow(10, -abs(token_decimals - stable_decimals)) AS scale_factor - FROM pools AS p - LEFT JOIN metadata AS m ON p.token0 = m.address OR p.token1 = m.address - WHERE - p.token0 = {contract: String} - OR p.token1 = {contract: String} -), -normalized_prices AS ( - SELECT - if( - toTime(toStartOfInterval(o.timestamp, INTERVAL {interval: UInt64} MINUTE)) = toDateTime('1970-01-02 00:00:00'), - toDate(toStartOfInterval(o.timestamp, INTERVAL {interval: UInt64} MINUTE)), - toStartOfInterval(o.timestamp, INTERVAL {interval: UInt64} MINUTE) - ) AS datetime, - argMin(open, o.timestamp) AS open, - max(high) AS high, - min(low) AS low, - argMax(close, o.timestamp) AS close, - sum(o.volume) AS volume, - sum(uaw) AS uaw, - sum(transactions) AS transactions - FROM ohlc_prices_by_contract AS o - JOIN filtered_pools AS p ON p.pool = o.pool - WHERE token = {contract: String} - AND o.timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} - GROUP BY datetime, pool, scale_factor -) -SELECT - datetime, - CONCAT((SELECT symbol FROM erc20_metadata_initialize FINAL WHERE address = {contract: String}), 'USD') AS ticker, - quantileExactWeighted(open, n.transactions + n.uaw) AS open, - quantileExactWeighted(high, n.transactions + n.uaw) AS high, - quantileExactWeighted(low, n.transactions + n.uaw) AS low, - quantileExactWeighted(close, n.transactions + n.uaw) AS close, - sum(volume) AS volume, - sum(uaw) AS uaw, - sum(transactions) AS transactions -FROM normalized_prices AS n -GROUP BY datetime, ticker -ORDER BY datetime DESC -LIMIT {limit:UInt64} -OFFSET {offset:UInt64}; \ No newline at end of file From 4de772317cebd3a78a63a03a5443d497beb19803 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Mon, 15 Dec 2025 16:11:32 -0500 Subject: [PATCH 33/52] Update pools --- src/sql/pools/evm.sql | 92 +++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 34 deletions(-) diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index 4a7d1442..96f94874 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -1,50 +1,74 @@ WITH has_pools AS ( SELECT DISTINCT pool FROM state_pools_aggregating_by_token + WHERE token IN {input_token:Array(String)} OR token IN {output_token:Array(String)} +), +pools AS ( + SELECT + pool, + factory, + protocol, + sum(transactions) as transactions + FROM state_pools_aggregating_by_pool WHERE - token IN {input_token:Array(String)} OR - token IN {output_token:Array(String)} + ({input_token:Array(String)} = [''] OR pool IN has_pools) + AND ({output_token:Array(String)} = [''] OR pool IN has_pools) + AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) + AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) + AND ({protocol:String} = '' OR toString(protocol) = {protocol:String}) + GROUP BY pool, factory, protocol + ORDER BY transactions DESC + LIMIT {limit:UInt64} + OFFSET {offset:UInt64} +), +pools_with_tokens AS ( + SELECT + pool, + factory, + protocol, + arraySort(groupArrayDistinct(token)) as tokens, + arrayElement(tokens, 1) AS token0, + arrayElement(tokens, 2) AS token1 + + FROM pools AS p + JOIN state_pools_aggregating_by_token AS pt ON p.pool = pt.pool + GROUP BY pool, factory, protocol ) SELECT - /* DEX identity */ - p.factory AS factory, - p.pool AS pool, - /* initialize */ - initialize_block_num AS block_num, - initialize_timestamp AS datetime, - initialize_tx_hash AS transaction_id, + i.block_num AS block_num, + i.timestamp AS timestamp, + i.tx_hash AS tx_hash, + + /* DEX */ + p.pool AS pool, + p.factory AS factory, + p.protocol AS protocol, /* tokens */ + pt.tokens AS tokens, + CAST (( - arrayElement(pt.tokens, 1), - m1.symbol, - m1.decimals + pt.token0, + m0.symbol, + m0.decimals ) AS Tuple(address String, symbol String, decimals UInt8)) AS input_token, + CAST (( - arrayElement(pt.tokens, 2), - m2.symbol, - m2.decimals + pt.token1, + m1.symbol, + m1.decimals ) AS Tuple(address String, symbol String, decimals UInt8)) AS output_token, - fee, - toString(protocol) AS protocol, - {network:String} AS network + /* stats */ + p.transactions AS transactions, + /* Fees */ + f.fee AS fee FROM pools AS p -WHERE - ({input_token:Array(String)} = [''] OR p.pool IN has_pools) -AND ({output_token:Array(String)} = [''] OR p.pool IN has_pools) -AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) -AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) -AND ({protocol:String} = '' OR toString(protocol) = {protocol:String}) -AND ({input_token:Array(String)} = [''] OR arrayElement(pt.tokens, 1) IN {input_token:Array(String)}) -AND ({output_token:Array(String)} = [''] OR arrayElement(pt.tokens, 2) IN {output_token:Array(String)}) - -LEFT JOIN pools_tokens AS pt ON pt.pool = p.pool -LEFT JOIN metadata AS m1 ON arrayElement(pt.tokens, 1) = m1.contract -LEFT JOIN metadata AS m2 ON arrayElement(pt.tokens, 2) = m2.contract - -ORDER BY p.transactions DESC -LIMIT {limit:UInt64} -OFFSET {offset:UInt64} +JOIN state_pools_initialize AS i ON p.pool = i.pool +JOIN state_pools_fees AS f ON p.pool = f.pool +JOIN pools_with_tokens AS pt ON p.pool = pt.pool +JOIN metadata AS m0 ON pt.token0 = m0.contract +JOIN metadata AS m1 ON pt.token1 = m1.contract +ORDER BY p.transactions DESC \ No newline at end of file From b4586c9d9dd5e5b5f5dcc7c518b7ed33df31b62c Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Mon, 15 Dec 2025 16:15:44 -0500 Subject: [PATCH 34/52] Fix Supported DEXes --- src/sql/supported_dexes/evm.sql | 35 ++++++++++----------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/src/sql/supported_dexes/evm.sql b/src/sql/supported_dexes/evm.sql index 23d52ff4..3482a72d 100644 --- a/src/sql/supported_dexes/evm.sql +++ b/src/sql/supported_dexes/evm.sql @@ -1,27 +1,12 @@ -WITH all_dexes AS ( - SELECT - replaceAll(CAST(protocol AS String), '-', '_') AS protocol, - factory, - sum(transactions) as transactions, - uniqMerge(uaw) as uaw, - max(timestamp) as last_activity - FROM ohlc_prices - WHERE interval_min = 10080 - GROUP BY - protocol, - factory -) -SELECT * FROM all_dexes +SELECT + protocol, + factory, + sum(transactions) as transactions, + max(max_timestamp) as last_activity, + uniqMerge(uniq_tx_from) as uaw +FROM state_pools_aggregating_by_pool +GROUP BY + protocol, + factory ORDER BY transactions DESC LIMIT 100 - --- SELECT --- toString(factory) AS factory, --- protocol, --- sum(uaw) AS uaw, --- sum(transactions) AS transactions, --- max(timestamp) as last_activity --- FROM pool_activity_summary --- GROUP BY --- factory, protocol --- ORDER BY transactions DESC, uaw DESC, protocol, factory From dcaaed63c4587c0cbd90b1c9e5ce4c76109c25f3 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Mon, 15 Dec 2025 16:24:33 -0500 Subject: [PATCH 35/52] update input/output --- src/sql/pools/evm.sql | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index 96f94874..978dc36c 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -1,7 +1,12 @@ -WITH has_pools AS ( +WITH output_pools AS ( SELECT DISTINCT pool FROM state_pools_aggregating_by_token - WHERE token IN {input_token:Array(String)} OR token IN {output_token:Array(String)} + WHERE token IN {output_token:Array(String)} +), +input_pools AS ( + SELECT DISTINCT pool + FROM state_pools_aggregating_by_token + WHERE token IN {input_token:Array(String)} ), pools AS ( SELECT @@ -11,8 +16,8 @@ pools AS ( sum(transactions) as transactions FROM state_pools_aggregating_by_pool WHERE - ({input_token:Array(String)} = [''] OR pool IN has_pools) - AND ({output_token:Array(String)} = [''] OR pool IN has_pools) + ({input_token:Array(String)} = [''] OR pool IN input_pools) + AND ({output_token:Array(String)} = [''] OR pool IN output_pools) AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) AND ({protocol:String} = '' OR toString(protocol) = {protocol:String}) @@ -46,8 +51,6 @@ SELECT p.protocol AS protocol, /* tokens */ - pt.tokens AS tokens, - CAST (( pt.token0, m0.symbol, From 1410a34292957999b668fd97a860165bb64a0952 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 16 Dec 2025 12:25:45 -0500 Subject: [PATCH 36/52] Update liquidity pools --- src/routes/v1/evm/dexes/evm.ts | 3 +-- src/routes/v1/evm/pools/evm.ts | 47 +++++++++++++++++++++------------ src/sql/pools/evm.sql | 9 ++++--- src/sql/supported_dexes/evm.sql | 3 ++- 4 files changed, 39 insertions(+), 23 deletions(-) diff --git a/src/routes/v1/evm/dexes/evm.ts b/src/routes/v1/evm/dexes/evm.ts index c8208571..86493a2d 100644 --- a/src/routes/v1/evm/dexes/evm.ts +++ b/src/routes/v1/evm/dexes/evm.ts @@ -17,8 +17,7 @@ import { validatorHook, withErrorResponses } from '../../../../utils.js'; const querySchema = createQuerySchema( { network: { schema: evmNetworkIdSchema }, - }, - false // Disable pagination for this endpoint, return all results in one go + } ); const responseSchema = apiUsageResponseSchema.extend({ diff --git a/src/routes/v1/evm/pools/evm.ts b/src/routes/v1/evm/pools/evm.ts index 5d9c91d7..a3cc6ecc 100644 --- a/src/routes/v1/evm/pools/evm.ts +++ b/src/routes/v1/evm/pools/evm.ts @@ -14,6 +14,7 @@ import { import { apiUsageResponseSchema, createQuerySchema, + dateTimeSchema, evmContractSchema, evmFactorySchema, evmNetworkIdSchema, @@ -52,19 +53,26 @@ const responseSchema = apiUsageResponseSchema.extend({ data: z.array( z.object({ // -- block -- - // block_num: z.number(), - // datetime: dateTimeSchema, + block_num: z.number(), + datetime: dateTimeSchema, + timestamp: z.number(), // -- transaction -- - // transaction_id: z.string(), + transaction_id: z.string(), // -- pool -- factory: evmFactorySchema, pool: evmPoolSchema, + protocol: evmProtocolSchema, + + // -- tokens -- input_token: evmTokenResponseSchema, output_token: evmTokenResponseSchema, + + // -- stats -- + transactions: z.number(), + uaw: z.number(), fee: z.number(), - protocol: evmProtocolSchema, // -- chain -- network: evmNetworkIdSchema, @@ -90,21 +98,26 @@ const openapi = describeRoute( value: { data: [ { - factory: '0x1f98431c8ad98523631ae4a59f267346ea31f984', - pool: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', - input_token: { - address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - symbol: 'USDC', - decimals: 6, + "block_num": 12376729, + "datetime": "2021-05-05 21:42:11", + "timestamp": 1620250931, + "transaction_id": "0x125e0b641d4a4b08806bf52c0c6757648c9963bcda8681e4f996f09e00d4c2cc", + "pool": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", + "factory": "0x1f98431c8ad98523631ae4a59f267346ea31f984", + "protocol": "uniswap_v3", + "input_token": { + "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + "symbol": "USDC", + "decimals": 6 }, - output_token: { - address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - symbol: 'WETH', - decimals: 18, + "output_token": { + "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", + "symbol": "WETH", + "decimals": 18 }, - fee: 500, - protocol: 'uniswap_v3', - network: 'mainnet', + "transactions": 10151470, + "uaw": 1684027, + "fee": 500 }, ], }, diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index 978dc36c..7ea845c0 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -13,7 +13,8 @@ pools AS ( pool, factory, protocol, - sum(transactions) as transactions + sum(transactions) as transactions, + uniqMerge(uniq_tx_from) as uaw FROM state_pools_aggregating_by_pool WHERE ({input_token:Array(String)} = [''] OR pool IN input_pools) @@ -42,8 +43,9 @@ pools_with_tokens AS ( SELECT /* initialize */ i.block_num AS block_num, - i.timestamp AS timestamp, - i.tx_hash AS tx_hash, + i.timestamp AS datetime, + toUnixTimestamp(i.timestamp) AS timestamp, + i.tx_hash AS transaction_id, /* DEX */ p.pool AS pool, @@ -65,6 +67,7 @@ SELECT /* stats */ p.transactions AS transactions, + p.uaw AS uaw, /* Fees */ f.fee AS fee diff --git a/src/sql/supported_dexes/evm.sql b/src/sql/supported_dexes/evm.sql index 3482a72d..25618fe0 100644 --- a/src/sql/supported_dexes/evm.sql +++ b/src/sql/supported_dexes/evm.sql @@ -9,4 +9,5 @@ GROUP BY protocol, factory ORDER BY transactions DESC -LIMIT 100 +LIMIT {limit:UInt64} +OFFSET {offset:UInt64} \ No newline at end of file From 858e8a46c89fbfd7789ac66361b2f2c39ec5611a Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 16 Dec 2025 13:53:09 -0500 Subject: [PATCH 37/52] Remove extra fields from /evm/pools --- src/routes/v1/evm/pools/evm.ts | 30 ++++++++++++------------------ src/sql/pools/evm.sql | 20 +++++--------------- src/sql/supported_dexes/evm.sql | 2 +- 3 files changed, 18 insertions(+), 34 deletions(-) diff --git a/src/routes/v1/evm/pools/evm.ts b/src/routes/v1/evm/pools/evm.ts index a3cc6ecc..ab9e1a57 100644 --- a/src/routes/v1/evm/pools/evm.ts +++ b/src/routes/v1/evm/pools/evm.ts @@ -52,27 +52,27 @@ const querySchema = createQuerySchema({ const responseSchema = apiUsageResponseSchema.extend({ data: z.array( z.object({ - // -- block -- - block_num: z.number(), - datetime: dateTimeSchema, - timestamp: z.number(), + // // -- block -- + // block_num: z.number(), + // datetime: dateTimeSchema, + // timestamp: z.number(), - // -- transaction -- - transaction_id: z.string(), + // // -- transaction -- + // transaction_id: z.string(), // -- pool -- - factory: evmFactorySchema, pool: evmPoolSchema, + factory: evmFactorySchema, protocol: evmProtocolSchema, // -- tokens -- input_token: evmTokenResponseSchema, output_token: evmTokenResponseSchema, - // -- stats -- - transactions: z.number(), - uaw: z.number(), - fee: z.number(), + // // -- stats -- + // transactions: z.number(), + // uaw: z.number(), + // fee: z.number(), // -- chain -- network: evmNetworkIdSchema, @@ -98,10 +98,6 @@ const openapi = describeRoute( value: { data: [ { - "block_num": 12376729, - "datetime": "2021-05-05 21:42:11", - "timestamp": 1620250931, - "transaction_id": "0x125e0b641d4a4b08806bf52c0c6757648c9963bcda8681e4f996f09e00d4c2cc", "pool": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", "factory": "0x1f98431c8ad98523631ae4a59f267346ea31f984", "protocol": "uniswap_v3", @@ -115,10 +111,8 @@ const openapi = describeRoute( "symbol": "WETH", "decimals": 18 }, - "transactions": 10151470, - "uaw": 1684027, "fee": 500 - }, + } ], }, }, diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index 7ea845c0..e0d198a9 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -1,4 +1,5 @@ -WITH output_pools AS ( +WITH +output_pools AS ( SELECT DISTINCT pool FROM state_pools_aggregating_by_token WHERE token IN {output_token:Array(String)} @@ -13,8 +14,7 @@ pools AS ( pool, factory, protocol, - sum(transactions) as transactions, - uniqMerge(uniq_tx_from) as uaw + transactions FROM state_pools_aggregating_by_pool WHERE ({input_token:Array(String)} = [''] OR pool IN input_pools) @@ -22,7 +22,7 @@ pools AS ( AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) AND ({protocol:String} = '' OR toString(protocol) = {protocol:String}) - GROUP BY pool, factory, protocol + ORDER BY transactions DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} @@ -37,16 +37,10 @@ pools_with_tokens AS ( arrayElement(tokens, 2) AS token1 FROM pools AS p - JOIN state_pools_aggregating_by_token AS pt ON p.pool = pt.pool + JOIN state_pools_aggregating_by_token AS pt ON p.pool = pt.pool AND p.factory = pt.factory AND p.protocol = pt.protocol GROUP BY pool, factory, protocol ) SELECT - /* initialize */ - i.block_num AS block_num, - i.timestamp AS datetime, - toUnixTimestamp(i.timestamp) AS timestamp, - i.tx_hash AS transaction_id, - /* DEX */ p.pool AS pool, p.factory AS factory, @@ -65,10 +59,6 @@ SELECT m1.decimals ) AS Tuple(address String, symbol String, decimals UInt8)) AS output_token, - /* stats */ - p.transactions AS transactions, - p.uaw AS uaw, - /* Fees */ f.fee AS fee FROM pools AS p diff --git a/src/sql/supported_dexes/evm.sql b/src/sql/supported_dexes/evm.sql index 25618fe0..e937325d 100644 --- a/src/sql/supported_dexes/evm.sql +++ b/src/sql/supported_dexes/evm.sql @@ -1,8 +1,8 @@ SELECT protocol, factory, - sum(transactions) as transactions, max(max_timestamp) as last_activity, + sum(transactions) as transactions, uniqMerge(uniq_tx_from) as uaw FROM state_pools_aggregating_by_pool GROUP BY From a4df8c7ff82938432cbcd286171734416515c7c3 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 16 Dec 2025 15:05:27 -0500 Subject: [PATCH 38/52] update OHLC --- src/config.ts | 3 + src/routes/v1/evm/pools/evm.ts | 13 +-- src/routes/v1/evm/pools/ohlc/evm.ts | 6 +- src/routes/v1/tvm/pools/index.ts | 4 +- src/routes/v1/tvm/pools/tvm.ts | 2 +- src/sql/ohlcv_prices_for_pool/tvm.sql | 50 +-------- src/sql/pools/evm.sql | 5 +- src/sql/pools/tvm.sql | 1 + src/sql/supported_dexes/evm.sql | 1 + src/sql/supported_dexes/tvm.sql | 17 +-- src/sql/swaps/tvm.sql | 149 +------------------------- 11 files changed, 17 insertions(+), 234 deletions(-) mode change 100644 => 120000 src/sql/ohlcv_prices_for_pool/tvm.sql create mode 120000 src/sql/pools/tvm.sql mode change 100644 => 120000 src/sql/supported_dexes/tvm.sql mode change 100644 => 120000 src/sql/swaps/tvm.sql diff --git a/src/config.ts b/src/config.ts index 3da534cf..2158b655 100644 --- a/src/config.ts +++ b/src/config.ts @@ -5,6 +5,9 @@ import { z } from 'zod'; import pkg from '../package.json' with { type: 'json' }; +// Set timezone to UTC +process.env.TZ = "Etc/UTC"; + // defaults export const DEFAULT_PORT = '8000'; export const DEFAULT_HOSTNAME = 'localhost'; diff --git a/src/routes/v1/evm/pools/evm.ts b/src/routes/v1/evm/pools/evm.ts index ab9e1a57..325b79ce 100644 --- a/src/routes/v1/evm/pools/evm.ts +++ b/src/routes/v1/evm/pools/evm.ts @@ -83,7 +83,7 @@ const responseSchema = apiUsageResponseSchema.extend({ const openapi = describeRoute( withErrorResponses({ summary: 'Liquidity Pools', - description: 'Returns Uniswap liquidity pool metadata including token pairs, fees, and protocol versions.', + description: 'Returns DEX pool metadata including tokens, fees and protocol.', tags: ['EVM DEXs'], security: [{ bearerAuth: [] }], @@ -130,20 +130,13 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const params = c.req.valid('query'); const dbConfig = config.uniswapDatabases[params.network]; - const db_evm_tokens = config.tokenDatabases[params.network]; - - if (!dbConfig || !db_evm_tokens) { + if (!dbConfig) { return c.json({ error: `Network not found: ${params.network}` }, 400); } const query = sqlQueries.pools?.[dbConfig.type]; if (!query) return c.json({ error: 'Query for pools could not be loaded' }, 500); - const response = await makeUsageQueryJson( - c, - [query], - { ...params, db_evm_tokens: db_evm_tokens.database }, - { database: dbConfig.database } - ); + const response = await makeUsageQueryJson(c, [query], params, { database: dbConfig.database }); return handleUsageQueryError(c, response); }); diff --git a/src/routes/v1/evm/pools/ohlc/evm.ts b/src/routes/v1/evm/pools/ohlc/evm.ts index dbd9746c..77062c60 100644 --- a/src/routes/v1/evm/pools/ohlc/evm.ts +++ b/src/routes/v1/evm/pools/ohlc/evm.ts @@ -90,9 +90,8 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const params = c.req.valid('query'); const dbConfig = config.uniswapDatabases[params.network]; - const dbEvmTokens = config.tokenDatabases[params.network]; - if (!dbConfig || !dbEvmTokens) { + if (!dbConfig) { return c.json({ error: `Network not found: ${params.network}` }, 400); } const query = sqlQueries.ohlcv_prices_for_pool?.[dbConfig.type]; @@ -103,9 +102,6 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat [query], { ...params, - db_evm_tokens: dbEvmTokens.database, - high_quantile: 1 - config.ohlcQuantile, - low_quantile: config.ohlcQuantile, stablecoin_contracts: [...stables], }, { database: dbConfig.database } diff --git a/src/routes/v1/tvm/pools/index.ts b/src/routes/v1/tvm/pools/index.ts index d180642b..2dcee776 100644 --- a/src/routes/v1/tvm/pools/index.ts +++ b/src/routes/v1/tvm/pools/index.ts @@ -1,10 +1,10 @@ import { Hono } from 'hono'; -// import tvm from './tvm.js'; +import tvm from './tvm.js'; import ohlc from './ohlc/index.js'; const router = new Hono(); -// router.route('/', tvm); +router.route('/', tvm); router.route('/ohlc', ohlc); export default router; diff --git a/src/routes/v1/tvm/pools/tvm.ts b/src/routes/v1/tvm/pools/tvm.ts index 3cbf6758..638e4c90 100644 --- a/src/routes/v1/tvm/pools/tvm.ts +++ b/src/routes/v1/tvm/pools/tvm.ts @@ -75,7 +75,7 @@ const responseSchema = apiUsageResponseSchema.extend({ const openapi = describeRoute( withErrorResponses({ summary: 'Liquidity Pools', - description: 'Returns Uniswap liquidity pool metadata including token pairs, fees, and protocol versions.', + description: 'Returns DEX pool metadata including tokens, fees and protocol.', tags: ['EVM DEXs'], security: [{ bearerAuth: [] }], diff --git a/src/sql/ohlcv_prices_for_pool/tvm.sql b/src/sql/ohlcv_prices_for_pool/tvm.sql deleted file mode 100644 index 7507e1d1..00000000 --- a/src/sql/ohlcv_prices_for_pool/tvm.sql +++ /dev/null @@ -1,49 +0,0 @@ -WITH ohlc AS ( - SELECT - if( - toTime(toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE)) = toDateTime('1970-01-02 00:00:00'), - toDate(toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE)), - toStartOfInterval(timestamp, INTERVAL {interval: UInt64} MINUTE) - ) AS datetime, - pool, - token0, - token1, - argMinMerge(open0) AS open_raw, - greatest(quantileDeterministicMerge({high_quantile: Float32})(quantile0), open_raw, close_raw) AS high_raw, - least(quantileDeterministicMerge({low_quantile: Float32})(quantile0), open_raw, close_raw) AS low_raw, - argMaxMerge(close0) AS close_raw, - sum(gross_volume0) AS volume, - uniqMerge(uaw) AS uaw, - sum(transactions) AS transactions, - toString(token0) IN {stablecoin_contracts: Array(String)} AS is_stablecoin - FROM ohlc_prices - WHERE pool = {pool: String} AND timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} - GROUP BY datetime, pool, token0, token1 - ORDER BY datetime DESC - LIMIT {limit:UInt64} - OFFSET {offset:UInt64} -) -SELECT - datetime, - CONCAT( - ( - SELECT symbol - FROM {db_tvm_tokens:Identifier}.metadata - WHERE contract = (SELECT DISTINCT token0 FROM ohlc) - ), - ( - SELECT symbol - FROM {db_tvm_tokens:Identifier}.metadata - WHERE contract = (SELECT DISTINCT token1 FROM ohlc) - ) - ) AS ticker, - pool, - if(is_stablecoin, 1/open_raw, open_raw) AS open, - if(is_stablecoin, 1/low_raw, high_raw) AS high, - if(is_stablecoin, 1/high_raw, low_raw) AS low, - if(is_stablecoin, 1/close_raw, close_raw) AS close, - volume, - uaw, - transactions -FROM ohlc -ORDER BY datetime DESC \ No newline at end of file diff --git a/src/sql/ohlcv_prices_for_pool/tvm.sql b/src/sql/ohlcv_prices_for_pool/tvm.sql new file mode 120000 index 00000000..a6d4668d --- /dev/null +++ b/src/sql/ohlcv_prices_for_pool/tvm.sql @@ -0,0 +1 @@ +evm.sql \ No newline at end of file diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index e0d198a9..6027d167 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -45,7 +45,6 @@ SELECT p.pool AS pool, p.factory AS factory, p.protocol AS protocol, - /* tokens */ CAST (( pt.token0, @@ -65,6 +64,6 @@ FROM pools AS p JOIN state_pools_initialize AS i ON p.pool = i.pool JOIN state_pools_fees AS f ON p.pool = f.pool JOIN pools_with_tokens AS pt ON p.pool = pt.pool -JOIN metadata AS m0 ON pt.token0 = m0.contract -JOIN metadata AS m1 ON pt.token1 = m1.contract +LEFT JOIN metadata AS m0 ON pt.token0 = m0.contract +LEFT JOIN metadata AS m1 ON pt.token1 = m1.contract ORDER BY p.transactions DESC \ No newline at end of file diff --git a/src/sql/pools/tvm.sql b/src/sql/pools/tvm.sql new file mode 120000 index 00000000..a6d4668d --- /dev/null +++ b/src/sql/pools/tvm.sql @@ -0,0 +1 @@ +evm.sql \ No newline at end of file diff --git a/src/sql/supported_dexes/evm.sql b/src/sql/supported_dexes/evm.sql index e937325d..d2f2383e 100644 --- a/src/sql/supported_dexes/evm.sql +++ b/src/sql/supported_dexes/evm.sql @@ -1,6 +1,7 @@ SELECT protocol, factory, + /* count() as pools, */ max(max_timestamp) as last_activity, sum(transactions) as transactions, uniqMerge(uniq_tx_from) as uaw diff --git a/src/sql/supported_dexes/tvm.sql b/src/sql/supported_dexes/tvm.sql deleted file mode 100644 index c3f82ba6..00000000 --- a/src/sql/supported_dexes/tvm.sql +++ /dev/null @@ -1,16 +0,0 @@ -WITH all_dexes AS ( - SELECT - factory, - protocol, - sum(transactions) as transactions, - uniqMerge(uaw) as uaw, - max(timestamp) as last_activity - FROM ohlc_prices - WHERE interval_min = 1440 - GROUP BY - protocol, - factory -) -SELECT * FROM all_dexes -ORDER BY transactions DESC, uaw DESC, protocol, factory -LIMIT 100 diff --git a/src/sql/supported_dexes/tvm.sql b/src/sql/supported_dexes/tvm.sql new file mode 120000 index 00000000..a6d4668d --- /dev/null +++ b/src/sql/supported_dexes/tvm.sql @@ -0,0 +1 @@ +evm.sql \ No newline at end of file diff --git a/src/sql/swaps/tvm.sql b/src/sql/swaps/tvm.sql deleted file mode 100644 index fd5c821d..00000000 --- a/src/sql/swaps/tvm.sql +++ /dev/null @@ -1,148 +0,0 @@ -WITH -/* 1) Count how many filters are active */ -active_filters AS -( - SELECT - toUInt8({transaction_id:Array(String)} != ['']) + - toUInt8({user:Array(String)} != ['']) + - toUInt8({pool:Array(String)} != ['']) + - toUInt8({factory:Array(String)} != ['']) + - toUInt8({protocol:String} != '') + - toUInt8({input_token:Array(String)} != ['']) + - toUInt8({output_token:Array(String)} != ['']) - AS n -), -/* 2) Union minutes from only active filters */ -minutes_union AS -( - SELECT toRelativeMinuteNum(timestamp) AS minute - FROM swaps - WHERE ({transaction_id:Array(String)} != [''] AND tx_hash IN {transaction_id:Array(String)}) - GROUP BY tx_hash, minute - - UNION ALL - - SELECT toRelativeMinuteNum(timestamp) AS minute - FROM swaps - WHERE ({user:Array(String)} != [''] AND user IN {user:Array(String)}) - GROUP BY user, minute - - UNION ALL - - SELECT toRelativeMinuteNum(timestamp) AS minute - FROM swaps - WHERE ({pool:Array(String)} != [''] AND pool IN {pool:Array(String)}) - GROUP BY pool, minute - - UNION ALL - - SELECT toRelativeMinuteNum(timestamp) AS minute - FROM swaps - WHERE ({factory:Array(String)} != [''] AND factory IN {factory:Array(String)}) - GROUP BY factory, minute - - UNION ALL - - SELECT toRelativeMinuteNum(timestamp) AS minute - FROM swaps - WHERE ({protocol:String} != '' AND protocol = {protocol:String}) - GROUP BY protocol, minute - - UNION ALL - - SELECT toRelativeMinuteNum(timestamp) AS minute - FROM swaps - WHERE ({input_token:Array(String)} != [''] AND input_contract IN {input_token:Array(String)}) - GROUP BY input_contract, minute - - UNION ALL - - SELECT toRelativeMinuteNum(timestamp) AS minute - FROM swaps - WHERE ({output_token:Array(String)} != [''] AND output_contract IN {output_token:Array(String)}) - GROUP BY output_contract, minute -), -filtered_minutes AS ( - SELECT minute FROM minutes_union - WHERE minute BETWEEN toRelativeMinuteNum(toDateTime({start_time:UInt64})) AND toRelativeMinuteNum(toDateTime({end_time:UInt64})) - GROUP BY minute - HAVING count() >= (SELECT n FROM active_filters) - ORDER BY minute DESC - LIMIT 1 BY minute - LIMIT if( - (SELECT n FROM active_filters) <= 1, - {limit:UInt64} + {offset:UInt64}, /* safe to limit if there is 1 active filter */ - ({limit:UInt64} + {offset:UInt64}) * 10 /* unsafe limit with a multiplier - usually safe but find a way to early return */ - ) -), -/* Latest ingested timestamp in source table */ -latest_ts AS -( - SELECT max(timestamp) AS ts FROM swaps -), -filtered_swaps AS ( - SELECT * FROM swaps - PREWHERE - timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} - AND block_num BETWEEN {start_block: UInt64} AND {end_block: UInt64} - AND ( - ( - /* if no filters are active search only the last 10 minutes */ - (SELECT n FROM active_filters) = 0 - AND timestamp BETWEEN - greatest( toDateTime({start_time:UInt64}), least(toDateTime({end_time:UInt64}), (SELECT ts FROM latest_ts)) - (INTERVAL 10 MINUTE + INTERVAL 10 * {offset:UInt64} SECOND)) - AND least(toDateTime({end_time:UInt64}), (SELECT ts FROM latest_ts)) - ) - /* if filters are active, search through the intersecting minute ranges */ - OR toRelativeMinuteNum(timestamp) IN (SELECT minute FROM filtered_minutes) - ) - WHERE - /* filter by active filters if any */ - ({transaction_id:Array(String)} = [''] OR tx_hash IN {transaction_id:Array(String)}) - AND ({user:Array(String)} = [''] OR user IN {user:Array(String)}) - AND ({pool:Array(String)} = [''] OR pool IN {pool:Array(String)}) - AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) - AND ({protocol:String} = '' OR protocol = {protocol:String}) - AND ({input_token:Array(String)} = [''] OR input_contract IN {input_token:Array(String)}) - AND ({output_token:Array(String)} = [''] OR output_contract IN {output_token:Array(String)}) - ORDER BY timestamp DESC, block_num DESC, block_hash DESC, tx_index DESC, log_index DESC - LIMIT {limit:UInt64} - OFFSET {offset:UInt64} -) -SELECT - /* block */ - s.block_num as block_num, - s.timestamp as datetime, - toUnixTimestamp(s.timestamp) as timestamp, - - /* transaction */ - toString(s.tx_hash) as transaction_id, - tx_index AS transaction_index, - - /* log */ - log_index, - log_ordinal, - log_address, - log_topic0, - - /* swap */ - protocol, - factory, - pool, - user, - - /* input token */ - toString(input_amount) AS input_amount, - s.input_amount / pow(10, m1.decimals) AS input_value, - CAST( ( s.input_contract, m1.symbol, m1.name, m1.decimals ) AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8))) AS input_token, - - /* output token */ - toString(output_amount) AS output_amount, - s.output_amount / pow(10, m2.decimals) AS output_value, - CAST( ( s.output_contract, m2.symbol, m2.name, m2.decimals ) AS Tuple(address String, symbol Nullable(String), name Nullable(String), decimals Nullable(UInt8))) AS output_token, - - {network:String} AS network -FROM filtered_swaps AS s -LEFT JOIN {db_tvm_tokens:Identifier}.metadata AS m1 ON s.input_contract = m1.contract -LEFT JOIN {db_tvm_tokens:Identifier}.metadata AS m2 ON s.output_contract = m2.contract -ORDER BY timestamp DESC, block_num DESC, tx_index DESC, log_index DESC diff --git a/src/sql/swaps/tvm.sql b/src/sql/swaps/tvm.sql new file mode 120000 index 00000000..a6d4668d --- /dev/null +++ b/src/sql/swaps/tvm.sql @@ -0,0 +1 @@ +evm.sql \ No newline at end of file From 4dd456fa16caba28644ca15697026e6909041d53 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 16 Dec 2025 15:33:14 -0500 Subject: [PATCH 39/52] Update swaps --- src/routes/v1/evm/swaps/evm.ts | 9 ++++++--- src/sql/swaps/evm.sql | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/routes/v1/evm/swaps/evm.ts b/src/routes/v1/evm/swaps/evm.ts index e411e918..a7c29105 100644 --- a/src/routes/v1/evm/swaps/evm.ts +++ b/src/routes/v1/evm/swaps/evm.ts @@ -88,6 +88,10 @@ const responseSchema = apiUsageResponseSchema.extend({ sender: evmAddressSchema, recipient: evmAddressSchema, + // -- log -- + // ordinal: z.number(), + + // -- price -- input_amount: z.string(), input_value: z.number(), output_amount: z.string(), @@ -169,9 +173,8 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const params = c.req.valid('query'); const dbConfig = config.uniswapDatabases[params.network]; - const db_evm_tokens = config.tokenDatabases[params.network]; - if (!dbConfig || !db_evm_tokens) { + if (!dbConfig) { return c.json({ error: `Network not found: ${params.network}` }, 400); } const query = sqlQueries.swaps?.[dbConfig.type]; @@ -180,7 +183,7 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const response = await makeUsageQueryJson( c, [query], - { ...params, db_evm_tokens: db_evm_tokens.database }, + { ...params }, { database: dbConfig.database } ); return handleUsageQueryError(c, response); diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index 4f4eb32a..3d4be5da 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -133,12 +133,12 @@ SELECT /* transaction */ s.tx_hash AS transaction_id, - s.log_ordinal AS ordinal, + /* s.log_ordinal AS ordinal, for `/v2` endpoint */ /* swap */ toString(s.factory) AS factory, s.pool AS pool, - s.user AS caller, /* rename to `s.tx_from` once v0.2.6 is deployed */ + s.tx_from AS caller, s.user AS sender, s.user AS recipient, From a3b5d0a45991dba9604ad9e2165b02447d52ea60 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 16 Dec 2025 16:08:40 -0500 Subject: [PATCH 40/52] Update TVM swaps --- src/routes/v1/evm/pools/ohlc/evm.ts | 2 +- src/routes/v1/evm/swaps/evm.ts | 2 +- src/routes/v1/svm/pools/ohlc/svm.ts | 2 +- src/routes/v1/tvm/pools/ohlc/tvm.ts | 2 +- src/routes/v1/tvm/swaps/tvm.ts | 105 +++++++++++++--------------- 5 files changed, 54 insertions(+), 59 deletions(-) diff --git a/src/routes/v1/evm/pools/ohlc/evm.ts b/src/routes/v1/evm/pools/ohlc/evm.ts index 77062c60..1eb50b19 100644 --- a/src/routes/v1/evm/pools/ohlc/evm.ts +++ b/src/routes/v1/evm/pools/ohlc/evm.ts @@ -46,7 +46,7 @@ const responseSchema = apiUsageResponseSchema.extend({ const openapi = describeRoute( withErrorResponses({ - summary: 'Pool OHLCV Data', + summary: 'Pool OHLCV', description: 'Returns OHLCV price data for liquidity pools.\n\nOHLCV historical depth is subject to plan restrictions.', tags: ['EVM DEXs'], diff --git a/src/routes/v1/evm/swaps/evm.ts b/src/routes/v1/evm/swaps/evm.ts index a7c29105..cc5874b2 100644 --- a/src/routes/v1/evm/swaps/evm.ts +++ b/src/routes/v1/evm/swaps/evm.ts @@ -110,7 +110,7 @@ const responseSchema = apiUsageResponseSchema.extend({ const openapi = describeRoute( withErrorResponses({ summary: 'Swap Events', - description: 'Returns DEX swap transactions from Uniswap protocols with token amounts and prices.', + description: 'Returns DEX swaps events with input & output token amounts.', tags: ['EVM DEXs'], security: [{ bearerAuth: [] }], diff --git a/src/routes/v1/svm/pools/ohlc/svm.ts b/src/routes/v1/svm/pools/ohlc/svm.ts index 18331eb8..59ac94c6 100644 --- a/src/routes/v1/svm/pools/ohlc/svm.ts +++ b/src/routes/v1/svm/pools/ohlc/svm.ts @@ -51,7 +51,7 @@ const responseSchema = apiUsageResponseSchema.extend({ const openapi = describeRoute( withErrorResponses({ - summary: 'Pool OHLCV Data', + summary: 'Pool OHLCV', description: 'Provides pricing data in the Open/High/Low/Close/Volume (OHCLV) format for DEX pools.', tags: ['SVM DEXs'], security: [{ bearerAuth: [] }], diff --git a/src/routes/v1/tvm/pools/ohlc/tvm.ts b/src/routes/v1/tvm/pools/ohlc/tvm.ts index ee843a4b..567d65f3 100644 --- a/src/routes/v1/tvm/pools/ohlc/tvm.ts +++ b/src/routes/v1/tvm/pools/ohlc/tvm.ts @@ -46,7 +46,7 @@ const responseSchema = apiUsageResponseSchema.extend({ const openapi = describeRoute( withErrorResponses({ - summary: 'Pool OHLCV Data', + summary: 'Pool OHLCV', description: 'Returns OHLCV price data for liquidity pools.\n\nOHLCV historical depth is subject to plan restrictions.', tags: ['TVM DEXs'], diff --git a/src/routes/v1/tvm/swaps/tvm.ts b/src/routes/v1/tvm/swaps/tvm.ts index b352112c..84e3acf3 100644 --- a/src/routes/v1/tvm/swaps/tvm.ts +++ b/src/routes/v1/tvm/swaps/tvm.ts @@ -43,9 +43,11 @@ const querySchema = createQuerySchema({ // swaps factory: { schema: tvmAddressSchema, batched: true, default: '', meta: { example: TVM_FACTORY_SUNSWAP_EXAMPLE } }, pool: { schema: tvmPoolSchema, batched: true, default: '', meta: { example: TVM_POOL_USDT_WTRX_EXAMPLE } }, - user: { schema: tvmAddressSchema, batched: true, default: '', meta: { example: TVM_ADDRESS_SWAP_EXAMPLE } }, - input_token: { schema: tvmAddressSchema, batched: true, default: '', meta: { example: TVM_CONTRACT_USDT_EXAMPLE } }, - output_token: { + caller: { schema: tvmAddressSchema, batched: true, default: '', meta: { example: TVM_ADDRESS_SWAP_EXAMPLE } }, + sender: { schema: tvmAddressSchema, batched: true, default: '', meta: { example: TVM_ADDRESS_SWAP_EXAMPLE } }, + recipient: { schema: tvmAddressSchema, batched: true, default: '', meta: { example: TVM_ADDRESS_SWAP_EXAMPLE } }, + input_contract: { schema: tvmAddressSchema, batched: true, default: '', meta: { example: TVM_CONTRACT_USDT_EXAMPLE } }, + output_contract: { schema: tvmAddressSchema, batched: true, default: '', @@ -68,29 +70,29 @@ const responseSchema = apiUsageResponseSchema.extend({ datetime: dateTimeSchema, timestamp: z.number(), - // -- transaction -- - transaction_id: z.string(), - transaction_index: z.number(), - - // -- log -- - log_index: z.number(), - log_ordinal: z.number(), - log_address: tvmAddressSchema, - log_topic0: z.string(), - // -- swap -- - protocol: tvmProtocolSchema, + transaction_id: z.string(), factory: tvmFactorySchema, pool: tvmPoolSchema, - user: tvmAddressSchema, + input_token: tvmTokenResponseSchema, + output_token: tvmTokenResponseSchema, - // -- amounts -- + caller: tvmAddressSchema, + sender: tvmAddressSchema, + recipient: tvmAddressSchema, + + // -- log -- + // ordinal: z.number(), + + // -- price -- input_amount: z.string(), input_value: z.number(), - input_token: tvmTokenResponseSchema, output_amount: z.string(), output_value: z.number(), - output_token: tvmTokenResponseSchema, + price: z.number(), + price_inv: z.number(), + protocol: tvmProtocolSchema, + summary: z.string(), // -- chain -- network: tvmNetworkIdSchema, @@ -101,7 +103,7 @@ const responseSchema = apiUsageResponseSchema.extend({ const openapi = describeRoute( withErrorResponses({ summary: 'Swap Events', - description: 'Returns DEX swap transactions from Tron protocols with token amounts and prices.', + description: 'Returns DEX swaps events with input & output token amounts.', tags: ['TVM DEXs'], security: [{ bearerAuth: [] }], @@ -116,39 +118,35 @@ const openapi = describeRoute( value: { data: [ { - block_num: 77233509, - datetime: '2025-11-05 16:55:03', - timestamp: 1762361703, - transaction_id: - 'e74815245a8f1321ce5ede99cde8e021f75bf8e3d4f94cd8949d283eb56fee63', - transaction_index: 0, - log_index: 1, - log_ordinal: 662, - log_address: 'TFGDbUyP8xez44C76fin3bn3Ss6jugoUwJ', - log_topic0: - 'd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822', - protocol: 'sunswap', - factory: 'TKWJdrQkqHisa1X8HUdHEfREvTzw4pMAaY', - pool: 'TFGDbUyP8xez44C76fin3bn3Ss6jugoUwJ', - user: 'TXF1xDbVGdxFGbovmmmXvBGu8ZiE3Lq4mR', - input_amount: '170000000', - input_value: 170, - input_token: { - address: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - symbol: 'USDT', - name: 'Tether USD', - decimals: 6, + "block_num": 28320009, + "datetime": "2021-03-10 04:43:33", + "timestamp": 1615351413, + "transaction_id": "0x3e0f39b48dae8c49d3f95bc6206a632af484059764487b0c7d3e3c97bb433130", + "factory": "TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF", + "pool": "TAqCH2kadHAugPEorFrpT7Kogqo2FckxWA", + "caller": "TSLjVj4sL7uDWQXDbHyV3Kbgz1KL9jB78w", + "sender": "TSLjVj4sL7uDWQXDbHyV3Kbgz1KL9jB78w", + "recipient": "TSLjVj4sL7uDWQXDbHyV3Kbgz1KL9jB78w", + "input_token": { + "address": "TGc9XV7skLENAHPj4afCpBS8JSHv6box9C", + "symbol": "", + "decimals": 0 }, - output_amount: '590270510', - output_value: 590.27051, - output_token: { - address: 'TNUC9Qb1rRpS5CbWLmNMxXBjyFoydXjWFR', - symbol: 'WTRX', - name: 'Wrapped TRX', - decimals: 6, + "output_token": { + "address": "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb", + "symbol": "TRX", + "decimals": 6 }, - network: 'tron', - }, + "input_amount": "20000000", + "input_value": 20000000, + "output_amount": "1258054968", + "output_value": 1258.054968, + "price": 0.0000629027484, + "price_inv": 15897.556552552798, + "protocol": "uniswap_v1", + "summary": "Swap 20.00 million for 1.26 thousand TRX on Uniswap V1", + "network": "tron" + } ], }, }, @@ -166,10 +164,7 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const params = c.req.valid('query'); const dbConfig = config.uniswapDatabases[params.network]; - // this DB is used to fetch TRC-20 token metadata (name, symbol, decimals) - const db_tvm_tokens = config.tokenDatabases[params.network]; - - if (!dbConfig || !db_tvm_tokens) { + if (!dbConfig) { return c.json({ error: `Network not found: ${params.network}` }, 400); } @@ -179,7 +174,7 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const response = await makeUsageQueryJson( c, [query], - { ...params, db_tvm_tokens: db_tvm_tokens.database }, + { ...params }, { database: dbConfig.database } ); return handleUsageQueryError(c, response); From c1e4431648955a4d9f7abed3de7a6d0826d17c95 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 16 Dec 2025 16:18:29 -0500 Subject: [PATCH 41/52] fix start time --- src/routes/v1/tvm/pools/ohlc/tvm.ts | 7 +------ src/sql/ohlcv_prices_for_pool/evm.sql | 7 ++++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/routes/v1/tvm/pools/ohlc/tvm.ts b/src/routes/v1/tvm/pools/ohlc/tvm.ts index 567d65f3..da626c32 100644 --- a/src/routes/v1/tvm/pools/ohlc/tvm.ts +++ b/src/routes/v1/tvm/pools/ohlc/tvm.ts @@ -90,10 +90,8 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const params = c.req.valid('query'); const dbConfig = config.uniswapDatabases[params.network]; - // this DB is used to fetch token metadata (symbol, name, decimals) - const db_tvm_tokens = config.tokenDatabases[params.network]; - if (!dbConfig || !db_tvm_tokens) { + if (!dbConfig) { return c.json({ error: `Network not found: ${params.network}` }, 400); } @@ -105,10 +103,7 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat [query], { ...params, - high_quantile: 1 - config.ohlcQuantile, - low_quantile: config.ohlcQuantile, stablecoin_contracts: [...stables], - db_tvm_tokens: db_tvm_tokens.database, }, { database: dbConfig.database } ); diff --git a/src/sql/ohlcv_prices_for_pool/evm.sql b/src/sql/ohlcv_prices_for_pool/evm.sql index b5df0993..ad182e69 100644 --- a/src/sql/ohlcv_prices_for_pool/evm.sql +++ b/src/sql/ohlcv_prices_for_pool/evm.sql @@ -31,12 +31,13 @@ WITH ohlc AS ( /* extra fields */ p.token0 IN {stablecoin_contracts: Array(String)} AS is_stablecoin FROM ohlc_prices p - JOIN metadata m0 ON p.token0 = m0.contract - JOIN metadata m1 ON p.token1 = m1.contract + LEFT JOIN metadata m0 ON p.token0 = m0.contract + LEFT JOIN metadata m1 ON p.token1 = m1.contract WHERE p.interval_min = {interval: UInt64} AND p.pool = {pool: String} - AND p.timestamp BETWEEN {start_time: UInt64} AND {end_time: UInt64} + AND ({start_time: UInt64} == 1763251200 OR timestamp >= toDateTime({start_time: UInt64})) + AND ({end_time: UInt64} == 2524608000 OR timestamp <= toDateTime({end_time: UInt64})) ORDER BY datetime DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} From 91d7e051d29f0870f05111e27c9b3094ac9246cb Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 16 Dec 2025 16:21:09 -0500 Subject: [PATCH 42/52] add TVM liquidity pools --- src/routes/v1/tvm/pools/tvm.ts | 38 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/routes/v1/tvm/pools/tvm.ts b/src/routes/v1/tvm/pools/tvm.ts index 638e4c90..d4ad7d82 100644 --- a/src/routes/v1/tvm/pools/tvm.ts +++ b/src/routes/v1/tvm/pools/tvm.ts @@ -20,14 +20,16 @@ import { evmPoolSchema, evmProtocolSchema, evmTokenResponseSchema, + tvmFactorySchema, + tvmNetworkIdSchema, } from '../../../../types/zod.js'; import { validatorHook, withErrorResponses } from '../../../../utils.js'; const querySchema = createQuerySchema({ - network: { schema: evmNetworkIdSchema }, + network: { schema: tvmNetworkIdSchema }, factory: { - schema: evmFactorySchema, + schema: tvmFactorySchema, batched: true, default: '', meta: { example: EVM_FACTORY_UNISWAP_V3_EXAMPLE }, @@ -76,8 +78,7 @@ const openapi = describeRoute( withErrorResponses({ summary: 'Liquidity Pools', description: 'Returns DEX pool metadata including tokens, fees and protocol.', - - tags: ['EVM DEXs'], + tags: ['TVM DEXs'], security: [{ bearerAuth: [] }], responses: { 200: { @@ -90,22 +91,21 @@ const openapi = describeRoute( value: { data: [ { - factory: '0x1f98431c8ad98523631ae4a59f267346ea31f984', - pool: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', - input_token: { - address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - symbol: 'USDC', - decimals: 6, - }, - output_token: { - address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', - symbol: 'WETH', - decimals: 18, - }, - fee: 500, - protocol: 'uniswap_v3', - network: 'mainnet', + "pool": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE", + "factory": "TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF", + "protocol": "uniswap_v1", + "input_token": { + "address": "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb", + "symbol": "TRX", + "decimals": 6 + }, + "output_token": { + "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", + "symbol": "USDT", + "decimals": 6 }, + "fee": 3000 + } ], }, }, From 829bc395f51390efeafc97cd12800d9db5003b36 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Tue, 16 Dec 2025 21:36:20 -0500 Subject: [PATCH 43/52] update TVM pools --- src/routes/v1/svm/dexes/svm.ts | 3 +-- src/routes/v1/tvm/dexes/tvm.ts | 13 ++++++------- src/routes/v1/tvm/pools/tvm.ts | 25 ++++++++++++++----------- src/sql/supported_dexes/svm.sql | 5 +++-- 4 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/routes/v1/svm/dexes/svm.ts b/src/routes/v1/svm/dexes/svm.ts index 8011d482..eca9d2de 100644 --- a/src/routes/v1/svm/dexes/svm.ts +++ b/src/routes/v1/svm/dexes/svm.ts @@ -17,8 +17,7 @@ import { validatorHook, withErrorResponses } from '../../../../utils.js'; const querySchema = createQuerySchema( { network: { schema: svmNetworkIdSchema }, - }, - false // Disable pagination for this endpoint, return all results in one go + } ); const responseSchema = apiUsageResponseSchema.extend({ diff --git a/src/routes/v1/tvm/dexes/tvm.ts b/src/routes/v1/tvm/dexes/tvm.ts index bcebbabc..ca434e84 100644 --- a/src/routes/v1/tvm/dexes/tvm.ts +++ b/src/routes/v1/tvm/dexes/tvm.ts @@ -18,8 +18,7 @@ import { validatorHook, withErrorResponses } from '../../../../utils.js'; const querySchema = createQuerySchema( { network: { schema: tvmNetworkIdSchema }, - }, - false // Disable pagination for this endpoint, return all results in one go + } ); const responseSchema = apiUsageResponseSchema.extend({ @@ -51,11 +50,11 @@ const openapi = describeRoute( value: { data: [ { - factory: 'TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF', - protocol: 'justswap', - transactions: 47301451, - uaw: 2562671, - last_activity: '2025-11-03 00:00:00', + "protocol": "uniswap_v1", + "factory": "TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF", + "last_activity": "2025-12-16 05:16:18", + "transactions": 48269088, + "uaw": 2848148 }, ], }, diff --git a/src/routes/v1/tvm/pools/tvm.ts b/src/routes/v1/tvm/pools/tvm.ts index d4ad7d82..74a4ceb3 100644 --- a/src/routes/v1/tvm/pools/tvm.ts +++ b/src/routes/v1/tvm/pools/tvm.ts @@ -6,10 +6,10 @@ import { config } from '../../../../config.js'; import { handleUsageQueryError, makeUsageQueryJson } from '../../../../handleQuery.js'; import { sqlQueries } from '../../../../sql/index.js'; import { - EVM_CONTRACT_USDC_EXAMPLE, - EVM_CONTRACT_WETH_EXAMPLE, - EVM_FACTORY_UNISWAP_V3_EXAMPLE, - EVM_POOL_USDC_WETH_EXAMPLE, + TVM_CONTRACT_USDT_EXAMPLE, + TVM_CONTRACT_WTRX_EXAMPLE, + TVM_FACTORY_SUNSWAP_EXAMPLE, + TVM_POOL_USDT_WTRX_EXAMPLE, } from '../../../../types/examples.js'; import { apiUsageResponseSchema, @@ -20,8 +20,11 @@ import { evmPoolSchema, evmProtocolSchema, evmTokenResponseSchema, + tvmContractSchema, tvmFactorySchema, tvmNetworkIdSchema, + tvmPoolSchema, + tvmProtocolSchema, } from '../../../../types/zod.js'; import { validatorHook, withErrorResponses } from '../../../../utils.js'; @@ -32,22 +35,22 @@ const querySchema = createQuerySchema({ schema: tvmFactorySchema, batched: true, default: '', - meta: { example: EVM_FACTORY_UNISWAP_V3_EXAMPLE }, + meta: { example: TVM_FACTORY_SUNSWAP_EXAMPLE }, }, - pool: { schema: evmPoolSchema, batched: true, default: '', meta: { example: EVM_POOL_USDC_WETH_EXAMPLE } }, + pool: { schema: tvmPoolSchema, batched: true, default: '', meta: { example: TVM_POOL_USDT_WTRX_EXAMPLE } }, input_token: { - schema: evmContractSchema, + schema: tvmContractSchema, batched: true, default: '', - meta: { example: EVM_CONTRACT_USDC_EXAMPLE }, + meta: { example: TVM_CONTRACT_USDT_EXAMPLE }, }, output_token: { - schema: evmContractSchema, + schema: tvmContractSchema, batched: true, default: '', - meta: { example: EVM_CONTRACT_WETH_EXAMPLE }, + meta: { example: TVM_CONTRACT_WTRX_EXAMPLE }, }, - protocol: { schema: evmProtocolSchema, default: '' }, + protocol: { schema: tvmProtocolSchema, default: '' }, }); const responseSchema = apiUsageResponseSchema.extend({ diff --git a/src/sql/supported_dexes/svm.sql b/src/sql/supported_dexes/svm.sql index 04a0b8a4..594c4966 100644 --- a/src/sql/supported_dexes/svm.sql +++ b/src/sql/supported_dexes/svm.sql @@ -9,5 +9,6 @@ FROM pool_activity_summary AS p GROUP BY p.program_id, p.amm -ORDER BY transactions DESC, program_id, amm -LIMIT 100 +ORDER BY transactions DESC +LIMIT {limit:UInt64} +OFFSET {offset:UInt64} From 8a24a668e09e758d0a1d865bfbe7246c2e70bc09 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 17 Dec 2025 09:25:55 -0500 Subject: [PATCH 44/52] Add GROUP BY --- src/sql/pools/evm.sql | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index 6027d167..9bf24959 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -14,7 +14,7 @@ pools AS ( pool, factory, protocol, - transactions + sum(transactions) as transactions FROM state_pools_aggregating_by_pool WHERE ({input_token:Array(String)} = [''] OR pool IN input_pools) @@ -23,6 +23,8 @@ pools AS ( AND ({factory:Array(String)} = [''] OR factory IN {factory:Array(String)}) AND ({protocol:String} = '' OR toString(protocol) = {protocol:String}) + GROUP BY pool, factory, protocol + ORDER BY transactions DESC LIMIT {limit:UInt64} OFFSET {offset:UInt64} @@ -36,8 +38,8 @@ pools_with_tokens AS ( arrayElement(tokens, 1) AS token0, arrayElement(tokens, 2) AS token1 - FROM pools AS p - JOIN state_pools_aggregating_by_token AS pt ON p.pool = pt.pool AND p.factory = pt.factory AND p.protocol = pt.protocol + FROM state_pools_aggregating_by_token AS pt + JOIN pools AS p ON p.pool = pt.pool AND p.factory = pt.factory AND p.protocol = pt.protocol GROUP BY pool, factory, protocol ) SELECT @@ -61,9 +63,8 @@ SELECT /* Fees */ f.fee AS fee FROM pools AS p -JOIN state_pools_initialize AS i ON p.pool = i.pool -JOIN state_pools_fees AS f ON p.pool = f.pool -JOIN pools_with_tokens AS pt ON p.pool = pt.pool -LEFT JOIN metadata AS m0 ON pt.token0 = m0.contract -LEFT JOIN metadata AS m1 ON pt.token1 = m1.contract +LEFT JOIN state_pools_fees AS f ON p.pool = f.pool AND p.factory = f.factory AND p.protocol = f.protocol +JOIN pools_with_tokens AS pt ON p.pool = pt.pool AND p.factory = pt.factory AND p.protocol = pt.protocol +LEFT JOIN metadata AS m0 ON {network: String} = m0.network AND pt.token0 = m0.contract +LEFT JOIN metadata AS m1 ON {network: String} = m1.network AND pt.token1 = m1.contract ORDER BY p.transactions DESC \ No newline at end of file From 8cc14712f6d49a0ecd6f3fdb507e61da11d5d7b8 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 17 Dec 2025 09:28:44 -0500 Subject: [PATCH 45/52] add network to metadata --- src/sql/swaps/evm.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sql/swaps/evm.sql b/src/sql/swaps/evm.sql index 3d4be5da..94d74349 100644 --- a/src/sql/swaps/evm.sql +++ b/src/sql/swaps/evm.sql @@ -179,6 +179,6 @@ SELECT /* network */ {network:String} AS network FROM filtered_swaps AS s -LEFT JOIN metadata AS m1 ON s.input_contract = m1.contract -LEFT JOIN metadata AS m2 ON s.output_contract = m2.contract +LEFT JOIN metadata AS m1 ON {network: String} = m1.network AND s.input_contract = m1.contract +LEFT JOIN metadata AS m2 ON {network: String} = m2.network AND s.output_contract = m2.contract ORDER BY minute DESC, timestamp DESC, block_num DESC, log_ordinal DESC From fbeb23632c35f09ee7659f985ee4401032dc023d Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 17 Dec 2025 09:35:28 -0500 Subject: [PATCH 46/52] add network --- src/sql/ohlcv_prices_for_pool/evm.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sql/ohlcv_prices_for_pool/evm.sql b/src/sql/ohlcv_prices_for_pool/evm.sql index ad182e69..a44d44b6 100644 --- a/src/sql/ohlcv_prices_for_pool/evm.sql +++ b/src/sql/ohlcv_prices_for_pool/evm.sql @@ -31,8 +31,8 @@ WITH ohlc AS ( /* extra fields */ p.token0 IN {stablecoin_contracts: Array(String)} AS is_stablecoin FROM ohlc_prices p - LEFT JOIN metadata m0 ON p.token0 = m0.contract - LEFT JOIN metadata m1 ON p.token1 = m1.contract + LEFT JOIN metadata m0 ON {network: String} = m0.network AND p.token0 = m0.contract + LEFT JOIN metadata m1 ON {network: String} = m1.network AND p.token1 = m1.contract WHERE p.interval_min = {interval: UInt64} AND p.pool = {pool: String} From 0816011705bdb53ed0d11bb11458e8662225f448 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 17 Dec 2025 10:06:33 -0500 Subject: [PATCH 47/52] add network field --- src/routes/v1/evm/dexes/evm.ts | 2 ++ src/routes/v1/evm/pools/ohlc/evm.ts | 2 ++ src/routes/v1/tvm/dexes/tvm.ts | 4 +++- src/routes/v1/tvm/pools/ohlc/tvm.ts | 2 ++ src/sql/ohlcv_prices_for_pool/evm.sql | 13 +++++++++++-- src/sql/pools/evm.sql | 6 +++++- src/sql/supported_dexes/evm.sql | 5 +++-- 7 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/routes/v1/evm/dexes/evm.ts b/src/routes/v1/evm/dexes/evm.ts index 86493a2d..47a7d4c2 100644 --- a/src/routes/v1/evm/dexes/evm.ts +++ b/src/routes/v1/evm/dexes/evm.ts @@ -28,6 +28,7 @@ const responseSchema = apiUsageResponseSchema.extend({ uaw: z.number(), transactions: z.number(), last_activity: z.string().describe('ISO 8601 datetime string'), + network: evmNetworkIdSchema, }) ), }); @@ -54,6 +55,7 @@ const openapi = describeRoute( uaw: 10432787, transactions: 16029788, last_activity: '2025-11-06 16:00:00', + network: 'mainnet' }, ], }, diff --git a/src/routes/v1/evm/pools/ohlc/evm.ts b/src/routes/v1/evm/pools/ohlc/evm.ts index 1eb50b19..becf84f2 100644 --- a/src/routes/v1/evm/pools/ohlc/evm.ts +++ b/src/routes/v1/evm/pools/ohlc/evm.ts @@ -40,6 +40,7 @@ const responseSchema = apiUsageResponseSchema.extend({ volume: z.number(), uaw: z.number(), transactions: z.number(), + network: evmNetworkIdSchema, }) ), }); @@ -72,6 +73,7 @@ const openapi = describeRoute( volume: 32956701.586648002, uaw: 1363, transactions: 3066, + network: 'mainnet' }, ], }, diff --git a/src/routes/v1/tvm/dexes/tvm.ts b/src/routes/v1/tvm/dexes/tvm.ts index ca434e84..1ec93904 100644 --- a/src/routes/v1/tvm/dexes/tvm.ts +++ b/src/routes/v1/tvm/dexes/tvm.ts @@ -29,6 +29,7 @@ const responseSchema = apiUsageResponseSchema.extend({ transactions: z.number(), uaw: z.number(), last_activity: dateTimeSchema, + network: tvmNetworkIdSchema, }) ), }); @@ -54,7 +55,8 @@ const openapi = describeRoute( "factory": "TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF", "last_activity": "2025-12-16 05:16:18", "transactions": 48269088, - "uaw": 2848148 + "uaw": 2848148, + "network": "tron" }, ], }, diff --git a/src/routes/v1/tvm/pools/ohlc/tvm.ts b/src/routes/v1/tvm/pools/ohlc/tvm.ts index da626c32..47264db1 100644 --- a/src/routes/v1/tvm/pools/ohlc/tvm.ts +++ b/src/routes/v1/tvm/pools/ohlc/tvm.ts @@ -40,6 +40,7 @@ const responseSchema = apiUsageResponseSchema.extend({ volume: z.number(), uaw: z.number(), transactions: z.number(), + network: tvmNetworkIdSchema, }) ), }); @@ -72,6 +73,7 @@ const openapi = describeRoute( volume: 15584135805763, uaw: 10, transactions: 102081, + network: 'tron' }, ], }, diff --git a/src/sql/ohlcv_prices_for_pool/evm.sql b/src/sql/ohlcv_prices_for_pool/evm.sql index a44d44b6..1fd40d7e 100644 --- a/src/sql/ohlcv_prices_for_pool/evm.sql +++ b/src/sql/ohlcv_prices_for_pool/evm.sql @@ -1,9 +1,10 @@ WITH ohlc AS ( SELECT + /* Time */ timestamp AS datetime, - CONCAT(m0.symbol, m1.symbol) AS ticker, /* DEX identity */ + CONCAT(m0.symbol, m1.symbol) AS ticker, pool, /* OHLC */ @@ -43,14 +44,22 @@ WITH ohlc AS ( OFFSET {offset:UInt64} ) SELECT + /* Time */ datetime, + + /* DEX identity */ ticker, pool, + + /* OHLC */ if(is_stablecoin, 1/open_raw, open_raw) AS open, if(is_stablecoin, 1/low_raw, high_raw) AS high, if(is_stablecoin, 1/high_raw, low_raw) AS low, if(is_stablecoin, 1/close_raw, close_raw) AS close, volume, uaw, - transactions + transactions, + + /* Network */ + {network: String} AS network, FROM ohlc \ No newline at end of file diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index 9bf24959..6c3c06c0 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -47,6 +47,7 @@ SELECT p.pool AS pool, p.factory AS factory, p.protocol AS protocol, + /* tokens */ CAST (( pt.token0, @@ -61,7 +62,10 @@ SELECT ) AS Tuple(address String, symbol String, decimals UInt8)) AS output_token, /* Fees */ - f.fee AS fee + f.fee AS fee, + + /* Network */ + {network: String} AS network FROM pools AS p LEFT JOIN state_pools_fees AS f ON p.pool = f.pool AND p.factory = f.factory AND p.protocol = f.protocol JOIN pools_with_tokens AS pt ON p.pool = pt.pool AND p.factory = pt.factory AND p.protocol = pt.protocol diff --git a/src/sql/supported_dexes/evm.sql b/src/sql/supported_dexes/evm.sql index d2f2383e..31e4b67d 100644 --- a/src/sql/supported_dexes/evm.sql +++ b/src/sql/supported_dexes/evm.sql @@ -1,10 +1,11 @@ SELECT - protocol, factory, + protocol, /* count() as pools, */ max(max_timestamp) as last_activity, sum(transactions) as transactions, - uniqMerge(uniq_tx_from) as uaw + uniqMerge(uniq_tx_from) as uaw, + {network: String} AS network FROM state_pools_aggregating_by_pool GROUP BY protocol, From 78e6f9a534e9cfeababad6d3c994d204d1dac21a Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 17 Dec 2025 10:07:44 -0500 Subject: [PATCH 48/52] fix lint --- src/config.ts | 2 +- src/routes/v1/evm/dexes/evm.ts | 10 ++--- src/routes/v1/evm/pools/evm.ts | 27 ++++++----- src/routes/v1/evm/pools/ohlc/evm.ts | 2 +- src/routes/v1/evm/swaps/evm.ts | 7 +-- src/routes/v1/svm/dexes/svm.ts | 8 ++-- src/routes/v1/tvm/dexes/tvm.ts | 20 ++++----- src/routes/v1/tvm/pools/index.ts | 2 +- src/routes/v1/tvm/pools/ohlc/tvm.ts | 2 +- src/routes/v1/tvm/pools/tvm.ts | 29 ++++++------ src/routes/v1/tvm/swaps/tvm.ts | 69 +++++++++++++++-------------- 11 files changed, 83 insertions(+), 95 deletions(-) diff --git a/src/config.ts b/src/config.ts index 2158b655..90db658b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -6,7 +6,7 @@ import { z } from 'zod'; import pkg from '../package.json' with { type: 'json' }; // Set timezone to UTC -process.env.TZ = "Etc/UTC"; +process.env.TZ = 'Etc/UTC'; // defaults export const DEFAULT_PORT = '8000'; diff --git a/src/routes/v1/evm/dexes/evm.ts b/src/routes/v1/evm/dexes/evm.ts index 47a7d4c2..20242e22 100644 --- a/src/routes/v1/evm/dexes/evm.ts +++ b/src/routes/v1/evm/dexes/evm.ts @@ -14,11 +14,9 @@ import { } from '../../../../types/zod.js'; import { validatorHook, withErrorResponses } from '../../../../utils.js'; -const querySchema = createQuerySchema( - { - network: { schema: evmNetworkIdSchema }, - } -); +const querySchema = createQuerySchema({ + network: { schema: evmNetworkIdSchema }, +}); const responseSchema = apiUsageResponseSchema.extend({ data: z.array( @@ -55,7 +53,7 @@ const openapi = describeRoute( uaw: 10432787, transactions: 16029788, last_activity: '2025-11-06 16:00:00', - network: 'mainnet' + network: 'mainnet', }, ], }, diff --git a/src/routes/v1/evm/pools/evm.ts b/src/routes/v1/evm/pools/evm.ts index 325b79ce..ff5b4240 100644 --- a/src/routes/v1/evm/pools/evm.ts +++ b/src/routes/v1/evm/pools/evm.ts @@ -14,7 +14,6 @@ import { import { apiUsageResponseSchema, createQuerySchema, - dateTimeSchema, evmContractSchema, evmFactorySchema, evmNetworkIdSchema, @@ -98,21 +97,21 @@ const openapi = describeRoute( value: { data: [ { - "pool": "0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640", - "factory": "0x1f98431c8ad98523631ae4a59f267346ea31f984", - "protocol": "uniswap_v3", - "input_token": { - "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", - "symbol": "USDC", - "decimals": 6 + pool: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', + factory: '0x1f98431c8ad98523631ae4a59f267346ea31f984', + protocol: 'uniswap_v3', + input_token: { + address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + symbol: 'USDC', + decimals: 6, }, - "output_token": { - "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2", - "symbol": "WETH", - "decimals": 18 + output_token: { + address: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2', + symbol: 'WETH', + decimals: 18, }, - "fee": 500 - } + fee: 500, + }, ], }, }, diff --git a/src/routes/v1/evm/pools/ohlc/evm.ts b/src/routes/v1/evm/pools/ohlc/evm.ts index becf84f2..6ba7d0c0 100644 --- a/src/routes/v1/evm/pools/ohlc/evm.ts +++ b/src/routes/v1/evm/pools/ohlc/evm.ts @@ -73,7 +73,7 @@ const openapi = describeRoute( volume: 32956701.586648002, uaw: 1363, transactions: 3066, - network: 'mainnet' + network: 'mainnet', }, ], }, diff --git a/src/routes/v1/evm/swaps/evm.ts b/src/routes/v1/evm/swaps/evm.ts index cc5874b2..b2d967a0 100644 --- a/src/routes/v1/evm/swaps/evm.ts +++ b/src/routes/v1/evm/swaps/evm.ts @@ -180,12 +180,7 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const query = sqlQueries.swaps?.[dbConfig.type]; if (!query) return c.json({ error: 'Query for swaps could not be loaded' }, 500); - const response = await makeUsageQueryJson( - c, - [query], - { ...params }, - { database: dbConfig.database } - ); + const response = await makeUsageQueryJson(c, [query], { ...params }, { database: dbConfig.database }); return handleUsageQueryError(c, response); }); diff --git a/src/routes/v1/svm/dexes/svm.ts b/src/routes/v1/svm/dexes/svm.ts index eca9d2de..4a3f3fc4 100644 --- a/src/routes/v1/svm/dexes/svm.ts +++ b/src/routes/v1/svm/dexes/svm.ts @@ -14,11 +14,9 @@ import { } from '../../../../types/zod.js'; import { validatorHook, withErrorResponses } from '../../../../utils.js'; -const querySchema = createQuerySchema( - { - network: { schema: svmNetworkIdSchema }, - } -); +const querySchema = createQuerySchema({ + network: { schema: svmNetworkIdSchema }, +}); const responseSchema = apiUsageResponseSchema.extend({ data: z.array( diff --git a/src/routes/v1/tvm/dexes/tvm.ts b/src/routes/v1/tvm/dexes/tvm.ts index 1ec93904..8fb00231 100644 --- a/src/routes/v1/tvm/dexes/tvm.ts +++ b/src/routes/v1/tvm/dexes/tvm.ts @@ -15,11 +15,9 @@ import { } from '../../../../types/zod.js'; import { validatorHook, withErrorResponses } from '../../../../utils.js'; -const querySchema = createQuerySchema( - { - network: { schema: tvmNetworkIdSchema }, - } -); +const querySchema = createQuerySchema({ + network: { schema: tvmNetworkIdSchema }, +}); const responseSchema = apiUsageResponseSchema.extend({ data: z.array( @@ -51,12 +49,12 @@ const openapi = describeRoute( value: { data: [ { - "protocol": "uniswap_v1", - "factory": "TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF", - "last_activity": "2025-12-16 05:16:18", - "transactions": 48269088, - "uaw": 2848148, - "network": "tron" + protocol: 'uniswap_v1', + factory: 'TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF', + last_activity: '2025-12-16 05:16:18', + transactions: 48269088, + uaw: 2848148, + network: 'tron', }, ], }, diff --git a/src/routes/v1/tvm/pools/index.ts b/src/routes/v1/tvm/pools/index.ts index 2dcee776..8270d67b 100644 --- a/src/routes/v1/tvm/pools/index.ts +++ b/src/routes/v1/tvm/pools/index.ts @@ -1,6 +1,6 @@ import { Hono } from 'hono'; -import tvm from './tvm.js'; import ohlc from './ohlc/index.js'; +import tvm from './tvm.js'; const router = new Hono(); diff --git a/src/routes/v1/tvm/pools/ohlc/tvm.ts b/src/routes/v1/tvm/pools/ohlc/tvm.ts index 47264db1..0b381660 100644 --- a/src/routes/v1/tvm/pools/ohlc/tvm.ts +++ b/src/routes/v1/tvm/pools/ohlc/tvm.ts @@ -73,7 +73,7 @@ const openapi = describeRoute( volume: 15584135805763, uaw: 10, transactions: 102081, - network: 'tron' + network: 'tron', }, ], }, diff --git a/src/routes/v1/tvm/pools/tvm.ts b/src/routes/v1/tvm/pools/tvm.ts index 74a4ceb3..bdd49abb 100644 --- a/src/routes/v1/tvm/pools/tvm.ts +++ b/src/routes/v1/tvm/pools/tvm.ts @@ -14,7 +14,6 @@ import { import { apiUsageResponseSchema, createQuerySchema, - evmContractSchema, evmFactorySchema, evmNetworkIdSchema, evmPoolSchema, @@ -94,21 +93,21 @@ const openapi = describeRoute( value: { data: [ { - "pool": "TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE", - "factory": "TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF", - "protocol": "uniswap_v1", - "input_token": { - "address": "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb", - "symbol": "TRX", - "decimals": 6 + pool: 'TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE', + factory: 'TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF', + protocol: 'uniswap_v1', + input_token: { + address: 'T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb', + symbol: 'TRX', + decimals: 6, + }, + output_token: { + address: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', + symbol: 'USDT', + decimals: 6, + }, + fee: 3000, }, - "output_token": { - "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", - "symbol": "USDT", - "decimals": 6 - }, - "fee": 3000 - } ], }, }, diff --git a/src/routes/v1/tvm/swaps/tvm.ts b/src/routes/v1/tvm/swaps/tvm.ts index 84e3acf3..dc4a216d 100644 --- a/src/routes/v1/tvm/swaps/tvm.ts +++ b/src/routes/v1/tvm/swaps/tvm.ts @@ -46,7 +46,12 @@ const querySchema = createQuerySchema({ caller: { schema: tvmAddressSchema, batched: true, default: '', meta: { example: TVM_ADDRESS_SWAP_EXAMPLE } }, sender: { schema: tvmAddressSchema, batched: true, default: '', meta: { example: TVM_ADDRESS_SWAP_EXAMPLE } }, recipient: { schema: tvmAddressSchema, batched: true, default: '', meta: { example: TVM_ADDRESS_SWAP_EXAMPLE } }, - input_contract: { schema: tvmAddressSchema, batched: true, default: '', meta: { example: TVM_CONTRACT_USDT_EXAMPLE } }, + input_contract: { + schema: tvmAddressSchema, + batched: true, + default: '', + meta: { example: TVM_CONTRACT_USDT_EXAMPLE }, + }, output_contract: { schema: tvmAddressSchema, batched: true, @@ -118,35 +123,36 @@ const openapi = describeRoute( value: { data: [ { - "block_num": 28320009, - "datetime": "2021-03-10 04:43:33", - "timestamp": 1615351413, - "transaction_id": "0x3e0f39b48dae8c49d3f95bc6206a632af484059764487b0c7d3e3c97bb433130", - "factory": "TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF", - "pool": "TAqCH2kadHAugPEorFrpT7Kogqo2FckxWA", - "caller": "TSLjVj4sL7uDWQXDbHyV3Kbgz1KL9jB78w", - "sender": "TSLjVj4sL7uDWQXDbHyV3Kbgz1KL9jB78w", - "recipient": "TSLjVj4sL7uDWQXDbHyV3Kbgz1KL9jB78w", - "input_token": { - "address": "TGc9XV7skLENAHPj4afCpBS8JSHv6box9C", - "symbol": "", - "decimals": 0 + block_num: 28320009, + datetime: '2021-03-10 04:43:33', + timestamp: 1615351413, + transaction_id: + '0x3e0f39b48dae8c49d3f95bc6206a632af484059764487b0c7d3e3c97bb433130', + factory: 'TXk8rQSAvPvBBNtqSoY6nCfsXWCSSpTVQF', + pool: 'TAqCH2kadHAugPEorFrpT7Kogqo2FckxWA', + caller: 'TSLjVj4sL7uDWQXDbHyV3Kbgz1KL9jB78w', + sender: 'TSLjVj4sL7uDWQXDbHyV3Kbgz1KL9jB78w', + recipient: 'TSLjVj4sL7uDWQXDbHyV3Kbgz1KL9jB78w', + input_token: { + address: 'TGc9XV7skLENAHPj4afCpBS8JSHv6box9C', + symbol: '', + decimals: 0, }, - "output_token": { - "address": "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb", - "symbol": "TRX", - "decimals": 6 + output_token: { + address: 'T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb', + symbol: 'TRX', + decimals: 6, }, - "input_amount": "20000000", - "input_value": 20000000, - "output_amount": "1258054968", - "output_value": 1258.054968, - "price": 0.0000629027484, - "price_inv": 15897.556552552798, - "protocol": "uniswap_v1", - "summary": "Swap 20.00 million for 1.26 thousand TRX on Uniswap V1", - "network": "tron" - } + input_amount: '20000000', + input_value: 20000000, + output_amount: '1258054968', + output_value: 1258.054968, + price: 0.0000629027484, + price_inv: 15897.556552552798, + protocol: 'uniswap_v1', + summary: 'Swap 20.00 million for 1.26 thousand TRX on Uniswap V1', + network: 'tron', + }, ], }, }, @@ -171,12 +177,7 @@ route.get('/', openapi, zValidator('query', querySchema, validatorHook), validat const query = sqlQueries.swaps?.[dbConfig.type]; if (!query) return c.json({ error: 'Query for swaps could not be loaded' }, 500); - const response = await makeUsageQueryJson( - c, - [query], - { ...params }, - { database: dbConfig.database } - ); + const response = await makeUsageQueryJson(c, [query], { ...params }, { database: dbConfig.database }); return handleUsageQueryError(c, response); }); From 8bf876030b79b7b8d9e74e60f99ef9907f7ff390 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 17 Dec 2025 10:10:01 -0500 Subject: [PATCH 49/52] add network --- src/routes/v1/evm/pools/evm.ts | 1 + src/routes/v1/tvm/pools/tvm.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/routes/v1/evm/pools/evm.ts b/src/routes/v1/evm/pools/evm.ts index ff5b4240..f52a02c5 100644 --- a/src/routes/v1/evm/pools/evm.ts +++ b/src/routes/v1/evm/pools/evm.ts @@ -111,6 +111,7 @@ const openapi = describeRoute( decimals: 18, }, fee: 500, + network: 'mainnet', }, ], }, diff --git a/src/routes/v1/tvm/pools/tvm.ts b/src/routes/v1/tvm/pools/tvm.ts index bdd49abb..716d4f14 100644 --- a/src/routes/v1/tvm/pools/tvm.ts +++ b/src/routes/v1/tvm/pools/tvm.ts @@ -107,6 +107,7 @@ const openapi = describeRoute( decimals: 6, }, fee: 3000, + network: 'tron', }, ], }, From c021d8c2467965027f99bc9bcf68f5696c16ef99 Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 17 Dec 2025 17:16:41 -0500 Subject: [PATCH 50/52] push fix to OHLC --- src/sql/ohlcv_prices_for_pool/evm.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sql/ohlcv_prices_for_pool/evm.sql b/src/sql/ohlcv_prices_for_pool/evm.sql index 1fd40d7e..04db8be1 100644 --- a/src/sql/ohlcv_prices_for_pool/evm.sql +++ b/src/sql/ohlcv_prices_for_pool/evm.sql @@ -61,5 +61,5 @@ SELECT transactions, /* Network */ - {network: String} AS network, + {network: String} AS network FROM ohlc \ No newline at end of file From 6e8166d2f0c061ca902f36645445bd04c1c179ac Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 17 Dec 2025 18:13:22 -0500 Subject: [PATCH 51/52] Fix duplicate pools --- src/sql/pools/evm.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sql/pools/evm.sql b/src/sql/pools/evm.sql index 6c3c06c0..a8984791 100644 --- a/src/sql/pools/evm.sql +++ b/src/sql/pools/evm.sql @@ -67,8 +67,8 @@ SELECT /* Network */ {network: String} AS network FROM pools AS p -LEFT JOIN state_pools_fees AS f ON p.pool = f.pool AND p.factory = f.factory AND p.protocol = f.protocol +ANY LEFT JOIN state_pools_fees AS f ON p.pool = f.pool AND p.factory = f.factory AND p.protocol = f.protocol JOIN pools_with_tokens AS pt ON p.pool = pt.pool AND p.factory = pt.factory AND p.protocol = pt.protocol -LEFT JOIN metadata AS m0 ON {network: String} = m0.network AND pt.token0 = m0.contract -LEFT JOIN metadata AS m1 ON {network: String} = m1.network AND pt.token1 = m1.contract +ANY LEFT JOIN metadata AS m0 ON {network: String} = m0.network AND pt.token0 = m0.contract +ANY LEFT JOIN metadata AS m1 ON {network: String} = m1.network AND pt.token1 = m1.contract ORDER BY p.transactions DESC \ No newline at end of file From 4ffab9d6811022552cdb9b570cea05ae8ff3723f Mon Sep 17 00:00:00 2001 From: Denis Carriere Date: Wed, 17 Dec 2025 18:47:32 -0500 Subject: [PATCH 52/52] remove high_quantile --- src/sql/ohlcv_prices_for_pool/svm.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sql/ohlcv_prices_for_pool/svm.sql b/src/sql/ohlcv_prices_for_pool/svm.sql index d98d59e1..e8d4309b 100644 --- a/src/sql/ohlcv_prices_for_pool/svm.sql +++ b/src/sql/ohlcv_prices_for_pool/svm.sql @@ -11,8 +11,8 @@ WITH ohlc AS toString(o.mint0) AS token0, toString(o.mint1) AS token1, argMinMerge(open0) AS open_raw, - quantileDeterministicMerge({high_quantile:Float64})(quantile0) AS high_raw, - quantileDeterministicMerge({low_quantile:Float64})(quantile0) AS low_raw, + quantileDeterministicMerge(0.95)(quantile0) AS high_raw, + quantileDeterministicMerge(0.05)(quantile0) AS low_raw, argMaxMerge(close0) AS close_raw, sum(gross_volume1) AS volume, uniqMerge(uaw) AS uaw,