sybil-detection について
Solana トークン市場の協調ウォレットや偽装された活動を分析するスキルです。資金源、同時取引、バンドル取引などを手掛かりに、Sybil クラスターや人為的な需要の兆候を検出します。
主な機能
- 01保有者ウォレットの資金源を追跡
- 02同時取引とバンドル買いを検出
- 03ウォッシュ取引と作成者との関連を分析
- 04Sybil リスク指標をスコア化
- 05クラスター検出・資金追跡スクリプト
活用シーン
- 01トークン保有者が関連ウォレットかを評価
- 02初期買いにバンドルや協調がないか確認
- 03取引量や保有者数の偽装を調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agiprolabs/ claude-trading-skills --skill sybil-detectionインストール後、Claude Code で/sybil-detectionを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/bundler_detection.mdclustering_methods.mdscripts/detect_sybils.pyfunding_tracer.py詳細
Sybil Detection — 協調されたウォレットと偽のアクティビティの分析
Solana のトークン市場における Sybil 攻撃では、単一の主体が多数のウォレットを操作し、自然なアクティビティを装います。このスキルでは、協調しているウォレットのクラスター、ウォッシュトレーディング、バンドルされたトランザクション、偽の保有者数の水増しを検出します。これは、トークンの指標が実際の需要を反映しているのか、人為的に作られたシグナルなのかを評価するうえで重要です。
Sybil 検出が重要な理由
Solana のトークン市場には、人為的に作られたシグナルがあふれています。
- 水増しされた保有者数:500 人の「保有者」が、実際にはそれぞれ 50 個のウォレットを持つ 10 の主体である
- 偽の取引量:自己管理ウォレット間のウォッシュトレーディングで需要を演出する
- 人為的なソーシャルプルーフ:多くのウォレットで少額ずつ保有し、広く分散しているように見せる
- ラグプルの準備:作成者が供給量を多数のウォレットに分散させ、その後、協調して売却する
- バンドルされたローンチ:PumpFun トークンで、作成者が最初のスロットで Jito バンドルを通じて購入する
保有者が 1,000 人いて、その 80%が 3 つのウォレットから資金提供されているトークンと、独立した資金源を持つ 1,000 人の保有者がいるトークンは、根本的に異なります。Sybil 検出によって、実際の需要と見せかけを区別できます。
検出カテゴリ
1. 資金提供元の分析
各保有者ウォレットを 1~2 ホップさかのぼり、SOL の送金元を特定します。
import httpx
def trace_funding_source(wallet: str, api_key: str, max_hops: int = 2) -> list[str]:
"""Trace SOL funding sources for a wallet via Helius parsed transactions."""
url = f"https://api.helius.xyz/v0/addresses/{wallet}/transactions"
resp = httpx.get(url, params={"api-key": api_key, "type": "TRANSFER", "limit": 50})
transfers = resp.json()
funders = []
for tx in transfers:
for transfer in tx.get("nativeTransfers", []):
if transfer["toUserAccount"] == wallet and transfer["amount"] > 0.001 * 1e9:
funders.append(transfer["fromUserAccount"])
return funders
主なシグナル:
- 3 つ以上の保有者ウォレットに同じ送金元から資金提供されている=クラスター
- トークン作成から 24 時間以内に資金提供されている=疑いが強い
- 資金提供額が同一(例:各ウォレットに 0.05 SOL)=自動化された分配
2. 同時取引パターン
ほぼ同時刻に同じトークンを購入するウォレットは、協調している可能性が高いです。
def detect_co_trades(buy_events: list[dict], slot_window: int = 3) -> list[list[str]]:
"""Group wallets that bought within the same slot window."""
buy_events.sort(key=lambda x: x["slot"])
clusters = []
current_cluster = [buy_events[0]]
for i in range(1, len(buy_events)):
if buy_events[i]["slot"] - current_cluster[0]["slot"] <= slot_window:
current_cluster.append(buy_events[i])
else:
if len(current_cluster) >= 3:
clusters.append([b["wallet"] for b in current_cluster])
current_cluster = [buy_events[i]]
if len(current_cluster) >= 3:
clusters.append([b["wallet"] for b in current_cluster])
return clusters
解釈:
- 同じスロット内の別々のトランザクション=協調(ボット主導)
- 同じトランザクション=バンドル(Sybil であることが確実)
- トークン作成後の最初の 3 スロット=ローンチスナイピングのクラスター
3. バンドルされたトランザクション
複数の購入を 1 つの Solana トランザクションまたは Jito バンドルにまとめたものです。
def check_bundle_ratio(early_buys: list[dict], bundle_window_slots: int = 5) -> dict:
"""Calculate the ratio of bundled vs independent early buys."""
bundled = [b for b in early_buys if b.get("is_bundled", False)]
first_slot = min(b["slot"] for b in early_buys) if early_buys else 0
early = [b for b in early_buys if b["slot"] - first_slot <= bundle_window_slots]
return {
"total_early_buys": len(early),
"bundled_buys": len(bundled),
"bundle_ratio": len(bundled) / max(len(early), 1),
"bundled_supply_pct": sum(b["amount"] for b in bundled) / max(sum(b["amount"] for b in early), 1),
}
PumpFun 固有のパターンと Jito バンドルの仕組みについては、references/bundler_detection.md を参照してください。
4. ウォッシュトレーディングの検出
同一の主体が複数のウォレットを通じて売買し、取引量を水増しします。
シグナル:
- ウォレット A がトークンを購入してウォレット B に転送し、ウォレット B が売却する――循環的な資金の流れ
- 複数のウォレットが互いに売買を繰り返し、ネットポジションに変化がない
- 資金提供元に関連があるウォレットのペアに取引量が集中している
def detect_wash_cycles(transfers: list[dict], holder_set: set[str]) -> list[tuple]:
"""Find circular transfer patterns among known holders."""
# Build directed graph of transfers between holders
edges: dict[tuple, float] = {}
for t in transfers:
if t["from"] in holder_set and t["to"] in holder_set:
key = (t["from"], t["to"])
edges[key] = edges.get(key, 0) + t["amount"]
# Find reciprocal pairs (A->B and B->A both exist)
wash_pairs = []
for (a, b), vol_ab in edges.items():
vol_ba = edges.get((b, a), 0)
if vol_ba > 0:
wash_pairs.append((a, b, vol_ab, vol_ba))
return wash_pairs
5. 作成者ネットワークの分析
トークン作成者が管理するウォレットを特定します。
- 作成者ウォレットの資金提供履歴から、作成者が資金提供した他のウォレットを特定できます
- それらのウォレットがトークン供給量を保有している=インサイダーによる分配
- 作成者が「別の」ウォレットから売却している=偽装された売り抜け
主な指標
| 指標 | 計算式 | 健全 | 要注意 | 重大 |
|---|---|---|---|---|
| 資金提供元が一意な割合 | unique_funders / total_holders | > 0.8 | 0.4-0.8 | < 0.4 |
| 資金提供クラスターの規模 | max(cluster_sizes) | < 5 | 5-20 | > 20 |
| 同時取引スコア | wallets_in_first_3_slots / total_holders | < 0.1 | 0.1-0.3 | > 0.3 |
| バンドル比率 | bundled_buys / total_early_buys | < 0.1 | 0.1-0.4 | > 0.4 |
| バンドルされた供給量の割合 | bundled_token_amount / total_supply_sold | < 5% | 5-20% | > 20% |
| 転送密度 | internal_transfers / total_transfers | < 0.1 | 0.1-0.3 | > 0.3 |
| ウォッシュトレードのペア数 | reciprocal_pairs / total_holder_pairs | 0 | 1-3 pairs | > 3 pairs |
複合リスクスコア
個々のシグナルを組み合わせ、単一の Sybil リスクスコア(0~100)を算出します。
def compute_sybil_score(metrics: dict) -> dict:
"""Compute composite sybil risk score from individual metrics."""
weights = {
"funding_cluster": 25, # Wallets from same funder
"co_trade": 20, # Coordinated buy timing
"bundle_ratio": 20, # Bundled early transactions
"unique_funder": 15, # Diversity of funding sources
"transfer_density": 10, # Internal transfers between holders
"wash_trade": 10, # Circular trading patterns
}
scores = {}
# Each sub-score normalized to 0-1, then weighted
scores["funding_cluster"] = min(metrics.get("max_cluster_size", 0) / 20, 1.0)
scores["co_trade"] = min(metrics.get("co_trade_pct", 0) / 0.3, 1.0)
scores["bundle_ratio"] = min(metrics.get("bundle_ratio", 0) / 0.5, 1.0)
scores["unique_funder"] = 1.0 - min(metrics.get("unique_funder_ratio", 1.0), 1.0)
scores["transfer_density"] = min(metrics.get("transfer_density", 0) / 0.3, 1.0)
scores["wash_trade"] = min(metrics.get("wash_pairs", 0) / 5, 1.0)
composite = sum(scores[k] * weights[k] for k in weights)
risk_level = "LOW" if composite < 30 else "MEDIUM" if composite < 60 else "HIGH"
return {"score": round(composite, 1), "risk_level": risk_level, "components": scores}
データソース
| ソース | 提供データ | 認証 |
|---|---|---|
| Helius のパース済みトランザクション | 資金提供履歴、転送の詳細、パース済み命令データ | API キー(無料枠:30 req/s) |
| SolanaTracker API | バンドル検出、保有者リスト、トークンメタデータ | API キー |
| Solana RPC (getSignaturesForAddress) | 任意のウォレットの生のトランザクション署名 | RPC URL |
| Solana RPC (getTokenLargestAccounts) | 残高上位の保有者 | RPC URL |
| DexScreener | クロスリファレンス用の基本的なトークン/ペアデータ | 不要 |
トークンを評価するワークフロー
# 1. Get top holders
holders = get_top_holders(token_mint, rpc_url)
# 2. Trace funding sources for each holder
funding_map = {}
for wallet in holders[:30]: # Top 30 is usually sufficient
funding_map[wallet] = trace_funding_source(wallet, helius_key)
# 3. Cluster by common funder
clusters = cluster_by_funder(funding_map)
# 4. Check co-trade timing
early_buys = get_early_buy_events(token_mint, helius_key)
co_trade_groups = detect_co_trades(early_buys)
# 5. Check for bundles
bundle_stats = check_bundle_ratio(early_buys)
# 6. Check wash trading
transfers = get_token_transfers(token_mint, helius_key)
wash_pairs = detect_wash_cycles(transfers, set(holders))
# 7. Compute composite score
metrics = {
"max_cluster_size": max(len(c) for c in clusters) if clusters else 0,
"co_trade_pct": sum(len(g) for g in co_trade_groups) / len(holders),
"bundle_ratio": bundle_stats["bundle_ratio"],
"unique_funder_ratio": len(set(f for fs in funding_map.values() for f in fs)) / len(holders),
"transfer_density": len(wash_pairs) / max(len(holders), 1),
"wash_pairs": len(wash_pairs),
}
result = compute_sybil_score(metrics)
print(f"Sybil Risk: {result['risk_level']} ({result['score']}/100)")
他のスキルとの連携
- token-holder-analysis:保有者リストを入力として使用します。シビル検出によりクラスターのコンテキストが加わります
- helius-api:パース済みトランザクション履歴の主要なデータソースです
- jito-bundles:バンドルの詳細な検出とMEVのコンテキストを提供します
- liquidity-analysis:シビルスコアと組み合わせます。流動性が低く、シビルスコアが高い場合は極めて高いリスクです
- whale-tracking:実際の大口保有者とシビルクラスターの集計を区別します
ファイル
| ファイル | 説明 |
|---|---|
references/clustering_methods.md | 資金源のクラスタリング、同時取引のタイミング分析、グラフベースの検出手法 |
references/bundler_detection.md | バンドルされたトランザクションの検出、PumpFunのパターン、Jitoのバンドルの仕組み |
scripts/detect_sybils.py | シビル検出の完全なパイプライン:保有者 -> 資金調達 -> クラスター -> リスクスコア |
scripts/funding_tracer.py | ウォレット群の資金源を追跡し、共通の祖先ごとにグループ化します |