FlareWatch 為每個 P-Chain 驗證者指派一個 0–100 的綜合評分,跨越 9 個維度。演算法是確定性的,輸入來自公開鏈上資料 [Flare Explorer] [FSE] [Flaremetrics],相同的演算法適用於網路上的每個驗證者——包括 FlareWatch 自己的驗證者節點,其評分遵循此精確函數,無特殊待遇。本頁記錄每個維度和閾值,使操作者和質押者可以準確看到評分如何計算,以及為什麼選擇每個值。此處的每項聲明都連結回其主要鏈上或上游來源——參見底部的 來源和參考資料。
質押模式中顯示的內容(將 FLR 委託給 P-Chain 驗證者以獲得 VRM + MIRROR 獎勵)。委託模式中顯示的FTSO 提供者評分(將 WFLR 委託給 FTSO 資料提供者)使用獨立的 13 維演算法,專注於資料提供者表現——準確度、V2 協議參與度等。它們是不同的鏈上角色,具有不同的獎勵,分別評分。詳見FTSO 提供者評分方法論以了解委託方面。質押表中的 APY 是委託人獲得的全額報酬率——一個數字,無需心算。它是從 Flare 的獎勵腳本測量而來(實際支付額,而非公式),已扣除驗證者費用,並在每個紀元隨實際獎勵變動。在整個 FlareWatch 中,APY 表示扣費後的,APY 也表示扣費前的。
與 Flare Systems Explorer 比較? FSE 和其他瀏覽器只顯示 委託利率 — 它們不添加 MIRROR — 所以我們的總 APY 在任何 MIRROR 活躍的驗證人上讀取更高(差額恰好是上方的 MIRROR 行)。兩個數字都是來自相同獎勵腳本數據的約 8 個紀元尾隨平均值,所以驗證人的中窗口手續費變更直到它經歷窗口期間前在任一網站上都會滯後於當前手續費快照。
另外兩個數字出現在 APY 提示中,不是委託人的利率:理論基線(網路總 APY × (1 − 手續費),僅質押 — 在存在足夠的測量歷史之前用作備選)和運營商的 自我債券收益率(驗證人 自己的質押回報,由手續費捕獲放大 — 運營商指標,不是你獲得的)。
對於評分:淨收益維度只評分 VRM 委託利率,MIRROR 在其自己的維度中評分 — 所以 MIRROR 永遠不會被雙重計算,儘管它包含在顯示的總 APY 中。
| 90+ | 頂級——排名前約 10–20% 的操作者。典型檔案:完整堆疊驗證者 + FTSO + FDC、低端費用、MIRROR 活躍、一致的 FIP-10 可靠性、健康的委託者基數、有意義的自有質押。無需單一維度——操作者透過跨大多數類別堆疊強度達到頂級。 |
| 80–89 | 強——符合大多數關鍵基準;一或兩個維度與頂級相差。 |
| 70–79 | 優秀——符合所有基線標準;無主要差距。 |
| 60–69 | 可接受——可用但未區別。 |
| <60 | 低於中位數——在一個或多個維度上有重大差距。數學事實,不是品質判斷。 |
if (uptime >= 99.5) raw = 17 + (uptime - 99.5) * 6
else if (uptime >= 99) raw = 13 + (uptime - 99) * 8
else if (uptime >= 95) raw = 4 + (uptime - 95) * 2.25 // v3.9: was (u - 95) * 3.25 starting at 0
else raw = max(0, uptime - 90) * 0.8 // 90 → 0, 95 → 4 (continuity)
raw = clamp(raw, 0, 20)
reliability = epochsIncluded / epochsObserved // last ~8 epochs · v4.2: the
// FULL FIP-10 minimums set
// (uptime + FSP + FTSO + FDC),
// not RPC-uptime alone
score = raw * clamp(reliability, 0, 1) // dimension max 20scoreAPR = delegationAPY > 0 ? delegationAPY : baseAPR // VRM, net of fee medianAPR = median(scoreAPR across all validators) cappedAPR = min(scoreAPR, 25) // APY_DISPLAY_CAP if (medianAPR > 0): ratio = cappedAPR / medianAPR score = clamp(((ratio - 0.6) / 0.6) * 18, 0, 18) else: score = min(18, (cappedAPR / 8) * 18) // fallback: BASE_APY = 8
// anchor = max(observed minimum active fee, 20% protocol floor) d = fee - anchor // distance above market best if (d <= 0) score = 7 // at/below best available else if (d <= 5) score = 7 - d * 0.2 // 0 → 5 over: 7 → 6 else if (d <= 10) score = 6 - (d - 5) * 0.3 // 5 → 10 over: 6 → 4.5 else if (d <= 15) score = 4.5 - (d - 10) * 0.4 // 10 → 15 over: 4.5 → 2.5 else if (d <= 20) score = 2.5 - (d - 15) * 0.5 // 15 → 20 over: 2.5 → 0 else score = 0 // fees > anchor+20 saturate at 0/7 — the v4.5 extreme-fee // penalty below takes over from there
// Verification baseline (v3.10 hybrid) isCurated = (in KNOWN_VALIDATORS) OR ( daysObserved >= 90 AND operatorDelegatorCount >= 25 AND retention30d >= -15% AND selfBondFLR >= 1_000_000 ) if (isCurated) verification = 7 else if (name auto-discovered) verification = 3 else verification = 0 // FTSO-derived (only when ftsoOperatorScore is a number) clamped = clamp(ftsoOperatorScore, 50, 100) ftsoDerived = 4 + (clamped - 50) * (8/50) // FTSO 50 → 4, FTSO 100 → 12 // Final score score = max(verification, ftsoDerived)
passthrough = max(0, 1 - fee / 100) if (mirrorStatus == "active") base = 10 * passthrough else if (mirrorStatus == "paused") base = 5 * passthrough else if (mirrorStatus == "inactive") base = 0 else base = 5 * passthrough // no data yet // v4.6 — capped, median-anchored bonus for delivered MIRROR yield. // Only mirror-active validators paying ABOVE 1.2x the network median // delivered rate (mirrorAPY, net of fee) earn it; size-neutral. ratio = mirrorAPY / networkMedianMirrorAPY bonus = clamp((ratio - 1.2) * 5, 0, 2) // active only, else 0 score = base + bonus // dimension max 12
utilization = clamp(1 - freeSpaceFLR / maxDelegationFLR, 0, 1) if (utilization <= 0.70): score = 1.75 + (utilization / 0.70) * 5.25 // 1.75 → 7 ramp else: score = 7 - ((utilization - 0.70) / 0.30) * 1.75 // 7 → 5.25 ramp
// Count signal (max 6)
if (delegatorCount <= 5) countScore = 0
else if (delegatorCount >= 500) countScore = 6
else countScore = clamp(log(delegatorCount / 5) / log(100) * 6, 0, 6)
// Concentration adjustment (-1 to +1) — skip if <3 delegators
avgFLR = delegatedFLR / delegatorCount
if (avgFLR < 500_000) concentrationAdj = +1
else if (avgFLR < 5_000_000) concentrationAdj = +0.5
else if (avgFLR > 50_000_000) concentrationAdj = -1
else if (avgFLR > 20_000_000) concentrationAdj = -0.5
else concentrationAdj = 0
// Longevity bonus (0 to +1)
daysObserved = (now - firstObservedAtMs) / 86400000
if (daysObserved >= 90) longevityBonus = +1
else if (daysObserved >= 30) longevityBonus = +0.5
else longevityBonus = 0
// Self-bond alignment (-1 to +2, two-axis since v4.7)
if (selfBondFLR < 1_000_000) selfBondAdj = -1 // hollow-operator floor
else:
ratio = selfBondFLR / totalStake // totalStake = selfBond + delegated
proportional = ratio >= 0.10 ? +2 : ratio >= 0.05 ? +1 : 0
absolute = min(1, selfBondFLR / 20_000_000) * 2 // saturates at top-decile bond
selfBondAdj = max(proportional, absolute) // the better of the two axes
// Retention (-0.5 to +0.5, v3.7) — skip if no 30-day baseline yet
delta = (delegatedFLR - delegatedFLR30dAgo) / delegatedFLR30dAgo
if (delta >= +0.10) retentionAdj = +0.5
else if (delta <= -0.15) retentionAdj = -0.5
else retentionAdj = 0
// Self-bond trajectory (-0.5 to +0.5, v3.7) — skip if no baseline
sbDelta = (selfBondFLR - selfBondFLR30dAgo) / selfBondFLR30dAgo
if (sbDelta >= +0.20) selfBondTrajectoryAdj = +0.5
else if (sbDelta <= -0.10) selfBondTrajectoryAdj = -0.5
else selfBondTrajectoryAdj = 0
score = clamp(countScore + concentrationAdj + longevityBonus + selfBondAdj
+ retentionAdj + selfBondTrajectoryAdj, 0, 11)// Time-weighted rate is computed upstream from per-epoch // reward-scripts data with decay = 0.85 per epoch back. r = deliveryRatio // capped at 1.0 if (r >= 1.00) base = 10 else if (r >= 0.97) base = 9 + (r - 0.97) * (1 / 0.03) // 0.97 → 9, 1.00 → 10 else if (r >= 0.95) base = 8 + (r - 0.95) * (1 / 0.02) // 0.95 → 8, 0.97 → 9 else if (r >= 0.90) base = 6 + (r - 0.90) * (2 / 0.05) // 0.90 → 6, 0.95 → 8 else if (r >= 0.85) base = 4 + (r - 0.85) * (2 / 0.05) // 0.85 → 4, 0.90 → 6 else if (r >= 0.80) base = 2 + (r - 0.80) * (2 / 0.05) // 0.80 → 2, 0.85 → 4 else base = max(0, r * 2.5) // 0 → 0, 0.80 → 2 // Variance penalty (CoV = std-dev / mean across per-epoch rates) variancePenalty = min(0.30, coefficientOfVariation * 0.5) score = base * (1 - variancePenalty) // Sample-size confidence dampener for < 3 epochs if (totalStakesCompleted < 3): confidence = totalStakesCompleted / 3 score = 5 + (score - 5) * confidence
daysLeft = (endTimeMs - now) / 86_400_000 if (daysLeft < 14) score = 0 else if (daysLeft < 30) score = 0 + (daysLeft - 14) * (2 / 16) // 14 → 0, 30 → 2 else if (daysLeft < 60) score = 2 + (daysLeft - 30) * (1 / 30) // 30 → 2, 60 → 3 else if (daysLeft < 120) score = 3 + (daysLeft - 60) * (2 / 60) // 60 → 3, 120 → 5 else score = 5
consecutiveMisses = 0 for entry in participation.recent (newest-first): if entry.eligible: break consecutiveMisses++ if consecutiveMisses < 2: penalty = 0 elif consecutiveMisses == 2: penalty = 3 elif consecutiveMisses == 3: penalty = 6 else: penalty = 10 // 4+ score = max(0, positiveDimensionsSum - penalty)
// v4.5 — fees beyond the Fee dimension's range (anchor+20)
if fee <= 50: penalty = 0
else: fraction = min(1, (fee - 50) / 50) * 0.75
penalty = positiveDimensionsSum * fraction
// fee 50% → no change · 75% → −37.5% of score · 100% → −75%
score = max(0, positiveDimensionsSum - outagePenalty - penalty)delegationFee、selfBond、delegatedStake 和 FTSO 得分(如果您也是數據提供者)。generated-files/reward-epoch-N/nodes-data.json。計算您的 nodeID 有多少個週期的 uptimeEligible: true。該比率驅動您的正常運行時間維度乘數。RewardClaimed 事件(其中 claimType=3 引用您的 nodeID)。如果最近沒有,您將顯示為 MIRROR 非活動。GET /api/validators/{nodeID}/score-breakdown 以檢索持久化細分——每個維度的值、生成它的算法版本和最近的得分歷史——如 JSON。UI 中的得分細分面板從相同來源讀取。// Step 1 — Raw composite (sum of dimensions, minus the two penalties)
positive = uptime + netYield + fee + operatorQuality
+ mirror + capacity + trust + delivery + timeRemaining
// Penalties (see the two penalty cards above):
// v4.3 active-outage streak — 0-1 missed epochs → 0, 2 → 3, 3 → 6, 4+ → 10
// v4.5 extreme fee (>50%) — positive × min(1, (fee - 50) / 50) × 0.75
raw = clamp(positive - streakPenalty - extremeFeePenalty, 0, 100)
// Step 2 — Smooth across recent cron snapshots (v3.5)
// Weights: current 0.5, prev1 0.3, prev2 0.15, prev3 0.05
smoothed = 0.5*raw + 0.3*prev1 + 0.15*prev2 + 0.05*prev3
// Step 3 — Apply sudden-change penalty if flagged this run
// Triggers: fee +50% or +5pt jump, self-bond -20% drop, uptime -5% crash
// Magnitude: -10 pts on detection, decays -7, -4, -1 over 3 runs
suddenPenalty = -10 if any flag triggered else (decaying remainder)
// Step 4 — Final score
score = clamp(smoothed + suddenPenalty, 0, 100)services/validators/scoring.ts 中實現。想要直接檢查實現代碼(而不是閱讀上面的散文和公式)或想為自己的用途分叉該代碼的運營商或研究人員可以發送電子郵件至 [email protected] 請求訪問權限。如果有真實需求,我們將發佈該文件作為獨立的開源程序包。/api/cron/refresh-validators 的 cron 每 5 分鐘重新計算每個活躍驗證者的分數。輸入(P-Chain RPC 讀取、Flaremetrics、FSE、reward-scripts)在每次運行時都會重新獲取。Flare 不會削減驗證者質押。驗證者不當行為的整個懲罰機制是獎勵沒收加上 FIP-10 通行證系統。沒有雙簽削減、沒有歧義削減、沒有我們需要追蹤的質押銷毀事件。未能達到 FIP-10 最低條件的驗證者會失去該 epoch 的獎勵(如果通行證為零則完全沒收,否則每個他們未能達到的協議失去一個通行證);他們的質押本金保持不變。
這意味著分數沒有「削減歷史」維度——沒有這樣的歷史要追蹤。我們確實追蹤的是每次最低失敗的後果:驗證者在該 epoch 獲得零收益,這被捕捉在 epochsIncluded / epochsObserved 中。2026-05-14 的 v4.2 更新擴大了分數的可靠性乘數,以使用該比率跨越完整 FIP-10 最低集合(正常運行時間、FSP 簽署、FTSO 提交率、FDC 參與),因此驗證者未能達到任何最低要求在正常運行時間維度上按比例受罰,無論哪個軸失敗。
FIP-10 最低閾值,來自 dev.flare.network/network/fsp/rewarding:質押需要 80% 的正常運行時間 + 100 萬 FLR 活躍自我質押;FTSO 錨定源需要估計值在共識中位數的 0.5% 以內(80% 的輪次);FTSO 區塊延遲源需要提交 80% 的預期更新;FDC 需要參與 60% 的投票輪次。滿足 80% 正常運行時間 + 100 萬自我質押底線但低於 300 萬 / 1500 萬收益閾值的驗證者仍會收到獎勵,但無法累積通行證——灰色地帶通過此卡的 passEligibility: "at-risk" 分類表面。