How to Detect Sybil Wallets: A Developer Guide
Sybil attacks cost protocols millions. When one person creates hundreds of wallets to claim an airdrop multiple times, legitimate users get diluted and the token distribution fails its purpose. Here’s how to detect and filter sybils programmatically.
What Makes a Wallet a Sybil?
Sybil wallets share common patterns that distinguish them from organic users:
- Young age — created shortly before the airdrop snapshot
- Low activity diversity — few unique contracts, repetitive transaction patterns
- Minimal value — small balances, just enough to cover gas
- Single-chain — no cross-chain activity
- No DeFi history — no protocol interactions beyond basic transfers
- Clustered behavior — similar transaction timing and amounts across wallets
No single signal is conclusive, but combining multiple signals creates a reliable sybil score.
Detection Strategy
The most effective approach uses a scoring model with weighted signals:
Signal 1: Wallet Age
Real users have history. Sybil wallets are typically less than 90 days old at snapshot time.
import { WalletIQ } from "walletiq";
const wiq = new WalletIQ({ apiKey: "wiq_..." });
const profile = await wiq.getProfile(address);
// Flag: wallet younger than 90 days
const isYoung = profile.age.days < 90; Signal 2: Transaction Diversity
Legitimate users interact with many contracts. Sybils interact with one or two (the qualifying contracts for the airdrop).
// Flag: fewer than 5 unique contracts
const isLowDiversity = profile.stats.uniqueContractsInteracted < 5; Signal 3: Multi-Chain Activity
Real DeFi users operate across multiple chains. Sybils usually stick to one.
// Flag: active on only 1 chain
const isSingleChain = profile.chains.length === 1; Signal 4: DeFi Protocol Usage
Organic users have DeFi history — swaps, lending, staking. Sybils typically don’t.
// Flag: no DeFi protocol interactions
const noDeFi = profile.defi.protocols.length === 0; Signal 5: Risk Score
WalletIQ’s built-in risk score combines age, activity, diversity, and known patterns into a 0-100 score. Higher means riskier.
// Flag: risk score above 60
const isHighRisk = profile.risk.score > 60; Signal 6: Behavioral Labels
WalletIQ automatically labels wallets based on behavior patterns. Specific labels are strong sybil indicators:
// Flag: has sybil-associated labels
const sybilLabels = ["new-wallet", "repetitive-pattern"];
const hasSybilLabels = profile.labels.some(l => sybilLabels.includes(l)); Combining Signals
Weight each signal and sum them. A threshold determines eligibility:
function sybilScore(profile) {
let score = 0;
if (profile.age.days < 90) score += 25;
if (profile.stats.uniqueContractsInteracted < 5) score += 20;
if (profile.chains.length === 1) score += 15;
if (profile.defi.protocols.length === 0) score += 15;
if (profile.risk.score > 60) score += 15;
if (profile.labels.includes("repetitive-pattern")) score += 10;
return score; // 0-100, higher = more likely sybil
}
const score = sybilScore(profile);
const isSybil = score >= 50; // threshold Putting It Together
Here’s a complete filtering function that processes a list of addresses:
import { WalletIQ } from "walletiq";
const wiq = new WalletIQ({ apiKey: "wiq_..." });
async function filterSybils(addresses, threshold = 50) {
const results = [];
for (const address of addresses) {
const profile = await wiq.getProfile(address);
const score = sybilScore(profile);
results.push({
address,
score,
eligible: score < threshold,
labels: profile.labels,
age: profile.age.days,
});
}
return results.filter(r => r.eligible);
} Recommended Thresholds
| Threshold | Effect | Best for |
|---|---|---|
| 30 | Strict — filters aggressively | High-value airdrops (>$100/wallet) |
| 50 | Balanced — catches most sybils | Standard airdrops |
| 70 | Lenient — only catches obvious bots | Community-focused drops |
Tips
- Don’t rely on a single signal. Age alone catches legitimate new users. Combine at least 3 signals.
- Test your thresholds against known-good addresses before deploying.
- Use the playground to manually inspect edge cases: walletiq.dev/playground
- Cache profiles — WalletIQ caches for 5 minutes. Batch your lookups efficiently.
Ready to filter sybils from your airdrop? Get a free API key and start with 100 lookups/month.
Ready to integrate wallet intelligence?
Get Free API Key