Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
5a384b5
add getSubVaults method, add isStateUpdateRequired to vault abi
dfkadyr Jan 20, 2026
bd89745
small improves
dfkadyr Jan 20, 2026
d293448
add isClaimed to getExitQueuePositions
dfkadyr Jan 20, 2026
dff7431
add support for sub-vault management with new methods and parameters
dfkadyr Jan 30, 2026
f5adb5a
add canHarvest to getVault request
dfkadyr Jan 30, 2026
7a0692b
Create MetaVault (#341)
Cast0001 Feb 3, 2026
3c09390
Add subvault (#344)
dfkadyr Feb 17, 2026
2e92cdd
[improve-sub-vaults] change methods (#345)
Cast0001 Feb 20, 2026
661401a
[new-metavaults-addresses] set new data (#346)
Cast0001 Feb 25, 2026
39241b9
Update state (#348)
mike-diamond Mar 17, 2026
78a39c1
add replica subgraphs
Cast0001 Mar 24, 2026
94d3b4b
Abort callback (#353)
Cast0001 Mar 24, 2026
047ee99
Merge branch 'main' into sub-vaults
Cast0001 Mar 24, 2026
4abc61d
Link checker (#355)
dfkadyr Apr 7, 2026
5b52db2
refactor gas & encode in setDepositData transactions (#359)
dfkadyr Apr 8, 2026
bceb1cd
[subgraph updates] update sub vaults request (#362)
mike-diamond Apr 21, 2026
e904379
update factories addresses (#365)
dfkadyr Apr 22, 2026
e4b1cf8
Merge main sdk (#366)
dfkadyr Apr 24, 2026
42a9bd7
[expand-sub-vaults-registry] change abi (#367)
Cast0001 Apr 27, 2026
b873d54
[curator-v2] add v2 curator for vault creation (#368)
Cast0001 Apr 29, 2026
e3c6dc2
add endpoints file (#369)
dfkadyr May 4, 2026
01b26e7
Merge main (#371)
Cast0001 May 6, 2026
d9a66b5
Context7 (#374)
mike-diamond May 11, 2026
2032bee
[context7] update branch
mike-diamond May 11, 2026
8db20ea
[small-improves] fixes (#377)
Cast0001 May 20, 2026
982a1f3
Merge main 2 (#379)
Cast0001 May 21, 2026
8d89cd8
Merge main (#380)
dfkadyr May 21, 2026
3d6d8dd
New merge 1 (#382)
dfkadyr May 21, 2026
90f1187
Merge branch 'main' into sub-vaults
Cast0001 May 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@ schema.graphql
src/types/graphql
src/contracts/types
src/contracts/vault/types

CLAUDE.md
2 changes: 1 addition & 1 deletion .graphqlconfig
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"extensions": {
"endpoints": {
"Subgraph GraphQL": {
"url": "https://graphs.stakewise.io/hoodi/subgraphs/name/stakewise/prod",
"url": "https://graphs-replica.stakewise.io/hoodi/subgraphs/name/stakewise/stage",
"headers": {
"user-agent": "JS GraphQL"
},
Expand Down
23 changes: 23 additions & 0 deletions changelog/next-release.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## Added methods

- [sdk.vault.getSubVaults](https://docs.stakewise.io/sdk/api/vault/requests/getsubvaults)
- [sdk.vault.addSubVault](https://docs.stakewise.io/sdk/api/vault/transactions/addsubvault)
- [sdk.vault.rejectSubVault](https://docs.stakewise.io/sdk/api/vault/transactions/rejectsubvault)
- [sdk.vault.ejectSubVault](https://docs.stakewise.io/sdk/api/vault/transactions/ejectsubvault)
- [sdk.vault.updateState](https://docs.stakewise.io/sdk/api/vault/transactions/updatestate)

## Modified methods

### 1. [sdk.vault.getVault](https://docs.stakewise.io/sdk/api/vault/requests/getvault)

#### Add output field:
```ts
type Output = {
canHarvest: boolean
exitingAssets: string
exitingTickets: string
ejectingSubVault: string
subVaultsRegistry: string
pendingMetaSubVault: string
}
```
4 changes: 2 additions & 2 deletions codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import type { CodegenConfig } from '@graphql-codegen/cli'
import { Network } from './src/helpers/enums'
import configs from './src/helpers/configs'


let network: Network = Network.Mainnet
// TODO change
let network: Network = Network.Hoodi

if (process.env.NETWORK === 'mainnet') {
network = Network.Mainnet
Expand Down
39 changes: 39 additions & 0 deletions context7.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,43 @@
{
"$schema": "https://context7.com/schema/context7.json",
"projectTitle": "StakeWise V3 SDK",
"description": "Official TypeScript SDK for StakeWise V3 liquid staking on Ethereum and Gnosis. Typed access to vaults, osToken (osETH/osGNO), boost leverage, rewards via subgraph and on-chain calls.",
"url": "https://context7.com/stakewise/v3-sdk",
"public_key": "pk_wpaUy9UwJWjviJip1LFYx",
"branch": "main",
"folders": ["documentation", "src/services"],
"excludeFolders": [
"scripts",
"dist",
"node_modules",
"changelog",
"documentation/_drafts"
],
"excludeFiles": [
"_category_.json",
"README.md",
"package.json",
"tsconfig.json",
"pnpm-lock.yaml",
"rollup.config.js",
"jest.config.ts",
"codegen.ts",
"hardhat.config.js",
"eslint.config.mjs",
"LICENSE",
"CHANGELOG.md"
],
"rules": [
"Init: `new StakeWiseSDK({ network, provider })` for read+write, or `{ network, endpoints: { web3: rpcUrl } }` for read-only.",
"After every write, `await sdk.utils.waitForSubgraph({ hash })` before refetching reads. Subgraph indexing lags transaction confirmation.",
"Writes have 3 forms: default sends a tx, `.encode(args)` returns `{data,to,value}` for multisig, `.estimateGas(args)` returns bigint. `sdk.vault.multicall<T>` lacks `.encode`/`.estimateGas`.",
"`Network.Mainnet=1` (osETH), `Network.Gnosis=100` (osGNO), `Network.Hoodi=560048`. SDK instances are immutable per network; recreate to switch.",
"V3 uses `osToken` (osETH/osGNO). `sETH2`/`rETH2` are V2, never reference in V3 code.",
"Reads return `AbortPromise<T>`; call `.abort()` to cancel. `.then`/`.catch` are silently suppressed after abort.",
"Contracts outside `sdk.contracts`: import top-level `createContract<T>(address, abi, sdk.provider)` from `@stakewise/v3-sdk`.",
"Batch independent reads with `Promise.all` / `AbortPromise.all`. Never parallelise writes; wallets serialise signing."
],
"previousVersions": []
"url": "https://context7.com/stakewise/v3-sdk",
"public_key": "pk_wpaUy9UwJWjviJip1LFYx"
}
4 changes: 2 additions & 2 deletions documentation/connecting-wallet.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
id: connecting
title: Connecting a Wallet
sidebar_position: 2
description: Connect wallets to the StakeWise SDK using EIP-1193 providers MetaMask, WalletConnect, Coinbase, Safe, Binance, and Wagmi integration.
description: Connect wallets to the StakeWise SDK using EIP-1193 providers - MetaMask, WalletConnect, Coinbase, Safe, Binance, and Wagmi integration.
---

# Connecting a Wallet
Expand All @@ -29,7 +29,7 @@ interface Eip1193Provider {
## Wallet Connection Types

Different wallets implement the EIP-1193 provider in different ways.
The most common type is **injected wallets** wallets that automatically inject a provider into the global `window` object under the `window.ethereum` property. This type of connection is used by wallets that are provided in the form of browsers or browser extensions, the most popular of which is **MetaMask**.
The most common type is **injected wallets** - wallets that automatically inject a provider into the global `window` object under the `window.ethereum` property. This type of connection is used by wallets that are provided in the form of browsers or browser extensions, the most popular of which is **MetaMask**.

This is the simplest connection method and works out of the box for most browser wallets.

Expand Down
75 changes: 75 additions & 0 deletions documentation/endpoints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
---
id: endpoints
title: Available Endpoints
sidebar_position: 4
description: RPC, API and Subgraph endpoints for Mainnet, Gnosis and Hoodi networks.
---

# Available Endpoints

---

## How to retrieve the subgraph endpoint URL

The StakeWise V3 subgraph URL depends on the network the SDK is bound to. For SDK-driven workflows the subgraph URL is configured at construction time and the SDK queries it transparently - you do not need to read the URL yourself for typical reads. For direct GraphQL calls (custom queries, dashboards, monitoring), use the production URLs listed below under [Subgraph Endpoint](#subgraph-endpoint).

```typescript
import { StakeWiseSDK, Network } from '@stakewise/v3-sdk'

const sdk = new StakeWiseSDK({
network: Network.Mainnet,
endpoints: { web3: 'https://main-rpc.io' },
})

const stats = await sdk.utils.getStakewiseStats()
```

The SDK ships with the StakeWise V3 subgraph URL baked in for each `Network` (Mainnet, Hoodi, Gnosis), so all read methods (`getVault`, `getStakeBalance`, `getStakewiseStats`, etc.) hit the right subgraph automatically.

---

## RPC Endpoint

The RPC endpoint is the JSON-RPC URL of an Ethereum node for the selected network. You can use any public RPC provider - a curated list with public nodes for each chain is available at:

🔗 **[chainlist.org](https://chainlist.org/)**

✅ **Tip:** For production, prefer a dedicated provider (Infura, Alchemy, QuickNode, etc.) over a free public RPC - public RPCs are rate-limited and may go down.

---

## API Endpoint

GraphQL endpoint of the StakeWise backend.

| Network | Endpoint |
|---------|----------|
| **Mainnet** | `https://mainnet-api.stakewise.io/graphql` |
| **Gnosis** | `https://gnosis-api.stakewise.io/graphql` |
| **Hoodi** | `https://hoodi-api.stakewise.io/graphql` |

---

## Subgraph Endpoint

GraphQL endpoint of the StakeWise subgraph.

### Production

Use the **`prod`** endpoint for production environments.

| Network | Endpoint |
|---------|----------|
| **Mainnet** | `https://graphs.stakewise.io/mainnet/subgraphs/name/stakewise/prod` |
| **Gnosis** | `https://graphs.stakewise.io/gnosis/subgraphs/name/stakewise/prod` |
| **Hoodi** | `https://graphs.stakewise.io/hoodi/subgraphs/name/stakewise/prod` |

### Stage

Mirrors the production schema but tracks the staging deployment - use it only when reproducing issues against a non-production environment.

| Network | Endpoint |
|---------|----------|
| **Mainnet** | `https://graphs.stakewise.io/mainnet/subgraphs/name/stakewise/stage` |
| **Gnosis** | `https://graphs.stakewise.io/gnosis/subgraphs/name/stakewise/stage` |
| **Hoodi** | `https://graphs.stakewise.io/hoodi/subgraphs/name/stakewise/stage` |
4 changes: 4 additions & 0 deletions documentation/fundamentals/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"position": 2,
"label": "Fundamentals"
}
58 changes: 58 additions & 0 deletions documentation/fundamentals/aggregate-queries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
id: aggregate-queries
title: Network-wide aggregates
sidebar_position: 3
description: Use sdk.utils.getStakewiseStats() to fetch total ETH staked, user count, and total earned rewards across all StakeWise V3 vaults on the configured chain.
---

# Network-wide aggregates


To answer "how much is staked across all StakeWise V3 vaults?" use `sdk.utils.getStakewiseStats()`. It returns the protocol-wide aggregate for the network the SDK is bound to.

## Total ETH staked across all V3 vaults

```typescript
import { formatEther } from 'ethers'
import { StakeWiseSDK, Network } from '@stakewise/v3-sdk'

const sdk = new StakeWiseSDK({
network: Network.Mainnet,
endpoints: { web3: 'https://main-rpc.io' },
})

const stats = await sdk.utils.getStakewiseStats()

console.log(`Total: ${formatEther(stats.totalAssets)} ETH`)
console.log(`Users: ${stats.usersCount}`)
console.log(`Earned: ${formatEther(stats.totalEarnedAssets)} ETH`)
```

`stats.totalAssets` and `stats.totalEarnedAssets` are wei strings; convert with `BigInt` for math, with `formatEther` for display. On Gnosis swap `Network.Mainnet` for `Network.Gnosis` and the value is in GNO.

## Cross-chain TVL

Instantiate one SDK per chain, run them concurrently:

```typescript
import { formatEther } from 'ethers'
import { StakeWiseSDK, Network } from '@stakewise/v3-sdk'

const mainnet = new StakeWiseSDK({
network: Network.Mainnet,
endpoints: { web3: 'https://main-rpc.io' },
})

const gnosis = new StakeWiseSDK({
network: Network.Gnosis,
endpoints: { web3: 'https://gnosis-rpc.io' },
})

const [ mainnetStats, gnosisStats ] = await Promise.all([
mainnet.utils.getStakewiseStats(),
gnosis.utils.getStakewiseStats(),
])

console.log(`Mainnet TVL: ${formatEther(mainnetStats.totalAssets)} ETH`)
console.log(`Gnosis TVL: ${formatEther(gnosisStats.totalAssets)} GNO`)
```
112 changes: 112 additions & 0 deletions documentation/fundamentals/concepts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
id: concepts
title: Core concepts
sidebar_position: 0
description: Conceptual overview of StakeWise V3 building blocks - vaults, osToken (osETH/osGNO), Boost leverage staking, MEV escrow vs Smoothing Pool, reward splitter, and the harvest workflow. Maps each concept to the SDK methods that interact with it.
---

# Core concepts

Short primer on the StakeWise V3 building blocks the SDK exposes. Each section maps the concept to the relevant SDK call.

## What is a Vault?

A **vault** is an on-chain contract that pools staked assets (ETH on Mainnet/Hoodi, GNO on Gnosis), runs validators against them, and tracks each staker's share. Anyone can deploy and manage their own vault. The SDK fetches vault state with `sdk.vault.getVault({ vaultAddress })` and creates new vaults with `sdk.vault.create({...})`.

```ts
import { StakeWiseSDK, Network } from '@stakewise/v3-sdk'

const sdk = new StakeWiseSDK({
network: Network.Mainnet,
endpoints: { web3: 'https://main-rpc.io' },
})

const vault = await sdk.vault.getVault({ vaultAddress: '0xVaultAddress' })
```

## What are the vault types?

Five vault types, set at creation time via the `type` argument of `sdk.vault.create`:

- **`VaultType.Default`** - regular vault open to any depositor.
- **`VaultType.Private`** - regular vault restricted to a whitelist managed by the vault admin (`sdk.vault.getWhitelist`, whitelist write methods).
- **`VaultType.Blocklist`** - regular vault open to anyone except blocked addresses (`sdk.vault.getBlocklist`).
- **`VaultType.MetaVault`** - meta vault that does not run validators directly and routes deposits across a registry of sub-vaults. Open to any depositor.
- **`VaultType.PrivateMetaVault`** - meta vault restricted to a whitelist (Mainnet and Hoodi only, not supported on Gnosis).

Orthogonal to that, the optional `vaultToken: { name, symbol }` argument turns a regular vault into an **ERC20 vault** that issues a transferable share token. Omit it for a non-ERC20 vault where shares are tracked internally. Meta vaults do not support ERC20 share tokens on Gnosis.

## What are meta vaults and sub-vaults?

A **meta vault** is a vault that does not run validators directly - instead it holds a registry of **sub-vaults** and aggregates their staking activity. Stakers deposit once into the meta vault; the meta vault routes the assets across its sub-vaults. The meta vault admin (the **curator**) controls which sub-vaults are part of the registry.

Lifecycle methods:

- **`sdk.vault.addSubVault({ vaultAddress, subVaultAddress, userAddress })`** - propose a new sub-vault for the meta vault registry.
- **`sdk.vault.rejectSubVault({...})`** - remove a proposed sub-vault before it becomes active.
- **`sdk.vault.ejectSubVault({...})`** - remove an active sub-vault from the registry.
- **`sdk.vault.getSubVaults({ vaultAddress, limit, skip })`** - list sub-vaults of a meta vault with paging, returning per-vault APY, staking and exiting assets.

Before calling `addSubVault`, pre-check the sub-vault's access flags via `sdk.vault.getVault({ vaultAddress: subVaultAddress })`: if the sub-vault is private (`isPrivate: true`), the meta vault address must be on the sub-vault's whitelist; if the sub-vault has a blocklist (`isBlocklist: true`), the meta vault must not be on it. The sub-vault itself must not be a meta vault (`isMetaVault: false`), nesting is not supported.

Use `VaultType.MetaVault` (or `VaultType.PrivateMetaVault` on Mainnet/Hoodi) when calling `sdk.vault.create` to deploy a meta vault. Meta vaults never support `isOwnMevEscrow`. On Gnosis, meta vaults additionally cannot use the `vaultToken` ERC20 share token, and `VaultType.PrivateMetaVault` is not supported at all.

## What is osToken (osETH / osGNO)?

**osToken** is the StakeWise liquid staking token: **osETH** on Ethereum Mainnet and Hoodi, **osGNO** on Gnosis. Stakers mint osToken against their vault deposit, keeping the underlying stake productive while gaining a transferable, redeemable token. The osToken ERC20 address lives at `sdk.config.addresses.tokens.mintToken`.

```ts
import { StakeWiseSDK, Network } from '@stakewise/v3-sdk'

const sdk = new StakeWiseSDK({
network: Network.Mainnet,
endpoints: { web3: 'https://main-rpc.io' },
})

const apy = await sdk.osToken.getAPY()
const osTokenAddress = sdk.config.addresses.tokens.mintToken
const osToken = sdk.contracts.helpers.createErc20(osTokenAddress)
const totalSupply = await osToken.totalSupply()
```

osToken redemption is at the protocol exchange rate - instant if unbonded assets are available in the vault, otherwise the vault exits validators to fulfill the request.

## What is the osToken health factor?

When a user mints osToken against their stake, the position has a **health factor** that reflects the LTV ratio against the vault's liquidation threshold. Use `sdk.osToken.getHealthFactor` before minting to avoid unhealthy positions; the result is one of `OsTokenPositionHealth.Healthy / Moderate / Risky / Unhealthy`.

## What is Boost?

**StakeWise Boost** is a leverage strategy: users mint osToken against their vault stake, then re-stake the borrowed value in a loop to amplify yield. The SDK exposes the strategy proxy address via `sdk.boost.getLeverageStrategyProxy` and the lock/unlock transactions via `sdk.boost.lock` / `sdk.boost.unlock`. Position state comes from `sdk.boost.getData`.

The strategy keeps near-perfect collateral correlation (osETH against ETH, osGNO against GNO), so liquidation risk is bounded by the protocol's redemption guarantee.

## What is the difference between MEV escrow and Smoothing Pool?

When creating a vault, `isOwnMevEscrow` decides where block rewards go:

- **`false` (default)** - rewards flow to the **Smoothing Pool**, a network-wide MEV pool that distributes proportionally across all participating vaults. Reduces variance.
- **`true`** - the vault has its **own MEV escrow** contract. The vault keeps its own MEV rewards but bears the variance.

## What is a reward splitter?

A **reward splitter** is a contract that distributes a vault's rewards across multiple recipients in fixed proportions. The vault admin deploys one with `sdk.rewardSplitter.createRewardSplitter`, configures shares with `updateFeeRecipients`, and recipients claim with `claimRewards`. List existing splitters for a vault with `sdk.vault.getRewardSplitters`.

## What is harvest and how to update vault state?

Before deposits, mints, or other state-dependent reads can use the latest validator rewards, the vault must be **harvested** - its on-chain state updated with the latest oracle proof. The SDK provides `sdk.vault.getHarvestParams` to fetch the proof and `canHarvest` flag, and `sdk.vault.updateState` to submit the state update transaction (returns an empty hash if the vault is already up to date). Most user-facing flows do not need to call this manually; the deposit/withdraw paths handle it transparently.

## How to wait for subgraph indexing after a transaction?

Every write transaction (`deposit`, `withdraw`, `mint`, `burn`, `lock`, `unlock`, `createVault`, ...) updates the StakeWise subgraph asynchronously. Always wait for the subgraph to catch up before refetching read methods, otherwise data is stale:

```ts
import { StakeWiseSDK, Network } from '@stakewise/v3-sdk'

const sdk = new StakeWiseSDK({ network: Network.Mainnet, endpoints: { web3: 'https://main-rpc.io' } })

const hash = await sdk.vault.deposit({ vaultAddress: '0x...', userAddress: '0x...', assets: 1n })

await sdk.provider.waitForTransaction(hash)
await sdk.utils.waitForSubgraph({ hash })
```
Loading
Loading