From 9dbc0b8441707ec9ff7b0d4b2d0f85e54084c2bc Mon Sep 17 00:00:00 2001 From: Florent Tapponnier <160007691+Flotapponnier@users.noreply.github.com> Date: Wed, 12 Aug 2026 01:21:33 +0200 Subject: [PATCH] feat(memecoin): 25 tokens, 4h/100 trades window, fresh cap 40, 4h cache TTL, weighted avg queries --- benchmarks/memecoin-platforms.yml | 90 +++++++++---------- .../memecoin-platforms/cmd/monitor/main.go | 4 +- .../memecoin-platforms/cmd/monitor/mobula.go | 4 +- .../memecoin-platforms/cmd/monitor/solana.go | 2 +- 4 files changed, 50 insertions(+), 50 deletions(-) diff --git a/benchmarks/memecoin-platforms.yml b/benchmarks/memecoin-platforms.yml index 89333f6c..cac1ea23 100644 --- a/benchmarks/memecoin-platforms.yml +++ b/benchmarks/memecoin-platforms.yml @@ -23,27 +23,27 @@ seo_intro: | button on each platform. abstract: | - The harness fetches the top 10 tokens by market cap from pump.fun every 5 - minutes, then pulls the last 50 trades per token from Mobula's - token/trades-enriched endpoint (chainId=solana:solana). For each trade carrying - a hash and sender address, the harness calls the public Solana RPC - (getTransaction, jsonParsed encoding) and computes explicit fees: Solana - transaction fee (gas), SOL transfers to known platform fee wallets, small SOL - recipients below 5% of user net flow, and small USDC/WSOL token recipients below - 5% of the largest pool receipt. Trades below $5 are excluded to avoid gas - dominating tiny amounts. Results are grouped by platform tag, averaged per - token, and emitted as memecoin_platform_fee_pct. + The harness fetches the top 25 tokens by market cap from pump.fun every 5 + minutes, then pulls the last 100 trades per token from Mobula's + token/trades-enriched endpoint (chainId=solana:solana) over a 4-hour window. + For each trade carrying a hash and sender address, the harness calls the public + Solana RPC (getTransaction, jsonParsed encoding) and computes explicit fees: + Solana transaction fee (gas), SOL transfers to known platform fee wallets, small + SOL recipients below 5% of user net flow, and small USDC/WSOL token recipients + below 5% of the largest pool receipt. Trades below $5 are excluded to avoid gas + dominating tiny amounts. Results are grouped by platform tag, weighted by trade + count across tokens, and emitted as memecoin_platform_fee_pct. methodology: - - "Tokens: top 10 by market cap from pump.fun, refreshed every 5 minutes." - - "Trades: last 50 trades per token from Mobula token/trades-enriched (chainId=solana:solana), filtered to amountUSD >= $5." + - "Tokens: top 25 by market cap from pump.fun, refreshed every 5 minutes." + - "Trades: last 100 trades per token from Mobula token/trades-enriched (chainId=solana:solana) over a 4-hour window, filtered to amountUSD >= $5." - "Fee source: Solana public RPC getTransaction (jsonParsed) for each trade hash. No third-party fee API." - "Gas: meta.fee (lamports) converted to USD at the current SOL/USD price fetched from CoinGecko every 5 min." - "Platform fees: explicit SOL or USDC/WSOL transfers to known fee wallet owners (confirmed on-chain). Unknown small recipients are captured via heuristics: SOL recipients receiving less than 5% of the user net flow, USDC/WSOL recipients receiving less than 5% of the largest pool receipt. Trading bots that use pre-funded escrow accounts (Trojan, Maestro) collect fees through a separate settlement mechanism not visible in the swap transaction; their displayed fee represents gas only." - "AMM LP fees excluded: the 0.20% PumpSwap fee and 0.25% Raydium fee stay inside pool accounts and are not counted because they apply equally to all frontends routing through the same pool." - "Grouping: trades are split by the platform field returned by Mobula. Trades with no platform tag are assigned to pump-fun." - "Cadence: full sweep every 5 minutes; tx results are cached to avoid re-parsing the same hash." - - "Aggregation: headline is the 24h median of memecoin_platform_fee_pct across all tracked tokens." + - "Aggregation: headline is the 24h median of the trade-count-weighted average of memecoin_platform_fee_pct across all tracked tokens." findings: - "{{best_name}} currently leads with the lowest average trading fee at {{best_p50}} (p50, 24h) across top pump.fun tokens." @@ -71,10 +71,10 @@ providers: tag: Native launchpad formula: "Explicit on-chain fee percent for trades on pump.fun and PumpSwap pools, 24h median. Trades with no platform tag from Mobula are assigned here since the bench exclusively samples pump.fun top tokens." queries: - p50: quantile_over_time(0.50, avg(memecoin_platform_fee_pct{platform="pump-fun"})[24h:5m]) - p90: quantile_over_time(0.90, avg(memecoin_platform_fee_pct{platform="pump-fun"})[24h:5m]) - p99: quantile_over_time(0.99, avg(memecoin_platform_fee_pct{platform="pump-fun"})[24h:5m]) - mean: avg_over_time(avg(memecoin_platform_fee_pct{platform="pump-fun"})[24h:5m]) + p50: quantile_over_time(0.50, (sum(memecoin_platform_fee_pct{platform="pump-fun"} * memecoin_platform_trade_count{platform="pump-fun"}) / sum(memecoin_platform_trade_count{platform="pump-fun"}))[24h:5m]) + p90: quantile_over_time(0.90, (sum(memecoin_platform_fee_pct{platform="pump-fun"} * memecoin_platform_trade_count{platform="pump-fun"}) / sum(memecoin_platform_trade_count{platform="pump-fun"}))[24h:5m]) + p99: quantile_over_time(0.99, (sum(memecoin_platform_fee_pct{platform="pump-fun"} * memecoin_platform_trade_count{platform="pump-fun"}) / sum(memecoin_platform_trade_count{platform="pump-fun"}))[24h:5m]) + mean: avg_over_time((sum(memecoin_platform_fee_pct{platform="pump-fun"} * memecoin_platform_trade_count{platform="pump-fun"}) / sum(memecoin_platform_trade_count{platform="pump-fun"}))[24h:5m]) sample_size: sum(avg_over_time(memecoin_platform_trade_count{platform="pump-fun"}[24h])) - slug: phantom @@ -82,10 +82,10 @@ providers: tag: Wallet + swap UI formula: "Explicit on-chain fee percent for trades tagged phantom by Mobula, 24h median." queries: - p50: quantile_over_time(0.50, avg(memecoin_platform_fee_pct{platform="phantom"})[24h:5m]) - p90: quantile_over_time(0.90, avg(memecoin_platform_fee_pct{platform="phantom"})[24h:5m]) - p99: quantile_over_time(0.99, avg(memecoin_platform_fee_pct{platform="phantom"})[24h:5m]) - mean: avg_over_time(avg(memecoin_platform_fee_pct{platform="phantom"})[24h:5m]) + p50: quantile_over_time(0.50, (sum(memecoin_platform_fee_pct{platform="phantom"} * memecoin_platform_trade_count{platform="phantom"}) / sum(memecoin_platform_trade_count{platform="phantom"}))[24h:5m]) + p90: quantile_over_time(0.90, (sum(memecoin_platform_fee_pct{platform="phantom"} * memecoin_platform_trade_count{platform="phantom"}) / sum(memecoin_platform_trade_count{platform="phantom"}))[24h:5m]) + p99: quantile_over_time(0.99, (sum(memecoin_platform_fee_pct{platform="phantom"} * memecoin_platform_trade_count{platform="phantom"}) / sum(memecoin_platform_trade_count{platform="phantom"}))[24h:5m]) + mean: avg_over_time((sum(memecoin_platform_fee_pct{platform="phantom"} * memecoin_platform_trade_count{platform="phantom"}) / sum(memecoin_platform_trade_count{platform="phantom"}))[24h:5m]) sample_size: sum(avg_over_time(memecoin_platform_trade_count{platform="phantom"}[24h])) - slug: fomo @@ -93,10 +93,10 @@ providers: tag: Mobile app formula: "Explicit on-chain fee percent for trades tagged fomo by Mobula, 24h median. Fomo collects a fee in USDC transferred to a confirmed fee wallet per trade." queries: - p50: quantile_over_time(0.50, avg(memecoin_platform_fee_pct{platform="fomo"})[24h:5m]) - p90: quantile_over_time(0.90, avg(memecoin_platform_fee_pct{platform="fomo"})[24h:5m]) - p99: quantile_over_time(0.99, avg(memecoin_platform_fee_pct{platform="fomo"})[24h:5m]) - mean: avg_over_time(avg(memecoin_platform_fee_pct{platform="fomo"})[24h:5m]) + p50: quantile_over_time(0.50, (sum(memecoin_platform_fee_pct{platform="fomo"} * memecoin_platform_trade_count{platform="fomo"}) / sum(memecoin_platform_trade_count{platform="fomo"}))[24h:5m]) + p90: quantile_over_time(0.90, (sum(memecoin_platform_fee_pct{platform="fomo"} * memecoin_platform_trade_count{platform="fomo"}) / sum(memecoin_platform_trade_count{platform="fomo"}))[24h:5m]) + p99: quantile_over_time(0.99, (sum(memecoin_platform_fee_pct{platform="fomo"} * memecoin_platform_trade_count{platform="fomo"}) / sum(memecoin_platform_trade_count{platform="fomo"}))[24h:5m]) + mean: avg_over_time((sum(memecoin_platform_fee_pct{platform="fomo"} * memecoin_platform_trade_count{platform="fomo"}) / sum(memecoin_platform_trade_count{platform="fomo"}))[24h:5m]) sample_size: sum(avg_over_time(memecoin_platform_trade_count{platform="fomo"}[24h])) - slug: photon @@ -104,10 +104,10 @@ providers: tag: Aggregator frontend formula: "Explicit on-chain fee percent for trades tagged photon by Mobula, 24h median." queries: - p50: quantile_over_time(0.50, avg(memecoin_platform_fee_pct{platform="photon"})[24h:5m]) - p90: quantile_over_time(0.90, avg(memecoin_platform_fee_pct{platform="photon"})[24h:5m]) - p99: quantile_over_time(0.99, avg(memecoin_platform_fee_pct{platform="photon"})[24h:5m]) - mean: avg_over_time(avg(memecoin_platform_fee_pct{platform="photon"})[24h:5m]) + p50: quantile_over_time(0.50, (sum(memecoin_platform_fee_pct{platform="photon"} * memecoin_platform_trade_count{platform="photon"}) / sum(memecoin_platform_trade_count{platform="photon"}))[24h:5m]) + p90: quantile_over_time(0.90, (sum(memecoin_platform_fee_pct{platform="photon"} * memecoin_platform_trade_count{platform="photon"}) / sum(memecoin_platform_trade_count{platform="photon"}))[24h:5m]) + p99: quantile_over_time(0.99, (sum(memecoin_platform_fee_pct{platform="photon"} * memecoin_platform_trade_count{platform="photon"}) / sum(memecoin_platform_trade_count{platform="photon"}))[24h:5m]) + mean: avg_over_time((sum(memecoin_platform_fee_pct{platform="photon"} * memecoin_platform_trade_count{platform="photon"}) / sum(memecoin_platform_trade_count{platform="photon"}))[24h:5m]) sample_size: sum(avg_over_time(memecoin_platform_trade_count{platform="photon"}[24h])) - slug: axiom @@ -115,10 +115,10 @@ providers: tag: Aggregator frontend formula: "Explicit on-chain fee percent for trades tagged axiom by Mobula, 24h median." queries: - p50: quantile_over_time(0.50, avg(memecoin_platform_fee_pct{platform="axiom"})[24h:5m]) - p90: quantile_over_time(0.90, avg(memecoin_platform_fee_pct{platform="axiom"})[24h:5m]) - p99: quantile_over_time(0.99, avg(memecoin_platform_fee_pct{platform="axiom"})[24h:5m]) - mean: avg_over_time(avg(memecoin_platform_fee_pct{platform="axiom"})[24h:5m]) + p50: quantile_over_time(0.50, (sum(memecoin_platform_fee_pct{platform="axiom"} * memecoin_platform_trade_count{platform="axiom"}) / sum(memecoin_platform_trade_count{platform="axiom"}))[24h:5m]) + p90: quantile_over_time(0.90, (sum(memecoin_platform_fee_pct{platform="axiom"} * memecoin_platform_trade_count{platform="axiom"}) / sum(memecoin_platform_trade_count{platform="axiom"}))[24h:5m]) + p99: quantile_over_time(0.99, (sum(memecoin_platform_fee_pct{platform="axiom"} * memecoin_platform_trade_count{platform="axiom"}) / sum(memecoin_platform_trade_count{platform="axiom"}))[24h:5m]) + mean: avg_over_time((sum(memecoin_platform_fee_pct{platform="axiom"} * memecoin_platform_trade_count{platform="axiom"}) / sum(memecoin_platform_trade_count{platform="axiom"}))[24h:5m]) sample_size: sum(avg_over_time(memecoin_platform_trade_count{platform="axiom"}[24h])) - slug: trojan @@ -126,10 +126,10 @@ providers: tag: Trading bot formula: "Gas-only on-chain cost for trades tagged trojan by Mobula, 24h median. Trojan collects its ~0.9% fee via pre-funded escrow settled outside the swap transaction; the swap itself shows no fee deduction." queries: - p50: quantile_over_time(0.50, avg(memecoin_platform_fee_pct{platform="trojan"})[24h:5m]) - p90: quantile_over_time(0.90, avg(memecoin_platform_fee_pct{platform="trojan"})[24h:5m]) - p99: quantile_over_time(0.99, avg(memecoin_platform_fee_pct{platform="trojan"})[24h:5m]) - mean: avg_over_time(avg(memecoin_platform_fee_pct{platform="trojan"})[24h:5m]) + p50: quantile_over_time(0.50, (sum(memecoin_platform_fee_pct{platform="trojan"} * memecoin_platform_trade_count{platform="trojan"}) / sum(memecoin_platform_trade_count{platform="trojan"}))[24h:5m]) + p90: quantile_over_time(0.90, (sum(memecoin_platform_fee_pct{platform="trojan"} * memecoin_platform_trade_count{platform="trojan"}) / sum(memecoin_platform_trade_count{platform="trojan"}))[24h:5m]) + p99: quantile_over_time(0.99, (sum(memecoin_platform_fee_pct{platform="trojan"} * memecoin_platform_trade_count{platform="trojan"}) / sum(memecoin_platform_trade_count{platform="trojan"}))[24h:5m]) + mean: avg_over_time((sum(memecoin_platform_fee_pct{platform="trojan"} * memecoin_platform_trade_count{platform="trojan"}) / sum(memecoin_platform_trade_count{platform="trojan"}))[24h:5m]) sample_size: sum(avg_over_time(memecoin_platform_trade_count{platform="trojan"}[24h])) - slug: gmgn @@ -137,10 +137,10 @@ providers: tag: Trading bot formula: "Explicit on-chain fee percent for trades tagged gmgn by Mobula, 24h median." queries: - p50: quantile_over_time(0.50, avg(memecoin_platform_fee_pct{platform="gmgn"})[24h:5m]) - p90: quantile_over_time(0.90, avg(memecoin_platform_fee_pct{platform="gmgn"})[24h:5m]) - p99: quantile_over_time(0.99, avg(memecoin_platform_fee_pct{platform="gmgn"})[24h:5m]) - mean: avg_over_time(avg(memecoin_platform_fee_pct{platform="gmgn"})[24h:5m]) + p50: quantile_over_time(0.50, (sum(memecoin_platform_fee_pct{platform="gmgn"} * memecoin_platform_trade_count{platform="gmgn"}) / sum(memecoin_platform_trade_count{platform="gmgn"}))[24h:5m]) + p90: quantile_over_time(0.90, (sum(memecoin_platform_fee_pct{platform="gmgn"} * memecoin_platform_trade_count{platform="gmgn"}) / sum(memecoin_platform_trade_count{platform="gmgn"}))[24h:5m]) + p99: quantile_over_time(0.99, (sum(memecoin_platform_fee_pct{platform="gmgn"} * memecoin_platform_trade_count{platform="gmgn"}) / sum(memecoin_platform_trade_count{platform="gmgn"}))[24h:5m]) + mean: avg_over_time((sum(memecoin_platform_fee_pct{platform="gmgn"} * memecoin_platform_trade_count{platform="gmgn"}) / sum(memecoin_platform_trade_count{platform="gmgn"}))[24h:5m]) sample_size: sum(avg_over_time(memecoin_platform_trade_count{platform="gmgn"}[24h])) - slug: maestro @@ -148,8 +148,8 @@ providers: tag: Trading bot formula: "Gas-only on-chain cost for trades tagged maestro by Mobula, 24h median. Maestro uses pre-funded escrow similar to Trojan; actual fee not visible in swap transaction." queries: - p50: quantile_over_time(0.50, avg(memecoin_platform_fee_pct{platform="maestro"})[24h:5m]) - p90: quantile_over_time(0.90, avg(memecoin_platform_fee_pct{platform="maestro"})[24h:5m]) - p99: quantile_over_time(0.99, avg(memecoin_platform_fee_pct{platform="maestro"})[24h:5m]) - mean: avg_over_time(avg(memecoin_platform_fee_pct{platform="maestro"})[24h:5m]) + p50: quantile_over_time(0.50, (sum(memecoin_platform_fee_pct{platform="maestro"} * memecoin_platform_trade_count{platform="maestro"}) / sum(memecoin_platform_trade_count{platform="maestro"}))[24h:5m]) + p90: quantile_over_time(0.90, (sum(memecoin_platform_fee_pct{platform="maestro"} * memecoin_platform_trade_count{platform="maestro"}) / sum(memecoin_platform_trade_count{platform="maestro"}))[24h:5m]) + p99: quantile_over_time(0.99, (sum(memecoin_platform_fee_pct{platform="maestro"} * memecoin_platform_trade_count{platform="maestro"}) / sum(memecoin_platform_trade_count{platform="maestro"}))[24h:5m]) + mean: avg_over_time((sum(memecoin_platform_fee_pct{platform="maestro"} * memecoin_platform_trade_count{platform="maestro"}) / sum(memecoin_platform_trade_count{platform="maestro"}))[24h:5m]) sample_size: sum(avg_over_time(memecoin_platform_trade_count{platform="maestro"}[24h])) diff --git a/harnesses/memecoin-platforms/cmd/monitor/main.go b/harnesses/memecoin-platforms/cmd/monitor/main.go index 4ed9c8b4..40a284ad 100644 --- a/harnesses/memecoin-platforms/cmd/monitor/main.go +++ b/harnesses/memecoin-platforms/cmd/monitor/main.go @@ -92,7 +92,7 @@ type platformStats struct { } func runPoll(mobulaClient, rpcClient, heliusClient *http.Client, heliusKey, apiKey string) { - tokens, err := fetchTopTokens(mobulaClient, 10) + tokens, err := fetchTopTokens(mobulaClient, 25) if err != nil { log.Printf("[pump.fun] %v", err) pollErrors.WithLabelValues("pumpfun").Inc() @@ -129,7 +129,7 @@ func runPoll(mobulaClient, rpcClient, heliusClient *http.Client, heliusKey, apiK byPlatform[p] = s } _, cached := txCache.Load(t.Hash) - if !cached && freshLookups >= 20 { + if !cached && freshLookups >= 40 { s.tradeValueSum += t.AmountUSD s.n++ continue diff --git a/harnesses/memecoin-platforms/cmd/monitor/mobula.go b/harnesses/memecoin-platforms/cmd/monitor/mobula.go index 135b7aab..9fced12f 100644 --- a/harnesses/memecoin-platforms/cmd/monitor/mobula.go +++ b/harnesses/memecoin-platforms/cmd/monitor/mobula.go @@ -20,9 +20,9 @@ type mobulaTradesResp struct { } func fetchTrades(client *http.Client, apiKey, mint string) ([]MobulaTrade, error) { - from := time.Now().Add(-2 * time.Hour).UnixMilli() + from := time.Now().Add(-4 * time.Hour).UnixMilli() url := fmt.Sprintf( - "https://api.mobula.io/api/2/token/trades-enriched?address=%s&chainId=solana:solana&sortOrder=desc&limit=50&from=%d", + "https://api.mobula.io/api/2/token/trades-enriched?address=%s&chainId=solana:solana&sortOrder=desc&limit=100&from=%d", mint, from, ) req, err := http.NewRequest("GET", url, nil) diff --git a/harnesses/memecoin-platforms/cmd/monitor/solana.go b/harnesses/memecoin-platforms/cmd/monitor/solana.go index bbe5c3d8..b08511d8 100644 --- a/harnesses/memecoin-platforms/cmd/monitor/solana.go +++ b/harnesses/memecoin-platforms/cmd/monitor/solana.go @@ -52,7 +52,7 @@ type cacheEntry struct { ts time.Time } -const txCacheTTL = 2 * time.Hour +const txCacheTTL = 4 * time.Hour var ( txCache sync.Map // string → cacheEntry