StakeWise V3
One immutable meta-adapter that reports an account's StakeWise V3 vault positions across any vault on a chain.
One immutable meta-adapter that reports an account's StakeWise V3 vault positions across any vault on a chain. Per vault it emits two gross legs: a Staking leg (vault shares converted to the underlying) and a Borrowed leg (minted osToken debt converted to the underlying).
Type: Meta-adapter
protocolSubId:
keccak256("stakewise-v3-vaults")Instance key: the StakeWise V3 vault address, widened to
bytes32.
Positions returned
Up to two legs per vault, both denominated in the underlying staking asset:
Staking
Staking
false
Vault shares converted to the underlying staking asset
osToken debt
Borrowed
true
Minted osToken position converted to the underlying staking asset
Both legs are dropped when their amount is zero. The whole instance returns empty if the underlying is unregistered in NAVCalculator or filtered out by assetFilter.
Balance calculation
Both legs are denominated in UNDERLYING_TOKEN (the chain-level staking asset, e.g. the ETH sentinel on mainnet, GNO on Gnosis):
The osToken debt is denominated in osToken shares, whose exchange rate is governed by the OsTokenVaultController — a different object from the staking vault's own share→asset rate. The Borrowed leg therefore converts through the controller (the same rate object the osToken price feed uses); converting through the vault's rate would mis-scale the debt.
The two legs are gross (not netted): the staking principal and the osToken debt are reported separately.
Identity
positionId:
abi.encode(address vault)positionKind:
Staking(vault shares),Borrowed(osToken debt)Labels: the adapter implements
positionLabels(positionId), returning a two-tier leaf — both tiers read live and fail-open, surfaced only on the verbose read path:the vault's ERC20
name()—["Vault", "Stakers Union GNO"]. Only StakeWise's…Erc20Vaultimplementation variants are ERC20s and answer it;otherwise
"<underlying symbol> <vault address>"—["Vault", "GNO 0x4b4406ed…"], where every instance configured today lands. The symbol comes from the NAV's asset registry rather than an ERC20symbol()read, because the mainnet underlying is the ETH sentinel0xEeee…EEeE, which has no code; an unregistered underlying degrades to the bare address.
Tier 2 is a coordinate rendering, not a name — the non-ERC20 vault variants expose no human-readable identity on-chain at all (
name(),symbol(),contractURI()andmetadataIpfsHash()all revert;vaultId()is a type hash that collides across vaults), and the names StakeWise's own UI shows come from off-chain IPFS metadata. Treat the leaf as descriptive, never as an identifier: operator names collide — three separate Gnosis vaults are all named"SEED". Key onpositionId.
The reconciliation key is keccak256(abi.encode(chainId, protocolSubId, positionId, balanceAsset.asset, positionKind)) — the Staking and Borrowed legs reconcile independently via positionKind.
Constructor
underlyingToken_
Underlying staking asset all configured vaults are denominated in (chain-level constant; e.g. ETH sentinel on mainnet, GNO on Gnosis). Must be non-zero
osTokenVaultController_
StakeWise OsTokenVaultController for this chain — converts osToken-debt shares to the underlying for the Borrowed leg (the same rate object the osToken price feed uses). Must be a contract
navCalculator_
NAVCalculator address, used for the registered-asset registry. Must be a contract
Registration
Register the adapter with addMetaBalanceAdapter(adapter, instances), then add or remove vaults with addMetaInstances(adapter, instances) / removeMetaInstances(adapter, instances). The instance coordinate is the vault address widened to bytes32.
Last updated