I Built a Fake Market Detector Using DEX Trade Fees
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)
| Component | What it is | Typical cost (Solana) |
|---|---|---|
| Gas Fee | Network cost to validators | ~ $0.35 |
| Platform Fee | Aggregator cut (Axiom, GMGN, etc.) | ~ 1 % of trade |
| MEV Fee | Priority 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 ]
| Ratio | Signal |
|---|---|
| 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 componentsgasFeesUSD– network transaction costplatformFeesUSD– aggregator/frontend feemevFeesUSD– 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
- Collect fee breakdowns (gas, platform, MEV) from Mobula.
- Compute the fee‑to‑volume ratio for the last 24 h.
- Flag tokens based on the ratio thresholds above (honeypot, wash‑trade, abnormal fees).
- 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
| Metric | Can be faked? | Reliability |
|---|---|---|
| Volume | ✅ Yes (wash trading) | Low |
| Transaction count | ✅ Yes (spam txs) | Low |
| Fees paid | ❌ No (costs real money) | High |
| Unique traders | Partially (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.