TL;DR — the decision rule
A 30-day realized-yield spread between two large ETH LSTs is not evidence of a yield edge. weETH appeared to out-yield wstETH by 25.6bps on a trailing 30-day read; at 180 days the gap is 5.1bps and at 366 days it inverts to −2.5bps. The lead changed hands 52 times in a year with a median regime of 3 days, and cumulatively wstETH paid more over the full year. Never size an LST switch on a spread measured over less than ~180 days, and quote the 1-year number alongside any short-window figure. Where a small persistent edge does exist, check first whether it is a redemption-driven transfer that will fade: a venue whose exit queue pays leavers the lesser of their request-time amount and their share value hands in-queue yield to stayers, and that flatters the rate exactly while outflows are large.
Question
Refreshing protocols/etherfi-weeth.md, weETH showed 2.48% realized against wstETH’s 2.22% — an apparent 26bps pickup on a token whose restaking sleeve is under 1% of the pool and pays nothing. Either there was an unexplained yield source, or the measurement was wrong. The answer generalises: we hold and compare LSTs routinely, and a 20bps phantom edge is more than enough to justify a bad rotation.
Methodology
Data sources & how to reproduce
All rates read from each protocol’s own exchange-rate getter via cast against an archive node, so no third-party APY feed is involved:
| Token | Contract | Getter |
|---|---|---|
| weETH | 0xCd5f…b7ee | getRate() |
| wstETH | 0x7f39…2Ca0 | stEthPerToken() |
| osETH | 0x2A26…0306 | convertToAssets(1e18) |
| rETH | 0xae78…6393 | getExchangeRate() |
| cbETH | 0xBe98…9704 | exchangeRate() |
Rates are compounded to an annualised figure over each window using measured block timestamps. Two passes: overlapping trailing windows (30/60/90/180/270/366d) and non-overlapping 30-day buckets over 12 months. Two weETH/wstETH series: daily over 150 days (data/weeth-wsteth-daily-rates.csv) and 3-day over a full year (data/weeth-wsteth-3day-1y.csv). Rerun with python3 scripts/peer-field.py; the queue check is python3 scripts/queue-forfeit.py. Head block 25,695,733 (2026-08-06).
Findings
1. The spread decays monotonically with window length
| Window | weETH | wstETH | Spread |
|---|---|---|---|
| 30d | 2.476% | 2.220% | +25.6 bps |
| 60d | 2.458% | 2.295% | +16.3 bps |
| 90d | 2.467% | 2.357% | +11.0 bps |
| 180d | 2.473% | 2.422% | +5.1 bps |
| 270d | 2.486% | 2.485% | +0.2 bps |
| 366d | 2.520% | 2.545% | −2.5 bps |
2. It is the peer declining, not the subject rising
Non-overlapping 30-day buckets, first vs last:
| Sep-2025 | Aug-2026 | Change | |
|---|---|---|---|
| weETH | 2.607% | 2.476% | −13 bps |
| wstETH | 2.723% | 2.220% | −50 bps |
| cbETH | 2.723% | 2.410% | −31 bps |
| rETH | 2.460% | 2.217% | −24 bps |
| osETH | 2.349% | 2.141% | −21 bps |
Network staking yield is compressing for everyone. weETH’s own rate is flat (2.40–2.66% every month, no trend); it ran below the peer median through 2025 and crossed over in March 2026.
3. The lead changes hands constantly — and wstETH wins the year
Over 122 three-day periods spanning 2025-08-03 → 2026-08-06 (data/weeth-wsteth-3day-1y.csv):
| Measure | Value |
|---|---|
| Periods weETH ahead | 68 / 122 (55.7%) |
| Lead changes | 52 |
| Median regime length | 1 period (3 days) |
| Longest weETH-ahead run | 75 days |
| Longest wstETH-ahead run | 39 days |
| Mean spread | −2.5 bps |
| Stdev of spread | 25.6 bps |
| Cumulative over the year | weETH +2.5390% vs wstETH +2.5640% → weETH 2.4 bps behind |
The noise is ten times the mean. Split in halves, the first six months had weETH ahead 39% of periods (mean −9.6bps) and the second six months 72% (mean +4.6bps) — a real recent tilt, but one that still leaves wstETH ahead cumulatively over the full year.
4. The short-window signal is inside its own noise
Daily annualised rates over 150 days: weETH mean 2.451%, stdev 0.400pp; wstETH mean 2.411%, stdev 0.243pp. weETH > wstETH on 83 of 150 days (55%). Standard error on the difference is ±8.5bps at 30 days but ±3.8bps at 150 — so the 150-day estimate of +4.0bps is the defensible one, and the 30-day +25.6bps is mostly one weak month at the peer.
5. Ruled out: fees, cash drag, and one-off accounting
- Fees: Lido
getFee()= 999bps at every sampled block over 12 months. Unchanged. - Cash drag: Lido’s buffered (unstaked) ETH is 0.01–0.13% of pooled ETH; ether.fi’s is 0.34–1.76%. ether.fi carries more idle drag, so this works against the observed spread.
- Lumpiness: if the excess came from one-off accounting during ether.fi’s restaking wind-down, it would arrive in spikes. weETH’s top-5 days are 5.0% of its 150-day total (uniform = 3.3%); wstETH’s are 4.6%. Essentially the same — the excess accrues smoothly.
6. The exit queue transfers yield from leavers to stayers
ether.fi’s WithdrawRequestNFT records both an ETH amount fixed at request time and a share count; getClaimableAmount pays the lesser of the two. Yield earned while a request sits in the queue is therefore forfeited by the leaver and accrues to remaining holders. Live open requests at block 25,695,733:
| Request | ETH at request | Share value now | Forfeited |
|---|---|---|---|
| 81311 | 6.000176 | 6.000248 | +0.000072 |
| 81316 | 4.159528 | 4.159578 | +0.000050 |
| 81314 | 3.000072 | 3.000107 | +0.000036 |
Small in a calm queue (hours of accrual). At the spring run’s scale — ~1.4M ETH exiting at a ~4.9d median wait — the transfer is worth roughly 5bps annualised to stayers. It appears exactly when outflows are large and switches off when they stop.
Decision framework
- Quote the 1-year spread beside any short-window spread. If they disagree in sign, the short window is noise.
- Require ~180 days before acting on an LST spread. Below that, the standard error on the difference exceeds most plausible real edges.
- Attribute before rotating. Work through fees, idle-ETH drag, lumpiness, and queue mechanics before concluding “better operators.” Only the last of those is durable.
- Treat redemption-driven yield as temporary. A lesser-of-amount-or-shares queue rule flatters the rate while a venue is bleeding deposits — the yield is being paid by the people leaving, and it ends when they finish.
- Read the field, not the pair. A stable cross-venue ordering (here cbETH > weETH > wstETH > osETH ≈ rETH) is operator-quality signal; a pair that crosses over is usually one side moving.
This stops applying when: a venue changes its fee schedule or queue accounting; a protocol adds a genuine non-staking revenue leg (real AVS fees, restaking that actually pays); or Ethereum issuance changes enough that cross-venue comparison needs re-basing.
Caveats
We measured exchange-rate growth, which is net of each protocol’s fees — so this compares what a holder receives, not validator-level gross performance, and cannot separate “better operators” from “lower fees.” Attributing the residual ~4bps to operator quality is inference from the stable cross-venue ordering, not a direct measurement of attestation effectiveness or MEV capture; a validator-level study using beacon-chain data would settle it. The 5bps queue-transfer estimate assumes the eval’s reported 4.9d median wait and uniform exit sizing, neither of which we re-derived here. osETH, rETH and cbETH were sampled only on the monthly grid, not daily.