Lido stETH vs wstETH Tracking: The Rebase Is the Whole Problem (2026)
Lido stETH vs wstETH Tracking: The Rebase Is the Whole Problem (2026)
Reviewed by Wag3s Editorial Team — verified against the Lido stETH rebasing model and the wstETH non-rebasing share/exchange-rate model · Last reviewed May 2026
Lido stETH vs wstETH Tracking: The Rebase Is the Whole Problem
What is unique here is that two tokens carry the identical staked-ETH exposure with opposite on-chain behaviour: stETH grows your balance every day through a rebase, while wstETH never changes its balance and pushes the same value into a rising exchange rate. A tracker that does not know which token it is holding produces either a stream of phantom inflows or a hidden gain. This guide is the rebase, the wrapper, and the tracking line between them, the staking-specific case of the general rebasing vs non-rebasing problem and one spoke of multi-wallet aggregation.
Why stETH and wstETH track differently
- stETH is rebasing: the balance grows roughly daily as rewards accrue, with no transfer, a recurring rebase.
- wstETH is non-rebasing: the balance is fixed and value rides an increasing wstETH↔stETH exchange rate via a share system.
- The rebase is a stream to characterise (reward accrual versus a plain balance change), not a matchable receipt.
- wstETH moves the value into a price, so the gain only surfaces on unwrap or disposal (rate then versus rate at acquisition).
- Tax of a rebase is jurisdiction-specific: track the signal, confirm tax separately.
- Same exposure, two behaviours, so a tracker must detect which token it actually holds.
stETH: a balance that rebases
stETH is rebasing: as Lido staking rewards accrue, the stETH balance in the wallet increases, typically daily, with no transfer. The economic meaning is "rewards accrued," but the on-chain signal is a recurring balance change. A tracker must:
- recognise the rebase increases, reading the balance rather than transfers (the same lesson as Aave V3 accrual);
- characterise them as reward accrual versus a plain balance change;
- avoid treating each daily bump as an unexplained inflow or new acquisition.
It is a continuous stream, not an event matched to one transaction, and the recurring rebase is the defining tracking challenge.
How the stETH rebase works on-chain
Lido implements the rebase through the Lido contract's handleOracleReport function. When the Lido oracle submits a new beacon chain report, the contract calls _rebase(), which adjusts the _totalShares and _totalPooledEther values. The balanceOf(account) function derives the displayed balance dynamically:
balance = shares[account] × totalPooledEther / totalShares
The shares[account] value is fixed between rebases. Only totalPooledEther increases. So a tracker that caches shares[account] and the old totalPooledEther will show the wrong balance immediately after any oracle report. Correct tracking reads balanceOf() directly, or monitors the TokenRebased event emitted on each rebase and updates the derived balance.
wstETH: the value moves into a rate
wstETH is the non-rebasing wrapper: the balance is fixed, and rewards are reflected by an increasing wstETH→stETH exchange rate via an underlying share system. There is no daily rebalance to track, but the value still grows, hidden in the rate. The gain surfaces when you unwrap or dispose of wstETH, comparing the rate then against the rate at acquisition. wstETH is often preferred in DeFi lending, collateral and bridges precisely because fixed balances integrate more cleanly.
Computing the wstETH/stETH exchange rate
The wstETH contract exposes stEthPerToken() (also tokensPerStEth() for the inverse). These return the current conversion ratio. At any point in time:
stETH equivalent = wstETH balance × stEthPerToken() / 10^18
For cost-basis purposes, the acquisition cost of wstETH is the ETH (or stETH) value at the time of wrapping; the disposal gain is the difference between the stETH-equivalent value at disposal and the acquisition cost, converted to fiat at the disposal-date rate.
Two behaviours, one exposure
| stETH | wstETH | |
|---|---|---|
| Balance | Grows (rebase, ~daily) | Fixed |
| Where value lives | Units | Exchange rate |
| Tracking signal | Stream of rebase increases | Rate change at unwrap/disposal |
| DeFi integration | Harder (rebasing) | Cleaner (fixed balance) |
A tracker that assumes the wrong one produces either phantom inflows (treating wstETH as if it rebased) or a hidden gain (treating stETH as static). It must detect which token is held and apply the matching model.
Step-by-step: how to track stETH and wstETH
- Detect the token address. stETH is at
0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84on Ethereum mainnet. wstETH is at0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0. Any other address is neither — confirm before applying a model. - For stETH: monitor the
TokenRebasedevent on the Lido contract. Each event includesreportTimestamp,preTotalShares,preTotalEther,postTotalShares,postTotalEther,sharesMintedAsFees. Compute the per-holder balance change asshares[account] × (postTotalEther - preTotalEther) / postTotalShares. - For stETH: read
balanceOf()at each portfolio snapshot. Do not use theshares[account]raw value; use the derived balance that incorporates the current index. - For wstETH: read
balanceOf()once. The balance does not change without a transaction. Record the quantity at acquisition and thestEthPerToken()rate at that time as the reference rate. - For wstETH: at disposal or unwrap, read
stEthPerToken()again. The gain is the increase in stETH-equivalent value since acquisition, converted to fiat at the disposal-date ETH price. - Track wrap and unwrap transactions.
WstETH.wrap(stETHAmount)is a conversion, not a disposal in most frameworks — confirm per jurisdiction. The shares relationship is preserved. - Apply the jurisdiction cost-basis method and confirm whether each stETH rebase is income, a balance adjustment, or deferred until disposal.
Common errors and how to fix them
Error 1 — Reading stETH balance from the Transfer event only. Rebases do not emit a Transfer event per holder. An ERC-20 transfer-based tracker will miss all daily rebase accruals and show the stETH balance frozen at the last transfer amount. Fix: read balanceOf() directly and compare to previous snapshot; or monitor the TokenRebased event and recompute per-holder balances.
Error 2 — Treating wstETH as rebasing. The wstETH balance never changes without a transaction. A tracker built for stETH that also monitors wstETH's Transfer events for rebases will find nothing and, if it then infers that the balance should be higher, may fabricate phantom inflows. Fix: apply the rate-change model exclusively to wstETH; read the exchange rate at acquisition and at disposal.
Error 3 — Ignoring the wstETH/stETH rate at wrap time. If the tracker records only the wstETH quantity at wrapping and not the stETH-per-token rate at that moment, it cannot compute the correct cost basis later. Fix: record both the wstETH quantity and stEthPerToken() at the time of wrapping as the cost-basis reference.
Error 4 — Booking a stETH→wstETH wrap as a disposal. Wrapping stETH into wstETH may not be a disposal in many frameworks (you continue to own the same economic exposure); unwrapping is similarly not necessarily an acquisition. Hard-coding wrap/unwrap as taxable events will over-report. Fix: leave the wrap/unwrap characterisation as a jurisdiction-confirmed flag, defaulting to non-disposal until confirmed otherwise.
Tax is jurisdiction-specific
Whether each rebase is taxable income, and when (the rebase complicates "received/controlled"), is jurisdiction-specific and must not be hard-coded either way (see staking rewards accounting and yield farming tracking). The rebase or rate is the tracking signal; the tax characterisation is a separate, adviser-confirmed question, and the cost-basis method remains the jurisdiction-mandated one.
Practical guidance
- Detect stETH versus wstETH; never assume, because the balance behaviour differs fundamentally.
- For stETH, model the rebase stream: read balances and characterise the accrual.
- For wstETH, track the exchange rate, since the gain realises on unwrap or disposal.
- Avoid booking rebases as acquisitions or inflows, or treating wstETH as static with no gain.
- Confirm rebase tax treatment per jurisdiction and apply the mandated cost-basis method.
- Reconcile to Lido (the rebase index or the wstETH rate) with an audit trail.
Choosing a tool for stETH and wstETH
Both Koinly and CoinTracker advertise support for rebasing and wrapped staking tokens, but the stETH/wstETH split is exactly where a generic model goes wrong. Before you rely on a Lido figure, check that the tool:
- detects which token is held from the contract address, applying the rebase model to stETH and the rate model to wstETH rather than one default;
- reads
balanceOf()(or theTokenRebasedevent) for stETH instead of freezing the balance at the last transfer, so daily accrual is not lost; - records
stEthPerToken()at the time of wrapping, so the wstETH cost basis is computable at unwrap or disposal; - treats a stETH↔wstETH wrap as a non-disposal by default, leaving the characterisation to the jurisdiction setting.
Assuming the wrong token model is the recurring Lido error, and it produces either invented inflows or a silently deferred gain.
How Wag3s handles it
Wag3s Folio detects stETH versus wstETH, models the stETH rebase as characterised accrual rather than phantom inflows, tracks the wstETH↔stETH rate so the gain surfaces correctly on unwrap or disposal, and applies your jurisdiction's cost-basis method and rebase tax treatment. See the Folio product page.
Further reading
- Aave V3 Position Tracking
- Rebasing vs Non-Rebasing Token Tracking
- Staking Rewards Accounting
- Liquid Restaking Token Accounting (LRTs)
- Yield Farming Tracking
- Crypto Cost Basis Methods 2026
Sources
- Lido — stETH and wstETH: stETH is a rebasing token whose balance updates daily as staking rewards accrue, while wstETH is the non-rebasing wrapper with a fixed balance and value carried in an increasing exchange rate.
- Lido — wstETH contract docs: the share-based wrapper, the
stEthPerToken()rate, and the wrap/unwrap mechanics.
Aave V3 Position Tracking: aTokens, Debt Tokens, and the Health Factor (2026)
An Aave V3 position is not a static balance — supply gives you aTokens whose balance grows as interest accrues, borrowing creates variableDebtTokens that grow too, and the Health Factor moves with oracle prices. Why interest-in-the-balance and the collateral/debt pair break a naive portfolio view.
Uniswap V3 LP Position Tracking: A Position Is an NFT, Not a Balance (2026)
A Uniswap V3 liquidity position is a non-fungible NFT with a price range — not a fungible LP token. It earns fees only while in range, the two-asset split shifts as price moves, and fees accrue separately. Why range, NFT identity, and separate fees break a balance-based tracker.
Every chain, integration, and competitor mentioned in this article gets its own page — coverage detail, comparison signals, and the audit trail your finance team needs.
- Chain
Ethereum
ERC-20, DeFi positions, gas treatment, restaking.
View page - Chain
Base
Coinbase L2 with USDC-native treasury flows.
View page - Chain
Solana
SPL tokens, native stake, Jupiter, Metaplex NFTs.
View page - Integration
NetSuite integration
Mid-market and enterprise crypto subledger.
View page - Integration
QuickBooks integration
SMB GL with daily JE sync.
View page - Integration
Safe integration
DAO and corporate multi-sig accounting.
View page