FlareWatch weist jedem FTSO-Datenprovider einen Composite-Score von 0–100 über 12 bewertete Dimensionen zu. Die Mathematik ist deterministisch, die Eingaben sind öffentliche On-Chain- und Flare-Ökosystem-Daten.[Flaremetrics] [FSE] [Flare Explorer], und der gleiche Algorithmus wird auf jeden Provider angewendet — einschließlich FlareWatch's eigenem FTSO-Provider, der durch diese genaue Funktion ohne Spezialbehandlung bewertet wird. Diese Seite dokumentiert jede Dimension und Schwelle, sodass Delegatoren und Operatoren genau sehen können, wie der Score berechnet wird und warum jeder Wert gewählt wurde. Jeder Anspruch hier verlinkt zurück zu seiner primären Upstream-Quelle — siehe Quellen und Referenzen am unteren Ende.
Delegierungsmodus auf der Validatoren-Seite sehen (Delegierung von WFLR an FTSO-Datenprovider für den FTSO-Inflationsanteil). Die Validator-Bewertung, die im Staking-Modus angezeigt wird (Delegierung von FLR an einen P-Chain-Validator für VRM + MIRROR Rewards), verwendet einen separaten 9-Dimensions-Algorithmus, der sich auf Validator-Betrieb konzentriert — Verfügbarkeit, Gebühren, Zuverlässigkeit usw. Sie sind unterschiedliche On-Chain-Rollen mit unterschiedlichen Rewards und werden separat bewertet. Siehe Validator Score Methodology für die Staking-Seite.| 90+ | Oberste Stufe — obere ~10–20% der FTSO Provider. Typisches Profil: überdurchschnittliche Reward-Rate, hohe Genauigkeit, vollständige V2-Protokollteilnahme (FTSO Scaling + Fast Updates + FDC), niedrige/keine Gebühr, große Delegierer-Basis, MIRROR-zahlende Validator-Knoten, etablierte Marke. Keine einzelne Dimension erforderlich — Provider erreichen die oberste Stufe, indem sie Stärke über die meisten Kategorien verteilen. |
| 80–89 | Stark — erfüllt die meisten Schlüsselbenchmarks; eine oder zwei Dimensionen unter der obersten Stufe. |
| 70–79 | Gut — erfüllt alle Basis-Kriterien; keine großen Lücken. |
| 60–69 | Akzeptabel — brauchbar, aber nicht differenziert. |
| <60 | Unter Mittelwert — erhebliche Lücken in einer oder mehreren Dimensionen. Mathematische Tatsache, keine Qualitätsbewertung. |
if (rate <= 0 || medianRate <= 0): score = 0 else: ratio = rate / medianRate score = min(25, round(ratio * 12.5 * 10) / 10) // 1 decimal place // Anomaly detection: providers > 3× the median are capped at // median × 3 for scoring purposes (prevents data outliers from // distorting the linear curve).
if (fseAccuracySecondary > 0): pct = fseAccuracySecondary / 100 if (pct >= 97) score = 25 elif (pct >= 95) score = 18 + (pct - 95) * 3.5 // 95 → 18, 97 → 25 elif (pct >= 93) score = 16 + (pct - 93) * 1 // 93 → 16, 95 → 18 elif (pct >= 90) score = 13 + (pct - 90) * 1 // 90 → 13, 93 → 16 elif (pct >= 85) score = 10 + (pct - 85) * 0.6 // 85 → 10, 90 → 13 elif (pct >= 80) score = 6 + (pct - 80) * 0.8 // 80 → 6, 85 → 10 else score = max(0, 2 + (pct - 70) * 0.4) elif (fseAccuracyPrimary > 0): // Primary fallback: similar piecewise linear curve. else: score = WEIGHT_ACCURACY / 2 // Neutral — no FSE data
earned = last 12 epochs where rewardRate > 0, keyed by epochId pairs = [earned[i-1], earned[i]] where epochId[i] - epochId[i-1] == 1 if (pairs.length < 3) return 10 // Neutral — too few consecutive pairs // DOWNSIDE volatility only: rises never hurt, so a stable or RISING // rate scores near full and a recovery lifts the score. Only drops // between CONSECUTIVE epochs count, in proportion to depth (RMS), // weighted toward recent pairs so an active recovery pulls the score up. drops[i] = max(0, (prev - cur) / prev) // rise -> 0 w[i] = 0.8 ^ (age of pair) // newest pair = highest cv = sqrt( sum(w[i] * drops[i]^2) / sum(w[i]) ) score = max(0, round((1 - min(1, cv * 6)) * 20 * 10) / 10)
if (!isActive) score = 0 // see "Active" below
else:
score = 3 // active baseline
if (hasSubmitAddress AND hasSigningPolicyAddress AND voterRegistered):
score += 4 // V1 registered
if (fseFtsoScaling) score += 8/3 // ~2.67 each
if (fseFastUpdates) score += 8/3
if (fseFdc) score += 8/3
score = min(15, round(score * 10) / 10)anchor = max(lowest active fee observed, protocol fee floor) // FIP-16 sets a 20% minimum entity fee. All 98 providers charge // exactly 20%, so the anchor is 20% and nobody is docked for // charging the only fee the protocol permits. Same curve and // same anchor the validator page's Fee dimension uses. if (!isActive) score = 0 d = fee - anchor // distance ABOVE the best real offer if (d <= 0) score = 15 // at or below the anchor → full marks elif (d <= 5) score = 15 - d * 0.43 elif (d <= 10) score = 12.9 - (d - 5) * 0.64 elif (d <= 15) score = 9.6 - (d - 10) * 0.86 elif (d <= 20) score = 5.4 - (d - 15) * 1.07 else: score = 0 // extractive
if (no fseNodeIDs) score = 0 if (mirrorStatsMap empty) score = 12 / 2 = 6 // Neutral seed before data lands activeCount = nodes_with_status_active fraction = activeCount / fseNodeIDs.length base = 12 * fraction // Overperformance bonus per node, applied only when ALL gates pass: // - >= 30 days observed since first reading (firstObservedAtMs) // - >= 3 paid stake observations // - finite medianOverpaymentRatio // Bayesian shrinkage with prior k=5 toward 1.0 (neutral): // shrunken = (observedRatio * N + 1.0 * 5) / (N + 5) // Bucketed bonus from shrunken: // < 1.05 → 0 < 1.15 → 1 < 1.30 → 2 >= 1.30 → 3 avgBonus = sum_per_node(bonus) / fseNodeIDs.length score = round((base + avgBonus) * 10) / 10
if (count <= 5) score = 0 elif (count >= 500) score = 12 else: ratio = log(count / 5) / log(100) // maps [5, 500] → [0, 1] score = round(min(12, max(0, ratio * 12)) * 10) / 10
if (fseActive) score = 10 elif (rewardRate > 0) score = 7 else score = 0
change = abs(votePowerDailyChangePct * 100) if (change < 1) score = 10 elif (change < 3) score = 10 - (change - 1) * 1.5 // 1 → 10, 3 → 7 elif (change < 5) score = 7 - (change - 3) * 1.5 // 3 → 7, 5 → 4 elif (change < 10) score = 4 - (change - 5) * 0.4 // 5 → 4, 10 → 2 else score = max(0, 2 - (change - 10) * 0.1)
if (no fspData OR totalEpochs <= 0) score = 5 // active window = epochs from the provider's first paid epoch to now missed = (active-window epochs) - (epochs the provider was paid) score = max(0, 10 - missed * 3)
if (no name) score = 0 elif (name starts with 0x or matches hex regex) score = 0 elif (name.length < 4) score = 4 else score = 8
ownBond = operator's own P-Chain node bond (FLR) total = ownBond + delegated WFLR vote power alignment = piecewise-linear ratio curve (0% → 0 … ≥10% → 7) absolute = min(7, ownBond / 5,000,000 * 7) // saturates at 5M FLR score = max(alignment, absolute)
fspRewardRate, delegationFeePercentage, wNatWeight und votePowerDailyChangePct.providersuccessrate.secondary für Genauigkeit, plus die entityminimalconditionslatest.ftso_scaling / ftso_fast_updates / fdc Flaggen für V2-Status.RewardClaimed Events mit claimType=3, die Ihre nodeIDs referenzieren. Wenn es keine neueren für irgendwelche Ihrer Knoten gibt, werden Sie auf dem Score als MIRROR-inaktiv angezeigt.// Step 1 — Raw composite (sum of 12 dimensions, max 172)
raw = rewardRate + accuracy + consistency + v2 + fee + mirror
+ delegators + participation + stability + compliance
+ identity + selfBond
// An UNMEASURED reward rate is not a FAILED one. When a provider is
// demonstrably distributing but we hold no rate figure for it, the
// Reward Rate weight leaves the DENOMINATOR rather than scoring 0
// against it — we score what we measured, over what we could measure.
maxRaw = (rewardRate figure missing AND isActive) ? 172 - 25 : 172
normalized = round((raw / maxRaw) * 100)
// (The separate vote-power dilution penalty was REMOVED in v4.9. It
// double-counted: an over-cap provider already earns a below-median
// realized reward rate, so the median-anchored Reward Rate dimension
// docks it for dilution once. Cap proximity is now a neutral DISPLAY
// signal on every provider, not a second deduction in the score.)
// Step 2 — Dynamic weight redistribution
// Across the active provider set, dimensions where everyone clusters
// (stddev < 1.0) become non-discriminating. Their weight gets
// redistributed evenly across dimensions where the spread is wider
// (stddev >= 1.0). The redistribution recomputes the score:
//
// for each dim d:
// multiplier[d] = 1.0 if stddev[d] < 1.0
// = (weight[d] + bonus) / weight[d] otherwise
// bonus = sum(weights of low-stddev dims) / count(high-stddev dims)
//
// adjusted_raw = sum(breakdown[d] * multiplier[d])
// adjusted_max = sum(weight[d] * multiplier[d])
// final = round((adjusted_raw / adjusted_max) * 100)
// Step 3 — Final score (capped at 100)
score = min(100, final)services/ftso/scoring.ts in der FlareWatch-Codebasis implementiert. Operatoren oder Forscher, die die Implementierung direkt inspizieren möchten (anstatt die obige Prosa und Formeln zu lesen) – oder die sie für ihre eigene Nutzung forken möchten – können eine E-Mail an [email protected] senden, um Zugriff anzufordern. Wir werden die Datei als eigenständiges Open-Source-Paket veröffentlichen, wenn es echte Nachfrage gibt./api/cron/refresh-validators, das den Score aller aktiven Provider alle 5 Minuten neu berechnet (derselbe Lauf, der P-Chain-Validatoren neu bewertet). Eingaben (Flaremetrics, FSE, FSP-Belohnungen, V2 RewardManager-Events) werden bei jedem Lauf frisch abgerufen.