diff --git a/benchmarks/memecoin-platforms.yml b/benchmarks/memecoin-platforms.yml index 37021177..4b4284c4 100644 --- a/benchmarks/memecoin-platforms.yml +++ b/benchmarks/memecoin-platforms.yml @@ -46,7 +46,7 @@ methodology: - "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 are settled inside pool accounts as LP fees — they are not transferred to any platform wallet and are outside this benchmark's scope." - - "Grouping: trades are split by the platform field returned by Mobula. Trades with no platform tag are currently assigned to pump-fun — known limitation: untagged traffic (MEV bots, snipers, direct scripts) inflates the pump-fun sample with zero-platform-fee trades, pulling its median toward gas-only. A dedicated Unattributed bucket is on the roadmap." + - "Grouping: platform tag from Mobula's platform field (frontend referral attribution). Trades with no platform tag use poolType to detect pump.fun natively: poolType=pumpfun (bonding curve) or poolType=pumpswap (graduated AMM) → attributed to pump-fun. All other untagged trades go to an internal unattributed bucket and are excluded from provider rows." - "Cadence: full sweep every 5 minutes; tx results are cached to avoid re-parsing the same hash." - "Aggregation: headline is the 24h median of the trade-count-weighted average of memecoin_platform_fee_pct across all tracked tokens." @@ -63,8 +63,8 @@ faq: a: "For confirmed platforms like Fomo, the fee wallet owner address is verified by inspecting multiple tagged trades on-chain. For platforms without a confirmed wallet, the harness uses a heuristic: any non-system, non-pool account receiving less than 5% of the user's net SOL flow, or less than 5% of the largest token pool receipt, is counted as a fee recipient. This captures Phantom-style referral tips without hardcoding every address." - q: "Why does Trojan show near-zero fee?" a: "Trojan and similar escrow-based bots (Maestro) pre-fund a shared wallet, execute trades from it, then settle with users in a separate transaction. The swap transaction itself shows a fair-price trade with no fee deduction. Their advertised ~0.9% fee is collected in the settlement step, which is not a swap and not captured by this benchmark. A near-zero value here does not mean Trojan is free — it means their fee is outside the on-chain scope this benchmark measures. Trojan's displayed value reflects gas only." - - q: "Why does pump.fun show near-zero?" - a: "Two factors combine. First, trades with no Mobula platform tag are assigned to the pump-fun row — this includes MEV bots, snipers, and untagged scripts that pay no platform fee, pulling the pump-fun median toward gas-only. Second, pump.fun's bonding-curve fee is embedded in the output token amount rather than a discrete SOL or USDC transfer to an identifiable wallet, so it is not captured by on-chain fee parsing. PumpSwap (the AMM for graduated tokens) does charge explicit protocol and creator fees as on-chain transfers — these are captured when they appear in tagged trades. The unattributed-to-pump-fun assignment rule is a known limitation; a dedicated Unattributed bucket is on the roadmap." + - q: "Why does pump.fun show a low fee?" + a: "pump.fun trades are identified via the poolType field in Mobula's trades-enriched API: poolType=pumpfun for bonding-curve swaps and poolType=pumpswap for post-migration AMM swaps. PumpSwap charges explicit protocol and creator fees as on-chain SOL or USDC transfers — these are captured. The bonding-curve fee (pre-migration) is embedded in the output token amount, not a discrete transfer to an identifiable wallet, so it is not captured. Since August 7 2026, pump.fun cut bonding-curve trading fees to zero, making the bonding-curve row gas-only by design. The low displayed value reflects PumpSwap protocol fees on graduated tokens." prometheus: window: 24h diff --git a/harnesses/memecoin-platforms/cmd/monitor/main.go b/harnesses/memecoin-platforms/cmd/monitor/main.go index c7f3fbb0..7a99a012 100644 --- a/harnesses/memecoin-platforms/cmd/monitor/main.go +++ b/harnesses/memecoin-platforms/cmd/monitor/main.go @@ -126,7 +126,11 @@ func runPoll(mobulaClient, rpcClient, heliusClient *http.Client, heliusKey, apiK } p := t.Platform if p == "" { - p = "unattributed" + if t.isPumpFunNative() { + p = "pump-fun" + } else { + p = "unattributed" + } } s := byPlatform[p] if s == nil { diff --git a/harnesses/memecoin-platforms/cmd/monitor/mobula.go b/harnesses/memecoin-platforms/cmd/monitor/mobula.go index 9fced12f..2a93487b 100644 --- a/harnesses/memecoin-platforms/cmd/monitor/mobula.go +++ b/harnesses/memecoin-platforms/cmd/monitor/mobula.go @@ -13,6 +13,13 @@ type MobulaTrade struct { Hash string `json:"hash"` Sender string `json:"sender"` AmountUSD float64 `json:"amountUSD"` + PoolType string `json:"poolType"` +} + +// isPumpFunNative returns true for trades on pump.fun's bonding curve or +// PumpSwap AMM (post-migration). Uses poolType field from token/trades-enriched. +func (t *MobulaTrade) isPumpFunNative() bool { + return t.PoolType == "pumpfun" || t.PoolType == "pumpswap" } type mobulaTradesResp struct {