Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions benchmarks/trading-app-execution.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# OpenChainBench. Bench 204

slug: trading-app-execution
number: "204"
title: "Trading app execution quality: Axiom vs GMGN vs Trojan vs Maestro, Solana + EVM"
seo_title: "Solana trading bot execution quality 2026: Axiom, GMGN, Trojan, Maestro, pump.fun"
seo_description: "Compare on-chain execution quality for Solana trading apps: avg platform fee, priority fee, Jito bundle rate, CU price. Axiom vs GMGN vs Trojan vs Maestro vs pump.fun vs Photon — measured passively from fee accounts, updated hourly."
subtitle: Passive on-chain execution metrics for the top Solana trading apps and Telegram bots. Measured directly from fee-account transactions — no synthetic trades. Priority fee, Jito rate, CU price, and platform fee per transaction. EVM chain revenue (Ethereum, BSC, Base) on the chain tabs.

category: Trading
status: live
metric: Avg platform fee
unit: sol
higher_is_better: false

source: https://github.com/ChainBench/OpenChainBench/tree/main/harnesses/solana-exec

abstract: |
The harness monitors the on-chain fee-receiver accounts for each trading app using
the Solana JSON-RPC getSignaturesForAddress method. For every incoming fee transaction,
it records the priority fee, compute units consumed, CU price, presence of a Jito tip,
and the SOL amount transferred to the fee account. Samples are bucketed by hour in
PostgreSQL and materialised every 5 minutes. No trades are simulated; the collector
reads only existing on-chain activity. For EVM chains (Ethereum, BSC, Base), a separate
collector tracks USDC and native ETH/BNB transfers to each platform's fee address using
eth_getLogs on public RPCs — no trace API required.

methodology:
- "Solana source: Helius RPC getSignaturesForAddress on each platform's fee wallet. 100 transactions sampled per poll (every ~5 min)."
- "Priority fee: transaction fee minus the 5 000-lamport base fee per signature. Paid by the user to compete for block space."
- "CU price: priority fee divided by compute units consumed (microlamports/CU). p50/p95 from sampled CU data."
- "Jito rate: fraction of sampled transactions tipping one of the 8 official Jito tip accounts."
- "Platform fee: average SOL transferred to the platform's fee account per incoming transaction."
- "Tx count: total transactions at the fee account over the window, from raw getSignaturesForAddress counts (not just the 100-tx sample)."
- "EVM source: eth_getLogs for USDC (ERC-20) transfers + native ETH/BNB transfers to each platform's fee address. Base chain: USDC only (no free trace API for native)."
- "EVM cadence: block-by-block scanning, bootstrapped 30 days back on first run, then continuous."
- "All measurements are passive — no test transactions, no funded wallets, no on-chain footprint."

findings:
- "Axiom leads Solana trading apps by transaction volume, processing over 400K fee transactions per 24h across its 20 fee wallets."
- "GMGN charges the highest average platform fee per transaction at ~0.005 SOL, reflecting its higher-notional trader base."
- "Maestro has the highest Jito bundle rate (~11%), indicating MEV-sensitive routing for its Telegram bot users."
- "Photon has the highest CU price p95 at ~40 000 µL/CU, showing aggressive compute-unit bidding during peak hours."
- "BullX and banana-gun show the lowest platform fees, suggesting a different or volume-based fee structure."

faq:
- q: "What is platform fee vs priority fee?"
a: "Priority fee is paid to Solana validators to compete for block space — it does not go to the trading app. Platform fee is the SOL transferred to the trading app's own fee wallet per transaction, which is the actual revenue the platform captures from each trade."
- q: "Why does Trojan show a near-zero Jito rate?"
a: "Trojan does not appear to use Jito MEV bundles for its standard execution path. This is consistent with its design as a Telegram bot that prioritises simplicity over MEV protection."
- q: "How is transaction count measured?"
a: "Tx count comes from getSignaturesForAddress on the platform's fee wallet(s), which gives the total number of transactions that sent fees to that address. This is the full population count, not a sample — the 100-tx sample is used only for fee amount and CU metrics."
- q: "Why are EVM revenues lower than Solana revenues?"
a: "Most platforms primarily target Solana users. EVM fee collection varies: some platforms charge mostly in native ETH/BNB via internal transactions which are not traceable without a trace API. The EVM figures reflect directly visible ERC-20 (USDC) and native transfers only."
- q: "How often is data updated?"
a: "Solana metrics update every 5 minutes (materialiser cycle). EVM revenue updates block-by-block continuously. The page reflects the state at the last materialiser run, shown in the table header."
- q: "Which platforms are tracked on EVM chains?"
a: "GMGN, Maestro, and Banana Gun are tracked on Ethereum. GMGN, Maestro, Axiom, and Banana Gun are tracked on BSC. GMGN, Maestro, and Banana Gun are tracked on Base. pump.fun Terminal is tracked on all three EVM chains."

# No prometheus section — this bench uses a custom page renderer
# at src/app/benchmarks/trading-app-execution/page.tsx that reads
# directly from the exec REST API (exec.openchainbench.com).
8 changes: 5 additions & 3 deletions harnesses/memecoin-platforms/cmd/monitor/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,15 @@ func main() {

mobulaClient := &http.Client{
Timeout: 30 * time.Second,
Transport: &http.Transport{Proxy: nil},
Transport: &http.Transport{Proxy: http.ProxyURL(nil)},
}

// rpcClient routes through rotating proxy to avoid per-IP rate limits
var rpcClient *http.Client
if proxyRaw := os.Getenv("HTTPS_PROXY"); proxyRaw != "" {
if proxyURL, err := url.Parse(proxyRaw); err == nil {
rpcClient = &http.Client{
Timeout: 30 * time.Second,
Timeout: 5 * time.Second,
Transport: &http.Transport{Proxy: http.ProxyURL(proxyURL)},
}
log.Printf("rpc: rotating proxy enabled")
Expand Down Expand Up @@ -100,6 +100,7 @@ func runPoll(mobulaClient, rpcClient, heliusClient *http.Client, heliusKey, apiK
}
log.Printf("[pump.fun] %d tokens", len(tokens))

globalFreshLookups := 0
for _, tok := range tokens {
if tok.Mint == "" {
continue
Expand Down Expand Up @@ -129,13 +130,14 @@ func runPoll(mobulaClient, rpcClient, heliusClient *http.Client, heliusKey, apiK
byPlatform[p] = s
}
_, cached := txCache.Load(t.Hash)
if !cached && freshLookups >= 40 {
if !cached && (freshLookups >= 40 || globalFreshLookups >= 300) {
s.tradeValueSum += t.AmountUSD
s.n++
continue
}
if !cached {
freshLookups++
globalFreshLookups++
}
feeUSD := computeExplicitFees(rpcClient, heliusClient, heliusKey, t.Hash, t.Sender)
s.totalFeeSum += feeUSD
Expand Down
11 changes: 9 additions & 2 deletions harnesses/memecoin-platforms/cmd/monitor/solana.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,21 @@ func computeExplicitFees(proxyClient, heliusClient *http.Client, heliusKey, txHa
txCache.Range(func(k, _ any) bool { txCache.Delete(k); return true })
txCacheSize.Store(0)
}
fee, err := fetchOnChainFee(proxyClient, rpcPublic, txHash, sender)
if err != nil && heliusKey != "" {
var fee float64
var err error
if heliusKey != "" {
// Helius is faster and more reliable; use it as primary when available.
fee, err = fetchOnChainFee(heliusClient, rpcHelius+heliusKey, txHash, sender)
if err != nil && err.Error() != "not found" {
// retry once on transient EOF from Helius
time.Sleep(500 * time.Millisecond)
fee, err = fetchOnChainFee(heliusClient, rpcHelius+heliusKey, txHash, sender)
}
if err != nil && err.Error() != "not found" {
fee, err = fetchOnChainFee(proxyClient, rpcPublic, txHash, sender)
}
} else {
fee, err = fetchOnChainFee(proxyClient, rpcPublic, txHash, sender)
}
if err != nil {
if err.Error() != "not found" {
Expand Down
40 changes: 29 additions & 11 deletions src/app/apps/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -136,17 +136,35 @@ export default async function AppsHubPage() {
</div>

<div className="mt-10 border-t border-rule pt-8">
<p className="text-xs font-medium text-ink-muted uppercase tracking-wide mb-3">Related</p>
<Link
href="/benchmarks/app-store-ratings"
className="inline-flex items-center gap-2.5 px-4 py-3 rounded-lg border border-rule bg-paper hover:bg-paper-soft transition-colors group"
>
<span className="text-lg">⭐</span>
<div>
<p className="text-sm font-medium text-ink group-hover:text-accent transition-colors">App Store Ratings</p>
<p className="text-xs text-ink-muted">iOS ratings for crypto trading apps, live</p>
</div>
</Link>
<p className="text-xs font-medium text-ink-muted uppercase tracking-wide mb-3">Related benchmarks</p>
<div className="flex flex-wrap gap-3">
<Link
href="/benchmarks/app-store-ratings"
className="flex items-center gap-2.5 px-4 py-3 rounded-lg border border-rule bg-paper hover:bg-paper-soft transition-colors group"
>
<span className="text-lg">⭐</span>
<div>
<p className="text-sm font-medium text-ink group-hover:text-accent transition-colors">App Store Ratings</p>
<p className="text-xs text-ink-muted">iOS ratings for crypto trading apps, live</p>
</div>
<svg className="ml-auto text-ink-faint group-hover:text-ink-muted transition-colors" width="14" height="14" viewBox="0 0 12 12" fill="none" aria-hidden="true">
<path d="M3.5 3H2a1 1 0 00-1 1v6a1 1 0 001 1h6a1 1 0 001-1V8.5M7 1h4m0 0v4m0-4L5.5 6.5" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</Link>
<Link
href="/benchmarks/trading-app-execution"
className="flex items-center gap-2.5 px-4 py-3 rounded-lg border border-rule bg-paper hover:bg-paper-soft transition-colors group"
>
<span className="text-lg">⚡</span>
<div>
<p className="text-sm font-medium text-ink group-hover:text-accent transition-colors">Execution Quality</p>
<p className="text-xs text-ink-muted">Priority fees, Jito rates, platform fees</p>
</div>
<svg className="ml-auto text-ink-faint group-hover:text-ink-muted transition-colors" width="14" height="14" viewBox="0 0 12 12" fill="none" aria-hidden="true">
<path d="M3.5 3H2a1 1 0 00-1 1v6a1 1 0 001 1h6a1 1 0 001-1V8.5M7 1h4m0 0v4m0-4L5.5 6.5" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</Link>
</div>
</div>
</article>
);
Expand Down
164 changes: 164 additions & 0 deletions src/app/benchmarks/trading-app-execution/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import type { Metadata } from "next";
import Link from "next/link";
import { pageMetadata } from "@/lib/page-metadata";
import { safeJsonLd, buildBreadcrumbJsonLd, buildFaqPageJsonLd } from "@/lib/jsonld";
import { SITE } from "@/data/site";
import { fetchExecLeaderboard } from "@/lib/solana-exec";
import { fetchEVMRevenue } from "@/lib/evm-exec";
import { ExecChainTabs } from "@/components/exec-chain-tabs";

export const revalidate = 60;

export const metadata: Metadata = pageMetadata({
path: "/benchmarks/trading-app-execution",
title: "Trading App Execution Quality — Axiom vs GMGN vs Trojan vs Maestro | OpenChainBench",
description:
"Compare on-chain execution quality for Solana trading apps: avg platform fee, priority fee, Jito bundle rate, CU price. Axiom vs GMGN vs Trojan vs Maestro — measured passively from fee accounts, updated hourly.",
});

const FAQ = [
{
q: "What is platform fee vs priority fee?",
a: "Priority fee is paid to Solana validators to compete for block space — it does not go to the trading app. Platform fee is the SOL transferred to the trading app's own fee wallet per transaction, which is the actual revenue the platform captures from each trade.",
},
{
q: "How is transaction count measured?",
a: "Tx count comes from getSignaturesForAddress on the platform's fee wallet(s), giving the total number of transactions that sent fees to that address. This is the full population count, not a sample — the 100-tx sample is used only for fee amount and CU metrics.",
},
{
q: "Why does Trojan show a near-zero Jito rate?",
a: "Trojan does not appear to use Jito MEV bundles for its standard execution path, consistent with its design as a Telegram bot that prioritises simplicity over MEV protection.",
},
{
q: "Why are EVM revenues lower than Solana revenues?",
a: "Most platforms primarily target Solana users. EVM fee collection varies: some platforms charge mostly in native ETH/BNB via internal transactions which are not traceable without a trace API. The EVM figures reflect directly visible USDC and native transfers only.",
},
{
q: "How often is data updated?",
a: "Solana metrics update every 5 minutes (materialiser cycle). EVM revenue updates block-by-block continuously. The timestamp in the table header reflects the last materialiser run.",
},
];

export default async function TradingAppExecutionPage() {
const [solanaData, evmData] = await Promise.all([
fetchExecLeaderboard(),
fetchEVMRevenue(),
]);

const breadcrumb = buildBreadcrumbJsonLd([
{ name: "Home", item: SITE.url },
{ name: "Benchmarks", item: `${SITE.url}/benchmarks` },
{ name: "Trading App Execution", item: `${SITE.url}/benchmarks/trading-app-execution` },
]);

const faqJsonLd = buildFaqPageJsonLd(
FAQ,
`${SITE.url}/benchmarks/trading-app-execution`,
);

return (
<article className="mx-auto max-w-[900px] px-4 sm:px-6 py-10 sm:py-14">
<script
type="application/ld+json"
// biome-ignore lint/security/noDangerouslySetInnerHtml: serialized via safeJsonLd
dangerouslySetInnerHTML={{ __html: safeJsonLd({ "@context": "https://schema.org", ...breadcrumb }) }}
/>
<script
type="application/ld+json"
// biome-ignore lint/security/noDangerouslySetInnerHtml: serialized via safeJsonLd
dangerouslySetInnerHTML={{ __html: safeJsonLd(faqJsonLd) }}
/>

{/* Breadcrumb */}
<nav className="flex items-center gap-1.5 text-xs text-ink-muted mb-6 font-mono">
<Link href="/" className="hover:text-ink-soft transition-colors">Home</Link>
<span>/</span>
<Link href="/benchmarks" className="hover:text-ink-soft transition-colors">Benchmarks</Link>
<span>/</span>
<span className="text-ink">Trading App Execution</span>
</nav>

{/* Header */}
<div className="flex items-start gap-3 flex-wrap">
<span
className="inline-flex items-center px-2.5 py-0.5 rounded-full text-[11px] font-medium text-white shrink-0 mt-0.5"
style={{ backgroundColor: "#a05688" }}
>
Trading
</span>
<span className="inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-[11px] font-medium bg-green-500/10 text-green-600 dark:text-green-400 border border-green-500/20 shrink-0 mt-0.5">
<span className="w-1.5 h-1.5 rounded-full bg-green-500 animate-pulse" />
Live
</span>
</div>

<h1 className="display text-3xl sm:text-4xl text-ink leading-[1.05] mt-3">
Trading app execution quality.
</h1>
<p className="mt-4 max-w-2xl text-base text-ink-soft leading-snug">
Passive on-chain execution metrics for the top Solana trading apps and Telegram bots.
Priority fee, Jito rate, CU price, and platform fee per transaction — measured directly
from fee accounts, no synthetic trades. EVM chain revenue on the chain tabs below.
</p>

<div className="mt-10">
<ExecChainTabs solanaData={solanaData} evmData={evmData} />
</div>

{/* Methodology */}
<div className="mt-10 border-t border-rule pt-8 text-xs text-ink-muted leading-relaxed max-w-2xl space-y-2">
<p className="text-xs font-medium text-ink-muted uppercase tracking-wide mb-3">Methodology</p>
<p>
<strong>Priority fee</strong> = total transaction fee minus the 5 000-lamport base fee per signature. Paid to validators, not to the platform.
</p>
<p>
<strong>CU price</strong> = priority fee ÷ compute units consumed (microlamports/CU). p50/p95 shows median and tail pressure on each platform.
</p>
<p>
<strong>Jito rate</strong> = fraction of transactions tipping one of the 8 official Jito tip accounts. Higher = more MEV-sensitive routing.
</p>
<p>
<strong>Platform fee</strong> = average SOL transferred to the platform's fee account per incoming transaction. This is actual protocol revenue per trade.
</p>
<p>
<strong>Tx count</strong> = total transactions at the fee wallet over the window (getSignaturesForAddress), not a sample. Fee metrics use a 100-tx sample per poll.
</p>
<p>
<strong>EVM</strong> = USDC (ERC-20) + native ETH/BNB direct transfers to each platform's fee address. Base chain: USDC only (no free trace API). Updated block-by-block.
</p>
<p className="text-ink-faint">
Source:{" "}
<a
href="https://github.com/ChainBench/OpenChainBench/tree/main/harnesses/solana-exec"
target="_blank"
rel="noopener noreferrer"
className="underline hover:text-ink-muted transition-colors"
>
github.com/ChainBench/OpenChainBench
</a>
. Bench #204.
</p>
</div>

{/* FAQ */}
<div className="mt-10 border-t border-rule pt-8 max-w-2xl">
<p className="text-xs font-medium text-ink-muted uppercase tracking-wide mb-5">FAQ</p>
<div className="space-y-6">
{FAQ.map((item) => (
<div key={item.q}>
<p className="font-medium text-sm text-ink mb-1">{item.q}</p>
<p className="text-sm text-ink-soft leading-relaxed">{item.a}</p>
</div>
))}
</div>
</div>

{/* Back link */}
<div className="mt-10 pt-6 border-t border-rule">
<Link href="/apps" className="text-sm text-ink-muted hover:text-ink-soft transition-colors">
← Back to trading app revenue
</Link>
</div>
</article>
);
}
Loading
Loading