A Standard for Solana Staking APY After Alpenglow
One validator, one day, with APY shown anywhere from 3.2% to 28.57%. The measurement is not the problem, the display rules are. And they are fixable.
Contents
Key findings
The same validator shows completely different yields on different sites. On a single day one validator ranged from 3.2% to 28.57% across three trackers, with no dashboard warning that the others disagreed.
This is not a measurement error, it is a display choice. The three trackers we compared compute the same underlying reward as we do; the spread comes entirely from how many past epochs each averages, how it averages them, how it handles outliers, and which reward streams it counts.
A single epoch is hard to read, and Alpenglow made it harder. Much of a validator's reward now depends on which blocks it is chosen to produce, and that luck varies epoch to epoch, most of all for smaller validators.
Averaging more past epochs does not fix it. The standard we propose forecasts a luck-free expected yield instead, and shows three numbers together: Expected APY, Paid APY, and Luck.
The forecast matches the best tracker, and catches validators that stopped or started paying. In testing, it is about as accurate as the best existing tracker for normally operating validators, while the usual multi-epoch averages still report stalled validators as earning or newly started ones as paying nothing.
This is an early, versioned proposal (v1). Only twelve post-Alpenglow outcome epochs exist so far. The forecast beat a faithful Stakewiz reconstruction in eleven of them, but in only eight once we look at normally operating validators alone. The results are encouraging, not yet proof.
A delegator picking a Solana validator today reads yield off a dashboard. If you open several trackers for the same validator on the same day, you will see that the numbers can disagree wildly, not by a rounding error but by multiples.
The natural assumption is that some projects are measuring it wrong. That assumption is wrong. For epoch 1068, three trackers showed an 8.9x spread on one validator, yet the realized reward behind each figure agreed with ours to within 0.005 pp (for Stakewiz, as rebuilt from its method). The whole spread comes from what each project does to that number, and adds to it, before putting it on screen.
This research takes the divergence apart, shows why a single epoch is genuinely hard to read after Alpenglow, and proposes a standard that forecasts a luck-free reward instead of averaging past ones. Every formula is public and every input is on chain, though rebuilding a closed epoch needs archival access and snapshots taken each epoch (section "Reproducing from public RPC"). The backtest behind it is our own measurement, and its limits are stated in full.
The spread: one validator, four numbers
We start with the scoreboard, so the problem is visible before any theory. On October 27, 2026, mainnet epoch 1069 in flight, three trackers showed the Cryptology validator (BfxZj7...) at four different yields, two of them on Trillium. Every truncated address here is given in full in the identifier table at the end of section "Reproducing from public RPC".
A second validator (FXcZJu..., Serhio911) shows a narrower spread: 4.1% on Compass, 4.31% on Stakewiz, and 3.80% and 4.22% on Trillium. These are established validators a delegator might choose, though neither was running cleanly: in epoch 1068, their vote participation was 91% and 67%, against a median of 99.5%.
The two Trillium figures at the top of the range, 25.57% and 28.57%, are explained by a one-time migration payout credited as epoch 1064's reward, a labelled special case that sections "Agreement on the reward, divergence in display" and "Why one epoch is hard to read" take apart. Even with those two set aside, the two remaining numbers still differ, 3.2% against 3.96%, for the same validator on the same day.
None of the four numbers above is flagged as wrong on the page that shows it. Each can be rebuilt from on-chain rewards, though for Stakewiz and Compass only if you apply a lump rule neither of them publishes. All four sit next to the same validator name and the same commission, and none carries a warning about the number. So a delegator reading any single dashboard has no signal that 3.2% and 28.57% describe the same validator on the same afternoon. That is what turns the spread from a curiosity into a problem: averaging yields from a few sites will not cancel it out, because each number is a defensible choice, and they pull in different directions. From here, we take apart the choices behind this gap, show why they diverge, and propose what to publish instead.
Agreement on the reward, divergence in display
The divergence is not a disagreement about what the validator earned. For epoch 1068, four independent derivations of the realized inflation reward line up almost exactly.
| Validator | JPool | Trillium | Compass | Stakewiz repro |
|---|---|---|---|---|
| CcaHc2... (Figment) | 4.653 | 4.649 | 4.65 | - |
| he1ius... (Helius) | 5.063 | 5.059 | 5.06 | - |
| 1234LB... (BlueLotus) | 4.275 | 4.272 | 4.27 | - |
| FXcZJu... (Serhio911) | 2.999 | 2.997 | 3.00 | 3.000 |
| BfxZj7... (Cryptology) | 2.341 | 2.339 | 2.34 | 2.342 |
They agree within 0.005 pp. The residual runs 0.002 to 0.004 pp and grows with the APY, exactly the signature of Trillium using a 365-day year where we and Stakewiz use 365.25 (Compass's two decimals cannot show the difference). So the payout is not where projects differ. They differ in four display choices applied to that same payout.
Window. A tracker can show the single closed epoch, an arithmetic mean of the last 5, a median of the last 10, or a recency-weighted blend. Compass takes a 5-epoch mean. Stakewiz takes a 10-epoch median. Trillium's calculator uses a recency-weighted average with roughly a 0.75 geometric decay; its dashboard opens on the latest epoch and offers that average in its epoch menu.
Aggregation. Even over the same window, a mean, a median, and a per-epoch compound give different answers once the series is volatile. Trillium's "compound" fields average per-epoch compounded values, which inflates a noisy series; its simple, non-compound fields do not.
Outlier rule. The Cryptology validator's epoch 1064 reward was a one-time deferred lump (a migration artifact, section "Deferred payouts, a one-time migration effect") that annualized to between 279% and 332% depending on the accounts sampled. Trillium keeps it raw, so it falls inside the recency-weighted window and drives most of the spread: the lump alone contributes about 23.4 of its 25.57% delegator figure. Stakewiz and Compass each remove it by a rule neither publishes. Stakewiz's described 10-epoch median would keep the lump and show 4.40%; the 3.96% it actually shows is epoch 1066 by itself. Zero-reward epochs are handled differently again: Trillium and Compass count them as zero, Stakewiz skips them, and Marinade drops a validator that missed a reward in its window.
Streams. Inflation only, inflation plus MEV, or inflation plus MEV plus block fees, each gross or net of commission. Trillium's APY Metrics view sorts by compound_overall_apy, which adds the operator's commission and the validator's entire block revenue, money a staker never receives. That lifts Cryptology from 25.57% to 28.57%, and almost all of those 3 points are commission on the same lump.
| Tracker | Window | Aggregation | Outlier rule | Streams |
|---|---|---|---|---|
| Compass | 5-epoch | Mean | Lump suppressed (undocumented) | Inflation only (headline) |
| Stakewiz | 10-epoch | Median | Lump removed by an undocumented rule; delinquent to 0 (observed, undocumented) | Inflation + Jito net of MEV commission |
| Trillium (recency-weighted) | Recency-weighted | Per-epoch compound | Nothing clipped; zeros averaged | Inflation + MEV + commission + all block revenue |
These settings are reconstructed, not read from every internal. Stakewiz's frontend is pinned at code level (its backend is closed and reconstructed); Trillium and Compass are partly inferred from their closed backends and reproduced against on-chain values. The point stands either way: identical measurement, four dials, an 8.9x spread (28.57 / 3.2).
Why one epoch is hard to read
If the measurement agrees, why not just show the single closed epoch and be done? Because a single epoch is a poor read. Three factors distort it, to different degrees and for different reasons, and a fourth zeroes it outright. They differ in how often they strike, how long they last, and how much they change the number. Each is something the standard's three numbers (section "The proposal: forecast, don't average") will later neutralize or expose, so it is worth seeing them in the raw first.
Leader luck, recurring and statistical
Under Alpenglow, a validator's inflation reward splits in two. The voter part is half of its stake's share of cluster inflation, earned every epoch at full vote participation. The leader part is paid per block the validator actually produces, and which blocks it produces is set by a stake-weighted draw before each epoch. A validator is entitled to a share of slots but draws a random number around it. The leader part equals the other half only when it draws exactly the slots its stake entitles it to. Draw fewer and it shrinks; draw more and it grows.
The reason the leader part floats while the voter part is steady is in how a single slot gets paid. The reward for slot s is paid only in block s+8. Every validator whose vote for s is included in that block earns B · stake / (432000 · total_stake). Half of that, rounded down, goes to the voter; the rest goes to whoever produced block s+8. The voter part tracks the voter's own stake. The leader part does not: each block a validator produces pays it about half a full slot's budget regardless of its own stake, and less if the block's vote aggregate is incomplete. If block s+8 is skipped, slot s pays no one.
Let k be the ratio of slots drawn to slots expected: k = 1 when a validator draws exactly what its stake entitles it to. Its inflation reward is then its stake share times (½ + ½·k). The leader schedule is fixed before each epoch as 108,000 independent stake-weighted draws of four-slot windows, so the relative spread of k is 2/√(expected slots) and narrows as stake grows. A validator expecting 50 slots (12.5 windows) typically draws 36 to 64, so k runs from about 0.7 to 1.3. At about 4,000 SOL, a validator expects one window an epoch and draws none in about 37% of them; at a few hundred SOL it draws none in most.
The realized data tracks this closely. At a 5% gross rate, the formula gives 2.5% when k = 0, 5% at k = 1, and 7.5% at k = 2: every 1.0 of k adds half the gross rate. Across validators above 50k SOL with at least 95% vote coverage in Trillium's data for epoch 1068 (n = 511), realized gross inflation APR correlates with k at 0.977, on a slope of 2.47 points per unit of k, as the formula predicts. The 213 SOL validator in section "Luck" shows the floor: 2.33% in epochs with no slot, half its expected 4.7%.
s carries B / 432000 of the epoch budget Bs+8, and if s+8 is skipped it pays no one s is in the s+8 aggregate earns r = ⌊B · stake / (432000 · total_stake)⌋⌊r/2⌋ to the voter, the rest to the leader of s+8B · aggregate_stake / (2 · 432000 · total_stake): half a slot's budget times the stake share in the aggregate, whatever its own stake. Stake flow, transient and one epoch long
A validator's reward for epoch E is sized on the stake that was effective in E minus 1, then split pro rata over the stake effective in E. The amount earned is fixed by the earlier stake; the per-SOL rate shown is that amount divided by the later stake. When stake leaves between those two points, the same reward is divided over a smaller base, so APY reads high for exactly one epoch. When stake arrives, the reward is divided over a larger base and APY reads low. This is the payout-basis lag. It is purely a timing artifact of the two bases: nothing about the validator's performance changed, and the distortion clears the next epoch once the two stake figures line up again. A tracker that divides by stake-in-E will show a sharp one-epoch move on any validator that had a large inflow or outflow across the boundary. One validator shows it cleanly. In epoch 1067, ERut3Cwq... drew close to its expected slots (1,524 against 1,448), yet its stake fell from 1.46M to 1.02M SOL across the boundary, so its stakers were paid 6.89% against 4.74% on the stake the reward was sized on, and 4.72% the next epoch. The mechanism is deterministic and one epoch long.
Deferred payouts, a one-time migration effect
From epoch 1006, a reward at each epoch boundary went only to vote accounts that passed the admission filter, which among other things needs a BLS key. Tower votes never needed one. So a validator without a key kept earning vote credits while its delegators received nothing and its stake accounts' creditsObserved stood still. Under Tower rules, that debt was not lost. Once the validator was admitted again, every credit newer than creditsObserved, up to 64 epochs back, was paid in one lump at the boundary's current rate. The last epoch paid even partly under Tower rules was the migration epoch, 1064. Of about 600 validators paid for it, at least 10 carried such a debt: at least 9 owed for epoch 1063 alone, and Cryptology for 59 epochs. Cryptology's lump annualized to between 279% in Trillium's sample and 332% on its longest-delegated stake accounts, depending on which accounts are sampled, while the epochs it actually covered had paid zero.
Even then the lump came to only about half of what those credits would have paid in their own epochs, for two reasons. Most of the credits were earned between epochs 1005 and 1051, when a longer nominal slot time made each credit worth about 1.6 times its 1063 value. And the whole debt was paid out of the Tower share of epoch 1064, its first 5,000 slots, which the debts had to split with ordinary rewards, cutting the rate to about 0.75 of 1063's.
This cannot happen again. Alpenglow has no catch-up: a validator that misses admission loses that epoch for good (see VAT, below). The boundary between epochs 1065 and 1066 confirmed it, paying readmitted validators for 1065 only, and across epochs 1065 to 1076 no validator's credits exceed the epoch maximum by more than 0.3%. It earned a place in this list only because of timing: epoch 1064 stayed inside a 10-epoch window through epoch 1073 and stays inside a 30-day window until about 1091, which is why it drove Trillium's 28.57% when we compared trackers on October 27, 2026.
VAT failure, rare and total
This factor does not blur an epoch. It zeroes it. At each epoch boundary, a vote account must burn 0.8 SOL (the value under the current 200 ms slot parameters) for a Validator Admission Ticket (VAT). The ticket burned at the boundary that opens an epoch admits it to the epoch after that one. Say a validator is refused at the boundary that opens epoch E: it has no BLS key, its balance is below rent plus the ticket, or it ranks outside the top 2000 by stake. Two rewards are then lost, one epoch apart. The inflation already earned for the epoch just ended, E minus 1, is paid only to admitted accounts, so it is forfeited: it is never minted, and since the account was refused, no ticket is burned either. And the admitted set also decides who may vote in E plus 1 and who leads in it, because the E plus 1 leader schedule is drawn from that same filtered set, so the validator neither votes nor produces a block in E plus 1 and earns nothing for it either. The validator keeps voting normally through E itself; what it loses is E minus 1 behind it and E plus 1 ahead of it.
Epoch 1068 shows this concretely. Four validators holding 3.96M SOL missed admission in epoch 1069 (their vote accounts are listed in the section "Reproducing from public RPC" identifier table), and 570 SOL of reward they had already earned for 1068 was forfeited: getInflationReward returns null for each of them for 1068, and our API reports 0. They kept voting normally through 1069; the second zero lands in 1070, the epoch their missed admission shuts them out of the vote set. Their 1069 reward reads null as well, but for a separate reason: they missed the next ticket too, and none of the four has been admitted since. There is nothing here to average away: a validator that misses admission once earns zero twice, for the epoch behind it and the epoch ahead.
Why averaging does not fix it
Most trackers apply the same fix: average the last few epochs instead of showing one. A mean or median over 5 or 10 epochs does damp the epoch-to-epoch bounce of leader luck. But it cannot remove it, because it is still a backward-looking average of realized APYs, and realized APY is the very thing luck distorts. The average reports what a validator happened to earn, blended across epochs; it does not say what the validator will earn next. Every factor from the last section is still buried in it, a VAT zero, a deferred lump, a lucky or unlucky draw, just spread thin instead of concentrated in one epoch.
Under Alpenglow, a median is not just weak but actively wrong for the validators it is meant to help. A median sorts the last several epochs by their yield and reports the middle value. For a validator whose leader slots arrive unevenly, most epochs are low, no-slot ones, so the middle value is a low epoch too. A validator with 200 SOL draws its four-slot window about once every 20 epochs. Across those epochs, it earns roughly the cluster APY on average, but in the single epoch it draws its window it earns about twenty times what it earns in a no-slot epoch, and in all the others about half. A 10-epoch median shows that half and calls it the yield. For a small validator a median is therefore worse than a plain mean, not better.
A shorter window does not help either. On TowerBFT data a fresh epoch beat a 10-epoch median (6.2 against 9.4 bps of mean absolute error), but almost entirely because the reward level was drifting down and the median kept averaging in older, higher epochs; adjust for that drift and the median nearly catches up, at 6.6. Under Alpenglow the luck-free level has held at 474 to 479 bps from epoch 1065 to 1076, so even that difference is gone. Neither the window length nor the averaging rule is the real problem: averaging realized APYs is the wrong tool, and the next section forecasts a luck-free reward instead.
The proposal: forecast, don't average
What the trackers share is that they all show past realized APYs, one epoch or an average of several. The standard we propose does something different: it forecasts the reward instead of averaging what was already paid. This is the core of the proposal, so we set it out as three steps.
- 1. Measure efficiency. In an epoch, a validator could have earned a certain maximum: a voter part from its stake, plus a leader part from the slots it drew. Efficiency is the share of that maximum it actually captured, by landing its votes and producing its blocks. Because the maximum is measured against the same slots it drew, a lucky or unlucky draw cancels out of the ratio, so efficiency is skill, not luck. It is read from the last closed epoch alone: in our backtest of the inflation reward, the luck-free estimate averaged over the last ten epochs predicted worse than the last epoch by itself (mean error 40.6 against 35.7 bps on the forecasts made at 1074 and 1075, the first whose ten-epoch history is all Alpenglow).
- 2. Read the two rates fresh. Inflation and commission must reflect the present, not an average of the past. Inflation comes from the last completed epoch, where it is effectively current. Commission is the rate that will actually apply: a change does not take effect for two epochs (the two-epoch commission delay), so it is not always the one set today.
- 3. Project forward on entitled slots. Carry the efficiency forward at those rates, but on the leader slots the validator's stake entitles it to, not the ones it happened to draw. That swap, entitled for drawn, is what removes luck from the number.
This division of labor is the point: the skill is measured on the slots the validator actually drew, while the rates are read fresh because each must be the one that applies next. A validator that draws twice its expected slots yet captures only part of that maximum is inefficient, even though its epoch looks lucky; one that draws half its slots but captures all of it is efficient, even though its epoch looks poor.
A large validator draws its leader slots almost exactly as entitled, so it has little luck to remove and the forecast should sit on top of the realized payout. Figment (vote account CcaHc2...) confirms it: projecting its roughly 99.98% efficiency forward lands within a few hundredths of a point of its realized 4.653% for epoch 1068 (the realized figure is the one in the section "Agreement on the reward, divergence in display" table), and its Luck reads close to zero.
This is a calibration check: when there is no luck to remove, the forecast matches what the validator actually earned, which is what lets us trust it when there is. The hard case is the small validator in section "Luck", which draws about 19 times its share of slots in one epoch and none the next, so its paid reward jumps around while its real earning power barely changes. There the forecast and the paid reward no longer agree, and removing luck is what reports the steady yield the raw number cannot.
Those three steps above produce one number, the Expected APY. Publish it beside two others, so the forecast is never shown alone.
- Expected APY removes leader luck analytically through the voter/leader split; where the split cannot be made, it carries the validator's last luck-free estimate forward with a flag, and shows no number if there is none. The zero-and-warning rule absorbs a VAT failure. This is the headline and the sort key.
- Paid APY is the realized reward over the last 30 days, compounded epoch by epoch and annualized once, counting a failed epoch as zero and counting a deferred lump only in the epoch when it is actually paid out.
- Luck compares the realized reward against the luck-free expectation for the same epochs, both divided by the stake the reward was sized on, so it shows the per-epoch draw instead of hiding it, and a stake inflow or outflow does not move it. On a deferred or VAT epoch the ratio moves too, and there it is flagging an artifact, not measuring luck.
| Factor | Expected APY | Paid APY |
|---|---|---|
| Leader luck | Removed (projected on entitled slots) | Kept (realized slots) |
| Stake flow | Sized on the stake the reward was earned on, so no shift | Kept (paid on the later stake) |
| Deferred 1064 lump | Not forecast | Counted only in 1064, flagged |
| VAT failure | 0, with a warning | 0 |
The three are of equal prominence, the version number is shown with them, and the formula is public. No mature Solana tracker publishes a luck-free expected yield in the headline today, though the idea exists elsewhere: Tezos (Baking Bad), Cardano's Daedalus wallet, and Ethereum's performance scores (beaconcha.in's BeaconScore, Rated's RAVER) all surface an expected or luck-neutral figure, and the retired Tezos indexer tzindex split income into fair, expected, and actual. So on Solana this is a new step, offered as a v1, proposed standard with its limits stated.
What is deliberately left out is stated too: incentives and block fees are not included in APY. Priority fees normally go to the validator, not to stakers, so they are left out as well; the one exception is the share a validator voluntarily distributes to stakers, which enters as a separate simple term. And there are no medians, no caps, and nothing annualized on a fixed two-day epoch: epoch length is measured, not assumed.
Expected APY
The headline number comes from the last closed epoch E, projected forward at today's parameters. It has two streams.
- The inflation stream is what the validator earned from the protocol, with its leader luck removed (the
g_inflgrowth below). - The MEV stream is the Jito tips and any priority fees it passes on (
g_mev).
Each is a one-epoch growth rate, net of commission, then grown to a full year: inflation compounds, MEV is added simply (section "Paid APY" explains why). The legend defines every symbol once.
| Symbol | Meaning |
|---|---|
R̂_E | Luck-free reward of epoch E, before commission |
R_E | Realized reward of E, before commission |
S_E | Epoch stake the reward was sized on (effective in E-1) |
c_next | Commission that will apply next (delay) |
c_mev | The validator's MEV commission |
τ_E | Cluster Jito tips per lamport of the stake of validators credited with tips in E |
f_jito | Jito TipRouter fee: 300 bps of the tips before the block builder's cut, charged as 309 bps of the tip distribution account (TDA) amount |
p_E, f_pf | Priority fees the validator distributed to its stakers per lamport, and the TipRouter's 150 bps fee on them |
L_E | Average leader reward per block: E's total reward before commission over twice the blocks the cluster produced |
T_E | Measured epoch duration in seconds (~92,500 s in epochs 1075 and 1076, ~341 epochs/yr) |
Y | One year in seconds, 31,557,600 (365.25 days) |
B_E | Epoch reward budget |
g_infl = (1 - c_next) * R̂_E / S_E
g_mev = τ_E * (1 - f_jito - c_mev) if E credited the validator with tips, else 0
+ p_E * (1 - f_pf) if it distributes priority fees
Expected APY = (1 + g_infl)^(Y / T_E) - 1 + g_mev * Y / T_E
The voter/leader split
R̂_E is the luck-free reward of E before commission, and it has two parts. The voter part is taken as earned. The leader part is rebuilt: instead of the slots the validator happened to draw, it is scaled to the slots its stake share entitles it to, at the reward per block and at the share of its own slots it produced (with no slot drawn, the cluster's share, scaled down by how much of the epoch it voted). That rebuild is where leader luck is dropped from the number.
The split is reconstructed from epoch totals rather than read block by block. The leader part is the average reward per block times the blocks the validator produced; the voter part is whatever remains, voter = R_E − blocks · L_E. Blocks are matched to the vote account through the identity its leader schedule was drawn with: the node key recorded with the epoch stakes, not the vote account's current identity. The schedule is fixed a boundary ahead, so after an identity change the slots stay under the old key for up to two epochs, and a match on the current key finds none.
When the split fails
The split can still fail two ways: two paid vote accounts share one identity, or the residual voter part lands outside the range its stake implies, from minus 0.25 to 1.5 times the voter half (an average-per-block figure that does not fit the validator's own blocks can push it there). When the split fails, Expected APY carries the validator's last luck-free estimate from the prior three epochs, flagged; with none to carry, it shows no number. It does not fall back to the realized reward, which keeps the very luck the split removes and has no bound. This is a limit of the totals-based estimate, not of the split itself: reading each block's real reward directly would remove the averaging case.
Identity changes cause most of the failures seen so far. Matched on the vote account's current identity, the split failed on 16 of 8,265 staked validator-epochs from 1065 to 1076, and 9 of those, holding nearly all of that stake, came with an identity change. The two largest, at 9.5M and 9.6M SOL, changed identity in epoch 1075; matched instead through the schedule identity for 1076, both split cleanly and removed 3.6 and 2.7 bps of luck in opposite directions, as expected at 9,500 slots.
The other 7 failures hold about 0.8M SOL-epochs. On five, the carried estimate missed by 19 bps on average against the realized reward's 29; on the other two the realized reward blew up (43% for the 213 SOL validator of section "Luck" in its one slot-drawing epoch, 353% for a validator paid on 0.1 SOL that then stopped). Few cases, but they point one way: a carried estimate has already passed the split's bounds, a realized reward has none.
apy_expected null and apy above 0.| Epoch | Validators | Their activated stake (SOL) |
|---|---|---|
| 1065, 1066 | 0 | 0 |
| 1067 | 1 | 213 |
| 1068 | 1 | 3,379,462 |
| 1069 | 1 | 3,373,259 |
| 1070 | 2 | 650,364 |
| 1071, 1072 | 0 | 0 |
| 1073 | 2 | 663,631 |
| 1074 | 3 | 101,644 |
| 1075 | 4 | 19,118,618 |
| 1076 | 2 | 18,996,912 |
Reading the terms
The mechanics live inside the terms. S_E is the epoch stake the reward was sized on, so inflows and outflows do not change it. c_next is the commission that will apply next, because a commission change in epoch X first applies to the rewards of X plus 2 (the two-epoch commission delay); using the commission shown today would give the wrong answer. τ_E is the cluster Jito tip rate per lamport of stake, measured on the tip distribution accounts. The block builder's cut (per leader, 3% today) is removed before the tips reach that account, and what is left carries two further charges taken from the same TDA amount: the TipRouter fee f_jito (309 bps of what reaches the TDA) and the validator's own MEV commission c_mev. They subtract rather than compound, so stakers keep τ_E · (1 − f_jito − c_mev). Pricing MEV at the stake-weighted cluster rate removes leader luck from tips the same way the split removes it from inflation.
Only validators credited with tips in E count, in the numerator and in the stake it is divided by. Under Alpenglow tips go to the leader, so a validator assigned at least 8 leader slots with no TDA for E, or a TDA that collected nothing, is credited nothing and its g_mev term is 0. A validator with fewer slots is judged by its own TDA: a missing one just reflects the slot draw, so its most recent TDA from the last 32 epochs stands, unless it has since led 8 or more slots without collecting a tip; with neither, it is credited nothing. Priority fees enter only when the validator distributes them through Jito's Priority Fee Distribution, counted at what reaches stake accounts after the TipRouter's 150 bps.
Both streams are then grown to a year, and the year is measured, not assumed. T_E is the epoch's actual duration, about 92,500 seconds in epochs 1075 and 1076 (91,800 in 1068), so a year holds about 341 epochs today, not the 365.24 the runtime budgets or the 182.5 that old 2-day-epoch assumptions imply. Y is that same year in seconds, 31,557,600 (365.25 days), so the exponent Y / T_E is a clean epochs-per-year ratio.
Zero, not smoothed
Failures are handled by setting the number to zero, not by smoothing. A validator known to be out of the vote set for the running or next epoch (VAT refused or not admitted) returns 0 and a warning. A 100%-commission validator earns its stakers no inflation by the formula itself; its MEV term follows its own MEV commission. A validator with no luck-free estimate yet (too new) returns no number at all, rather than a guess.
Alongside the point estimate sits an 80% range for the next 30 days, built from Poisson leader-slot draws and width multipliers m. The range is flagged provisional: m was fitted on 1-epoch horizons, so its 30-day behavior is assumed rather than measured.
Paid APY
Paid APY answers a different question: what have stakers of this validator actually received? And it is where the rule against averaging APYs does real work.
i_E = stakers_inflation_E / paid_stake_E
m_E = (stakers_mev_E + stakers_priority_fees_E) / paid_stake_E both after the TipRouter's fees
Paid APY = (Π_E (1 + i_E))^(Y / Σ T_E) - 1 + Σ_E m_E * Y / Σ T_E over epochs ended in the last 30 days
paid_stake_E is the stake the runtime actually split the reward over, the exact split rather than a sample. The per-epoch values are compounded as growth and annualized once at the very end. An average of per-epoch APYs is never taken, and the reason is arithmetic, not stylistic.
Three mechanics come into play:
Zero epochs count as zero, not as skipped, so a validator that stopped paying is not made to look better by the epochs it missed.
A one-time payment is counted only in the epoch it actually arrives and flagged ("includes a one-time payment") rather than silently suppressed the way some trackers do. There are two kinds, each spotted by its mechanism rather than its size (a small validator's lucky epoch can pay nearly eight times its expected growth): the deferred lump of section "Deferred payouts, a one-time migration effect", a reward for more credits than one epoch holds; and Alpenglow's own, a reward earned on stake that left before the payout, then paid out to the stake that stayed.
It is flagged when the reward was paid over less than a third of the stake it was earned on and came to more than three times the epoch's expected growth (a validator expected to earn nothing, at 100% commission, is not flagged). In epoch 1070 one validator's reward, earned on about 51,500 SOL, was paid over the 2 SOL still delegated, so a 1 SOL stake account received 3.35 SOL: real cash, so Paid keeps it, flagged, and for the 30 days that include it that validator's Paid APY reads in the billions of percent, while Expected APY and Luck divide by the stake it was earned on and never see it. From 1065 to 1076 this flag marks 10 validator-epochs.
- Jito tips do not compound because they land in the stake account undelegated; MEV and the separate Jito Priority Fee Distribution (which reaches 2 to 3 validators per epoch and moves 1 to 12 SOL per epoch in total, in epochs 1065 to 1068) are added as a simple rate, not folded into the compounding inflation term; the priority fees count at what reaches stake accounts, after the TipRouter's 150 bps.
Luck
Luck makes the per-epoch draw visible instead of leaving it to distort the other two.
Realized APY on S = the Paid APY formula with each paid_stake_E replaced by S_E
Luck = (1 + Realized APY on S) / (1 + Expected APY over the same epochs) - 1 over epochs ended in the last 30 days
The Expected APY in this denominator is not the forward-looking headline number but the luck-free expectation computed for those same past epochs, so the ratio isolates luck rather than re-measuring the forecast. The numerator is not Paid APY, for a matching reason: Paid APY divides each epoch's reward by the stake it was paid to, while Luck divides it by S_E, the stake it was sized on, the same basis Expected APY uses. So a stake inflow or outflow moves Paid but not Luck, and the ratio carries the draw alone. An epoch whose split failed has no luck-free estimate of its own, so it is scored against the carried one Expected APY used, with the same flag. Dropping those epochs would throw out the ones where luck is largest: the 213 SOL validator below drew its single group of slots in such an epoch, and over epochs 1066 to 1076, where it earned 5.5% against an expected 4.8%, Luck reads plus 0.6% with that epoch and minus 2.4% without it.
Per-epoch yield is uneven by design, and the size of that variation scales with validator size. The leader half arrives in groups of four slots that land at random, following a Poisson process, so one epoch's inflation part has a standard deviation of about 0.5 / sqrt(λ) of itself, where λ is the number of four-slot groups its stake entitles it to per epoch. At a 5% expected inflation APY, one epoch annualized varies by roughly plus or minus 1.2 pp at 20k SOL, 0.5 pp at 100k, 0.26 pp at 400k, and 0.08 pp at 4M. A large validator pays close to its Expected APY every epoch. A small one meets it only on average across many.
The backtest: how it compares
Does the forecast actually beat what trackers show today? We tested it against reconstructions of the trackers. Two of these were faithful rebuilds (Stakewiz and Marinade UI), meaning we reproduced the real display method rather than a simplified stand-in; the others are close approximations. The edge we found is real but slim.
The measure and the first test
The measure is mean absolute error (MAE): on average, how far a prediction landed from what the validator actually paid, in basis points, so lower is better. We took 2,641 forecasts made at epochs 1064 to 1067, every one that all the predictors in the test could price, and scored them on the epochs closed by then (up to 1068). Expected APY missed the realized payout by 31.7 bps on average. The closest competitor, a faithful rebuild of Stakewiz, missed by 34.7, so the forecast sat a little nearer the truth. Faithful means we ran Stakewiz's reconstructed display method, its published 10-epoch median per stream plus the delinquent-counts-as-zero rule observed on its site, not a weakened version that would be easy to beat. Every other tracker missed by more.
That first test scored our API's estimate with MEV shrunk toward the validator's own history, a refinement the backtest added. It is close to v1 but not identical: it prices commission for the epoch itself rather than at c_next, and has no number where the split fails, so those forecasts were dropped. We then scored v1 as written at three sets of starting epochs, each over the four epochs that followed (or as many as have closed): the original 1064 to 1067, now with all four outcome epochs; and two that did not exist when the test was built, 1069 to 1072 and 1074 and 1075. The 1074 and 1075 starts are the first whose 10-epoch history lies entirely after the migration epoch 1064.
Scoring the v1 formula
In v1 as written, commission is taken at c_next, MEV at the cluster rate, and a failed split carries the last luck-free estimate; priority-fee distributions (1 to 12 SOL an epoch in total over 1065 to 1068) are left out of both forecast and outcome. Where the split failed on an identity change, the realized reward stands in for the split on the schedule identity. For the two largest validators, re-split on chain for 1076, that split came within 4 bps of realized; for smaller ones the stand-in keeps their luck, which on average adds error to v1 rather than removing it.
Three groups go unscored: 12 forecasts v1 cannot price because the validator had no recorded epoch stake, 52 whose validator dropped out of our list before the outcome closed, and 6 whose realized outcome is above 100% or missing, windfalls of the kind section "Paid APY" describes (DrKHZXtu... in 1070, ADoJoWDc... in 1069). The 22 forecasts whose outcome holds a smaller flagged one-time payment stay scored. Where v1 and the first test's estimate both have a number, their mean errors are within 0.15 bps on every set, and the shrinkage moves the error by at most 0.3 bps. The commission rule matters on few forecasts but a lot on those: it changes 6 of the later forecasts, cutting their error from 152 to 13 bps on 1069 to 1072 and from 40 to 23 on 1074 and 1075 (one validator that moved to 100% commission had been forecast at 4.2%); on 1064 to 1067 it changes 2, by under 1 bp.
| Predictor | 1064 to 1067 | 1069 to 1072 | 1074 and 1075 |
|---|---|---|---|
| Forecasts (validators) | 2,679 (675) | 2,735 (691) | 1,383 (693) |
| JPool (v1 Expected APY) | 29.3 | 29.5 | 38.7 |
| Stakewiz, faithful | 30.2, gap -0.9 [-3.5, 1.4] | 32.6, gap -3.1 [-5.4, -0.7] | 42.4, gap -3.6 [-6.9, -0.7] |
| Marinade UI, faithful, on its own rows | 29.5, JPool 30.1 (2,267) | 33.3, JPool 28.9 (2,659) | 43.8, JPool 39.8 (1,333) |
Where the edge comes from
On the two later sets that edge is real but not broad: 16 and 12 validators account for the whole net gap, and removing the ten that favour us most brings the two within a basis point. Trimming the ten most extreme on both sides still leaves the forecast ahead, by 2.9 and 2.4 bps, and validator by validator it is the closer one for 355 against 253 on 1069 to 1072 and 336 against 264 on 1074 and 1075. On 1064 to 1067 there is no edge to speak of: two validators carry the whole 0.9 bps gap, trimming both sides leaves Stakewiz 0.3 bps ahead, the count is 305 against 306, and a faithful Marinade UI is 0.6 bps ahead on its own rows.
Most of the validators that carry the edge are of two kinds. Some had stopped paying while a 10-epoch median, still averaging older paying epochs, showed about 5%: the four validators refused admission in 1069 (section "VAT failure, rare and total") read zero or nearly zero in our forecast from that epoch on, while a faithful Marinade UI still showed 1.8% to 1.9% for them at epoch 1075, eight epochs after their last payment. Others had just started: new validators that sat at 1 to 4 SOL for a few epochs before their stake arrived. A 10-epoch median keeps counting that zero-pay start, so it shows 0% for an operator already paying about 5%. Either way, a backward average describes the validator as it used to be. A few are neither. On 1069 to 1072, three validators that kept paying about 5% read 0% on a faithful Stakewiz at one starting epoch each, because its rule zeroes a validator flagged delinquent at that moment; they carry about 15% of that set's net gap. The rest are small validators, one on 1069 to 1072 and two on 1074 and 1075, whose uneven leader slots make a 10-epoch median miss what the next epochs pay (section "Why averaging does not fix it").
The edge on ordinary validators
These are real defects in how trackers display yield, but narrow ones. Drop every forecast whose validator was out of the vote set from its starting epoch to its outcome, or paid under 0.5% in any epoch from nine before it to its outcome (100%-commission validators aside), and the two nearly converge: 22.7 against 23.0 bps on 1064 to 1067, 24.3 against 25.5 and 38.5 against 39.3 on the later sets, all three with confidence intervals that include zero. On those validators, the forecast is ahead in only 8 of the 12 outcome epochs (section "What is still open"). Grouped by stake size in the first test, the two largest buckets, 50k to 500k SOL and above, showed no significant gap. They hold 92% of the forecasts and nearly all the delegated SOL, so for almost any validator a delegator would actually weigh, the two come out even. Where the split failed, 11 forecasts in all, v1 is slightly behind Stakewiz on every set: carrying the last luck-free estimate avoids the blow-up a realized fallback would produce there, but it is not yet a better forecast. So the claim is a narrow one.
This is why the case for the standard is not accuracy. On the validators a delegator would actually weigh, it ties the best trackers, and that tie is expected: the same realized rewards feed both. Its value is in the two things a backward average cannot give. First, a correct read on the validators whose pay has just stopped or started, where a stale average is confidently wrong. Second, a single method anyone can run and check, rather than a different undisclosed rule behind each tracker (section "The spread: one validator, four numbers"). A forecast that ties on error but is checkable and right about the edge cases is still worth adopting over one that is neither.
One caveat: these are our own measurements, run on snapshots of our public API that sit in a private repository, so a reader cannot rerun them exactly as published. The input underneath is still checkable: cross-check the published per-epoch rewards against Trillium (section "Agreement on the reward, divergence in display" does this for epoch 1068) or Marinade's DS2 on closed epochs, or rebuild them from public RPC (section "Reproducing from public RPC").
What is still open
This is a proposed standard, and the gaps are explicitly stated.
- Twelve Alpenglow outcome epochs now exist (1065 to 1076). With v1 held to a single-epoch horizon, it beats the faithful Stakewiz reconstruction in eleven (one-sided sign test p = 0.0032) and a faithful Marinade UI in all twelve (p = 0.0002). The margin is narrow in who it covers: it comes from validators whose pay stopped or started, and on normally operating validators alone the count falls to 8 of 12 against Stakewiz (p = 0.19) and 9 of 12 against Marinade UI (p = 0.073). Over four-epoch horizons it is ahead on the two later sets of starting epochs and level on the first, where a faithful Marinade UI is 0.6 bps ahead on its own rows; a significant edge on ordinary validators is not shown.
- The interval widths
mwere fitted on 1-epoch horizons. With no widening the 80% interval would cover only 72.3% of outcomes (58.8% below 50k SOL); with the fittedmit covers about 81% on a single epoch, but that figure is in-sample, on the same three epochsmwas fit to. The 30-day range is assumed until 30 days of Alpenglow outcomes exist. - The MEV capture-ratio shrinkage is a proposed refinement, not part of the v1 formula: the v1
g_mevterm prices MEV at the full cluster rate with no shrink. Measured since on every set of starting epochs, it lowers the forecast error by at most 0.3 bps, so it stays out of v1. - The forecast is made after the epoch boundary settles, about 2 minutes into E plus 1, once the VAT outcome (in the first block of E plus 1) and the staker inflation rewards (spread across its first ~530 blocks) have landed. The MEV leg settles much later: Jito merkle roots appear roughly 20 minutes in and claims run for hours, so the tip figure for E is still provisional at forecast time. The forecast is not made at the start of E plus 1.
Reproducing from public RPC
The standard, unlike the backtest, needs nothing private: every input is on-chain, so a reader can rebuild all three numbers from public data, with three qualifications the piece has already named. The voter/leader split is reconstructed, not read: it is not published slot by slot, so the leader part comes from blocks produced and the voter part is the residual, with blocks matched through the epoch's schedule identity and the last luck-free estimate carried, flagged, where the split still fails (section "Expected APY"). Two implementers match only if they use that same reconstruction, so the method is pinned here, not left to the data. Some inputs do not survive in live chain state: two of the accounts below are rolling, and the VAT outcome and epoch length are read from boundary blocks that a size-limited node prunes, so reproducing a closed epoch needs archival access and per-epoch snapshots. And the Jito tip figure is provisional until the merkle roots land, about 20 minutes into the next epoch (section "What is still open"), so the numbers settle to one answer only then.
| Input | Public source | Term it feeds |
|---|---|---|
| Inflation reward of E before commission | getVoteAccounts epochCredits: under Alpenglow the credits a vote account gains in E are the reward it earned in E, in lamports, before commission; they are paid only if the vote account is admitted at the next boundary (VAT outcome below) | R_E, R̂_E |
| Staker inflation reward of E | getInflationReward on the stake accounts | i_E |
| Stake the reward was sized on (effective in E-1) | getVoteAccounts activatedStake read during E-1 (the epoch_stakes(E) snapshot) | S_E |
| Distribution denominator (stake effective in E) | Delegated-stakes PDA CHfmHwNcskfxg1ZnLatbHbmVvYbA6rLDz3Xok5a3Ku8i (rolling) | paid_stake_E |
| Per-epoch reward budget and slot count | Reward-budget PDA 3vJzniWALu2qGFJ1ZY6JD3Y2ZmA5zWqmVdDX7yBXHgu7 (rolling) | B_E |
| Blocks produced (leader part) | getLeaderSchedule / getBlockProduction | R̂_E split |
| Schedule identity of each vote account | Its node key when the epoch stakes were snapshotted, a boundary ahead (vote-account state at that boundary) | R̂_E split |
| Reward captured and leader eligibility | getVoteAccounts (Δ epochCredits, the same reward as the first row, and epochVoteAccount) | Efficiency, entitlement |
| Commission that will apply next | Vote-account state (getInflationReward.commission is empty since SIMD-0232) | c_next |
| VAT outcome | First block of E+1 (VATDebit, numRewardPartitions) | Zero-and-warning |
| Jito cluster tips | Per-validator tip distribution accounts (one per validator per epoch) + Jito fee configs | τ_E, m_E, f_jito, c_mev |
| Priority-fee distribution | Priority Fee Distribution accounts | p_E, f_pf, m_E |
| Network inflation rate and supply | getInflationRate, getSupply | Sanity check (realized ≈ 0.93 to 0.94 × rate, drifts with slot time) |
| Measured epoch length | Block times at the epoch boundary | T_E |
- Read E's inflation reward before commission and the epoch stake it was sized on; remove leader luck via the voter/leader split, matching blocks through the schedule identity, to get R̂_E (or, where the split still fails, carry the last luck-free estimate and flag it), then price it at
c_nextand the measured epoch length for Expected APY. - Compound the realized per-epoch growth over the last 30 days, add the undelegated Jito and priority-fee rate simply, and annualize once for Paid APY.
- Repeat step 2 with each epoch's reward divided by
S_Einstead ofpaid_stake_E, divide (1 + that) by (1 + Expected APY over the same epochs, carried estimates included), and subtract 1 for Luck.
Every identifier named in the piece is listed in full below, so each truncated address can be checked on-chain directly.
| Label | Address |
|---|---|
| Cryptology (validator vote account) | BfxZj7ckfRGHxByn7aHgH2puyXhfjAUvULtRjJo4rd8C |
| Serhio911 | FXcZJuQwkcQpw2YrkTaxWJ6rnw4P12wvULttviMRn655 |
| Figment | CcaHc2L43ZWjwCHART3oZoJvHLAe9hzT2DJNUpBzoTN1 |
| Helius | he1iusunGwqrNtafDtLdhsUQDFvo13z9sUa36PauBtk |
| BlueLotus | 1234LB7uvDC23rdCQoK8C3jNwnovUNyeKxz8wC3dghJ5 |
| ERut3Cwq (stake-flow example, section "Stake flow, transient and one epoch long") | ERut3CwqVeoa616QBaoHc5jL52RpkXjZZZ7MeaMaCtLi |
| DrKHZXtu (windfall, epoch 1070) | DrKHZXtuGhuYbe5MfigvCXR7VFd3u2wxepXei8m2GsDE |
| ADoJoWDc (windfall, epoch 1069) | ADoJoWDcMS7HVW8cMu5GRvy3FBm3RG5bEWQi74YRnwKt |
| Delegated-stakes PDA (paid_stake_E) | CHfmHwNcskfxg1ZnLatbHbmVvYbA6rLDz3Xok5a3Ku8i |
| Reward-budget PDA (B_E) | 3vJzniWALu2qGFJ1ZY6JD3Y2ZmA5zWqmVdDX7yBXHgu7 |
| Alpenglow feature gate (the two PDAs above are owned by the System Program) | A1pengvuM6JEcyNuTnMqepBKhwHE3N6PmUrdATGawhJS |
| VAT refusals, epoch 1069 (four) | EXhYxF25PJEHb3v5G1HY8Jn8Jm7bRjJtaxEghGrUuhQw, FQwewNXahV7MiZcLpY6p1xhUs2acVGQ3U5Xxc7FzV571, J21SMPFJEY9ExCDPiSJQXN23PVSeoQe3LnKD7QcP3bgP, NDf9Pv6TAxTDPR6ud3djsd2Ux1WS2m2YfTw4qEmSnQH |
A shared standard
A single formula on our pages fixes nothing on its own. The spread this piece documents exists because each site makes display choices behind closed doors, and a delegator often has no way of telling what those choices are. What closes that gap is not a better private method but a common one, published and identical across sites, so that two trackers showing one validator either agree or disagree for a reason anyone can check.
We are releasing this as a first version precisely so it can be taken apart. The formula and every input are open (sections "Expected APY" through "Reproducing from public RPC"); the backtest runs on snapshots of our public API kept in a private repository (section "The backtest: how it compares"), and the limits are listed rather than buried (section "What is still open"). If your project reports Solana yield or runs staking of its own, treat this as a draft to contest: rerun it, break it on a case we missed, or bring a rule that beats it. The outcome worth having is one method the whole ecosystem can point to, not four that quietly disagree.