diff --git a/benchmarks/solana-unique-traders.yml b/benchmarks/solana-unique-traders.yml index 41e81807..6a29351b 100644 --- a/benchmarks/solana-unique-traders.yml +++ b/benchmarks/solana-unique-traders.yml @@ -30,13 +30,14 @@ seo_intro: | abstract: | The harness wraps the Dune Analytics API. A single saved query counts distinct - fee_payer addresses in solana.transactions that touched each platform's known fee - wallet addresses in the rolling 24-hour window, joined from solana.account_activity - for efficiency. All platforms including pump.fun use the same fee wallet attribution - approach against solana.account_activity (standard Dune tier). The harness re-executes - the query every hour, polls for completion, then updates the Prometheus gauge - solana_platform_unique_traders_24h per platform. Between executions it serves the - latest cached result every 15 minutes. + tx_id values from solana.account_activity where the fee wallet address received + a native SOL inflow (post_balance > pre_balance) or a USDC/WSOL token inflow + (post_token_balance > pre_token_balance via token_balance_owner) in the rolling + 24-hour window. All platforms use the same inflow-only attribution against + solana.account_activity (standard Dune tier, no trace API required). The harness + re-executes the query every hour, polls for completion, then updates the Prometheus + gauge solana_platform_unique_traders_24h per platform. Between executions it serves + the latest cached result every 15 minutes. methodology: - "Source: Dune Analytics (dune.com). Query updated hourly, results fetched every 15 min." @@ -62,7 +63,7 @@ prometheus: faq: - q: "What does unique daily traders measure?" - a: "Unique daily traders counts the number of distinct wallet addresses (fee_payer in Solana transactions) that executed at least one trade through a platform in the rolling 24-hour window. It measures user breadth, not volume or frequency. A wallet that trades 1000 times counts as 1 unique trader." + a: "Unique daily traders counts the number of distinct fee-touching transactions (tx_id) in solana.account_activity where a platform fee wallet received SOL or USDC/WSOL in the rolling 24-hour window. It is a proxy for user breadth: the actual unique-wallet count is typically 3-10x lower since active traders execute multiple transactions per day. A wallet that trades 1000 times generates up to 1000 counted transactions." - q: "Why does pump.fun have so many more unique traders than GMGN?" a: "pump.fun is the default entry point for new Solana users and meme coin traders. Its bonding curve launch mechanic triggers massive multi-wallet bot activity as snipers race to buy newly created tokens. GMGN serves a more deliberate, power-trader segment that skews toward fewer unique wallets but larger position sizes." - q: "Is this apple-to-apple between pump.fun and the others?" diff --git a/harnesses/solana-unique-traders/cmd/script/dune.go b/harnesses/solana-unique-traders/cmd/script/dune.go index 7fadc36f..25d4d2ef 100644 --- a/harnesses/solana-unique-traders/cmd/script/dune.go +++ b/harnesses/solana-unique-traders/cmd/script/dune.go @@ -9,12 +9,12 @@ import ( "time" ) -// querySQL counts unique fee-touching transactions per Solana trading platform. -// Source: solana.account_activity filtered to known fee wallet addresses. -// Count distinct tx_ids per platform as a proxy for daily active traders. -// pump_fun_solana.trades (Dune Spellbook) is unavailable on our API tier. -// Since pump.fun cut bonding-curve trading fees to 0% on 2026-08-07, -// its count reflects only transactions generating graduation/creator fees. +// querySQL counts unique fee-generating transactions per Solana trading platform. +// Mirrors bench 203: only rows where the fee wallet actually received SOL +// (post_balance > pre_balance) or USDC/WSOL tokens (token_balance_owner match, +// post > pre). Avoids counting txs where fee wallet addresses appear as +// program IDs or read-only accounts without any balance change. +// Fomo uses R4rN... (owner wallet) for token_balance_owner matching. const querySQL = ` WITH fee_wallets AS ( SELECT address, platform FROM (VALUES @@ -56,7 +56,7 @@ WITH fee_wallets AS ( ('Hbj6XdxX6eV4nfbYTseysibp4zZJtVRRPn2J3BhGRuK9','axiom'), ('846ah7iBSu9ApuCyEhA5xpnjHHX7d4QJKetWLbwzmJZ8','axiom'), ('5BqYhuD4q1YD3DMAYkc1FeTu9vqQVYYdfBAmkZjamyZg','axiom'), - ('HrTf9CzXR1dRH4Sof5QrpmGWwpwAf3qZzwCsEjQpXcSq','fomo'), + ('R4rNJHaffSUotNmqSKNEfDcJE8A7zJUkaoM5Jkd7cYX','fomo'), ('9yMwSPk9mrXSN7yDHUuZurAh1sjbJsfpUqjZ7SvVtdco','trojan'), ('92Med3qeK7duC5iiYsHX38H2f2twJfRsSx93oNrza2VH','trojan'), ('2jwHNxavSoMZMEDbT1eV9PcPt5dDcayCqM6MkgaPpmWQ','trojan'), @@ -67,12 +67,32 @@ WITH fee_wallets AS ( ('MaestroUL88UBnZr3wfoN7hqmNWFi3ZYCGqZoJJHE36','maestro'), ('FRMxAnZgkW58zbYcE7Bxqsg99VWpJh6sMP5xLzAWNabN','maestro') ) AS t(address, platform) +), +fee_activity AS ( + SELECT fw.platform, a.tx_id + FROM solana.account_activity a + JOIN fee_wallets fw ON a.address = fw.address + WHERE a.block_time >= NOW() - INTERVAL '1' DAY + AND a.token_mint_address IS NULL + AND a.post_balance > a.pre_balance + UNION + SELECT fw.platform, a.tx_id + FROM solana.account_activity a + JOIN fee_wallets fw ON a.token_balance_owner = fw.address + WHERE a.block_time >= NOW() - INTERVAL '1' DAY + AND a.token_mint_address = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v' + AND a.post_token_balance > a.pre_token_balance + UNION + SELECT fw.platform, a.tx_id + FROM solana.account_activity a + JOIN fee_wallets fw ON a.token_balance_owner = fw.address + WHERE a.block_time >= NOW() - INTERVAL '1' DAY + AND a.token_mint_address = 'So11111111111111111111111111111111111111112' + AND a.post_token_balance > a.pre_token_balance ) -SELECT fw.platform, COUNT(DISTINCT a.tx_id) AS unique_traders_24h -FROM solana.account_activity a -JOIN fee_wallets fw ON a.address = fw.address -WHERE a.block_time >= NOW() - INTERVAL '1' DAY -GROUP BY fw.platform +SELECT platform, COUNT(DISTINCT tx_id) AS unique_traders_24h +FROM fee_activity +GROUP BY platform ORDER BY unique_traders_24h DESC `