I Built a Fake Market Detector Using DEX Trade Fees

Published: (February 27, 2026 at 12:27 PM EST)
6 min read
Source: Dev.to

Source: Dev.to

🚀 How I Discovered a Wash‑Traded Solana Token (and Built a Scanner)

Last month I almost bought a Solana token that showed $2 M in daily volume.
Everything looked legit – active chart, thousands of transactions, growing holder count.

When I dug into the fees I saw the token had generated $12 in total platform fees on $2 M of volume – a 0.0006 % fee ratio.
In a real market you’d expect something between 0.5 % – 2 %.

It turned out to be a wash‑traded token: bots were trading back‑and‑forth with themselves. I would have lost everything.

That experience inspired me to build a market‑legitimacy scanner powered by fee data. Below is a cleaned‑up guide on how it works and how you can build one too.


🧩 Every DEX Trade Has Three Cost Components (Most Platforms Hide)

ComponentWhat it isTypical cost (Solana)
Gas FeeNetwork cost to validators~ $0.35
Platform FeeAggregator cut (Axiom, GMGN, etc.)~ 1 % of trade
MEV FeePriority tips, Jito bundles~ $2 – $5

Key insight: On a $2,500 trade, the platform fee ($25) is 90 % of the total cost, yet most interfaces only display the gas fee.

Real traders pay real fees.
Wash traders control the entire flow and often trade directly through DEX contracts to avoid platform fees entirely. This asymmetry is the detection signal.


📊 Market‑Manipulation Stats

  • Chainalysis 2025 report: > 42 % of tokens launched in 2024 were listed on a DEX, and wash‑trading remains one of the most prevalent manipulation tactics.
  • Solidus Labs: Self‑trading on DEX pools is far more common than expected.

📈 Fee‑to‑Volume Ratio

[ \text{Fee‑to‑Volume Ratio} = \frac{\text{Fees Paid (24 h)}}{\text{Volume (24 h)}} \times 100 ]

RatioSignal
0.5 % – 2.5 %✅ Healthy, organic trading
0.1 % – 0.5 %⚠️ Investigate further
** 5 %**⚠️ Unusual fee structure

Example: A token with $500 K daily volume but only $50 in fees → 0.01 % ratio → Something is very wrong.


📡 Pulling Fee Data from Mobula

Most crypto APIs only give you volume and price. Mobula exposes the full fee breakdown (gas, platform, MEV) per trade and aggregated per token.

Token Details (REST)

curl -X GET "https://api.mobula.io/api/2/token/details?blockchain=solana&address=TOKEN_ADDRESS" \
  -H "Authorization: YOUR_API_KEY"

Sample response

{
  "data": {
    "symbol": "EXAMPLE",
    "totalFeesPaidUSD": 125000.50,
    "feesPaid24hUSD": 4450.00,
    "feesPaid1hUSD": 185.00,
    "feesPaid5minUSD": 15.50,
    "volume24hUSD": 890000.00
  }
}

Recent Trades (REST)

curl -X GET "https://api.mobula.io/api/2/token/trades?blockchain=solana&address=TOKEN_ADDRESS&limit=50" \
  -H "Authorization: YOUR_API_KEY"

Each trade returns:

  • totalFeesUSD – sum of all fee components
  • gasFeesUSD – network transaction cost
  • platformFeesUSD – aggregator/frontend fee
  • mevFeesUSD – priority/MEV‑related cost

💻 TypeScript Scanner – Flag Suspicious Fee Patterns

import { MobulaClient } from "@mobula_labs/sdk";

interface FeeAnalysis {
  symbol: string;
  volume24h: number;
  fees24h: number;
  feeRatio: number;
  verdict: "ORGANIC" | "SUSPICIOUS" | "WARNING";
  reason: string;
}

async function scanToken(
  blockchain: string,
  address: string
): Promise {
  const client = new MobulaClient({ apiKey: process.env.MOBULA_API_KEY! });

  const details = await client.fetchTokenDetails({ blockchain, address });

  const volume = details.volume24hUSD ?? 0;
  const fees = details.feesPaid24hUSD ?? 0;
  const symbol = details.symbol ?? "UNKNOWN";
  const ratio = volume > 0 ? (fees / volume) * 100 : 0;

  // Zero fees + active volume = honeypot signal
  if (fees === 0 && volume > 10_000) {
    return {
      symbol,
      volume24h: volume,
      fees24h: fees,
      feeRatio: 0,
      verdict: "WARNING",
      reason: "Zero fees with active volume — possible honeypot",
    };
  }

  // Very low ratio + high volume = wash‑trading signal
  if (ratio  100_000) {
    return {
      symbol,
      volume24h: volume,
      fees24h: fees,
      feeRatio: ratio,
      verdict: "SUSPICIOUS",
      reason: `Fee ratio ${ratio.toFixed(4)}% is far below expected 0.5‑2%`,
    };
  }

  // Abnormally high fees = investigate
  if (ratio > 5) {
    return {
      symbol,
      volume24h: volume,
      fees24h: fees,
      feeRatio: ratio,
      verdict: "WARNING",
      reason: `Fee ratio ${ratio.toFixed(2)}% is unusually high`,
    };
  }

  // Default – looks normal
  return {
    symbol,
    volume24h: volume,
    fees24h: fees,
    feeRatio: ratio,
    verdict: "ORGANIC",
    reason: "Fee distribution looks normal",
  };
}

// Scan multiple tokens
async function main() {
  const tokens = [
    "9BB6NFEcjBCtnNLFko2FqVQBq8HHM13kCyYcdQbgpump",
    "8J69rbLTzWWgUJziFY8jeu5tDQEPBwUz4pKBMr5rpump",
  ];

  for (const addr of tokens) {
    const result = await scanToken("solana", addr);
    const icon =
      result.verdict === "ORGANIC" ? "✅" :
      result.verdict === "SUSPICIOUS" ? "⚠️" : "🚨";

    console.log(`\n${icon} ${result.symbol} [${result.verdict}]`);
    console.log(`   Volume 24h: $${result.volume24h.toLocaleString()}`);
    console.log(`   Fees 24h:   $${result.fees24h.toLocaleString()}`);
    console.log(`   Fee ratio:  ${result.feeRatio.toFixed(4)}%`);
    console.log(`   → ${result.reason}`);
  }
}

main();

Sample Output

✅ FARTCOIN [ORGANIC]
   Volume 24h: $12,450,000
   Fees 24h:   $89,200
   Fee ratio:  0.7166%
   → Fee distribution looks normal

🚨 SCAMTOKEN [WARNING]
   Volume 24h: $2,100,000
   Fees 24h:   $12
   Fee ratio:  0.0006%
   → Zero fees with active volume — possible honeypot

🔔 Live Alerting via Mobula’s Trade Stream

const ws = new WebSocket("wss://general-api-v2.mobula.io");

ws.onopen = () => {
  ws.send(JSON.stringify({
    type: "fast-trades",
    authorization: process.env.MOBULA_API_KEY,
    payload: {
      tokens: [{ address: "TOKEN_ADDRESS", chainId: "solana:solana" }],
    },
  }));
};

ws.onmessage = (event) => {
  const trade = JSON.parse(event.data);
  const feePercent = (trade.totalFeesUSD / trade.amountUSD) * 100;

  // Apply the same logic as `scanToken` here for real‑time alerts
  // …
};

🎉 TL;DR

  1. Collect fee breakdowns (gas, platform, MEV) from Mobula.
  2. Compute the fee‑to‑volume ratio for the last 24 h.
  3. Flag tokens based on the ratio thresholds above (honeypot, wash‑trade, abnormal fees).
  4. Optionally listen to the live trade stream for instant alerts.

With just a few lines of code you can separate genuine liquidity from manipulative wash‑trading and protect yourself (and your community) from costly scams. Happy scanning!

// Calculate fee percentage
const feePercent = (trade.totalFeesUSD / trade.baseTokenAmountUSD) * 100;

// Alert on suspicious zero‑fee large trades
if (feePercent  1000) {
  console.log(
    `🚨 SUSPICIOUS: $${trade.baseTokenAmountUSD} trade with $${trade.totalFeesUSD} fees`
  );
}

Fee data flips the script on how we evaluate tokens

MetricCan be faked?Reliability
Volume✅ Yes (wash trading)Low
Transaction count✅ Yes (spam txs)Low
Fees paid❌ No (costs real money)High
Unique tradersPartially (sybil)Medium

Tokens with rapidly increasing feesPaid1hUSD indicate genuine interest from real traders willing to pay premium costs. That’s a signal you can’t manufacture cheaply.

0 views
Back to Blog

Related posts

Read more »