Last month I almost aped into a Solana token showing $2M in daily volume. Everything looked legit active chart, thousands of transactions, growing holder count.
Then I looked at the fees. The token had generated $12 in total platform fees on $2M of volume. That's a 0.0006% fee ratio. On a real market, that number should be somewhere between 0.5% and 2%.
It was a wash traded token. The "volume" was bots trading back and forth with themselves. I would have lost everything.
That's when I started building a market legitimacy scanner powered by fee data. Here's how it works and how you can build one too.
Why Fees Can't Be Faked
Every DEX trade has three cost components that most platforms hide from you:
| 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 |
Here's the key insight: on a $2,500 trade, the platform fee ($25) is 90% of your total cost but most interfaces only show you the gas fee.
More importantly: real traders pay real fees. Wash traders don't. They control the entire flow, often trading through direct DEX contracts to avoid platform fees entirely. This asymmetry is your detection signal.
According to Chainalysis's 2025 report, over 42% of tokens launched in 2024 were listed on a DEX, and wash trading remains one of the most prevalent forms of manipulation. Solidus Labs found that self-trading on DEX pools is far more common than expected.
The Detection Logic
The math is simple:
Fee-to-Volume Ratio = (Fees Paid 24h / Volume 24h) × 100
Here's what the ratio tells you:
| Ratio | Signal |
|---|---|
| 0.5% - 2.5% | ✅ Healthy, organic trading |
| 0.1% - 0.5% | ⚠️ Investigate further |
| < 0.1% with high volume | 🚨 Very likely wash traded |
| 0% with any volume | 🚨 Probable honeypot or scam |
| > 5% | ⚠️ Unusual fee structure |
A token with $500K daily volume but only $50 in fees? That's a 0.01% ratio. Something is very wrong.
Fetching Fee Data with Mobula API
Most crypto APIs only give you volume and price. Mobula exposes the full fee breakdown — gas, platform, and MEV — per trade and aggregated per token.
Get token-level fee stats
curl -X GET "https://api.mobula.io/api/2/token/details?blockchain=solana&address=TOKEN_ADDRESS" \
-H "Authorization: YOUR_API_KEY"
The response includes fee metrics across multiple timeframes:
{
"data": {
"symbol": "EXAMPLE",
"totalFeesPaidUSD": 125000.50,
"feesPaid24hUSD": 4450.00,
"feesPaid1hUSD": 185.00,
"feesPaid5minUSD": 15.50,
"volume24hUSD": 890000.00
}
}
Get individual trade fee breakdown
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 and MEV-related cost
Building the Scanner
Here's a TypeScript scanner that analyzes any token and flags 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<FeeAnalysis> {
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 < 0.1 && volume > 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`,
};
}
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();
Output looks like this:
✅ 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
Real-Time Monitoring with WebSocket
For live alerting, connect to 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.baseTokenAmountUSD) * 100;
// Alert on suspicious zero-fee large trades
if (feePercent < 0.01 && trade.baseTokenAmountUSD > 1000) {
console.log(`🚨 SUSPICIOUS: $${trade.baseTokenAmountUSD} trade with $${trade.totalFeesUSD} fees`);
}
};
Why This Matters
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.



Top comments (0)