If you build anything that touches staked ETH, sooner or later you'll run into a token like ETHx. It looks like "ETH, but earning", and that framing hides most of what a developer actually needs to know. This post uses Stader Labs' ETHx as a concrete case to walk through how a value-accruing liquid staking token works, where its price comes from, and how to model the two ways out of it.
For the full background on the protocol itself, including which of Stader's older tokens are now redeem-only, see this explainer on Stader Labs and how Stader liquid staking works.
Balance stays flat, the rate moves
There are two common designs for liquid staking tokens. Rebasing tokens (like Lido's stETH) change your balance as rewards arrive. Value-accruing tokens (like ETHx, rETH and cbETH) keep your balance fixed and instead raise the amount of ETH each token can be redeemed for.
For ETHx, that redemption rate is simple on paper:
exchange rate = total ETH in the staking pool / total ETHx in circulation
The practical consequence for your code: never treat 1 ETHx as 1 ETH. Store token amounts and convert at read time with a fresh rate. If you cache a rate, cache its timestamp too.
Where does the rate come from?
Smart contracts on Ethereum's execution layer can't directly see validator balances on the consensus layer. So ETHx relies on a small oracle committee that reports pool balances on-chain, and a majority has to agree before the rate updates. Stader also has a safeguard that pauses into an "inspection mode" if a reported rate jumps too far from the previous one.
That's a useful pattern to recognize: your "price" here is a trusted report, not a pure on-chain calculation. If you're building dashboards or risk checks, it's worth alerting on stale or unusually large rate changes rather than assuming the number is always fresh.
Contract rate vs market rate
There are really two prices for ETHx:
- The contract rate, which is what the protocol will redeem at.
- The market rate, which is what a DEX will give you right now.
They're usually close, but not equal. The NutshellCrypto guide recorded a snapshot where the market sat roughly 0.1% below the contract rate. Small, but in stressed markets that gap can widen, and it's exactly the kind of number you'd want to track.
Modeling the two exits
Stader's own unstake path has two details that are easy to miss: rewards stop the moment you request, and you receive the lower of the rate at request time and the rate at finalization. Processing typically takes about a week or more. The DEX path is instant but pays the market rate plus swap fees.
Here's a small, dependency-free sketch to compare them. The numbers are examples, not live data:
from dataclasses import dataclass
@dataclass
class Exit:
label: str
eth_out: float
days: int
def ethx_for_deposit(eth: float, rate: float) -> float:
"""ETHx minted for a deposit at the contract rate (ETH per ETHx)."""
return eth / rate
def stader_unstake(ethx: float, rate_at_request: float, rate_at_finalize: float) -> Exit:
# You get the LOWER of the two rates, and rewards stop at request time.
rate = min(rate_at_request, rate_at_finalize)
return Exit("Stader unstake", ethx * rate, 10)
def dex_swap(ethx: float, market_rate: float, fee_bps: float = 5) -> Exit:
return Exit("DEX swap", ethx * market_rate * (1 - fee_bps / 10_000), 0)
if __name__ == "__main__":
contract_rate = 1.10025 # example: ETH per ETHx from the pool contract
market_rate = 1.0992 # example: ETH per ETHx implied by market prices
ethx = ethx_for_deposit(10, contract_rate)
print(f"10 ETH -> {ethx:.4f} ETHx")
discount = (contract_rate - market_rate) / contract_rate * 100
print(f"Market discount vs contract rate: {discount:.2f}%")
for exit_ in (stader_unstake(ethx, contract_rate, 1.1001),
dex_swap(ethx, market_rate)):
print(f"{exit_.label:15} {exit_.eth_out:.4f} ETH after ~{exit_.days} days")
Output:
10 ETH -> 9.0888 ETHx
Market discount vs contract rate: 0.10%
Stader unstake 9.9986 ETH after ~10 days
DEX swap 9.9855 ETH after ~0 days
The point isn't the exact figures. It's that "which exit is better" is a trade-off between time and price, and it's easy to put real numbers on it once you separate the two rates.
Who's on the hook if a validator misbehaves?
ETHx validators come from a permissionless pool (operators post a 4 ETH bond plus some SD token collateral) and a permissioned pool of curated operators. The bond is the first layer of loss absorption if a validator gets slashed. If you've looked at Rocket Pool's bonded node operator model, the design will feel familiar. It's also worth comparing with how Lido staking works at a much larger scale.
Quick takeaways
- Value-accruing tokens keep balances flat; convert with a fresh rate, never 1:1.
- The redemption rate comes from an oracle committee, so monitor freshness and jumps.
- Track contract rate and market rate separately; the gap is your liquidity signal.
- Protocol unstaking stops rewards at request and pays the lower of two rates.
- Yield figures you see quoted are snapshots; see this note on staking APR vs APY before comparing them.
Read the full guide on NutshellCrypto
This post is for education only and is not financial advice.
This post was written with AI assistance.
Top comments (0)