From 5a384b5c7b7855a81b1fccfc1303d7af0daeba4a Mon Sep 17 00:00:00 2001 From: dfkadyr Date: Tue, 20 Jan 2026 11:20:22 +0300 Subject: [PATCH 01/27] add getSubVaults method, add isStateUpdateRequired to vault abi --- changelog/next-release.md | 4 + src/contracts/vault/abis/DefaultVaultAbi.json | 17 ++++ .../allocator/allocatorsQuery.graphql | 1 + src/graphql/subgraph/vault/index.ts | 3 + .../subgraph/vault/subVaultsQuery.graphql | 13 +++ src/services/vault/index.ts | 9 ++ .../requests/getSubVaults/getSubVaults.md | 48 ++++++++++ .../vault/requests/getSubVaults/index.ts | 94 +++++++++++++++++++ src/services/vault/requests/index.ts | 3 + 9 files changed, 192 insertions(+) create mode 100644 src/graphql/subgraph/vault/subVaultsQuery.graphql create mode 100644 src/services/vault/requests/getSubVaults/getSubVaults.md create mode 100644 src/services/vault/requests/getSubVaults/index.ts diff --git a/changelog/next-release.md b/changelog/next-release.md index e69de29b..f6da4bda 100644 --- a/changelog/next-release.md +++ b/changelog/next-release.md @@ -0,0 +1,4 @@ +## Added methods + +- sdk.vault.getSubVaults + diff --git a/src/contracts/vault/abis/DefaultVaultAbi.json b/src/contracts/vault/abis/DefaultVaultAbi.json index e1303657..0462cd9c 100644 --- a/src/contracts/vault/abis/DefaultVaultAbi.json +++ b/src/contracts/vault/abis/DefaultVaultAbi.json @@ -525,5 +525,22 @@ ], "outputs": [], "stateMutability": "nonpayable" + }, + { + "inputs": [], + "name": "isStateUpdateRequired", + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "view", + "type": "function" } ] + + + + diff --git a/src/graphql/subgraph/allocator/allocatorsQuery.graphql b/src/graphql/subgraph/allocator/allocatorsQuery.graphql index 918b86dc..b875f0c2 100644 --- a/src/graphql/subgraph/allocator/allocatorsQuery.graphql +++ b/src/graphql/subgraph/allocator/allocatorsQuery.graphql @@ -5,6 +5,7 @@ query Allocators($address: Bytes!, $vaultAddress: String!) { vault: $vaultAddress } ) { + apy assets totalEarnedAssets totalStakeEarnedAssets diff --git a/src/graphql/subgraph/vault/index.ts b/src/graphql/subgraph/vault/index.ts index f6e2aaa2..1f326d5c 100644 --- a/src/graphql/subgraph/vault/index.ts +++ b/src/graphql/subgraph/vault/index.ts @@ -4,6 +4,9 @@ export type { VaultQueryPayload, VaultQueryVariables } from './vaultQuery.graphq export { fetchUserApyQuery } from './userApyQuery.graphql' export type { UserApyQueryPayload, UserApyQueryVariables } from './userApyQuery.graphql' +export { fetchSubVaultsQuery } from './subVaultsQuery.graphql' +export type { SubVaultsQueryPayload, SubVaultsQueryVariables } from './subVaultsQuery.graphql' + export { fetchVaultStatsQuery } from './vaultStatsQuery.graphql' export type { VaultStatsQueryPayload, VaultStatsQueryVariables } from './vaultStatsQuery.graphql' diff --git a/src/graphql/subgraph/vault/subVaultsQuery.graphql b/src/graphql/subgraph/vault/subVaultsQuery.graphql new file mode 100644 index 00000000..d7aa27d4 --- /dev/null +++ b/src/graphql/subgraph/vault/subVaultsQuery.graphql @@ -0,0 +1,13 @@ +query SubVaults( + $skip: Int! + $first: Int! + $where: SubVault_filter! +) { + subVaults( + skip: $skip, + first: $first, + where: $where, + ) { + subVault + } +} diff --git a/src/services/vault/index.ts b/src/services/vault/index.ts index 77276173..9c7256c8 100644 --- a/src/services/vault/index.ts +++ b/src/services/vault/index.ts @@ -1,6 +1,7 @@ import { getVault, GetVaultInput, getUserApy, GetUserApyInput, + getSubVaults, GetSubVaultsInput, getWhitelist, GetWhitelistInput, getBlocklist, GetBlocklistInput, getUserStats, GetUserStatsInput, @@ -183,6 +184,14 @@ class Vault extends VaultTransactions { public getOsTokenConfig(values: StakeWise.ExtractInput) { return getOsTokenConfig({ ...this.params, ...values }) } + + /** + * @description Returns the list of sub vaults. + * @see https://docs.stakewise.io/vault/requests/getsubvaults + */ + public getSubVaults(values: StakeWise.ExtractInput) { + return getSubVaults({ ...this.params, ...values }) + } } diff --git a/src/services/vault/requests/getSubVaults/getSubVaults.md b/src/services/vault/requests/getSubVaults/getSubVaults.md new file mode 100644 index 00000000..5f88a922 --- /dev/null +++ b/src/services/vault/requests/getSubVaults/getSubVaults.md @@ -0,0 +1,48 @@ +--- +id: getSubVaults +slug: /vault/requests/getsubvaults +--- + +#### Description: + +Returns the list of sub vaults. + +#### Arguments: + +| Name | Type | Required | Description | +|------|------|----------|-----------------------------------------------------------| +| vaultAddress | `string` | **Yes** | The address of the meta vault | +| limit | `number` | **No** | Limits the number of sub vaults returned. Defaults to 100 | +| skip | `number` | **No** | Skips the specified number of sub vaults. Defaults to 0 | + +#### Returns: + +```ts +type Output = { + id: string + apy: string + imageUrl: string + displayName: string + stakingAssets: bigint + exitingAssets: bigint +} +``` + +| Name | Description | +|------|-------------| +| `id` | Vault address | +| `imageUrl` | The image URL extracted from the metadata IPFS file. Will be `null` if the vault does not have an image. | +| `displayName` | Name of vault | +| `stakingAssets` | The amount of assets staking in the sub-vault. | +| `exitingAssets` | The amount of assets exiting the sub-vault. | +| `apy` | The sub-vaul average weekly APY | + +#### Example: + +```ts +await sdk.vault.getSubVaults({ + skip: 0, + limit: 5, + vaultAddress: '0x...' +}) +``` diff --git a/src/services/vault/requests/getSubVaults/index.ts b/src/services/vault/requests/getSubVaults/index.ts new file mode 100644 index 00000000..baf4429b --- /dev/null +++ b/src/services/vault/requests/getSubVaults/index.ts @@ -0,0 +1,94 @@ +import type { SubVaultsQueryPayload, SubVaultsQueryVariables } from '../../../../graphql/subgraph/vault' +import { apiUrls, validateArgs } from '../../../../helpers' + +import getVault from '../getVault' +import getExitQueuePositions from '../getExitQueuePositions' + +import graphql from '../../../../graphql' + + +export type GetSubVaultsInput = StakeWise.CommonParams & { + skip: SubVaultsQueryVariables['skip'] + limit: SubVaultsQueryVariables['first'] + vaultAddress: SubVaultsQueryVariables['where']['metaVault'] +} + +type OutputSubVault = { + id: string + apy: string + imageUrl: string + displayName: string + stakingAssets: bigint + exitingAssets: bigint +} + +const getSubVaults = async (input: GetSubVaultsInput): Promise => { + const { skip, limit, vaultAddress, ...commonParams } = input + + validateArgs.address({ vaultAddress }) + validateArgs.number({ skip, limit }) + + const url = apiUrls.getSubgraphqlUrl(commonParams.options) + + const metaVaultId = vaultAddress.toLowerCase() + + const subVaults = await graphql.subgraph.vault.fetchSubVaultsQuery({ + url, + variables: { + skip, + first: limit, + where: { + metaVault_: { + id: metaVaultId, + }, + } as SubVaultsQueryVariables['where'], + }, + modifyResult:(data: SubVaultsQueryPayload) => data.subVaults.map((item => item.subVault)), + }) + + const results = await Promise.all( + subVaults.map(async (subVaultId) => { + const vaultId = subVaultId.toLowerCase() + + const [ allocatorData, vaultData, exitQueue ] = await Promise.all([ + graphql.subgraph.allocator.fetchAllocatorsQuery({ + url, + variables: { + address: metaVaultId, + vaultAddress: vaultId, + }, + modifyResult: (data) => { + const first = data?.allocators?.[0] + + return { + assets: BigInt(first?.assets || 0), + apy: (Number(first?.apy) || 0).toFixed(2), + } + }, + }), + + getVault({ ...commonParams, vaultAddress: vaultId }), + + getExitQueuePositions({ + ...commonParams, + vaultAddress: vaultId, + userAddress: metaVaultId, + }), + ]) + + return { + id: vaultId, + apy: allocatorData.apy, + imageUrl: vaultData.imageUrl, + exitingAssets: exitQueue.total, + displayName: vaultData.displayName, + stakingAssets: allocatorData.assets, + } + }) + ) + + return results +} + + +export default getSubVaults diff --git a/src/services/vault/requests/index.ts b/src/services/vault/requests/index.ts index ecc8d4c0..1e9c7727 100644 --- a/src/services/vault/requests/index.ts +++ b/src/services/vault/requests/index.ts @@ -40,6 +40,9 @@ export type { GetValidatorsInput } from './getValidators' export { default as getVaultStats } from './getVaultStats' export type { GetVaultStatsInput } from './getVaultStats' +export { default as getSubVaults } from './getSubVaults' +export type { GetSubVaultsInput } from './getSubVaults' + export { default as getWhitelist } from './getWhitelist' export type { GetWhitelistInput } from './getWhitelist' From bd89745b164d14991b0d3949943c45d37ced6962 Mon Sep 17 00:00:00 2001 From: dfkadyr Date: Tue, 20 Jan 2026 13:36:07 +0300 Subject: [PATCH 02/27] small improves --- src/services/vault/requests/getSubVaults/getSubVaults.md | 2 +- src/services/vault/requests/getSubVaults/index.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/vault/requests/getSubVaults/getSubVaults.md b/src/services/vault/requests/getSubVaults/getSubVaults.md index 5f88a922..92859174 100644 --- a/src/services/vault/requests/getSubVaults/getSubVaults.md +++ b/src/services/vault/requests/getSubVaults/getSubVaults.md @@ -35,7 +35,7 @@ type Output = { | `displayName` | Name of vault | | `stakingAssets` | The amount of assets staking in the sub-vault. | | `exitingAssets` | The amount of assets exiting the sub-vault. | -| `apy` | The sub-vaul average weekly APY | +| `apy` | The sub-vault average weekly APY | #### Example: diff --git a/src/services/vault/requests/getSubVaults/index.ts b/src/services/vault/requests/getSubVaults/index.ts index baf4429b..72882df4 100644 --- a/src/services/vault/requests/getSubVaults/index.ts +++ b/src/services/vault/requests/getSubVaults/index.ts @@ -43,7 +43,7 @@ const getSubVaults = async (input: GetSubVaultsInput): Promise }, } as SubVaultsQueryVariables['where'], }, - modifyResult:(data: SubVaultsQueryPayload) => data.subVaults.map((item => item.subVault)), + modifyResult:(data: SubVaultsQueryPayload) => data.subVaults.map(((vault) => vault.subVault)), }) const results = await Promise.all( From d293448696f58de153a34a448805b429c000ccbf Mon Sep 17 00:00:00 2001 From: dfkadyr Date: Tue, 20 Jan 2026 14:37:33 +0300 Subject: [PATCH 03/27] add isClaimed to getExitQueuePositions --- src/services/vault/requests/getSubVaults/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/vault/requests/getSubVaults/index.ts b/src/services/vault/requests/getSubVaults/index.ts index 72882df4..2ed90af7 100644 --- a/src/services/vault/requests/getSubVaults/index.ts +++ b/src/services/vault/requests/getSubVaults/index.ts @@ -71,6 +71,7 @@ const getSubVaults = async (input: GetSubVaultsInput): Promise getExitQueuePositions({ ...commonParams, + isClaimed: false, vaultAddress: vaultId, userAddress: metaVaultId, }), From dff7431301751b341ec21548fcf4f198102d0400 Mon Sep 17 00:00:00 2001 From: dfkadyr Date: Fri, 30 Jan 2026 16:28:06 +0300 Subject: [PATCH 04/27] add support for sub-vault management with new methods and parameters --- changelog/next-release.md | 24 ++++++- .../vault/abis/MetaVaultDiffAbi.json | 67 +++++++++++++++++++ src/contracts/vault/abis/index.js | 2 + src/contracts/vault/createVaultContract.ts | 20 ++++-- src/graphql/subgraph/vault/vaultQuery.graphql | 2 + .../requests/getSubVaults/getSubVaults.md | 1 + .../vault/requests/getSubVaults/index.ts | 17 +++-- .../vault/requests/getVault/getVault.md | 4 ++ .../requests/getVault/modifyVault.spec.ts | 4 ++ .../vault/requests/getVault/modifyVault.ts | 4 ++ .../vault/transactions/operate/checkAccess.ts | 7 +- .../vault/transactions/operate/common.ts | 27 +++++++- .../vault/transactions/operate/operate.md | 6 ++ .../vault/transactions/operate/types.d.ts | 6 ++ .../util/params/getAddSubVaultParams.ts | 24 +++++++ .../util/params/getEjectSubVaultParams.ts | 24 +++++++ .../util/params/getRejectSubVaultParams.ts | 24 +++++++ .../vault/transactions/util/params/index.ts | 3 + 18 files changed, 250 insertions(+), 16 deletions(-) create mode 100644 src/contracts/vault/abis/MetaVaultDiffAbi.json create mode 100644 src/services/vault/transactions/util/params/getAddSubVaultParams.ts create mode 100644 src/services/vault/transactions/util/params/getEjectSubVaultParams.ts create mode 100644 src/services/vault/transactions/util/params/getRejectSubVaultParams.ts diff --git a/changelog/next-release.md b/changelog/next-release.md index f6da4bda..dc4f033f 100644 --- a/changelog/next-release.md +++ b/changelog/next-release.md @@ -1,4 +1,26 @@ ## Added methods -- sdk.vault.getSubVaults +- [sdk.vault.getSubVaults](https://docs.stakewise.io/vault/requests/getsubvaults) +## Modified methods + +### 1. [sdk.vault.getVault](https://docs.stakewise.io/vault/requests/getvault) + +#### Add output field: +```ts +type Output = { + exitingAssets: string + exitingTickets: string +} +``` + +### 2. [signSDK.vault.operate](https://docs.stakewise.io/vault/transactions/operate) + +#### Add new params field to update sub-vault addresses: +```ts +type Output = { + subVaultAddress: string + ejectSubVaultAddress: string + rejectMetaSubVaultAddress: string +} +``` diff --git a/src/contracts/vault/abis/MetaVaultDiffAbi.json b/src/contracts/vault/abis/MetaVaultDiffAbi.json new file mode 100644 index 00000000..d6f2d43b --- /dev/null +++ b/src/contracts/vault/abis/MetaVaultDiffAbi.json @@ -0,0 +1,67 @@ +[ + { + "inputs": [ + { + "internalType": "address", + "name": "metaSubVault", + "type": "address" + } + ], + "name": "rejectMetaSubVault", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "pendingMetaSubVault", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "ejectingSubVault", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vault", + "type": "address" + } + ], + "name": "addSubVault", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vault", + "type": "address" + } + ], + "name": "ejectSubVault", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/src/contracts/vault/abis/index.js b/src/contracts/vault/abis/index.js index 07cf2f46..aa04d95c 100644 --- a/src/contracts/vault/abis/index.js +++ b/src/contracts/vault/abis/index.js @@ -3,11 +3,13 @@ import BlocklistVaultDiffAbi from './BlocklistVaultDiffAbi.json' import PrivateVaultDiffAbi from './PrivateVaultDiffAbi.json' import MainnetVaultDiffAbi from './MainnetVaultDiffAbi.json' import GnosisVaultDiffAbi from './GnosisVaultDiffAbi.json' +import MetaVaultDiffAbi from './MetaVaultDiffAbi.json' import DefaultVaultAbi from './DefaultVaultAbi.json' export { DefaultVaultAbi, + MetaVaultDiffAbi, GnosisVaultDiffAbi, MainnetVaultDiffAbi, PrivateVaultDiffAbi, diff --git a/src/contracts/vault/createVaultContract.ts b/src/contracts/vault/createVaultContract.ts index 82075918..89c88b69 100644 --- a/src/contracts/vault/createVaultContract.ts +++ b/src/contracts/vault/createVaultContract.ts @@ -3,6 +3,7 @@ import type { Provider } from 'ethers' import { DefaultVaultAbi, + MetaVaultDiffAbi, GnosisVaultDiffAbi, MainnetVaultDiffAbi, PrivateVaultDiffAbi, @@ -11,7 +12,8 @@ import { } from './abis' import { - DefaultVaultAbi as DefaultVaultAbiType, + DefaultVaultAbi as DefaultVaultType, + MetaVaultDiffAbi as MetaVaultDiffType, GnosisVaultDiffAbi as GnosisVaultDiffType, MainnetVaultDiffAbi as MainnetVaultDiffType, PrivateVaultDiffAbi as PrivateVaultDiffType, @@ -24,7 +26,7 @@ import createContract from '../createContract' import { ModifiedVault } from '../../services/vault/requests/getVault/types' -type Options = Partial> & { +type Options = Partial> & { chainId?: Network isDepositWithMint?: boolean } @@ -36,8 +38,8 @@ type CreateContractsInput = { type Output = Omit< (T['chainId'] extends Network.Gnosis - ? DefaultVaultAbiType & GnosisVaultDiffType - : DefaultVaultAbiType & MainnetVaultDiffType + ? DefaultVaultType & GnosisVaultDiffType + : DefaultVaultType & MainnetVaultDiffType ) & (T['isBlocklist'] extends true ? BlocklistVaultDiffType @@ -50,7 +52,11 @@ type Output = Omit< (T['isDepositWithMint'] extends true ? DepositWithMintDiffType : object - ), + ) & + (T['isMetaVault'] extends true + ? MetaVaultDiffType + : object + ), 'connect' > & { // overwrite, since each abi returns itself @@ -79,6 +85,10 @@ const createVaultContract = (provider: Provider) => ( baseAbi = baseAbi.concat(DepositWithMintDiffAbi) } + if (options?.isMetaVault) { + baseAbi = baseAbi.concat(MetaVaultDiffAbi) + } + return createContract(vaultAddress, baseAbi, provider) as Output & { connect: () => Output } diff --git a/src/graphql/subgraph/vault/vaultQuery.graphql b/src/graphql/subgraph/vault/vaultQuery.graphql index 4d96c6d9..75970807 100644 --- a/src/graphql/subgraph/vault/vaultQuery.graphql +++ b/src/graphql/subgraph/vault/vaultQuery.graphql @@ -29,9 +29,11 @@ query Vault($address: ID!) { tokenSymbol feeRecipient queuedShares + exitingAssets lastFeePercent blocklistCount whitelistCount + exitingTickets depositDataRoot isCollateralized blocklistManager diff --git a/src/services/vault/requests/getSubVaults/getSubVaults.md b/src/services/vault/requests/getSubVaults/getSubVaults.md index 92859174..d1d4c544 100644 --- a/src/services/vault/requests/getSubVaults/getSubVaults.md +++ b/src/services/vault/requests/getSubVaults/getSubVaults.md @@ -12,6 +12,7 @@ Returns the list of sub vaults. | Name | Type | Required | Description | |------|------|----------|-----------------------------------------------------------| | vaultAddress | `string` | **Yes** | The address of the meta vault | +| search | `string` | **No** | Filters results by the address field | | limit | `number` | **No** | Limits the number of sub vaults returned. Defaults to 100 | | skip | `number` | **No** | Skips the specified number of sub vaults. Defaults to 0 | diff --git a/src/services/vault/requests/getSubVaults/index.ts b/src/services/vault/requests/getSubVaults/index.ts index 2ed90af7..37635dad 100644 --- a/src/services/vault/requests/getSubVaults/index.ts +++ b/src/services/vault/requests/getSubVaults/index.ts @@ -8,6 +8,7 @@ import graphql from '../../../../graphql' export type GetSubVaultsInput = StakeWise.CommonParams & { + search?: string skip: SubVaultsQueryVariables['skip'] limit: SubVaultsQueryVariables['first'] vaultAddress: SubVaultsQueryVariables['where']['metaVault'] @@ -23,25 +24,29 @@ type OutputSubVault = { } const getSubVaults = async (input: GetSubVaultsInput): Promise => { - const { skip, limit, vaultAddress, ...commonParams } = input + const { skip, limit, search, vaultAddress, ...commonParams } = input validateArgs.address({ vaultAddress }) validateArgs.number({ skip, limit }) + if (typeof search !== 'undefined') { + validateArgs.string({ search }) + } + const url = apiUrls.getSubgraphqlUrl(commonParams.options) const metaVaultId = vaultAddress.toLowerCase() + const where = search + ? { metaVault_: { id: metaVaultId }, subVault_contains: search.toLowerCase() } + : { metaVault_: { id: metaVaultId } } + const subVaults = await graphql.subgraph.vault.fetchSubVaultsQuery({ url, variables: { skip, first: limit, - where: { - metaVault_: { - id: metaVaultId, - }, - } as SubVaultsQueryVariables['where'], + where: where as SubVaultsQueryVariables['where'], }, modifyResult:(data: SubVaultsQueryPayload) => data.subVaults.map(((vault) => vault.subVault)), }) diff --git a/src/services/vault/requests/getVault/getVault.md b/src/services/vault/requests/getVault/getVault.md index 79dd3ab2..8461cfe9 100644 --- a/src/services/vault/requests/getVault/getVault.md +++ b/src/services/vault/requests/getVault/getVault.md @@ -34,9 +34,11 @@ type Output = { vaultAddress: string mevRecipient: string queuedShares: string + exitingAssets: string whitelistCount: number lastFeePercent: number blocklistCount: number + exitingTickets: string imageUrl: string | null isSmoothingPool: boolean tokenName: string | null @@ -90,6 +92,8 @@ type Output = { | `performance` | Vault performance indicator (percent) | | `lastFeeUpdateTimestamp` | The timestamp of the last fee update | | `lastFeePercent` | The vault last fee percent | +| `exitingAssets` | The total number of assets that are exiting (in V2 vaults) | +| `exitingTickets` | The total number of tickets that are exiting (in V2 vaults) | | `osTokenConfig` | contains the ltvPercent, which is the percentage used to calculate how much a user can mint in OsToken shares, and thresholdPercent, which is the liquidation threshold percentage used to calculate the health factor for the OsToken position | #### Example: diff --git a/src/services/vault/requests/getVault/modifyVault.spec.ts b/src/services/vault/requests/getVault/modifyVault.spec.ts index 0f1cf9ab..9aa888f4 100644 --- a/src/services/vault/requests/getVault/modifyVault.spec.ts +++ b/src/services/vault/requests/getVault/modifyVault.spec.ts @@ -33,6 +33,8 @@ describe('modifyVault', () => { blocklistCount: '0', whitelistCount: '0', totalAssets: '150000000000', + exitingTickets: '150000000000', + exitingAssets: '150000000000', capacity: '1000000000000000', depositDataRoot: 'mockValidators', description: 'This is a mock vault', @@ -79,6 +81,8 @@ describe('modifyVault', () => { createdAt: 1693395816000, displayName: 'Mock Vault', totalAssets: '0.00000015', + exitingTickets: '0.00000015', + exitingAssets: '0.00000015', depositDataRoot: 'mockValidators', description: 'This is a mock vault', osTokenConfig: { diff --git a/src/services/vault/requests/getVault/modifyVault.ts b/src/services/vault/requests/getVault/modifyVault.ts index 88239919..104cbd98 100644 --- a/src/services/vault/requests/getVault/modifyVault.ts +++ b/src/services/vault/requests/getVault/modifyVault.ts @@ -31,10 +31,12 @@ const modifyVault = (input: ModifyVaultInput): ModifiedVault => { totalAssets, whitelister, feeRecipient, + exitingAssets, osTokenConfig, blocklistCount, lastFeePercent, whitelistCount, + exitingTickets, validatorsManager, depositDataManager, allocatorMaxBoostApy, @@ -57,6 +59,8 @@ const modifyVault = (input: ModifyVaultInput): ModifiedVault => { feeRecipient: getAddress(feeRecipient), blocklistCount: Number(blocklistCount), whitelistCount: Number(whitelistCount), + exitingAssets: formatEther(exitingAssets), + exitingTickets: formatEther(exitingTickets), allocatorMaxBoostApy: Number(allocatorMaxBoostApy), whitelistManager: whitelister ? getAddress(whitelister) : '', validatorsManager: validatorsManager ? getAddress(validatorsManager) : '', diff --git a/src/services/vault/transactions/operate/checkAccess.ts b/src/services/vault/transactions/operate/checkAccess.ts index dd03c81f..e3aa4444 100644 --- a/src/services/vault/transactions/operate/checkAccess.ts +++ b/src/services/vault/transactions/operate/checkAccess.ts @@ -12,8 +12,8 @@ type Action = (values: Input) => Promise const checkAccess = (action: Action) => ( async (values: Input) => { const { - blocklist, whitelist, whitelistManager, feeRecipient, feePercent, - blocklistManager, metadataIpfsHash, validatorsManager, admin, + blocklist, whitelist, whitelistManager, feeRecipient, feePercent, subVaultAddress, + blocklistManager, metadataIpfsHash, validatorsManager, admin, ejectSubVaultAddress, rejectMetaSubVaultAddress, } = values try { @@ -26,10 +26,13 @@ const checkAccess = (action: Action) => ( admin || feePercent || feeRecipient + || subVaultAddress || whitelistManager || blocklistManager || metadataIpfsHash || validatorsManager + || ejectSubVaultAddress + || rejectMetaSubVaultAddress ) const isWhitelistManager = Boolean(whitelist) const isBlocklistManager = Boolean(blocklist) diff --git a/src/services/vault/transactions/operate/common.ts b/src/services/vault/transactions/operate/common.ts index dcda2eef..00daa3bf 100644 --- a/src/services/vault/transactions/operate/common.ts +++ b/src/services/vault/transactions/operate/common.ts @@ -9,8 +9,11 @@ import { getBlocklistParams, getWhitelistParams, getFeePercentParams, + getAddSubVaultParams, getWhitelisterParams, getFeeRecipientParams, + getEjectSubVaultParams, + getRejectSubVaultParams, getBlocklistManagerParams, getValidatorsManagerParams, } from '../util' @@ -19,8 +22,8 @@ import { export const commonLogic = async (values: OperateTransactionInput) => { const { blocklistManager, metadataIpfsHash, admin, feePercent, - blocklist, whitelist, whitelistManager, feeRecipient, - options, contracts, userAddress, vaultAddress, provider, validatorsManager, + blocklist, whitelist, whitelistManager, feeRecipient, subVaultAddress, ejectSubVaultAddress, + options, contracts, userAddress, vaultAddress, provider, validatorsManager, rejectMetaSubVaultAddress, } = values validateArgs.address({ vaultAddress, userAddress }) @@ -28,12 +31,14 @@ export const commonLogic = async (values: OperateTransactionInput) => { const chainId = options.network const isPrivate = Boolean(whitelist?.length || whitelistManager) const isBlocklist = Boolean(blocklist?.length || blocklistManager) + const isMetaVault = Boolean(subVaultAddress || ejectSubVaultAddress || rejectMetaSubVaultAddress) const vaultContract = contracts.helpers.createVault({ vaultAddress, options: { chainId, isPrivate, + isMetaVault, isBlocklist, }, }) @@ -124,6 +129,24 @@ export const commonLogic = async (values: OperateTransactionInput) => { params.push(...adminParams) } + if (subVaultAddress) { + const addSubVaultParams = getAddSubVaultParams({ ...baseInput, subVaultAddress }) + + params.push(...addSubVaultParams) + } + + if (ejectSubVaultAddress) { + const ejectSubVaultParams = getEjectSubVaultParams({ ...baseInput, ejectSubVaultAddress }) + + params.push(...ejectSubVaultParams) + } + + if (rejectMetaSubVaultAddress) { + const rejectSubVaultParams = getRejectSubVaultParams({ ...baseInput, rejectMetaSubVaultAddress }) + + params.push(...rejectSubVaultParams) + } + return { ...baseMulticall, request: { diff --git a/src/services/vault/transactions/operate/operate.md b/src/services/vault/transactions/operate/operate.md index bfba5ad9..e1046e61 100644 --- a/src/services/vault/transactions/operate/operate.md +++ b/src/services/vault/transactions/operate/operate.md @@ -24,6 +24,9 @@ Updates the vault by authorized personnel such as the vault admin, whitelistMana | vaultAddress | `string` | **Yes** | - | The address of the vault | | admin | `string` | **No** | - | Changing the vault administrator | | feePercent | `number` | **No** | Admin | Changing fee percent charged by the vault | +| subVaultAddress | `string` | **No** | Admin | Add a new sub-vault | +| ejectSubVaultAddress | `string` | **No** | Admin | Start ejecting a sub-vault | +| rejectMetaSubVaultAddress | `string` | **No** | Admin or DAO | Cancel pending meta sub-vault | #### Example: @@ -38,9 +41,12 @@ const params = { displayName: '...', description: '...', feeRecipient: '0x...', + subVaultAddress: '0x...', blocklistManager: '0x...', whitelistManager: '0x...', validatorsManager: '0x...', + ejectSubVaultAddress: '0x...', + rejectMetaSubVaultAddress: '0x...', } // Data to update the vault by vault keys manager. diff --git a/src/services/vault/transactions/operate/types.d.ts b/src/services/vault/transactions/operate/types.d.ts index ee0009e0..c0d390de 100644 --- a/src/services/vault/transactions/operate/types.d.ts +++ b/src/services/vault/transactions/operate/types.d.ts @@ -1,11 +1,14 @@ import type { SetAdminParams } from '../util/params/getAdminParams' import type { UploadMetadataInput } from '../util/metadata/uploadMetadata' import type { SetMetadataParams } from '../util/params/getMetadataParams' +import type { AddSubVaultParams } from '../util/params/getAddSubVaultParams' import type { SetFeePercentParams } from '../util/params/getFeePercentParams' import type { UpdateBlocklistParams } from '../util/params/getBlocklistParams' import type { UpdateWhitelistParams } from '../util/params/getWhitelistParams' import type { SetWhitelisterParams } from '../util/params/getWhitelisterParams' import type { SetFeeRecipientParams } from '../util/params/getFeeRecipientParams' +import type { EjectMetaSubVaultParams } from '../util/params/getEjectSubVaultParams' +import type { RejectMetaSubVaultParams } from '../util/params/getRejectSubVaultParams' import type { SetBlocklistManagerParams } from '../util/params/getBlocklistManagerParams' import type { SetValidatorsManagerParams } from '../util/params/getValidatorsManagerParams' @@ -13,10 +16,13 @@ import type { SetValidatorsManagerParams } from '../util/params/getValidatorsMan type OperateCommonParams = SetWhitelisterParams & SetAdminParams + & AddSubVaultParams & SetFeePercentParams & SetFeeRecipientParams & UpdateBlocklistParams & UpdateWhitelistParams + & EjectMetaSubVaultParams + & RejectMetaSubVaultParams & SetBlocklistManagerParams & SetValidatorsManagerParams diff --git a/src/services/vault/transactions/util/params/getAddSubVaultParams.ts b/src/services/vault/transactions/util/params/getAddSubVaultParams.ts new file mode 100644 index 00000000..d681fb08 --- /dev/null +++ b/src/services/vault/transactions/util/params/getAddSubVaultParams.ts @@ -0,0 +1,24 @@ +import { validateArgs } from '../../../../../helpers' +import { vaultMulticall } from '../../../../../contracts' + + +export type AddSubVaultParams = { + subVaultAddress: string +} + +const getAddSubVaultParams = (values: AddSubVaultParams) => { + const { subVaultAddress } = values + + validateArgs.address({ subVaultAddress }) + + const params: Parameters[0]['request']['params'] = [ + { + method: 'addSubVault', args: [ subVaultAddress ], + }, + ] + + return params +} + + +export default getAddSubVaultParams diff --git a/src/services/vault/transactions/util/params/getEjectSubVaultParams.ts b/src/services/vault/transactions/util/params/getEjectSubVaultParams.ts new file mode 100644 index 00000000..70ed4efb --- /dev/null +++ b/src/services/vault/transactions/util/params/getEjectSubVaultParams.ts @@ -0,0 +1,24 @@ +import { validateArgs } from '../../../../../helpers' +import { vaultMulticall } from '../../../../../contracts' + + +export type EjectMetaSubVaultParams = { + ejectSubVaultAddress: string +} + +const getEjectSubVaultParams = (values: EjectMetaSubVaultParams) => { + const { ejectSubVaultAddress } = values + + validateArgs.address({ ejectSubVaultAddress }) + + const params: Parameters[0]['request']['params'] = [ + { + method: 'ejectSubVault', args: [ ejectSubVaultAddress ], + }, + ] + + return params +} + + +export default getEjectSubVaultParams diff --git a/src/services/vault/transactions/util/params/getRejectSubVaultParams.ts b/src/services/vault/transactions/util/params/getRejectSubVaultParams.ts new file mode 100644 index 00000000..55bb37c8 --- /dev/null +++ b/src/services/vault/transactions/util/params/getRejectSubVaultParams.ts @@ -0,0 +1,24 @@ +import { validateArgs } from '../../../../../helpers' +import { vaultMulticall } from '../../../../../contracts' + + +export type RejectMetaSubVaultParams = { + rejectMetaSubVaultAddress: string +} + +const getRejectSubVaultParams = (values: RejectMetaSubVaultParams) => { + const { rejectMetaSubVaultAddress } = values + + validateArgs.address({ rejectMetaSubVaultAddress }) + + const params: Parameters[0]['request']['params'] = [ + { + method: 'rejectMetaSubVault', args: [ rejectMetaSubVaultAddress ], + }, + ] + + return params +} + + +export default getRejectSubVaultParams diff --git a/src/services/vault/transactions/util/params/index.ts b/src/services/vault/transactions/util/params/index.ts index ed827aff..10735dd1 100644 --- a/src/services/vault/transactions/util/params/index.ts +++ b/src/services/vault/transactions/util/params/index.ts @@ -3,7 +3,10 @@ export { default as getMetadataParams } from './getMetadataParams' export { default as getBlocklistParams } from './getBlocklistParams' export { default as getWhitelistParams } from './getWhitelistParams' export { default as getFeePercentParams } from './getFeePercentParams' +export { default as getAddSubVaultParams } from './getAddSubVaultParams' export { default as getWhitelisterParams } from './getWhitelisterParams' export { default as getFeeRecipientParams } from './getFeeRecipientParams' +export { default as getEjectSubVaultParams } from './getEjectSubVaultParams' +export { default as getRejectSubVaultParams } from './getRejectSubVaultParams' export { default as getBlocklistManagerParams } from './getBlocklistManagerParams' export { default as getValidatorsManagerParams } from './getValidatorsManagerParams' From f5adb5ad8af46caffaaa80bab3847a06b76a43d1 Mon Sep 17 00:00:00 2001 From: dfkadyr Date: Fri, 30 Jan 2026 17:27:19 +0300 Subject: [PATCH 05/27] add canHarvest to getVault request --- changelog/next-release.md | 1 + src/graphql/subgraph/vault/vaultQuery.graphql | 1 + src/services/vault/requests/getVault/getVault.md | 2 ++ 3 files changed, 4 insertions(+) diff --git a/changelog/next-release.md b/changelog/next-release.md index dc4f033f..e65d4414 100644 --- a/changelog/next-release.md +++ b/changelog/next-release.md @@ -9,6 +9,7 @@ #### Add output field: ```ts type Output = { + canHarvest: boolen exitingAssets: string exitingTickets: string } diff --git a/src/graphql/subgraph/vault/vaultQuery.graphql b/src/graphql/subgraph/vault/vaultQuery.graphql index 75970807..dffbace0 100644 --- a/src/graphql/subgraph/vault/vaultQuery.graphql +++ b/src/graphql/subgraph/vault/vaultQuery.graphql @@ -19,6 +19,7 @@ query Vault($address: ID!) { mevEscrow tokenName isGenesis + canHarvest feePercent isMetaVault totalAssets diff --git a/src/services/vault/requests/getVault/getVault.md b/src/services/vault/requests/getVault/getVault.md index 8461cfe9..e0b473a8 100644 --- a/src/services/vault/requests/getVault/getVault.md +++ b/src/services/vault/requests/getVault/getVault.md @@ -27,6 +27,7 @@ type Output = { isPrivate: boolean isGenesis: boolean vaultAdmin: string + canHarvest: boolean totalAssets: string performance: number isMetaVault: boolean @@ -85,6 +86,7 @@ type Output = { | `tokenName` | ERC20 token name | | `tokenSymbol` | ERC20 token symbol | | `displayName` | Name of vault | +| `canHarvest` | Defines whether the vault can harvest new rewards | | `allocatorMaxBoostApy` | The average max boost APY earned in this vault by the allocator | | `description` | Description of vault | | `whitelist` | List of authorized users for deposits | From 7a0692b30e7dab8720423c89886aee9656ec1ea6 Mon Sep 17 00:00:00 2001 From: CAst Date: Tue, 3 Feb 2026 18:52:12 +0500 Subject: [PATCH 06/27] Create MetaVault (#341) * [create-metavault] add metavault creation support * [create-metavault] fixes * [create-metavault] improve types --- src/contracts/abis/MetaVaultFactoryAbi.json | 21 ++++ src/contracts/abis/index.js | 3 +- src/contracts/createContracts.ts | 14 +++ src/helpers/configs/gnosis.ts | 6 + src/helpers/configs/hoodi.ts | 6 + src/helpers/configs/mainnet.ts | 6 + src/helpers/enums.ts | 2 + .../requests/getVault/modifyVault.spec.ts | 2 + .../vault/requests/getVaultFactory/index.ts | 4 + .../vault/transactions/createVault/common.ts | 70 ++++++----- .../transactions/createVault/createVault.md | 22 ++-- .../transactions/createVault/createVault.ts | 1 + .../createVault/helpers/getEncodeBytes.ts | 110 ++++++++++++++++++ .../transactions/createVault/helpers/index.ts | 2 + .../{ => helpers}/validateCreateVaultArgs.ts | 38 +++++- src/types/global.ts | 2 + 16 files changed, 261 insertions(+), 48 deletions(-) create mode 100644 src/contracts/abis/MetaVaultFactoryAbi.json create mode 100644 src/services/vault/transactions/createVault/helpers/getEncodeBytes.ts create mode 100644 src/services/vault/transactions/createVault/helpers/index.ts rename src/services/vault/transactions/createVault/{ => helpers}/validateCreateVaultArgs.ts (67%) diff --git a/src/contracts/abis/MetaVaultFactoryAbi.json b/src/contracts/abis/MetaVaultFactoryAbi.json new file mode 100644 index 00000000..750a1dc8 --- /dev/null +++ b/src/contracts/abis/MetaVaultFactoryAbi.json @@ -0,0 +1,21 @@ +[ + { + "inputs": [ + { + "internalType": "bytes", + "name": "params", + "type": "bytes" + } + ], + "name": "createVault", + "outputs": [ + { + "internalType": "address", + "name": "vault", + "type": "address" + } + ], + "stateMutability": "payable", + "type": "function" + } +] diff --git a/src/contracts/abis/index.js b/src/contracts/abis/index.js index 89e66e21..532c3523 100644 --- a/src/contracts/abis/index.js +++ b/src/contracts/abis/index.js @@ -6,7 +6,7 @@ import DepositDataRegistryAbi from './DepositDataRegistryAbi.json' import MintTokenConfigV1Abi from './MintTokenConfigV1Abi.json' import MintTokenConfigV2Abi from './MintTokenConfigV2Abi.json' import LeverageStrategyAbi from './LeverageStrategyAbi.json' - +import MetaVaultFactoryAbi from './MetaVaultFactoryAbi.json' import StakeCalculatorAbi from './StakeCalculatorAbi.json' import VaultsRegistryAbi from './VaultsRegistryAbi.json' import RewardSplitterAbi from './RewardSplitterAbi.json' @@ -31,6 +31,7 @@ export { MintTokenConfigV1Abi, MintTokenConfigV2Abi, LeverageStrategyAbi, + MetaVaultFactoryAbi, StakeCalculatorAbi, VaultsRegistryAbi, RewardSplitterAbi, diff --git a/src/contracts/createContracts.ts b/src/contracts/createContracts.ts index 6b499b97..70d5518d 100644 --- a/src/contracts/createContracts.ts +++ b/src/contracts/createContracts.ts @@ -14,6 +14,7 @@ import { VaultsRegistryAbi, RewardSplitterAbi, StakeCalculatorAbi, + MetaVaultFactoryAbi, LeverageStrategyAbi, MintTokenConfigV1Abi, MintTokenConfigV2Abi, @@ -48,6 +49,13 @@ const getVaultFactory = (provider: Provider, address: string) => createContract< provider ) +const getMetaVaultFactory = (provider: Provider, address: string) => createContract( + address, + MetaVaultFactoryAbi, + provider +) + + const getVaultsRegistry = (provider: Provider, config: StakeWise.Config) => createContract( config.addresses.base.vaultsRegistry, VaultsRegistryAbi, @@ -181,6 +189,12 @@ export const createContracts = (input: CreateContractsInput) => { blocklistVault: getVaultFactory(provider, config.addresses.factories.blocklistVault), erc20BlocklistVault: getVaultFactory(provider, config.addresses.factories.erc20BlocklistVault), + + metavault: getMetaVaultFactory(provider, config.addresses.factories.metavault), + erc20Metavault: getMetaVaultFactory(provider, config.addresses.factories.erc20Metavault), + + privateMetavault: getMetaVaultFactory(provider, config.addresses.factories.privateMetavault), + erc20PrivateMetavault: getMetaVaultFactory(provider, config.addresses.factories.erc20PrivateMetavault), }, special: { stakeCalculator: getStakeCalculator(provider, config), diff --git a/src/helpers/configs/gnosis.ts b/src/helpers/configs/gnosis.ts index e543e4a7..707c3fe8 100644 --- a/src/helpers/configs/gnosis.ts +++ b/src/helpers/configs/gnosis.ts @@ -43,8 +43,14 @@ export default { blocklistVault: '0x608d8Ca6916b96edf63Dd429e62Fe1366ae6f3B5', erc20BlocklistVault: '0x39c6eef5f955bcC280966504bc5c82F2394Fa368', + + metavault: ZeroAddress, + erc20Metavault: ZeroAddress, + privateMetavault: ZeroAddress, + erc20PrivateMetavault: ZeroAddress, }, special: { + balancedCurator: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', stakeCalculator: '0x2A415b65207049AC7481BF69ff9fc1B3Def97c9A', leverageStrategy: ZeroAddress, leverageStrategyV2: ZeroAddress, diff --git a/src/helpers/configs/hoodi.ts b/src/helpers/configs/hoodi.ts index c6b8c58c..2226036a 100644 --- a/src/helpers/configs/hoodi.ts +++ b/src/helpers/configs/hoodi.ts @@ -43,8 +43,14 @@ export default { blocklistVault: '0x608d8Ca6916b96edf63Dd429e62Fe1366ae6f3B5', erc20BlocklistVault: '0x39c6eef5f955bcC280966504bc5c82F2394Fa368', + + metavault: '0x3C97239F12A94b914361F41B51869218a16c2026', + erc20Metavault: '0x94E1adDa4f5ca28aA2549aA9e18D89E3184F8b70', + privateMetavault: '0xe914Cfb2EB9e2d208b19b3E280A3096479491eAd', + erc20PrivateMetavault: '0x6ba3d8DF1ECa6201cc30D5D2E58294B23DAFF221', }, special: { + balancedCurator: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', stakeCalculator: '0xaE9A192Ed2030444eB9323C592F1b85801EA0Ec3', leverageStrategy: '0x154628AC72533aad39aBdcaE2055Dced0b4Eef4D', leverageStrategyV2: '0xe382BD0c48A7dd435bE911e0f663cbCAa94AF965', diff --git a/src/helpers/configs/mainnet.ts b/src/helpers/configs/mainnet.ts index 3a37341b..3c91cd3b 100644 --- a/src/helpers/configs/mainnet.ts +++ b/src/helpers/configs/mainnet.ts @@ -46,8 +46,14 @@ export default { blocklistVault: '0x608d8Ca6916b96edf63Dd429e62Fe1366ae6f3B5', erc20BlocklistVault: '0x39c6eef5f955bcC280966504bc5c82F2394Fa368', + + metavault: ZeroAddress, + erc20Metavault: ZeroAddress, + privateMetavault: ZeroAddress, + erc20PrivateMetavault: ZeroAddress, }, special: { + balancedCurator: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', stakeCalculator: '0x75c57bd50A3EB7291Da3429956D3566E0153A38f', leverageStrategy: '0x48cD14FDB8e72A03C8D952af081DBB127D6281fc', leverageStrategyV2: '0x7575BC9E5168f27B97F9028905A2Adf91d2fF53d', diff --git a/src/helpers/enums.ts b/src/helpers/enums.ts index fa461916..3c06583a 100644 --- a/src/helpers/enums.ts +++ b/src/helpers/enums.ts @@ -12,6 +12,8 @@ export enum VaultType { Default = 'Default', Private = 'Private', Blocklist = 'Blocklist', + MetaVault = 'MetaVault', + PrivateMetaVault = 'PrivateMetaVault', } export enum AllocatorActionType { diff --git a/src/services/vault/requests/getVault/modifyVault.spec.ts b/src/services/vault/requests/getVault/modifyVault.spec.ts index 9aa888f4..2bc8ae40 100644 --- a/src/services/vault/requests/getVault/modifyVault.spec.ts +++ b/src/services/vault/requests/getVault/modifyVault.spec.ts @@ -17,6 +17,7 @@ describe('modifyVault', () => { isGenesis: true, isMetaVault: false, isBlocklist: false, + canHarvest: false, version: '1', performance: '10', tokenSymbol: 'mTKN', @@ -67,6 +68,7 @@ describe('modifyVault', () => { isGenesis: true, isMetaVault: false, isBlocklist: false, + canHarvest: false, blocklistCount: 0, whitelistCount: 0, capacity: '0.001', diff --git a/src/services/vault/requests/getVaultFactory/index.ts b/src/services/vault/requests/getVaultFactory/index.ts index a0aaac83..52fe385c 100644 --- a/src/services/vault/requests/getVaultFactory/index.ts +++ b/src/services/vault/requests/getVaultFactory/index.ts @@ -9,12 +9,16 @@ export type GetVaultFactoryInput = StakeWise.CommonParams & { const getVaultFactory = ({ vaultType, contracts, isErc20 }: GetVaultFactoryInput) => { const vaultFactories = isErc20 ? { [VaultType.Default]: contracts.factories.erc20Vault, + [VaultType.MetaVault]: contracts.factories.erc20Metavault, [VaultType.Private]: contracts.factories.erc20PrivateVault, [VaultType.Blocklist]: contracts.factories.erc20BlocklistVault, + [VaultType.PrivateMetaVault]: contracts.factories.erc20PrivateMetavault, } : { [VaultType.Default]: contracts.factories.vault, + [VaultType.MetaVault]: contracts.factories.metavault, [VaultType.Private]: contracts.factories.privateVault, [VaultType.Blocklist]: contracts.factories.blocklistVault, + [VaultType.PrivateMetaVault]: contracts.factories.privateMetavault, } return vaultFactories[vaultType || VaultType.Default] diff --git a/src/services/vault/transactions/createVault/common.ts b/src/services/vault/transactions/createVault/common.ts index 2d2e2568..32a71fc0 100644 --- a/src/services/vault/transactions/createVault/common.ts +++ b/src/services/vault/transactions/createVault/common.ts @@ -1,19 +1,40 @@ -import { AbiCoder, MaxUint256 } from 'ethers' import type { CreateVaultTransactionInput } from './types' -import validateCreateVaultArgs from './validateCreateVaultArgs' +import getVaultFactory from '../../requests/getVaultFactory' +import { validateCreateVaultArgs, getEncodeBytes } from './helpers' import { PayableOverrides } from '../../../../contracts/types/common' import { constants, Network, validateArgs, VaultType } from '../../../../helpers' export const commonLogic = async (values: CreateVaultTransactionInput) => { const { - type = VaultType.Default, vaultToken, capacity, keysManagerFee, isOwnMevEscrow = false, metadataIpfsHash = '', - contracts, userAddress, options, + options, + capacity, + vaultToken, + userAddress, + keysManagerFee, + isOwnMevEscrow = false, + type = VaultType.Default, } = values + const isMainnet = [ Network.Mainnet, Network.Hoodi ].includes(options.network) + const isMetaVault = [ VaultType.MetaVault, VaultType.PrivateMetaVault ].includes(type) + + const vaultFactory = getVaultFactory({ + ...values, + isErc20: Boolean(vaultToken), + vaultType: type, + }) as typeof isMetaVault extends true + ? StakeWise.ABI.MetaVaultFactory + : StakeWise.ABI.VaultFactory + + validateArgs.address({ userAddress }) validateCreateVaultArgs.vaultType(type) - validateCreateVaultArgs.mevEscrow(isOwnMevEscrow) + validateCreateVaultArgs.metaVault({ type, vaultToken, isMainnet, isOwnMevEscrow }) + + if (!isMetaVault) { + validateCreateVaultArgs.mevEscrow(isOwnMevEscrow) + } if (vaultToken) { validateCreateVaultArgs.vaultToken(vaultToken) @@ -28,42 +49,17 @@ export const commonLogic = async (values: CreateVaultTransactionInput) => { validateCreateVaultArgs.keysManagerFee(keysManagerFee) } - const vaultFactories = vaultToken ? { - [VaultType.Default]: contracts.factories.erc20Vault, - [VaultType.Private]: contracts.factories.erc20PrivateVault, - [VaultType.Blocklist]: contracts.factories.erc20BlocklistVault, - } : { - [VaultType.Default]: contracts.factories.vault, - [VaultType.Private]: contracts.factories.privateVault, - [VaultType.Blocklist]: contracts.factories.blocklistVault, - } - - const vaultFactory = vaultFactories[type] - const defaultAbiCoder = AbiCoder.defaultAbiCoder() + const encodedParams = getEncodeBytes({ ...values, isMetaVault }) - const formattedParams = { - feePercent: (keysManagerFee || 0) * 100, - capacity: capacity || MaxUint256, - symbol: vaultToken?.symbol, - name: vaultToken?.name, - } - - const encodedParams = vaultToken - ? defaultAbiCoder.encode( - [ 'tuple(uint256 capacity, uint16 feePercent, string name, string symbol, string metadataIpfsHash)' ], - [ [ formattedParams.capacity, formattedParams.feePercent, formattedParams.name, formattedParams.symbol, metadataIpfsHash ] ] - ) - : defaultAbiCoder.encode( - [ 'tuple(uint256 capacity, uint16 feePercent, string metadataIpfsHash)' ], - [ [ formattedParams.capacity, formattedParams.feePercent, metadataIpfsHash ] ] - ) - - const isStakeNativeToken = [ Network.Mainnet, Network.Hoodi ].includes(options.network) - - const params: [ string, boolean, PayableOverrides ] = isStakeNativeToken + const params: [ string, boolean, PayableOverrides ] = isMainnet ? [ encodedParams, isOwnMevEscrow, { value: constants.blockchain.gwei } ] : [ encodedParams, isOwnMevEscrow, {} ] + if (isMetaVault) { + // MetaVault does not support isOwnMevEscrow + params.splice(1, 1) + } + return { vaultFactory, params, diff --git a/src/services/vault/transactions/createVault/createVault.md b/src/services/vault/transactions/createVault/createVault.md index 9e9dd2b1..49dcdcbb 100644 --- a/src/services/vault/transactions/createVault/createVault.md +++ b/src/services/vault/transactions/createVault/createVault.md @@ -6,24 +6,30 @@ slug: /vault/transactions/create #### Description: Create a vault. When the transaction is executed, one gwei of the deposit token must be stored in the vault to avoid [inflation attack](https://blog.openzeppelin.com/a-novel-defense-against-erc4626-inflation-attacks). + Pay attention to chains where the deposit token is not a native token such as Gnosis. On these chains before creating the vault, ensure that you call the `approve` function on the deposit token contract, allowing the vault factory address to spend one gwei. + You can retrieve the vault factory contract using the helper function: `sdk.getVaultFactory({ vaultType: params.type, isErc20: params.isErc20 })`. +**Important**: When creating a metavault on Gnosis, only the default vault type is supported. ERC20 tokens and private vaults are not available. Additionally, all metavaults do not support the `isOwnMevEscrow` parameter. + + + #### Arguments: | Name | Type | Required | Description | |----------------|------------------------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------| -| userAddress | `string` | **Yes** | The address of the user initiating the action. This address will become the vault admin | +| userAddress | `string` | **Yes** | The address of the user initiating the action. This address will become the vault admin | | type | `VaultType` | **No** | Allowed vault types: Default, Private and Blocklist. Available vault types can be found in the `enum VaultType` which you can be imported from the library | -| vaultToken | `{ name: string, symbol: string }` | **No** | If provided, the vault will be created with its own ERC20 token | -| capacity | `bigint` | **No** | If provided, should be defined in gwei. By default, capacity is `MaxUint256`; the minimum allowed capacity is `parseEther('32')` | -| keysManagerFee | `number` | **No** | If provided, should be between `0` and `100`, inclusive with a maximum of two decimal digits allowed (e.g., `15.35`). By default, the fee is `0` | -| isOwnMevEscrow | `boolean` | **No** | Defines whether to send block rewards to the Smoothing Pool (`false`) or keep them only to your Vault (`true`). By default, this value is `false` | -| image | `string` | **No** | The vault image in base64 string format (will be uploaded to IPFS; maximum size is 1 MB) | -| displayName | `string` | **No** | The vault display name (will be uploaded to IPFS; maximum size is 30 characters) | -| description | `string` | **No** | The vault description (will be uploaded to IPFS; maximum size is 1000 characters) | +| vaultToken | `{ name: string, symbol: string }` | **No** | If provided, the vault will be created with its own ERC20 token | +| capacity | `bigint` | **No** | If provided, should be defined in gwei. By default, capacity is `MaxUint256`; the minimum allowed capacity is `parseEther('32')`| +| keysManagerFee | `number` | **No** | If provided, should be between `0` and `100`, inclusive with a maximum of two decimal digits allowed (e.g., `15.35`). By default, the fee is `0`| +| isOwnMevEscrow | `boolean` | **No** | Defines whether to send block rewards to the Smoothing Pool (`false`) or keep them only to your Vault (`true`). By default, this value is `false`. **Note**: This parameter is not supported for metavaults| +| image | `string` | **No** | The vault image in base64 string format (will be uploaded to IPFS; maximum size is 1 MB)| +| displayName | `string` | **No** | The vault display name (will be uploaded to IPFS; maximum size is 30 characters)| +| description | `string` | **No** | The vault description (will be uploaded to IPFS; maximum size is 1000 characters)| #### Example: diff --git a/src/services/vault/transactions/createVault/createVault.ts b/src/services/vault/transactions/createVault/createVault.ts index d8b1be94..dfebfad5 100644 --- a/src/services/vault/transactions/createVault/createVault.ts +++ b/src/services/vault/transactions/createVault/createVault.ts @@ -12,6 +12,7 @@ const create = async (values: CreateVaultInput) => { const { vaultFactory, params } = await commonLogic({ metadataIpfsHash, ...rest }) const signer = await provider.getSigner(userAddress) + const signedContract = vaultFactory.connect(signer) const response = await wrapErrorHandler( diff --git a/src/services/vault/transactions/createVault/helpers/getEncodeBytes.ts b/src/services/vault/transactions/createVault/helpers/getEncodeBytes.ts new file mode 100644 index 00000000..c7c3e599 --- /dev/null +++ b/src/services/vault/transactions/createVault/helpers/getEncodeBytes.ts @@ -0,0 +1,110 @@ +import { AbiCoder, MaxUint256 } from 'ethers' + +import { configs } from '../../../../../helpers' +import type { CreateVaultTransactionInput } from '../types' + + +type EncodeBytesInput = Pick & { + isMetaVault: boolean + options: StakeWise.Options +} + +type GetTupleInput = Array<{ + type: keyof typeof tuple + value: any +}> + +const tuple = { + tokenName: 'string name', + tokenSymbol: 'string symbol', + capacity: 'uint256 capacity', + feePercent: 'uint16 feePercent', + metadata: 'string metadataIpfsHash', + curator: 'address subVaultsCurator', +} + +const _getTuple = (values: GetTupleInput) => { + let params: any[] = [] + let types = 'tuple(' + + values.forEach((item, index) => { + types += `${tuple[item.type]}` + params.push(item.value) + + if (values.length - 1 > index) { + types += ', ' + } + }) + + types += ')' + + return { + types: [ types ], + params: [ params ], + } +} + +const getEncodeBytes = (values: EncodeBytesInput) => { + const { options, vaultToken, keysManagerFee, capacity, metadataIpfsHash, isMetaVault } = values + + const defaultAbiCoder = AbiCoder.defaultAbiCoder() + + const data = { + metadataIpfsHash: metadataIpfsHash || '', + feePercent: (keysManagerFee || 0) * 100, + capacity: capacity || MaxUint256, + symbol: vaultToken?.symbol, + name: vaultToken?.name, + } + + let encodedParams: GetTupleInput = [] + + if (isMetaVault) { + encodedParams.push({ + type: 'curator', + value: configs[options.network].addresses.special.balancedCurator, + }) + } + + encodedParams.push( + { + type: 'capacity', + value: data.capacity, + }, + { + type: 'feePercent', + value: data.feePercent, + } + ) + + if (vaultToken) { + encodedParams.push( + { + type: 'tokenName', + value: data.name, + }, + { + type: 'tokenSymbol', + value: data.symbol, + } + ) + } + + encodedParams.push({ + type: 'metadata', + value: data.metadataIpfsHash, + }) + + const { types, params } = _getTuple(encodedParams) + + return defaultAbiCoder.encode(types, params) +} + + +export default getEncodeBytes diff --git a/src/services/vault/transactions/createVault/helpers/index.ts b/src/services/vault/transactions/createVault/helpers/index.ts new file mode 100644 index 00000000..e6caf8bb --- /dev/null +++ b/src/services/vault/transactions/createVault/helpers/index.ts @@ -0,0 +1,2 @@ +export { default as validateCreateVaultArgs } from './validateCreateVaultArgs' +export { default as getEncodeBytes } from './getEncodeBytes' diff --git a/src/services/vault/transactions/createVault/validateCreateVaultArgs.ts b/src/services/vault/transactions/createVault/helpers/validateCreateVaultArgs.ts similarity index 67% rename from src/services/vault/transactions/createVault/validateCreateVaultArgs.ts rename to src/services/vault/transactions/createVault/helpers/validateCreateVaultArgs.ts index b559f19d..fde3eb72 100644 --- a/src/services/vault/transactions/createVault/validateCreateVaultArgs.ts +++ b/src/services/vault/transactions/createVault/helpers/validateCreateVaultArgs.ts @@ -1,5 +1,7 @@ import { MaxUint256 } from 'ethers' -import { VaultType, constants } from '../../../../helpers' + +import { CreateVaultCommonInput } from '../types' +import { VaultType, constants } from '../../../../../helpers' const capacity = (value: bigint) => { @@ -26,7 +28,7 @@ const vaultType = (value: VaultType) => { } } -const vaultToken = (vaultToken: { name: string, symbol: string }) => { +const vaultToken = (vaultToken: CreateVaultCommonInput['vaultToken']) => { if (typeof vaultToken !== 'object') { throw new Error(`The "vaultToken" argument must be an object`) } @@ -65,9 +67,41 @@ const keysManagerFee = (value: number) => { } } +type GnosisMetaVaultInput = Pick & { + isMainnet: boolean +} + +const metaVault = (values: GnosisMetaVaultInput) => { + const { type, vaultToken, isMainnet, isOwnMevEscrow } = values + + const isMetaVault = [ + VaultType.MetaVault, + VaultType.PrivateMetaVault, + ].includes(type as VaultType) + + if (isMetaVault) { + return + } + + if (isOwnMevEscrow) { + throw new Error('MetaVault does not support the "isOwnMevEscrow" parameter.') + } + + if (!isMainnet) { + if (vaultToken) { + throw new Error('MetaVault does not support the ERC20 token on gnosis chain.') + } + + if (type === VaultType.PrivateMetaVault) { + throw new Error('Gnosis chain does not support private MetaVault.') + } + } +} + export default { capacity, + metaVault, mevEscrow, vaultType, vaultToken, diff --git a/src/types/global.ts b/src/types/global.ts index 29442c2d..9b8011ad 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -24,6 +24,7 @@ import type { RewardSplitterAbi, StakeCalculatorAbi, LeverageStrategyAbi, + MetaVaultFactoryAbi, MintTokenConfigV1Abi, MintTokenConfigV2Abi, DepositDataRegistryAbi, @@ -120,6 +121,7 @@ declare global { type RewardSplitter = RewardSplitterAbi type VaultsRegistry = VaultsRegistryAbi type StakeCalculator = StakeCalculatorAbi + type MetaVaultFactory = MetaVaultFactoryAbi type LeverageStrategy = LeverageStrategyAbi type MintTokenConfigV1 = MintTokenConfigV1Abi type MintTokenConfigV2 = MintTokenConfigV2Abi From 3c09390f03107c3349c72b70dbf8dd67d9dc2411 Mon Sep 17 00:00:00 2001 From: Kadyr Dzhemaledinov Date: Tue, 17 Feb 2026 17:18:31 +0300 Subject: [PATCH 07/27] Add subvault (#344) * add ejectingSubVault and pendingMetaSubVault fields to vault * add new methods to sub-vaults (add, eject, reject) --- .graphqlconfig | 2 +- changelog/next-release.md | 17 ++++----- codegen.ts | 2 +- .../SubVaultsRegistryAbi.json} | 26 -------------- src/contracts/abis/index.js | 2 ++ src/contracts/createContracts.ts | 8 +++++ src/contracts/vault/abis/index.js | 2 -- src/contracts/vault/createVaultContract.ts | 14 ++------ src/graphql/subgraph/vault/vaultQuery.graphql | 3 ++ src/helpers/configs/hoodi.ts | 2 +- .../vault/requests/getVault/getVault.md | 7 ++++ .../requests/getVault/modifyVault.spec.ts | 6 ++++ .../vault/requests/getVault/modifyVault.ts | 6 ++++ .../transactions/addSubVault/addSubVault.md | 35 +++++++++++++++++++ .../transactions/addSubVault/addSubVault.ts | 24 +++++++++++++ .../addSubVault/addSubVaultEncode.ts | 12 +++++++ .../addSubVault/addSubVaultGas.ts | 23 ++++++++++++ .../transactions/addSubVault/checkAccess.ts | 25 +++++++++++++ .../vault/transactions/addSubVault/common.ts | 11 ++++++ .../vault/transactions/addSubVault/index.ts | 15 ++++++++ .../vault/transactions/addSubVault/types.d.ts | 12 +++++++ .../transactions/ejectSubVault/checkAccess.ts | 25 +++++++++++++ .../transactions/ejectSubVault/common.ts | 11 ++++++ .../ejectSubVault/ejectSubVault.md | 35 +++++++++++++++++++ .../ejectSubVault/ejectSubVault.ts | 24 +++++++++++++ .../ejectSubVault/ejectSubVaultEncode.ts | 12 +++++++ .../ejectSubVault/ejectSubVaultGas.ts | 23 ++++++++++++ .../vault/transactions/ejectSubVault/index.ts | 15 ++++++++ .../transactions/ejectSubVault/types.d.ts | 12 +++++++ src/services/vault/transactions/index.ts | 24 +++++++++++++ .../vault/transactions/operate/checkAccess.ts | 7 ++-- .../vault/transactions/operate/common.ts | 27 ++------------ .../vault/transactions/operate/operate.md | 7 ---- .../vault/transactions/operate/types.d.ts | 6 ---- .../rejectSubVault/checkAccess.ts | 25 +++++++++++++ .../transactions/rejectSubVault/common.ts | 11 ++++++ .../transactions/rejectSubVault/index.ts | 15 ++++++++ .../rejectSubVault/rejectSubVault.md | 35 +++++++++++++++++++ .../rejectSubVault/rejectSubVault.ts | 24 +++++++++++++ .../rejectSubVault/rejectSubVaultEncode.ts | 12 +++++++ .../rejectSubVault/rejectSubVaultGas.ts | 23 ++++++++++++ .../transactions/rejectSubVault/types.d.ts | 12 +++++++ .../util/params/getAddSubVaultParams.ts | 24 ------------- .../util/params/getEjectSubVaultParams.ts | 24 ------------- .../util/params/getRejectSubVaultParams.ts | 24 ------------- .../vault/transactions/util/params/index.ts | 3 -- src/types/global.ts | 2 ++ 47 files changed, 544 insertions(+), 172 deletions(-) rename src/contracts/{vault/abis/MetaVaultDiffAbi.json => abis/SubVaultsRegistryAbi.json} (61%) create mode 100644 src/services/vault/transactions/addSubVault/addSubVault.md create mode 100644 src/services/vault/transactions/addSubVault/addSubVault.ts create mode 100644 src/services/vault/transactions/addSubVault/addSubVaultEncode.ts create mode 100644 src/services/vault/transactions/addSubVault/addSubVaultGas.ts create mode 100644 src/services/vault/transactions/addSubVault/checkAccess.ts create mode 100644 src/services/vault/transactions/addSubVault/common.ts create mode 100644 src/services/vault/transactions/addSubVault/index.ts create mode 100644 src/services/vault/transactions/addSubVault/types.d.ts create mode 100644 src/services/vault/transactions/ejectSubVault/checkAccess.ts create mode 100644 src/services/vault/transactions/ejectSubVault/common.ts create mode 100644 src/services/vault/transactions/ejectSubVault/ejectSubVault.md create mode 100644 src/services/vault/transactions/ejectSubVault/ejectSubVault.ts create mode 100644 src/services/vault/transactions/ejectSubVault/ejectSubVaultEncode.ts create mode 100644 src/services/vault/transactions/ejectSubVault/ejectSubVaultGas.ts create mode 100644 src/services/vault/transactions/ejectSubVault/index.ts create mode 100644 src/services/vault/transactions/ejectSubVault/types.d.ts create mode 100644 src/services/vault/transactions/rejectSubVault/checkAccess.ts create mode 100644 src/services/vault/transactions/rejectSubVault/common.ts create mode 100644 src/services/vault/transactions/rejectSubVault/index.ts create mode 100644 src/services/vault/transactions/rejectSubVault/rejectSubVault.md create mode 100644 src/services/vault/transactions/rejectSubVault/rejectSubVault.ts create mode 100644 src/services/vault/transactions/rejectSubVault/rejectSubVaultEncode.ts create mode 100644 src/services/vault/transactions/rejectSubVault/rejectSubVaultGas.ts create mode 100644 src/services/vault/transactions/rejectSubVault/types.d.ts delete mode 100644 src/services/vault/transactions/util/params/getAddSubVaultParams.ts delete mode 100644 src/services/vault/transactions/util/params/getEjectSubVaultParams.ts delete mode 100644 src/services/vault/transactions/util/params/getRejectSubVaultParams.ts diff --git a/.graphqlconfig b/.graphqlconfig index 45328b40..14330f00 100644 --- a/.graphqlconfig +++ b/.graphqlconfig @@ -11,7 +11,7 @@ "extensions": { "endpoints": { "Subgraph GraphQL": { - "url": "https://graphs.stakewise.io/hoodi/subgraphs/name/stakewise/prod", + "url": "https://graphs.stakewise.io/hoodi/subgraphs/name/stakewise/stage", "headers": { "user-agent": "JS GraphQL" }, diff --git a/changelog/next-release.md b/changelog/next-release.md index e65d4414..43fcf3c4 100644 --- a/changelog/next-release.md +++ b/changelog/next-release.md @@ -1,6 +1,9 @@ ## Added methods - [sdk.vault.getSubVaults](https://docs.stakewise.io/vault/requests/getsubvaults) +- [sdk.vault.addSubVault](https://docs.stakewise.io/vault/transactions/addsubvault) +- [sdk.vault.rejectSubVault](https://docs.stakewise.io/vault/transactions/rejectsubvault) +- [sdk.vault.ejectSubVault](https://docs.stakewise.io/vault/transactions/ejectsubvault) ## Modified methods @@ -12,16 +15,8 @@ type Output = { canHarvest: boolen exitingAssets: string exitingTickets: string -} -``` - -### 2. [signSDK.vault.operate](https://docs.stakewise.io/vault/transactions/operate) - -#### Add new params field to update sub-vault addresses: -```ts -type Output = { - subVaultAddress: string - ejectSubVaultAddress: string - rejectMetaSubVaultAddress: string + ejectingSubVault: string + subVaultsRegistry: string + pendingMetaSubVault: string } ``` diff --git a/codegen.ts b/codegen.ts index b9cbb7c2..947586ff 100644 --- a/codegen.ts +++ b/codegen.ts @@ -3,7 +3,7 @@ import { Network } from './src/helpers/enums' import configs from './src/helpers/configs' -let network: Network = Network.Mainnet +let network: Network = Network.Hoodi if (process.env.NETWORK === 'mainnet') { network = Network.Mainnet diff --git a/src/contracts/vault/abis/MetaVaultDiffAbi.json b/src/contracts/abis/SubVaultsRegistryAbi.json similarity index 61% rename from src/contracts/vault/abis/MetaVaultDiffAbi.json rename to src/contracts/abis/SubVaultsRegistryAbi.json index d6f2d43b..83e825cb 100644 --- a/src/contracts/vault/abis/MetaVaultDiffAbi.json +++ b/src/contracts/abis/SubVaultsRegistryAbi.json @@ -12,32 +12,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [], - "name": "pendingMetaSubVault", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "ejectingSubVault", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, { "inputs": [ { diff --git a/src/contracts/abis/index.js b/src/contracts/abis/index.js index 532c3523..26f47ca7 100644 --- a/src/contracts/abis/index.js +++ b/src/contracts/abis/index.js @@ -3,6 +3,7 @@ import VestingEscrowFactoryAbi from './VestingEscrowFactoryAbi.json' import MintTokenControllerAbi from './MintTokenControllerAbi.json' import MerkleDistributorV2Abi from './MerkleDistributorV2Abi.json' import DepositDataRegistryAbi from './DepositDataRegistryAbi.json' +import SubVaultsRegistryAbi from './SubVaultsRegistryAbi.json' import MintTokenConfigV1Abi from './MintTokenConfigV1Abi.json' import MintTokenConfigV2Abi from './MintTokenConfigV2Abi.json' import LeverageStrategyAbi from './LeverageStrategyAbi.json' @@ -28,6 +29,7 @@ export { MintTokenControllerAbi, MerkleDistributorV2Abi, DepositDataRegistryAbi, + SubVaultsRegistryAbi, MintTokenConfigV1Abi, MintTokenConfigV2Abi, LeverageStrategyAbi, diff --git a/src/contracts/createContracts.ts b/src/contracts/createContracts.ts index 70d5518d..087e3a2c 100644 --- a/src/contracts/createContracts.ts +++ b/src/contracts/createContracts.ts @@ -18,6 +18,7 @@ import { LeverageStrategyAbi, MintTokenConfigV1Abi, MintTokenConfigV2Abi, + SubVaultsRegistryAbi, DepositDataRegistryAbi, MerkleDistributorV2Abi, MintTokenControllerAbi, @@ -116,6 +117,12 @@ const getDepositDataRegistry = (provider: Provider, config: StakeWise.Config) => provider ) +const getSubVaultsRegistry = (provider: Provider, address: string) => createContract( + address, + SubVaultsRegistryAbi, + provider +) + const getMerkleDistributorV2 = (provider: Provider, config: StakeWise.Config) => createContract( config.addresses.special.merkleDistributorV2, MerkleDistributorV2Abi, @@ -174,6 +181,7 @@ export const createContracts = (input: CreateContractsInput) => { depositDataRegistry: getDepositDataRegistry(provider, config), mintTokenController: getMintTokenController(provider, config), rewardSplitterFactory: getRewardSplitterFactory(provider, config), + subVaultsRegistry: (address: string) => getSubVaultsRegistry(provider, address), }, tokens: { mintToken: getMintToken(provider, config), diff --git a/src/contracts/vault/abis/index.js b/src/contracts/vault/abis/index.js index aa04d95c..07cf2f46 100644 --- a/src/contracts/vault/abis/index.js +++ b/src/contracts/vault/abis/index.js @@ -3,13 +3,11 @@ import BlocklistVaultDiffAbi from './BlocklistVaultDiffAbi.json' import PrivateVaultDiffAbi from './PrivateVaultDiffAbi.json' import MainnetVaultDiffAbi from './MainnetVaultDiffAbi.json' import GnosisVaultDiffAbi from './GnosisVaultDiffAbi.json' -import MetaVaultDiffAbi from './MetaVaultDiffAbi.json' import DefaultVaultAbi from './DefaultVaultAbi.json' export { DefaultVaultAbi, - MetaVaultDiffAbi, GnosisVaultDiffAbi, MainnetVaultDiffAbi, PrivateVaultDiffAbi, diff --git a/src/contracts/vault/createVaultContract.ts b/src/contracts/vault/createVaultContract.ts index 89c88b69..c51aab1b 100644 --- a/src/contracts/vault/createVaultContract.ts +++ b/src/contracts/vault/createVaultContract.ts @@ -3,7 +3,6 @@ import type { Provider } from 'ethers' import { DefaultVaultAbi, - MetaVaultDiffAbi, GnosisVaultDiffAbi, MainnetVaultDiffAbi, PrivateVaultDiffAbi, @@ -13,7 +12,6 @@ import { import { DefaultVaultAbi as DefaultVaultType, - MetaVaultDiffAbi as MetaVaultDiffType, GnosisVaultDiffAbi as GnosisVaultDiffType, MainnetVaultDiffAbi as MainnetVaultDiffType, PrivateVaultDiffAbi as PrivateVaultDiffType, @@ -26,7 +24,7 @@ import createContract from '../createContract' import { ModifiedVault } from '../../services/vault/requests/getVault/types' -type Options = Partial> & { +type Options = Partial> & { chainId?: Network isDepositWithMint?: boolean } @@ -52,11 +50,7 @@ type Output = Omit< (T['isDepositWithMint'] extends true ? DepositWithMintDiffType : object - ) & - (T['isMetaVault'] extends true - ? MetaVaultDiffType - : object - ), + ), 'connect' > & { // overwrite, since each abi returns itself @@ -85,10 +79,6 @@ const createVaultContract = (provider: Provider) => ( baseAbi = baseAbi.concat(DepositWithMintDiffAbi) } - if (options?.isMetaVault) { - baseAbi = baseAbi.concat(MetaVaultDiffAbi) - } - return createContract(vaultAddress, baseAbi, provider) as Output & { connect: () => Output } diff --git a/src/graphql/subgraph/vault/vaultQuery.graphql b/src/graphql/subgraph/vault/vaultQuery.graphql index dffbace0..91ea4013 100644 --- a/src/graphql/subgraph/vault/vaultQuery.graphql +++ b/src/graphql/subgraph/vault/vaultQuery.graphql @@ -38,8 +38,11 @@ query Vault($address: ID!) { depositDataRoot isCollateralized blocklistManager + ejectingSubVault validatorsManager + subVaultsRegistry depositDataManager + pendingMetaSubVault allocatorMaxBoostApy lastFeeUpdateTimestamp } diff --git a/src/helpers/configs/hoodi.ts b/src/helpers/configs/hoodi.ts index 2226036a..6a7ad167 100644 --- a/src/helpers/configs/hoodi.ts +++ b/src/helpers/configs/hoodi.ts @@ -7,7 +7,7 @@ export default { network: constants.chains.hoodi, api: { backend: 'https://hoodi-api.stakewise.io/graphql', - subgraph: 'https://graphs.stakewise.io/hoodi/subgraphs/name/stakewise/prod', + subgraph: 'https://graphs.stakewise.io/hoodi/subgraphs/name/stakewise/stage', }, pages: { beaconchain: 'https://hoodi.beaconcha.in/', diff --git a/src/services/vault/requests/getVault/getVault.md b/src/services/vault/requests/getVault/getVault.md index e0b473a8..429dc9f7 100644 --- a/src/services/vault/requests/getVault/getVault.md +++ b/src/services/vault/requests/getVault/getVault.md @@ -44,8 +44,12 @@ type Output = { isSmoothingPool: boolean tokenName: string | null whitelistManager: string + whitelistManager: string blocklistManager: string + ejectingSubVault: string + subVaultsRegistry: string depositDataManager: string + pendingMetaSubVault: string tokenSymbol: string | null displayName: string | null description: string | null @@ -86,6 +90,8 @@ type Output = { | `tokenName` | ERC20 token name | | `tokenSymbol` | ERC20 token symbol | | `displayName` | Name of vault | +| `pendingMetaSubVault` | The address of the meta vault that is pending to join as a sub vault | +| `ejectingSubVault` | The address of the sub vault currently being ejected (for meta vaults) | | `canHarvest` | Defines whether the vault can harvest new rewards | | `allocatorMaxBoostApy` | The average max boost APY earned in this vault by the allocator | | `description` | Description of vault | @@ -96,6 +102,7 @@ type Output = { | `lastFeePercent` | The vault last fee percent | | `exitingAssets` | The total number of assets that are exiting (in V2 vaults) | | `exitingTickets` | The total number of tickets that are exiting (in V2 vaults) | +| `subVaultsRegistry` | The address of the SubVaultsRegistry contract (for meta vaults v4+ on Gnosis, v6+ on mainnet/hoodi) | | `osTokenConfig` | contains the ltvPercent, which is the percentage used to calculate how much a user can mint in OsToken shares, and thresholdPercent, which is the liquidation threshold percentage used to calculate the health factor for the OsToken position | #### Example: diff --git a/src/services/vault/requests/getVault/modifyVault.spec.ts b/src/services/vault/requests/getVault/modifyVault.spec.ts index 2bc8ae40..2e52bd5f 100644 --- a/src/services/vault/requests/getVault/modifyVault.spec.ts +++ b/src/services/vault/requests/getVault/modifyVault.spec.ts @@ -45,9 +45,12 @@ describe('modifyVault', () => { mevEscrow: '0xeefffd4c23d2e8c845870e273861e7d60df49663', whitelister: '0xeefffd4c23d2e8c845870e273861e7d60df49663', feeRecipient: '0xeefffd4c23d2e8c845870e273861e7d60df49663', + ejectingSubVault: '0xeefffd4c23d2e8c845870e273861e7d60df49663', blocklistManager: '0xeefffd4c23d2e8c845870e273861e7d60df49663', + subVaultsRegistry: '0xeefffd4c23d2e8c845870e273861e7d60df49663', validatorsManager: '0xeefffd4c23d2e8c845870e273861e7d60df49663', depositDataManager: '0xeefffd4c23d2e8c845870e273861e7d60df49663', + pendingMetaSubVault: '0xeefffd4c23d2e8c845870e273861e7d60df49663', osTokenConfig: { ltvPercent: '0', liqThresholdPercent: '0', @@ -98,7 +101,10 @@ describe('modifyVault', () => { whitelistManager: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', blocklistManager: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', validatorsManager: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', + subVaultsRegistry: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', depositDataManager: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', + ejectingSubVault: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', + pendingMetaSubVault: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', } const result = modifyVault({ diff --git a/src/services/vault/requests/getVault/modifyVault.ts b/src/services/vault/requests/getVault/modifyVault.ts index 104cbd98..d73cf2ef 100644 --- a/src/services/vault/requests/getVault/modifyVault.ts +++ b/src/services/vault/requests/getVault/modifyVault.ts @@ -37,8 +37,11 @@ const modifyVault = (input: ModifyVaultInput): ModifiedVault => { lastFeePercent, whitelistCount, exitingTickets, + ejectingSubVault, validatorsManager, + subVaultsRegistry, depositDataManager, + pendingMetaSubVault, allocatorMaxBoostApy, ...rest } = vault @@ -63,8 +66,11 @@ const modifyVault = (input: ModifyVaultInput): ModifiedVault => { exitingTickets: formatEther(exitingTickets), allocatorMaxBoostApy: Number(allocatorMaxBoostApy), whitelistManager: whitelister ? getAddress(whitelister) : '', + ejectingSubVault: ejectingSubVault ? getAddress(ejectingSubVault) : '', validatorsManager: validatorsManager ? getAddress(validatorsManager) : '', + subVaultsRegistry: subVaultsRegistry ? getAddress(subVaultsRegistry) : '', depositDataManager: depositDataManager ? getAddress(depositDataManager) : '', + pendingMetaSubVault: pendingMetaSubVault ? getAddress(pendingMetaSubVault) : '', blocklistManager: vault.blocklistManager ? getAddress(vault.blocklistManager) : '', mevRecipient: mevEscrow ? getAddress(mevEscrow) diff --git a/src/services/vault/transactions/addSubVault/addSubVault.md b/src/services/vault/transactions/addSubVault/addSubVault.md new file mode 100644 index 00000000..1f73e5fc --- /dev/null +++ b/src/services/vault/transactions/addSubVault/addSubVault.md @@ -0,0 +1,35 @@ +--- +id: addSubVault +slug: /vault/transactions/addsubvault +--- + +#### Description: + +Adding a new sub-vault to the vault registry. + +#### Arguments: + +| Name | Type | Required | Description | +|----------------|----------|----------|---------------------------| +| subVaultAddress | `string` | **Yes** | New sub-vault address | +| userAddress | `string` | **Yes** | The user address | +| vaultAddress | `string` | **Yes** | The address of the vault | +| subVaultsRegistryAddress | `string` | **Yes** | The sub-vault registry address | + +#### Example: + +```ts +const params = { + subVaultsRegistryAddress: '0x...', + subVaultAddress: '0x...', + vaultAddress: '0x...', + userAddress: '0x...', +} + +// Send transaction +const hash = await sdk.vault.addSubVault(params) +// When you sign transactions on the backend (for custodians) +const { data, to } = await sdk.vault.addSubVault.encode(params) +// Get an approximate gas per transaction +const gas = await sdk.vault.addSubVault.estimateGas(params) +``` diff --git a/src/services/vault/transactions/addSubVault/addSubVault.ts b/src/services/vault/transactions/addSubVault/addSubVault.ts new file mode 100644 index 00000000..b3336626 --- /dev/null +++ b/src/services/vault/transactions/addSubVault/addSubVault.ts @@ -0,0 +1,24 @@ +import { commonLogic } from './common' +import checkAccess from './checkAccess' +import type { AddSubVaultInput } from './types' +import { wrapErrorHandler } from '../../../../helpers' + + +const addSubVault = checkAccess(async (values: AddSubVaultInput) => { + const { provider, userAddress, subVaultAddress } = values + + const signer = await provider.getSigner(userAddress) + + const contract = commonLogic(values) + const signedContract = contract.connect(signer) + + const result = await wrapErrorHandler( + signedContract.addSubVault(subVaultAddress), + 'transaction' + ) + + return result?.hash +}) + + +export default addSubVault diff --git a/src/services/vault/transactions/addSubVault/addSubVaultEncode.ts b/src/services/vault/transactions/addSubVault/addSubVaultEncode.ts new file mode 100644 index 00000000..c96c5d0d --- /dev/null +++ b/src/services/vault/transactions/addSubVault/addSubVaultEncode.ts @@ -0,0 +1,12 @@ +import { commonLogic } from './common' +import type { AddSubVaultInput } from './types' + + +const addSubVaultEncode = async (values: AddSubVaultInput) => { + const contract = commonLogic(values) + + return contract.addSubVault.populateTransaction(values.subVaultAddress) +} + + +export default addSubVaultEncode diff --git a/src/services/vault/transactions/addSubVault/addSubVaultGas.ts b/src/services/vault/transactions/addSubVault/addSubVaultGas.ts new file mode 100644 index 00000000..fa0b0d4c --- /dev/null +++ b/src/services/vault/transactions/addSubVault/addSubVaultGas.ts @@ -0,0 +1,23 @@ +import { commonLogic } from './common' +import { getGas, wrapErrorHandler } from '../../../../helpers' +import type { AddSubVaultInput } from './types' + + +const addSubVaultGas = async (values: AddSubVaultInput) => { + const { provider, userAddress, subVaultAddress } = values + + const contract = commonLogic(values) + + const signer = await provider.getSigner(userAddress) + const signedContract = contract.connect(signer) + + const estimatedGas = await wrapErrorHandler( + signedContract.addSubVault.estimateGas(subVaultAddress), + 'transaction' + ) + + return getGas({ estimatedGas, provider: values.provider }) +} + + +export default addSubVaultGas diff --git a/src/services/vault/transactions/addSubVault/checkAccess.ts b/src/services/vault/transactions/addSubVault/checkAccess.ts new file mode 100644 index 00000000..d343be14 --- /dev/null +++ b/src/services/vault/transactions/addSubVault/checkAccess.ts @@ -0,0 +1,25 @@ +import { checkAdminAccess } from '../util' +import type { AddSubVaultInput as Input } from './types' + + +type Action = (values: Input) => Promise + +const checkAccess = (action: Action) => ( + async (values: Input) => { + try { + const result = await action(values) + + return result + } + catch (actionError) { + return checkAdminAccess(values) + .then( + () => Promise.reject(actionError), + (error) => Promise.reject(error) + ) + } + } +) + + +export default checkAccess diff --git a/src/services/vault/transactions/addSubVault/common.ts b/src/services/vault/transactions/addSubVault/common.ts new file mode 100644 index 00000000..684ae715 --- /dev/null +++ b/src/services/vault/transactions/addSubVault/common.ts @@ -0,0 +1,11 @@ +import { AddSubVaultInput } from './types' +import { validateArgs } from '../../../../helpers' + + +export const commonLogic = (values: AddSubVaultInput) => { + const { vaultAddress, subVaultsRegistryAddress, subVaultAddress, userAddress } = values + + validateArgs.address({ vaultAddress, userAddress, subVaultsRegistryAddress, subVaultAddress }) + + return values.contracts.base.subVaultsRegistry(subVaultsRegistryAddress) +} diff --git a/src/services/vault/transactions/addSubVault/index.ts b/src/services/vault/transactions/addSubVault/index.ts new file mode 100644 index 00000000..993894ec --- /dev/null +++ b/src/services/vault/transactions/addSubVault/index.ts @@ -0,0 +1,15 @@ +import addSubVault from './addSubVault' +import addSubVaultGas from './addSubVaultGas' +import addSubVaultEncode from './addSubVaultEncode' +import type { AddSubVaultInput, ExtractAddSubVaultInput } from './types' + + +export const createAddSubVault = (params: StakeWise.CommonParams): ExtractAddSubVaultInput => { + const result = (values: StakeWise.ExtractInput) => addSubVault({ ...params, ...values }) + result.encode = (values: StakeWise.ExtractInput) => addSubVaultEncode({ ...params, ...values }) + result.estimateGas = (values: StakeWise.ExtractInput) => addSubVaultGas({ ...params, ...values }) + + return result +} + +export type { ExtractAddSubVaultInput } from './types' diff --git a/src/services/vault/transactions/addSubVault/types.d.ts b/src/services/vault/transactions/addSubVault/types.d.ts new file mode 100644 index 00000000..dfb8bbc4 --- /dev/null +++ b/src/services/vault/transactions/addSubVault/types.d.ts @@ -0,0 +1,12 @@ +export type AddSubVaultInput = StakeWise.CommonParams & { + userAddress: string + vaultAddress: string + subVaultAddress: string + subVaultsRegistryAddress: string +} + +export interface ExtractAddSubVaultInput { + (values: StakeWise.ExtractInput): Promise + estimateGas: (values: StakeWise.ExtractInput) => Promise + encode: (values: StakeWise.ExtractInput) => Promise +} diff --git a/src/services/vault/transactions/ejectSubVault/checkAccess.ts b/src/services/vault/transactions/ejectSubVault/checkAccess.ts new file mode 100644 index 00000000..42de5aad --- /dev/null +++ b/src/services/vault/transactions/ejectSubVault/checkAccess.ts @@ -0,0 +1,25 @@ +import { checkAdminAccess } from '../util' +import type { EjectSubVaultInput as Input } from './types' + + +type Action = (values: Input) => Promise + +const checkAccess = (action: Action) => ( + async (values: Input) => { + try { + const result = await action(values) + + return result + } + catch (actionError) { + return checkAdminAccess(values) + .then( + () => Promise.reject(actionError), + (error) => Promise.reject(error) + ) + } + } +) + + +export default checkAccess diff --git a/src/services/vault/transactions/ejectSubVault/common.ts b/src/services/vault/transactions/ejectSubVault/common.ts new file mode 100644 index 00000000..c0abca16 --- /dev/null +++ b/src/services/vault/transactions/ejectSubVault/common.ts @@ -0,0 +1,11 @@ +import { EjectSubVaultInput } from './types' +import { validateArgs } from '../../../../helpers' + + +export const commonLogic = (values: EjectSubVaultInput) => { + const { vaultAddress, subVaultsRegistryAddress, subVaultAddress, userAddress } = values + + validateArgs.address({ vaultAddress, userAddress, subVaultsRegistryAddress, subVaultAddress }) + + return values.contracts.base.subVaultsRegistry(subVaultsRegistryAddress) +} diff --git a/src/services/vault/transactions/ejectSubVault/ejectSubVault.md b/src/services/vault/transactions/ejectSubVault/ejectSubVault.md new file mode 100644 index 00000000..4b91c093 --- /dev/null +++ b/src/services/vault/transactions/ejectSubVault/ejectSubVault.md @@ -0,0 +1,35 @@ +--- +id: ejectSubVault +slug: /vault/transactions/ejectsubvault +--- + +#### Description: + +Ejecting a sub-vault from the vault registry. + +#### Arguments: + +| Name | Type | Required | Description | +|----------------|----------|----------|---------------------------| +| subVaultAddress | `string` | **Yes** | The sub-vault address to eject | +| userAddress | `string` | **Yes** | The user address | +| vaultAddress | `string` | **Yes** | The address of the vault | +| subVaultsRegistryAddress | `string` | **Yes** | The sub-vault registry address | + +#### Example: + +```ts +const params = { + subVaultsRegistryAddress: '0x...', + subVaultAddress: '0x...', + vaultAddress: '0x...', + userAddress: '0x...', +} + +// Send transaction +const hash = await sdk.vault.ejectSubVault(params) +// When you sign transactions on the backend (for custodians) +const { data, to } = await sdk.vault.ejectSubVault.encode(params) +// Get an approximate gas per transaction +const gas = await sdk.vault.ejectSubVault.estimateGas(params) +``` diff --git a/src/services/vault/transactions/ejectSubVault/ejectSubVault.ts b/src/services/vault/transactions/ejectSubVault/ejectSubVault.ts new file mode 100644 index 00000000..4a169283 --- /dev/null +++ b/src/services/vault/transactions/ejectSubVault/ejectSubVault.ts @@ -0,0 +1,24 @@ +import { commonLogic } from './common' +import checkAccess from './checkAccess' +import type { EjectSubVaultInput } from './types' +import { wrapErrorHandler } from '../../../../helpers' + + +const ejectSubVault = checkAccess(async (values: EjectSubVaultInput) => { + const { provider, userAddress, subVaultAddress } = values + + const signer = await provider.getSigner(userAddress) + + const contract = commonLogic(values) + const signedContract = contract.connect(signer) + + const result = await wrapErrorHandler( + signedContract.ejectSubVault(subVaultAddress), + 'transaction' + ) + + return result?.hash +}) + + +export default ejectSubVault diff --git a/src/services/vault/transactions/ejectSubVault/ejectSubVaultEncode.ts b/src/services/vault/transactions/ejectSubVault/ejectSubVaultEncode.ts new file mode 100644 index 00000000..ab7e3431 --- /dev/null +++ b/src/services/vault/transactions/ejectSubVault/ejectSubVaultEncode.ts @@ -0,0 +1,12 @@ +import { commonLogic } from './common' +import type { EjectSubVaultInput } from './types' + + +const ejectSubVaultEncode = async (values: EjectSubVaultInput) => { + const contract = commonLogic(values) + + return contract.ejectSubVault.populateTransaction(values.subVaultAddress) +} + + +export default ejectSubVaultEncode diff --git a/src/services/vault/transactions/ejectSubVault/ejectSubVaultGas.ts b/src/services/vault/transactions/ejectSubVault/ejectSubVaultGas.ts new file mode 100644 index 00000000..0a57c149 --- /dev/null +++ b/src/services/vault/transactions/ejectSubVault/ejectSubVaultGas.ts @@ -0,0 +1,23 @@ +import { commonLogic } from './common' +import { getGas, wrapErrorHandler } from '../../../../helpers' +import type { EjectSubVaultInput } from './types' + + +const ejectSubVaultGas = async (values: EjectSubVaultInput) => { + const { provider, userAddress, subVaultAddress } = values + + const contract = commonLogic(values) + + const signer = await provider.getSigner(userAddress) + const signedContract = contract.connect(signer) + + const estimatedGas = await wrapErrorHandler( + signedContract.ejectSubVault.estimateGas(subVaultAddress), + 'transaction' + ) + + return getGas({ estimatedGas, provider: values.provider }) +} + + +export default ejectSubVaultGas diff --git a/src/services/vault/transactions/ejectSubVault/index.ts b/src/services/vault/transactions/ejectSubVault/index.ts new file mode 100644 index 00000000..336d011e --- /dev/null +++ b/src/services/vault/transactions/ejectSubVault/index.ts @@ -0,0 +1,15 @@ +import ejectSubVault from './ejectSubVault' +import ejectSubVaultGas from './ejectSubVaultGas' +import ejectSubVaultEncode from './ejectSubVaultEncode' +import type { EjectSubVaultInput, ExtractEjectSubVaultInput } from './types' + + +export const createEjectSubVault = (params: StakeWise.CommonParams): ExtractEjectSubVaultInput => { + const result = (values: StakeWise.ExtractInput) => ejectSubVault({ ...params, ...values }) + result.encode = (values: StakeWise.ExtractInput) => ejectSubVaultEncode({ ...params, ...values }) + result.estimateGas = (values: StakeWise.ExtractInput) => ejectSubVaultGas({ ...params, ...values }) + + return result +} + +export type { ExtractEjectSubVaultInput } from './types' diff --git a/src/services/vault/transactions/ejectSubVault/types.d.ts b/src/services/vault/transactions/ejectSubVault/types.d.ts new file mode 100644 index 00000000..c325c816 --- /dev/null +++ b/src/services/vault/transactions/ejectSubVault/types.d.ts @@ -0,0 +1,12 @@ +export type EjectSubVaultInput = StakeWise.CommonParams & { + userAddress: string + vaultAddress: string + subVaultAddress: string + subVaultsRegistryAddress: string +} + +export interface ExtractEjectSubVaultInput { + (values: StakeWise.ExtractInput): Promise + estimateGas: (values: StakeWise.ExtractInput) => Promise + encode: (values: StakeWise.ExtractInput) => Promise +} diff --git a/src/services/vault/transactions/index.ts b/src/services/vault/transactions/index.ts index 8639fb85..5d1490f0 100644 --- a/src/services/vault/transactions/index.ts +++ b/src/services/vault/transactions/index.ts @@ -4,6 +4,9 @@ import { createOperate, ExtractOperate } from './operate' import { multicall, VaultMulticallInput } from './multicall' import { createWithdraw, ExtractWithdraw } from './withdraw' import { createVaultCreator, ExtractCreateVault } from './createVault' +import { createAddSubVault, ExtractAddSubVaultInput } from './addSubVault' +import { createRejectSubVault, ExtractRejectSubVaultInput } from './rejectSubVault' +import { createEjectSubVault, ExtractEjectSubVaultInput } from './ejectSubVault' import { createClaimExitQueue, ExtractClaimExitQueue } from './claimExitQueue' import { createSetDepositDataRoot, ExtractSetDepositDataRoot } from './setDepositDataRoot' import { createNativeTokenDeposit, createOtherTokenDeposit, ExtractDeposit } from './deposit' @@ -56,6 +59,24 @@ class VaultTransactions { */ public setDepositDataManager: ExtractSetDepositDataManager + /** + * @description Adding new sub-vault. Supports only in metaVault. + * @see https://docs.stakewise.io/vault/transactions/addsubvault + */ + public addSubVault: ExtractAddSubVaultInput + + /** + * @description Rejecting a sub-vault. Supports only in metaVault. + * @see https://docs.stakewise.io/vault/transactions/rejectsubvault + */ + public rejectSubVault: ExtractRejectSubVaultInput + + /** + * @description Ejecting a sub-vault. Supports only in metaVault. + * @see https://docs.stakewise.io/vault/transactions/ejectsubvault + */ + public ejectSubVault: ExtractEjectSubVaultInput + constructor(params: StakeWise.CommonParams) { this.params = params @@ -71,6 +92,9 @@ class VaultTransactions { this.operate = transactionWrapper(params, createOperate(params)) this.withdraw = transactionWrapper(params, createWithdraw(params)) this.create = transactionWrapper(params, createVaultCreator(params)) + this.addSubVault = transactionWrapper(params, createAddSubVault(params)) + this.rejectSubVault = transactionWrapper(params, createRejectSubVault(params)) + this.ejectSubVault = transactionWrapper(params, createEjectSubVault(params)) this.claimExitQueue = transactionWrapper(params, createClaimExitQueue(params)) this.setDepositDataRoot = transactionWrapper(params, createSetDepositDataRoot(params)) this.setDepositDataManager = transactionWrapper(params, createSetDepositDataManager(params)) diff --git a/src/services/vault/transactions/operate/checkAccess.ts b/src/services/vault/transactions/operate/checkAccess.ts index e3aa4444..dd03c81f 100644 --- a/src/services/vault/transactions/operate/checkAccess.ts +++ b/src/services/vault/transactions/operate/checkAccess.ts @@ -12,8 +12,8 @@ type Action = (values: Input) => Promise const checkAccess = (action: Action) => ( async (values: Input) => { const { - blocklist, whitelist, whitelistManager, feeRecipient, feePercent, subVaultAddress, - blocklistManager, metadataIpfsHash, validatorsManager, admin, ejectSubVaultAddress, rejectMetaSubVaultAddress, + blocklist, whitelist, whitelistManager, feeRecipient, feePercent, + blocklistManager, metadataIpfsHash, validatorsManager, admin, } = values try { @@ -26,13 +26,10 @@ const checkAccess = (action: Action) => ( admin || feePercent || feeRecipient - || subVaultAddress || whitelistManager || blocklistManager || metadataIpfsHash || validatorsManager - || ejectSubVaultAddress - || rejectMetaSubVaultAddress ) const isWhitelistManager = Boolean(whitelist) const isBlocklistManager = Boolean(blocklist) diff --git a/src/services/vault/transactions/operate/common.ts b/src/services/vault/transactions/operate/common.ts index 00daa3bf..dcda2eef 100644 --- a/src/services/vault/transactions/operate/common.ts +++ b/src/services/vault/transactions/operate/common.ts @@ -9,11 +9,8 @@ import { getBlocklistParams, getWhitelistParams, getFeePercentParams, - getAddSubVaultParams, getWhitelisterParams, getFeeRecipientParams, - getEjectSubVaultParams, - getRejectSubVaultParams, getBlocklistManagerParams, getValidatorsManagerParams, } from '../util' @@ -22,8 +19,8 @@ import { export const commonLogic = async (values: OperateTransactionInput) => { const { blocklistManager, metadataIpfsHash, admin, feePercent, - blocklist, whitelist, whitelistManager, feeRecipient, subVaultAddress, ejectSubVaultAddress, - options, contracts, userAddress, vaultAddress, provider, validatorsManager, rejectMetaSubVaultAddress, + blocklist, whitelist, whitelistManager, feeRecipient, + options, contracts, userAddress, vaultAddress, provider, validatorsManager, } = values validateArgs.address({ vaultAddress, userAddress }) @@ -31,14 +28,12 @@ export const commonLogic = async (values: OperateTransactionInput) => { const chainId = options.network const isPrivate = Boolean(whitelist?.length || whitelistManager) const isBlocklist = Boolean(blocklist?.length || blocklistManager) - const isMetaVault = Boolean(subVaultAddress || ejectSubVaultAddress || rejectMetaSubVaultAddress) const vaultContract = contracts.helpers.createVault({ vaultAddress, options: { chainId, isPrivate, - isMetaVault, isBlocklist, }, }) @@ -129,24 +124,6 @@ export const commonLogic = async (values: OperateTransactionInput) => { params.push(...adminParams) } - if (subVaultAddress) { - const addSubVaultParams = getAddSubVaultParams({ ...baseInput, subVaultAddress }) - - params.push(...addSubVaultParams) - } - - if (ejectSubVaultAddress) { - const ejectSubVaultParams = getEjectSubVaultParams({ ...baseInput, ejectSubVaultAddress }) - - params.push(...ejectSubVaultParams) - } - - if (rejectMetaSubVaultAddress) { - const rejectSubVaultParams = getRejectSubVaultParams({ ...baseInput, rejectMetaSubVaultAddress }) - - params.push(...rejectSubVaultParams) - } - return { ...baseMulticall, request: { diff --git a/src/services/vault/transactions/operate/operate.md b/src/services/vault/transactions/operate/operate.md index e1046e61..8d3d491f 100644 --- a/src/services/vault/transactions/operate/operate.md +++ b/src/services/vault/transactions/operate/operate.md @@ -24,10 +24,6 @@ Updates the vault by authorized personnel such as the vault admin, whitelistMana | vaultAddress | `string` | **Yes** | - | The address of the vault | | admin | `string` | **No** | - | Changing the vault administrator | | feePercent | `number` | **No** | Admin | Changing fee percent charged by the vault | -| subVaultAddress | `string` | **No** | Admin | Add a new sub-vault | -| ejectSubVaultAddress | `string` | **No** | Admin | Start ejecting a sub-vault | -| rejectMetaSubVaultAddress | `string` | **No** | Admin or DAO | Cancel pending meta sub-vault | - #### Example: ```ts @@ -41,12 +37,9 @@ const params = { displayName: '...', description: '...', feeRecipient: '0x...', - subVaultAddress: '0x...', blocklistManager: '0x...', whitelistManager: '0x...', validatorsManager: '0x...', - ejectSubVaultAddress: '0x...', - rejectMetaSubVaultAddress: '0x...', } // Data to update the vault by vault keys manager. diff --git a/src/services/vault/transactions/operate/types.d.ts b/src/services/vault/transactions/operate/types.d.ts index c0d390de..ee0009e0 100644 --- a/src/services/vault/transactions/operate/types.d.ts +++ b/src/services/vault/transactions/operate/types.d.ts @@ -1,14 +1,11 @@ import type { SetAdminParams } from '../util/params/getAdminParams' import type { UploadMetadataInput } from '../util/metadata/uploadMetadata' import type { SetMetadataParams } from '../util/params/getMetadataParams' -import type { AddSubVaultParams } from '../util/params/getAddSubVaultParams' import type { SetFeePercentParams } from '../util/params/getFeePercentParams' import type { UpdateBlocklistParams } from '../util/params/getBlocklistParams' import type { UpdateWhitelistParams } from '../util/params/getWhitelistParams' import type { SetWhitelisterParams } from '../util/params/getWhitelisterParams' import type { SetFeeRecipientParams } from '../util/params/getFeeRecipientParams' -import type { EjectMetaSubVaultParams } from '../util/params/getEjectSubVaultParams' -import type { RejectMetaSubVaultParams } from '../util/params/getRejectSubVaultParams' import type { SetBlocklistManagerParams } from '../util/params/getBlocklistManagerParams' import type { SetValidatorsManagerParams } from '../util/params/getValidatorsManagerParams' @@ -16,13 +13,10 @@ import type { SetValidatorsManagerParams } from '../util/params/getValidatorsMan type OperateCommonParams = SetWhitelisterParams & SetAdminParams - & AddSubVaultParams & SetFeePercentParams & SetFeeRecipientParams & UpdateBlocklistParams & UpdateWhitelistParams - & EjectMetaSubVaultParams - & RejectMetaSubVaultParams & SetBlocklistManagerParams & SetValidatorsManagerParams diff --git a/src/services/vault/transactions/rejectSubVault/checkAccess.ts b/src/services/vault/transactions/rejectSubVault/checkAccess.ts new file mode 100644 index 00000000..8c5a141f --- /dev/null +++ b/src/services/vault/transactions/rejectSubVault/checkAccess.ts @@ -0,0 +1,25 @@ +import { checkAdminAccess } from '../util' +import type { RejectSubVaultInput as Input } from './types' + + +type Action = (values: Input) => Promise + +const checkAccess = (action: Action) => ( + async (values: Input) => { + try { + const result = await action(values) + + return result + } + catch (actionError) { + return checkAdminAccess(values) + .then( + () => Promise.reject(actionError), + (error) => Promise.reject(error) + ) + } + } +) + + +export default checkAccess diff --git a/src/services/vault/transactions/rejectSubVault/common.ts b/src/services/vault/transactions/rejectSubVault/common.ts new file mode 100644 index 00000000..f1ffa483 --- /dev/null +++ b/src/services/vault/transactions/rejectSubVault/common.ts @@ -0,0 +1,11 @@ +import { RejectSubVaultInput } from './types' +import { validateArgs } from '../../../../helpers' + + +export const commonLogic = (values: RejectSubVaultInput) => { + const { vaultAddress, subVaultsRegistryAddress, subVaultAddress, userAddress } = values + + validateArgs.address({ vaultAddress, userAddress, subVaultsRegistryAddress, subVaultAddress }) + + return values.contracts.base.subVaultsRegistry(subVaultsRegistryAddress) +} diff --git a/src/services/vault/transactions/rejectSubVault/index.ts b/src/services/vault/transactions/rejectSubVault/index.ts new file mode 100644 index 00000000..984d53c4 --- /dev/null +++ b/src/services/vault/transactions/rejectSubVault/index.ts @@ -0,0 +1,15 @@ +import rejectSubVault from './rejectSubVault' +import rejectSubVaultGas from './rejectSubVaultGas' +import rejectSubVaultEncode from './rejectSubVaultEncode' +import type { RejectSubVaultInput, ExtractRejectSubVaultInput } from './types' + + +export const createRejectSubVault = (params: StakeWise.CommonParams): ExtractRejectSubVaultInput => { + const result = (values: StakeWise.ExtractInput) => rejectSubVault({ ...params, ...values }) + result.encode = (values: StakeWise.ExtractInput) => rejectSubVaultEncode({ ...params, ...values }) + result.estimateGas = (values: StakeWise.ExtractInput) => rejectSubVaultGas({ ...params, ...values }) + + return result +} + +export type { ExtractRejectSubVaultInput } from './types' diff --git a/src/services/vault/transactions/rejectSubVault/rejectSubVault.md b/src/services/vault/transactions/rejectSubVault/rejectSubVault.md new file mode 100644 index 00000000..e83760a0 --- /dev/null +++ b/src/services/vault/transactions/rejectSubVault/rejectSubVault.md @@ -0,0 +1,35 @@ +--- +id: rejectSubVault +slug: /vault/transactions/rejectsubvault +--- + +#### Description: + +Rejecting a sub-vault from the vault registry. + +#### Arguments: + +| Name | Type | Required | Description | +|----------------|----------|----------|---------------------------| +| subVaultAddress | `string` | **Yes** | The sub-vault address to reject | +| userAddress | `string` | **Yes** | The user address | +| vaultAddress | `string` | **Yes** | The address of the vault | +| subVaultsRegistryAddress | `string` | **Yes** | The sub-vault registry address | + +#### Example: + +```ts +const params = { + subVaultsRegistryAddress: '0x...', + subVaultAddress: '0x...', + vaultAddress: '0x...', + userAddress: '0x...', +} + +// Send transaction +const hash = await sdk.vault.rejectSubVault(params) +// When you sign transactions on the backend (for custodians) +const { data, to } = await sdk.vault.rejectSubVault.encode(params) +// Get an approximate gas per transaction +const gas = await sdk.vault.rejectSubVault.estimateGas(params) +``` diff --git a/src/services/vault/transactions/rejectSubVault/rejectSubVault.ts b/src/services/vault/transactions/rejectSubVault/rejectSubVault.ts new file mode 100644 index 00000000..e97dc573 --- /dev/null +++ b/src/services/vault/transactions/rejectSubVault/rejectSubVault.ts @@ -0,0 +1,24 @@ +import { commonLogic } from './common' +import checkAccess from './checkAccess' +import type { RejectSubVaultInput } from './types' +import { wrapErrorHandler } from '../../../../helpers' + + +const rejectSubVault = checkAccess(async (values: RejectSubVaultInput) => { + const { provider, userAddress, subVaultAddress } = values + + const signer = await provider.getSigner(userAddress) + + const contract = commonLogic(values) + const signedContract = contract.connect(signer) + + const result = await wrapErrorHandler( + signedContract.rejectMetaSubVault(subVaultAddress), + 'transaction' + ) + + return result?.hash +}) + + +export default rejectSubVault diff --git a/src/services/vault/transactions/rejectSubVault/rejectSubVaultEncode.ts b/src/services/vault/transactions/rejectSubVault/rejectSubVaultEncode.ts new file mode 100644 index 00000000..fe599700 --- /dev/null +++ b/src/services/vault/transactions/rejectSubVault/rejectSubVaultEncode.ts @@ -0,0 +1,12 @@ +import { commonLogic } from './common' +import type { RejectSubVaultInput } from './types' + + +const rejectSubVaultEncode = async (values: RejectSubVaultInput) => { + const contract = commonLogic(values) + + return contract.rejectMetaSubVault.populateTransaction(values.subVaultAddress) +} + + +export default rejectSubVaultEncode diff --git a/src/services/vault/transactions/rejectSubVault/rejectSubVaultGas.ts b/src/services/vault/transactions/rejectSubVault/rejectSubVaultGas.ts new file mode 100644 index 00000000..048b89ba --- /dev/null +++ b/src/services/vault/transactions/rejectSubVault/rejectSubVaultGas.ts @@ -0,0 +1,23 @@ +import { commonLogic } from './common' +import { getGas, wrapErrorHandler } from '../../../../helpers' +import type { RejectSubVaultInput } from './types' + + +const rejectSubVaultGas = async (values: RejectSubVaultInput) => { + const { provider, userAddress, subVaultAddress } = values + + const contract = commonLogic(values) + + const signer = await provider.getSigner(userAddress) + const signedContract = contract.connect(signer) + + const estimatedGas = await wrapErrorHandler( + signedContract.rejectMetaSubVault.estimateGas(subVaultAddress), + 'transaction' + ) + + return getGas({ estimatedGas, provider: values.provider }) +} + + +export default rejectSubVaultGas diff --git a/src/services/vault/transactions/rejectSubVault/types.d.ts b/src/services/vault/transactions/rejectSubVault/types.d.ts new file mode 100644 index 00000000..12612787 --- /dev/null +++ b/src/services/vault/transactions/rejectSubVault/types.d.ts @@ -0,0 +1,12 @@ +export type RejectSubVaultInput = StakeWise.CommonParams & { + userAddress: string + vaultAddress: string + subVaultAddress: string + subVaultsRegistryAddress: string +} + +export interface ExtractRejectSubVaultInput { + (values: StakeWise.ExtractInput): Promise + estimateGas: (values: StakeWise.ExtractInput) => Promise + encode: (values: StakeWise.ExtractInput) => Promise +} diff --git a/src/services/vault/transactions/util/params/getAddSubVaultParams.ts b/src/services/vault/transactions/util/params/getAddSubVaultParams.ts deleted file mode 100644 index d681fb08..00000000 --- a/src/services/vault/transactions/util/params/getAddSubVaultParams.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { validateArgs } from '../../../../../helpers' -import { vaultMulticall } from '../../../../../contracts' - - -export type AddSubVaultParams = { - subVaultAddress: string -} - -const getAddSubVaultParams = (values: AddSubVaultParams) => { - const { subVaultAddress } = values - - validateArgs.address({ subVaultAddress }) - - const params: Parameters[0]['request']['params'] = [ - { - method: 'addSubVault', args: [ subVaultAddress ], - }, - ] - - return params -} - - -export default getAddSubVaultParams diff --git a/src/services/vault/transactions/util/params/getEjectSubVaultParams.ts b/src/services/vault/transactions/util/params/getEjectSubVaultParams.ts deleted file mode 100644 index 70ed4efb..00000000 --- a/src/services/vault/transactions/util/params/getEjectSubVaultParams.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { validateArgs } from '../../../../../helpers' -import { vaultMulticall } from '../../../../../contracts' - - -export type EjectMetaSubVaultParams = { - ejectSubVaultAddress: string -} - -const getEjectSubVaultParams = (values: EjectMetaSubVaultParams) => { - const { ejectSubVaultAddress } = values - - validateArgs.address({ ejectSubVaultAddress }) - - const params: Parameters[0]['request']['params'] = [ - { - method: 'ejectSubVault', args: [ ejectSubVaultAddress ], - }, - ] - - return params -} - - -export default getEjectSubVaultParams diff --git a/src/services/vault/transactions/util/params/getRejectSubVaultParams.ts b/src/services/vault/transactions/util/params/getRejectSubVaultParams.ts deleted file mode 100644 index 55bb37c8..00000000 --- a/src/services/vault/transactions/util/params/getRejectSubVaultParams.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { validateArgs } from '../../../../../helpers' -import { vaultMulticall } from '../../../../../contracts' - - -export type RejectMetaSubVaultParams = { - rejectMetaSubVaultAddress: string -} - -const getRejectSubVaultParams = (values: RejectMetaSubVaultParams) => { - const { rejectMetaSubVaultAddress } = values - - validateArgs.address({ rejectMetaSubVaultAddress }) - - const params: Parameters[0]['request']['params'] = [ - { - method: 'rejectMetaSubVault', args: [ rejectMetaSubVaultAddress ], - }, - ] - - return params -} - - -export default getRejectSubVaultParams diff --git a/src/services/vault/transactions/util/params/index.ts b/src/services/vault/transactions/util/params/index.ts index 10735dd1..ed827aff 100644 --- a/src/services/vault/transactions/util/params/index.ts +++ b/src/services/vault/transactions/util/params/index.ts @@ -3,10 +3,7 @@ export { default as getMetadataParams } from './getMetadataParams' export { default as getBlocklistParams } from './getBlocklistParams' export { default as getWhitelistParams } from './getWhitelistParams' export { default as getFeePercentParams } from './getFeePercentParams' -export { default as getAddSubVaultParams } from './getAddSubVaultParams' export { default as getWhitelisterParams } from './getWhitelisterParams' export { default as getFeeRecipientParams } from './getFeeRecipientParams' -export { default as getEjectSubVaultParams } from './getEjectSubVaultParams' -export { default as getRejectSubVaultParams } from './getRejectSubVaultParams' export { default as getBlocklistManagerParams } from './getBlocklistManagerParams' export { default as getValidatorsManagerParams } from './getValidatorsManagerParams' diff --git a/src/types/global.ts b/src/types/global.ts index 9b8011ad..9485750d 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -27,6 +27,7 @@ import type { MetaVaultFactoryAbi, MintTokenConfigV1Abi, MintTokenConfigV2Abi, + SubVaultsRegistryAbi, DepositDataRegistryAbi, MerkleDistributorV2Abi, MintTokenControllerAbi, @@ -125,6 +126,7 @@ declare global { type LeverageStrategy = LeverageStrategyAbi type MintTokenConfigV1 = MintTokenConfigV1Abi type MintTokenConfigV2 = MintTokenConfigV2Abi + type SubVaultsRegistry = SubVaultsRegistryAbi type DepositDataRegistry = DepositDataRegistryAbi type MerkleDistributorV2 = MerkleDistributorV2Abi type MintTokenController = MintTokenControllerAbi From 2e92cdd3fdf9fb64d992cf05108606bdbadaa7f0 Mon Sep 17 00:00:00 2001 From: CAst Date: Fri, 20 Feb 2026 18:05:55 +0500 Subject: [PATCH 08/27] [improve-sub-vaults] change methods (#345) --- codegen.ts | 2 +- src/contracts/createContracts.ts | 8 +------- src/contracts/vault/abis/DefaultVaultAbi.json | 4 ---- src/helpers/configs/hoodi.ts | 1 + .../vault/transactions/addSubVault/addSubVault.md | 2 -- .../vault/transactions/addSubVault/addSubVault.ts | 2 +- .../transactions/addSubVault/addSubVaultEncode.ts | 2 +- .../vault/transactions/addSubVault/addSubVaultGas.ts | 4 ++-- src/services/vault/transactions/addSubVault/common.ts | 11 +++++++---- .../vault/transactions/addSubVault/types.d.ts | 1 - .../vault/transactions/ejectSubVault/common.ts | 11 +++++++---- .../vault/transactions/ejectSubVault/ejectSubVault.md | 2 -- .../vault/transactions/ejectSubVault/ejectSubVault.ts | 2 +- .../transactions/ejectSubVault/ejectSubVaultEncode.ts | 2 +- .../transactions/ejectSubVault/ejectSubVaultGas.ts | 4 ++-- .../vault/transactions/ejectSubVault/types.d.ts | 1 - .../vault/transactions/rejectSubVault/common.ts | 11 +++++++---- .../transactions/rejectSubVault/rejectSubVault.md | 2 -- .../transactions/rejectSubVault/rejectSubVault.ts | 2 +- .../rejectSubVault/rejectSubVaultEncode.ts | 2 +- .../transactions/rejectSubVault/rejectSubVaultGas.ts | 4 ++-- .../vault/transactions/rejectSubVault/types.d.ts | 1 - 22 files changed, 36 insertions(+), 45 deletions(-) diff --git a/codegen.ts b/codegen.ts index 947586ff..8b3a9146 100644 --- a/codegen.ts +++ b/codegen.ts @@ -2,7 +2,7 @@ import type { CodegenConfig } from '@graphql-codegen/cli' import { Network } from './src/helpers/enums' import configs from './src/helpers/configs' - +// TODO change let network: Network = Network.Hoodi if (process.env.NETWORK === 'mainnet') { diff --git a/src/contracts/createContracts.ts b/src/contracts/createContracts.ts index 087e3a2c..b4569e2f 100644 --- a/src/contracts/createContracts.ts +++ b/src/contracts/createContracts.ts @@ -117,12 +117,6 @@ const getDepositDataRegistry = (provider: Provider, config: StakeWise.Config) => provider ) -const getSubVaultsRegistry = (provider: Provider, address: string) => createContract( - address, - SubVaultsRegistryAbi, - provider -) - const getMerkleDistributorV2 = (provider: Provider, config: StakeWise.Config) => createContract( config.addresses.special.merkleDistributorV2, MerkleDistributorV2Abi, @@ -167,6 +161,7 @@ export const createContracts = (input: CreateContractsInput) => { createEigenPodOwner: (address: string) => createContract(address, EigenPodOwnerAbi, provider), createRewardSplitter: (address: string) => createContract(address, RewardSplitterAbi, provider), createVestingEscrowDirect: (address: string) => createContract(address, VestingEscrowAbi, provider), + createSubVaultsRegistry: (address: string) => createContract(address, SubVaultsRegistryAbi, provider), createUsdRate: (address: string, _provider?: Provider) => createContract(address, UsdRateAbi, _provider || provider), createVestingEscrowFactory: (address: string) => createContract(address, VestingEscrowFactoryAbi, provider), }, @@ -181,7 +176,6 @@ export const createContracts = (input: CreateContractsInput) => { depositDataRegistry: getDepositDataRegistry(provider, config), mintTokenController: getMintTokenController(provider, config), rewardSplitterFactory: getRewardSplitterFactory(provider, config), - subVaultsRegistry: (address: string) => getSubVaultsRegistry(provider, address), }, tokens: { mintToken: getMintToken(provider, config), diff --git a/src/contracts/vault/abis/DefaultVaultAbi.json b/src/contracts/vault/abis/DefaultVaultAbi.json index 0462cd9c..6b763990 100644 --- a/src/contracts/vault/abis/DefaultVaultAbi.json +++ b/src/contracts/vault/abis/DefaultVaultAbi.json @@ -540,7 +540,3 @@ "type": "function" } ] - - - - diff --git a/src/helpers/configs/hoodi.ts b/src/helpers/configs/hoodi.ts index 6a7ad167..038970c7 100644 --- a/src/helpers/configs/hoodi.ts +++ b/src/helpers/configs/hoodi.ts @@ -7,6 +7,7 @@ export default { network: constants.chains.hoodi, api: { backend: 'https://hoodi-api.stakewise.io/graphql', + // TODO change (+ change .graphqlconfig) subgraph: 'https://graphs.stakewise.io/hoodi/subgraphs/name/stakewise/stage', }, pages: { diff --git a/src/services/vault/transactions/addSubVault/addSubVault.md b/src/services/vault/transactions/addSubVault/addSubVault.md index 1f73e5fc..83a2f336 100644 --- a/src/services/vault/transactions/addSubVault/addSubVault.md +++ b/src/services/vault/transactions/addSubVault/addSubVault.md @@ -14,13 +14,11 @@ Adding a new sub-vault to the vault registry. | subVaultAddress | `string` | **Yes** | New sub-vault address | | userAddress | `string` | **Yes** | The user address | | vaultAddress | `string` | **Yes** | The address of the vault | -| subVaultsRegistryAddress | `string` | **Yes** | The sub-vault registry address | #### Example: ```ts const params = { - subVaultsRegistryAddress: '0x...', subVaultAddress: '0x...', vaultAddress: '0x...', userAddress: '0x...', diff --git a/src/services/vault/transactions/addSubVault/addSubVault.ts b/src/services/vault/transactions/addSubVault/addSubVault.ts index b3336626..34ddf7cb 100644 --- a/src/services/vault/transactions/addSubVault/addSubVault.ts +++ b/src/services/vault/transactions/addSubVault/addSubVault.ts @@ -9,7 +9,7 @@ const addSubVault = checkAccess(async (values: AddSubVaultInput) => { const signer = await provider.getSigner(userAddress) - const contract = commonLogic(values) + const contract = await commonLogic(values) const signedContract = contract.connect(signer) const result = await wrapErrorHandler( diff --git a/src/services/vault/transactions/addSubVault/addSubVaultEncode.ts b/src/services/vault/transactions/addSubVault/addSubVaultEncode.ts index c96c5d0d..6d4b17e9 100644 --- a/src/services/vault/transactions/addSubVault/addSubVaultEncode.ts +++ b/src/services/vault/transactions/addSubVault/addSubVaultEncode.ts @@ -3,7 +3,7 @@ import type { AddSubVaultInput } from './types' const addSubVaultEncode = async (values: AddSubVaultInput) => { - const contract = commonLogic(values) + const contract = await commonLogic(values) return contract.addSubVault.populateTransaction(values.subVaultAddress) } diff --git a/src/services/vault/transactions/addSubVault/addSubVaultGas.ts b/src/services/vault/transactions/addSubVault/addSubVaultGas.ts index fa0b0d4c..29219df5 100644 --- a/src/services/vault/transactions/addSubVault/addSubVaultGas.ts +++ b/src/services/vault/transactions/addSubVault/addSubVaultGas.ts @@ -6,14 +6,14 @@ import type { AddSubVaultInput } from './types' const addSubVaultGas = async (values: AddSubVaultInput) => { const { provider, userAddress, subVaultAddress } = values - const contract = commonLogic(values) + const contract = await commonLogic(values) const signer = await provider.getSigner(userAddress) const signedContract = contract.connect(signer) const estimatedGas = await wrapErrorHandler( signedContract.addSubVault.estimateGas(subVaultAddress), - 'transaction' + 'gas' ) return getGas({ estimatedGas, provider: values.provider }) diff --git a/src/services/vault/transactions/addSubVault/common.ts b/src/services/vault/transactions/addSubVault/common.ts index 684ae715..67252d9d 100644 --- a/src/services/vault/transactions/addSubVault/common.ts +++ b/src/services/vault/transactions/addSubVault/common.ts @@ -1,11 +1,14 @@ import { AddSubVaultInput } from './types' +import getVault from '../../requests/getVault' import { validateArgs } from '../../../../helpers' -export const commonLogic = (values: AddSubVaultInput) => { - const { vaultAddress, subVaultsRegistryAddress, subVaultAddress, userAddress } = values +export const commonLogic = async (values: AddSubVaultInput) => { + const { vaultAddress, subVaultAddress, userAddress } = values - validateArgs.address({ vaultAddress, userAddress, subVaultsRegistryAddress, subVaultAddress }) + validateArgs.address({ vaultAddress, userAddress, subVaultAddress }) - return values.contracts.base.subVaultsRegistry(subVaultsRegistryAddress) + const { subVaultsRegistry } = await getVault(values) + + return values.contracts.helpers.createSubVaultsRegistry(subVaultsRegistry) } diff --git a/src/services/vault/transactions/addSubVault/types.d.ts b/src/services/vault/transactions/addSubVault/types.d.ts index dfb8bbc4..8cb99272 100644 --- a/src/services/vault/transactions/addSubVault/types.d.ts +++ b/src/services/vault/transactions/addSubVault/types.d.ts @@ -2,7 +2,6 @@ export type AddSubVaultInput = StakeWise.CommonParams & { userAddress: string vaultAddress: string subVaultAddress: string - subVaultsRegistryAddress: string } export interface ExtractAddSubVaultInput { diff --git a/src/services/vault/transactions/ejectSubVault/common.ts b/src/services/vault/transactions/ejectSubVault/common.ts index c0abca16..d39b3023 100644 --- a/src/services/vault/transactions/ejectSubVault/common.ts +++ b/src/services/vault/transactions/ejectSubVault/common.ts @@ -1,11 +1,14 @@ import { EjectSubVaultInput } from './types' +import getVault from '../../requests/getVault' import { validateArgs } from '../../../../helpers' -export const commonLogic = (values: EjectSubVaultInput) => { - const { vaultAddress, subVaultsRegistryAddress, subVaultAddress, userAddress } = values +export const commonLogic = async (values: EjectSubVaultInput) => { + const { vaultAddress, subVaultAddress, userAddress } = values - validateArgs.address({ vaultAddress, userAddress, subVaultsRegistryAddress, subVaultAddress }) + validateArgs.address({ vaultAddress, userAddress, subVaultAddress }) - return values.contracts.base.subVaultsRegistry(subVaultsRegistryAddress) + const { subVaultsRegistry } = await getVault(values) + + return values.contracts.helpers.createSubVaultsRegistry(subVaultsRegistry) } diff --git a/src/services/vault/transactions/ejectSubVault/ejectSubVault.md b/src/services/vault/transactions/ejectSubVault/ejectSubVault.md index 4b91c093..5becc786 100644 --- a/src/services/vault/transactions/ejectSubVault/ejectSubVault.md +++ b/src/services/vault/transactions/ejectSubVault/ejectSubVault.md @@ -14,13 +14,11 @@ Ejecting a sub-vault from the vault registry. | subVaultAddress | `string` | **Yes** | The sub-vault address to eject | | userAddress | `string` | **Yes** | The user address | | vaultAddress | `string` | **Yes** | The address of the vault | -| subVaultsRegistryAddress | `string` | **Yes** | The sub-vault registry address | #### Example: ```ts const params = { - subVaultsRegistryAddress: '0x...', subVaultAddress: '0x...', vaultAddress: '0x...', userAddress: '0x...', diff --git a/src/services/vault/transactions/ejectSubVault/ejectSubVault.ts b/src/services/vault/transactions/ejectSubVault/ejectSubVault.ts index 4a169283..80a9c23d 100644 --- a/src/services/vault/transactions/ejectSubVault/ejectSubVault.ts +++ b/src/services/vault/transactions/ejectSubVault/ejectSubVault.ts @@ -9,7 +9,7 @@ const ejectSubVault = checkAccess(async (values: EjectSubVaultInput) => const signer = await provider.getSigner(userAddress) - const contract = commonLogic(values) + const contract = await commonLogic(values) const signedContract = contract.connect(signer) const result = await wrapErrorHandler( diff --git a/src/services/vault/transactions/ejectSubVault/ejectSubVaultEncode.ts b/src/services/vault/transactions/ejectSubVault/ejectSubVaultEncode.ts index ab7e3431..02165ddd 100644 --- a/src/services/vault/transactions/ejectSubVault/ejectSubVaultEncode.ts +++ b/src/services/vault/transactions/ejectSubVault/ejectSubVaultEncode.ts @@ -3,7 +3,7 @@ import type { EjectSubVaultInput } from './types' const ejectSubVaultEncode = async (values: EjectSubVaultInput) => { - const contract = commonLogic(values) + const contract = await commonLogic(values) return contract.ejectSubVault.populateTransaction(values.subVaultAddress) } diff --git a/src/services/vault/transactions/ejectSubVault/ejectSubVaultGas.ts b/src/services/vault/transactions/ejectSubVault/ejectSubVaultGas.ts index 0a57c149..965e22f2 100644 --- a/src/services/vault/transactions/ejectSubVault/ejectSubVaultGas.ts +++ b/src/services/vault/transactions/ejectSubVault/ejectSubVaultGas.ts @@ -6,14 +6,14 @@ import type { EjectSubVaultInput } from './types' const ejectSubVaultGas = async (values: EjectSubVaultInput) => { const { provider, userAddress, subVaultAddress } = values - const contract = commonLogic(values) + const contract = await commonLogic(values) const signer = await provider.getSigner(userAddress) const signedContract = contract.connect(signer) const estimatedGas = await wrapErrorHandler( signedContract.ejectSubVault.estimateGas(subVaultAddress), - 'transaction' + 'gas' ) return getGas({ estimatedGas, provider: values.provider }) diff --git a/src/services/vault/transactions/ejectSubVault/types.d.ts b/src/services/vault/transactions/ejectSubVault/types.d.ts index c325c816..93383824 100644 --- a/src/services/vault/transactions/ejectSubVault/types.d.ts +++ b/src/services/vault/transactions/ejectSubVault/types.d.ts @@ -2,7 +2,6 @@ export type EjectSubVaultInput = StakeWise.CommonParams & { userAddress: string vaultAddress: string subVaultAddress: string - subVaultsRegistryAddress: string } export interface ExtractEjectSubVaultInput { diff --git a/src/services/vault/transactions/rejectSubVault/common.ts b/src/services/vault/transactions/rejectSubVault/common.ts index f1ffa483..9e5e9dc8 100644 --- a/src/services/vault/transactions/rejectSubVault/common.ts +++ b/src/services/vault/transactions/rejectSubVault/common.ts @@ -1,11 +1,14 @@ import { RejectSubVaultInput } from './types' +import getVault from '../../requests/getVault' import { validateArgs } from '../../../../helpers' -export const commonLogic = (values: RejectSubVaultInput) => { - const { vaultAddress, subVaultsRegistryAddress, subVaultAddress, userAddress } = values +export const commonLogic = async (values: RejectSubVaultInput) => { + const { vaultAddress, subVaultAddress, userAddress } = values - validateArgs.address({ vaultAddress, userAddress, subVaultsRegistryAddress, subVaultAddress }) + validateArgs.address({ vaultAddress, userAddress, subVaultAddress }) - return values.contracts.base.subVaultsRegistry(subVaultsRegistryAddress) + const { subVaultsRegistry } = await getVault(values) + + return values.contracts.helpers.createSubVaultsRegistry(subVaultsRegistry) } diff --git a/src/services/vault/transactions/rejectSubVault/rejectSubVault.md b/src/services/vault/transactions/rejectSubVault/rejectSubVault.md index e83760a0..c8f3ca1e 100644 --- a/src/services/vault/transactions/rejectSubVault/rejectSubVault.md +++ b/src/services/vault/transactions/rejectSubVault/rejectSubVault.md @@ -14,13 +14,11 @@ Rejecting a sub-vault from the vault registry. | subVaultAddress | `string` | **Yes** | The sub-vault address to reject | | userAddress | `string` | **Yes** | The user address | | vaultAddress | `string` | **Yes** | The address of the vault | -| subVaultsRegistryAddress | `string` | **Yes** | The sub-vault registry address | #### Example: ```ts const params = { - subVaultsRegistryAddress: '0x...', subVaultAddress: '0x...', vaultAddress: '0x...', userAddress: '0x...', diff --git a/src/services/vault/transactions/rejectSubVault/rejectSubVault.ts b/src/services/vault/transactions/rejectSubVault/rejectSubVault.ts index e97dc573..6f0622c8 100644 --- a/src/services/vault/transactions/rejectSubVault/rejectSubVault.ts +++ b/src/services/vault/transactions/rejectSubVault/rejectSubVault.ts @@ -9,7 +9,7 @@ const rejectSubVault = checkAccess(async (values: RejectSubVaultInput) = const signer = await provider.getSigner(userAddress) - const contract = commonLogic(values) + const contract = await commonLogic(values) const signedContract = contract.connect(signer) const result = await wrapErrorHandler( diff --git a/src/services/vault/transactions/rejectSubVault/rejectSubVaultEncode.ts b/src/services/vault/transactions/rejectSubVault/rejectSubVaultEncode.ts index fe599700..f20718f7 100644 --- a/src/services/vault/transactions/rejectSubVault/rejectSubVaultEncode.ts +++ b/src/services/vault/transactions/rejectSubVault/rejectSubVaultEncode.ts @@ -3,7 +3,7 @@ import type { RejectSubVaultInput } from './types' const rejectSubVaultEncode = async (values: RejectSubVaultInput) => { - const contract = commonLogic(values) + const contract = await commonLogic(values) return contract.rejectMetaSubVault.populateTransaction(values.subVaultAddress) } diff --git a/src/services/vault/transactions/rejectSubVault/rejectSubVaultGas.ts b/src/services/vault/transactions/rejectSubVault/rejectSubVaultGas.ts index 048b89ba..488cf9ca 100644 --- a/src/services/vault/transactions/rejectSubVault/rejectSubVaultGas.ts +++ b/src/services/vault/transactions/rejectSubVault/rejectSubVaultGas.ts @@ -6,14 +6,14 @@ import type { RejectSubVaultInput } from './types' const rejectSubVaultGas = async (values: RejectSubVaultInput) => { const { provider, userAddress, subVaultAddress } = values - const contract = commonLogic(values) + const contract = await commonLogic(values) const signer = await provider.getSigner(userAddress) const signedContract = contract.connect(signer) const estimatedGas = await wrapErrorHandler( signedContract.rejectMetaSubVault.estimateGas(subVaultAddress), - 'transaction' + 'gas' ) return getGas({ estimatedGas, provider: values.provider }) diff --git a/src/services/vault/transactions/rejectSubVault/types.d.ts b/src/services/vault/transactions/rejectSubVault/types.d.ts index 12612787..83f08946 100644 --- a/src/services/vault/transactions/rejectSubVault/types.d.ts +++ b/src/services/vault/transactions/rejectSubVault/types.d.ts @@ -2,7 +2,6 @@ export type RejectSubVaultInput = StakeWise.CommonParams & { userAddress: string vaultAddress: string subVaultAddress: string - subVaultsRegistryAddress: string } export interface ExtractRejectSubVaultInput { From 661401a93cfff6e60dcc1f651751422969539562 Mon Sep 17 00:00:00 2001 From: CAst Date: Wed, 25 Feb 2026 20:40:24 +0500 Subject: [PATCH 09/27] [new-metavaults-addresses] set new data (#346) --- src/helpers/configs/hoodi.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/helpers/configs/hoodi.ts b/src/helpers/configs/hoodi.ts index 038970c7..a241a123 100644 --- a/src/helpers/configs/hoodi.ts +++ b/src/helpers/configs/hoodi.ts @@ -45,10 +45,11 @@ export default { blocklistVault: '0x608d8Ca6916b96edf63Dd429e62Fe1366ae6f3B5', erc20BlocklistVault: '0x39c6eef5f955bcC280966504bc5c82F2394Fa368', - metavault: '0x3C97239F12A94b914361F41B51869218a16c2026', - erc20Metavault: '0x94E1adDa4f5ca28aA2549aA9e18D89E3184F8b70', - privateMetavault: '0xe914Cfb2EB9e2d208b19b3E280A3096479491eAd', - erc20PrivateMetavault: '0x6ba3d8DF1ECa6201cc30D5D2E58294B23DAFF221', + metavault: '0x721C63fc53C432FC0feA4e0775e7ABFd29983347', + erc20Metavault: '0x0aca1A126d0636bf74086DD077b47366a1353D4D', + + privateMetavault: '0xa11f61D2687993CF29B6aEb8f9EFb3147F34Dbb6', + erc20PrivateMetavault: '0xCCf6D110181330fB8b62de8FA37fd0a905665376', }, special: { balancedCurator: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', From 39241b96fead6f9536737a859c1e32afb1307614 Mon Sep 17 00:00:00 2001 From: Mike Diamond Date: Tue, 17 Mar 2026 10:30:15 +0300 Subject: [PATCH 10/27] Update state (#348) * [meta vaults] add updateState method Signed-off-by: MikeDiam * [meta vaults] update getHarvestArgs Signed-off-by: MikeDiam --------- Signed-off-by: MikeDiam --- changelog/next-release.md | 1 + src/contracts/createContracts.ts | 2 +- .../multicall/util/getHarvestArgs.ts | 8 ++- src/contracts/multicall/vaultMulticall.ts | 6 +- src/contracts/vault/createVaultContract.ts | 34 ++++------ .../subgraph/vault/harvestParamsQuery.graphql | 1 + .../createRewardSplitter/common.ts | 3 - .../createRewardSplitter.ts | 5 +- .../updateFeeRecipients/common.ts | 5 +- .../updateFeeRecipients.ts | 5 +- .../getHarvestParams/modifyHarvestParams.ts | 3 +- .../transactions/addSubVault/addSubVault.ts | 4 +- .../transactions/addSubVault/checkAccess.ts | 25 ------- .../transactions/claimExitQueue/common.ts | 2 +- .../deposit/nativeToken/common.ts | 12 ++-- .../transactions/deposit/otherToken/common.ts | 3 +- .../transactions/ejectSubVault/checkAccess.ts | 25 ------- .../ejectSubVault/ejectSubVault.ts | 4 +- src/services/vault/transactions/index.ts | 14 +++- .../vault/transactions/multicall/index.ts | 3 +- .../vault/transactions/operate/checkAccess.ts | 65 ------------------- .../vault/transactions/operate/common.ts | 2 - .../transactions/operate/getRolesList.ts | 40 ++++++++++++ .../vault/transactions/operate/operate.ts | 23 ++++--- .../rejectSubVault/checkAccess.ts | 25 ------- .../rejectSubVault/rejectSubVault.ts | 4 +- .../setDepositDataManager/checkAccess.ts | 25 ------- .../setDepositDataManager.ts | 9 +-- .../setDepositDataRoot/checkAccess.ts | 25 ------- .../setDepositDataRoot/setDepositDataRoot.ts | 54 +++++++-------- .../vault/transactions/updateState/common.ts | 21 ++++++ .../vault/transactions/updateState/index.ts | 15 +++++ .../vault/transactions/updateState/types.d.ts | 10 +++ .../transactions/updateState/updateState.md | 34 ++++++++++ .../transactions/updateState/updateState.ts | 28 ++++++++ .../updateState/updateStateEncode.ts | 16 +++++ .../updateState/updateStateGas.ts | 27 ++++++++ .../transactions/util/check/checkAccess.ts | 35 ++++++++++ .../vault/transactions/util/check/index.ts | 6 +- .../check/{ => roles}/checkAdminAccess.ts | 2 +- .../checkBlocklistManagerAccess.ts | 2 +- .../checkDepositDataManagerAccess.ts | 4 +- .../{ => roles}/checkWhitelisterAccess.ts | 2 +- .../transactions/util/check/roles/index.ts | 16 +++++ 44 files changed, 346 insertions(+), 309 deletions(-) delete mode 100644 src/services/vault/transactions/addSubVault/checkAccess.ts delete mode 100644 src/services/vault/transactions/ejectSubVault/checkAccess.ts delete mode 100644 src/services/vault/transactions/operate/checkAccess.ts create mode 100644 src/services/vault/transactions/operate/getRolesList.ts delete mode 100644 src/services/vault/transactions/rejectSubVault/checkAccess.ts delete mode 100644 src/services/vault/transactions/setDepositDataManager/checkAccess.ts delete mode 100644 src/services/vault/transactions/setDepositDataRoot/checkAccess.ts create mode 100644 src/services/vault/transactions/updateState/common.ts create mode 100644 src/services/vault/transactions/updateState/index.ts create mode 100644 src/services/vault/transactions/updateState/types.d.ts create mode 100644 src/services/vault/transactions/updateState/updateState.md create mode 100644 src/services/vault/transactions/updateState/updateState.ts create mode 100644 src/services/vault/transactions/updateState/updateStateEncode.ts create mode 100644 src/services/vault/transactions/updateState/updateStateGas.ts create mode 100644 src/services/vault/transactions/util/check/checkAccess.ts rename src/services/vault/transactions/util/check/{ => roles}/checkAdminAccess.ts (92%) rename src/services/vault/transactions/util/check/{ => roles}/checkBlocklistManagerAccess.ts (93%) rename src/services/vault/transactions/util/check/{ => roles}/checkDepositDataManagerAccess.ts (88%) rename src/services/vault/transactions/util/check/{ => roles}/checkWhitelisterAccess.ts (93%) create mode 100644 src/services/vault/transactions/util/check/roles/index.ts diff --git a/changelog/next-release.md b/changelog/next-release.md index 43fcf3c4..37789ce7 100644 --- a/changelog/next-release.md +++ b/changelog/next-release.md @@ -4,6 +4,7 @@ - [sdk.vault.addSubVault](https://docs.stakewise.io/vault/transactions/addsubvault) - [sdk.vault.rejectSubVault](https://docs.stakewise.io/vault/transactions/rejectsubvault) - [sdk.vault.ejectSubVault](https://docs.stakewise.io/vault/transactions/ejectsubvault) +- [sdk.vault.updateState](https://docs.stakewise.io/vault/transactions/updatestate) ## Modified methods diff --git a/src/contracts/createContracts.ts b/src/contracts/createContracts.ts index b4569e2f..ebcd3114 100644 --- a/src/contracts/createContracts.ts +++ b/src/contracts/createContracts.ts @@ -149,7 +149,7 @@ type CreateContractsInput = { export const createContracts = (input: CreateContractsInput) => { const { provider, config } = input - const createVault = createVaultContract(provider) + const createVault = createVaultContract(provider, config) const multicallContract = getMulticall(provider, config) return { diff --git a/src/contracts/multicall/util/getHarvestArgs.ts b/src/contracts/multicall/util/getHarvestArgs.ts index 1bb2577c..e812dd6b 100644 --- a/src/contracts/multicall/util/getHarvestArgs.ts +++ b/src/contracts/multicall/util/getHarvestArgs.ts @@ -6,12 +6,14 @@ type Input = StakeWise.CommonParams & { vaultAddress: string } -type Output = Promise | null> +export type HarvestArgs = Omit + +type Output = Promise const getHarvestArgs = async (values: Input): Output => { - const { params, canHarvest } = await getHarvestParams(values) + const { params, canHarvest, isMetaVault } = await getHarvestParams(values) - if (canHarvest) { + if (canHarvest && !isMetaVault) { return params } diff --git a/src/contracts/multicall/vaultMulticall.ts b/src/contracts/multicall/vaultMulticall.ts index 091334e1..9affb208 100644 --- a/src/contracts/multicall/vaultMulticall.ts +++ b/src/contracts/multicall/vaultMulticall.ts @@ -1,5 +1,3 @@ -import getVault from '../../services/vault/requests/getVault' - import { getHarvestArgs, handleMulticall, @@ -58,9 +56,7 @@ const vaultMulticall = async (values: VaultMulticallInput): P const needHarvest = params.some(({ method }) => harvestCheckMethods.includes(method)) - const { isMetaVault } = await getVault(values) - - if (needHarvest && !isMetaVault) { + if (needHarvest) { const harvestArgs = await getHarvestArgs(values) if (harvestArgs) { diff --git a/src/contracts/vault/createVaultContract.ts b/src/contracts/vault/createVaultContract.ts index c51aab1b..33bbae62 100644 --- a/src/contracts/vault/createVaultContract.ts +++ b/src/contracts/vault/createVaultContract.ts @@ -12,7 +12,6 @@ import { import { DefaultVaultAbi as DefaultVaultType, - GnosisVaultDiffAbi as GnosisVaultDiffType, MainnetVaultDiffAbi as MainnetVaultDiffType, PrivateVaultDiffAbi as PrivateVaultDiffType, BlocklistVaultDiffAbi as BlocklistVaultDiffType, @@ -25,7 +24,6 @@ import { ModifiedVault } from '../../services/vault/requests/getVault/types' type Options = Partial> & { - chainId?: Network isDepositWithMint?: boolean } @@ -34,34 +32,24 @@ type CreateContractsInput = { options?: T } -type Output = Omit< - (T['chainId'] extends Network.Gnosis - ? DefaultVaultType & GnosisVaultDiffType - : DefaultVaultType & MainnetVaultDiffType - ) & - (T['isBlocklist'] extends true - ? BlocklistVaultDiffType - : object - ) & - (T['isPrivate'] extends true - ? PrivateVaultDiffType - : object - ) & - (T['isDepositWithMint'] extends true - ? DepositWithMintDiffType - : object - ), - 'connect' -> & { +type VaultType = ( + DefaultVaultType + & MainnetVaultDiffType + & (T['isBlocklist'] extends true ? BlocklistVaultDiffType : object) + & (T['isPrivate'] extends true ? PrivateVaultDiffType : object) + & (T['isDepositWithMint'] extends true ? DepositWithMintDiffType : object) +) + +type Output = Omit, 'connect'> & { // overwrite, since each abi returns itself connect: (signer: any) => Output } -const createVaultContract = (provider: Provider) => ( +const createVaultContract = (provider: Provider, config: StakeWise.Config) => ( (input: CreateContractsInput): Output => { const { vaultAddress, options } = input - const isGnosis = Network.Gnosis === (options?.chainId || Network.Mainnet) + const isGnosis = config.network.chainId === Network.Gnosis let baseAbi = isGnosis ? DefaultVaultAbi.concat(GnosisVaultDiffAbi) diff --git a/src/graphql/subgraph/vault/harvestParamsQuery.graphql b/src/graphql/subgraph/vault/harvestParamsQuery.graphql index 9af08379..a1aac80b 100644 --- a/src/graphql/subgraph/vault/harvestParamsQuery.graphql +++ b/src/graphql/subgraph/vault/harvestParamsQuery.graphql @@ -3,6 +3,7 @@ query HarvestParams($address: ID!) { proof canHarvest rewardsRoot + isMetaVault reward: proofReward unlockedMevReward: proofUnlockedMevReward } diff --git a/src/services/rewardSplitter/transactions/createRewardSplitter/common.ts b/src/services/rewardSplitter/transactions/createRewardSplitter/common.ts index becd7e7f..5a0eb49c 100644 --- a/src/services/rewardSplitter/transactions/createRewardSplitter/common.ts +++ b/src/services/rewardSplitter/transactions/createRewardSplitter/common.ts @@ -1,6 +1,5 @@ import { validateArgs } from '../../../../helpers' import type { CreateRewardSplitterInput } from './types' -import { checkAdminAccess } from '../../../vault/transactions/util' export const commonLogic = async (values: CreateRewardSplitterInput) => { @@ -8,8 +7,6 @@ export const commonLogic = async (values: CreateRewardSplitterInput) => { validateArgs.address({ vaultAddress, userAddress }) - await checkAdminAccess(values) - const signer = await provider.getSigner(userAddress) return contracts.base.rewardSplitterFactory.connect(signer) diff --git a/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.ts b/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.ts index feea8a1c..b70c46b7 100644 --- a/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.ts +++ b/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.ts @@ -1,9 +1,10 @@ import { commonLogic } from './common' import type { CreateRewardSplitterInput } from './types' import { wrapErrorHandler } from '../../../../helpers' +import { checkAccess } from '../../../vault/transactions/util' -const createRewardSplitter = async (values: CreateRewardSplitterInput) => { +const createRewardSplitter = checkAccess(async (values) => { const rewardSplitterFactory = await commonLogic(values) const result = await wrapErrorHandler( @@ -12,7 +13,7 @@ const createRewardSplitter = async (values: CreateRewardSplitterInput) => { ) return result.hash -} +}) export default createRewardSplitter diff --git a/src/services/rewardSplitter/transactions/updateFeeRecipients/common.ts b/src/services/rewardSplitter/transactions/updateFeeRecipients/common.ts index 85168890..b938554a 100644 --- a/src/services/rewardSplitter/transactions/updateFeeRecipients/common.ts +++ b/src/services/rewardSplitter/transactions/updateFeeRecipients/common.ts @@ -4,7 +4,6 @@ import Vault from '../../../vault' import { validateArgs } from '../../../../helpers' import { rewardSplitterMulticall } from '../../../../contracts' import type { RewardSplitterMulticallBaseInput } from '../../../../contracts' -import { checkAdminAccess } from '../../../vault/transactions/util' import type { FeeRecipient, UpdateFeeRecipientsInput } from './types' @@ -27,7 +26,7 @@ const validateList = (values: Record, withEmptyCheck?: b export const commonLogic = async (values: UpdateFeeRecipientsInput) => { const { - contracts, userAddress, vaultAddress, options, + contracts, userAddress, vaultAddress, rewardSplitterAddress, feeRecipients, } = values @@ -40,8 +39,6 @@ export const commonLogic = async (values: UpdateFeeRecipientsInput) => { validateList({ oldFeeRecipients }, false) } - await checkAdminAccess(values) - const baseMulticall: RewardSplitterMulticallBaseInput = { rewardSplitterContract: contracts.helpers.createRewardSplitter(rewardSplitterAddress), ...values, diff --git a/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.ts b/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.ts index 840871c5..eb0d0ff4 100644 --- a/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.ts +++ b/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.ts @@ -1,15 +1,16 @@ import { commonLogic } from './common' import type { UpdateFeeRecipientsInput } from './types' import { rewardSplitterMulticall } from '../../../../contracts' +import { checkAccess } from '../../../vault/transactions/util' -const updateFeeRecipients = async (values: UpdateFeeRecipientsInput) => { +const updateFeeRecipients = checkAccess(async (values) => { const multicallArgs = await commonLogic(values) const result = await rewardSplitterMulticall<{ hash: string }>(multicallArgs) return result.hash -} +}) export default updateFeeRecipients diff --git a/src/services/vault/requests/getHarvestParams/modifyHarvestParams.ts b/src/services/vault/requests/getHarvestParams/modifyHarvestParams.ts index 24ca6dd9..eb175dad 100644 --- a/src/services/vault/requests/getHarvestParams/modifyHarvestParams.ts +++ b/src/services/vault/requests/getHarvestParams/modifyHarvestParams.ts @@ -2,10 +2,11 @@ import { HarvestParamsQueryPayload } from '../../../../graphql/subgraph/vault' const modifyHarvestParams = (data: HarvestParamsQueryPayload) => { - const { canHarvest, ...params } = data.harvestParams || {} as HarvestParamsQueryPayload['harvestParams'] + const { canHarvest, isMetaVault, ...params } = data.harvestParams || {} as HarvestParamsQueryPayload['harvestParams'] return { canHarvest, + isMetaVault, params: { proof: params.proof || [], reward: params.reward || '0', diff --git a/src/services/vault/transactions/addSubVault/addSubVault.ts b/src/services/vault/transactions/addSubVault/addSubVault.ts index 34ddf7cb..aa933c84 100644 --- a/src/services/vault/transactions/addSubVault/addSubVault.ts +++ b/src/services/vault/transactions/addSubVault/addSubVault.ts @@ -1,10 +1,10 @@ import { commonLogic } from './common' -import checkAccess from './checkAccess' +import { checkAccess } from '../util' import type { AddSubVaultInput } from './types' import { wrapErrorHandler } from '../../../../helpers' -const addSubVault = checkAccess(async (values: AddSubVaultInput) => { +const addSubVault = checkAccess(async (values) => { const { provider, userAddress, subVaultAddress } = values const signer = await provider.getSigner(userAddress) diff --git a/src/services/vault/transactions/addSubVault/checkAccess.ts b/src/services/vault/transactions/addSubVault/checkAccess.ts deleted file mode 100644 index d343be14..00000000 --- a/src/services/vault/transactions/addSubVault/checkAccess.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { checkAdminAccess } from '../util' -import type { AddSubVaultInput as Input } from './types' - - -type Action = (values: Input) => Promise - -const checkAccess = (action: Action) => ( - async (values: Input) => { - try { - const result = await action(values) - - return result - } - catch (actionError) { - return checkAdminAccess(values) - .then( - () => Promise.reject(actionError), - (error) => Promise.reject(error) - ) - } - } -) - - -export default checkAccess diff --git a/src/services/vault/transactions/claimExitQueue/common.ts b/src/services/vault/transactions/claimExitQueue/common.ts index 0bc58fee..10289b42 100644 --- a/src/services/vault/transactions/claimExitQueue/common.ts +++ b/src/services/vault/transactions/claimExitQueue/common.ts @@ -13,7 +13,7 @@ const validatePositions = (positions: ClaimExitQueueInput['positions']) => { } export const commonLogic = (values: ClaimExitQueueInput) => { - const { contracts, positions, vaultAddress, userAddress } = values + const { contracts, positions, vaultAddress } = values validatePositions(positions) diff --git a/src/services/vault/transactions/deposit/nativeToken/common.ts b/src/services/vault/transactions/deposit/nativeToken/common.ts index 91cc6c52..18c7f62a 100644 --- a/src/services/vault/transactions/deposit/nativeToken/common.ts +++ b/src/services/vault/transactions/deposit/nativeToken/common.ts @@ -2,14 +2,12 @@ import { ZeroAddress } from 'ethers' import { validate } from '../validate' import type { DepositInput } from '../types' -import getHarvestParams from '../../../requests/getHarvestParams' +import getHarvestArgs, { HarvestArgs } from '../../../../../contracts/multicall/util/getHarvestArgs' import { PayableOverrides } from '../../../../../contracts/types/common' -import { HarvestParamsQueryPayload } from '../../../../../graphql/subgraph/vault' -type HarvestParams = Omit type BaseParams = [ string, string, PayableOverrides ] -type UpdateStateParams = [ string, string, HarvestParams, PayableOverrides ] +type UpdateStateParams = [ string, string, HarvestArgs, PayableOverrides ] export const commonLogic = async (values: DepositInput) => { const { contracts, userAddress, vaultAddress, referrerAddress = ZeroAddress, assets } = values @@ -22,15 +20,15 @@ export const commonLogic = async (values: DepositInput) => { value: assets, } - const { params: harvestParams, canHarvest } = await getHarvestParams(values) + const harvestArgs = await getHarvestArgs(values) const baseParams: BaseParams = [ userAddress, referrerAddress, overrides ] - const updateStateParams: UpdateStateParams = [ userAddress, referrerAddress, harvestParams, overrides ] + const updateStateParams: UpdateStateParams = [ userAddress, referrerAddress, harvestArgs as HarvestArgs, overrides ] return { vaultContract, baseParams, updateStateParams, - canHarvest, + canHarvest: Boolean(harvestArgs), } } diff --git a/src/services/vault/transactions/deposit/otherToken/common.ts b/src/services/vault/transactions/deposit/otherToken/common.ts index a6a45aec..93838c6d 100644 --- a/src/services/vault/transactions/deposit/otherToken/common.ts +++ b/src/services/vault/transactions/deposit/otherToken/common.ts @@ -7,7 +7,7 @@ import type { VaultMulticallBaseInput } from '../../../../../contracts' export const commonLogic = (values: DepositInput) => { - const { options, contracts, vaultAddress, userAddress, referrerAddress = ZeroAddress, assets } = values + const { contracts, vaultAddress, userAddress, referrerAddress = ZeroAddress, assets } = values validate(values) @@ -19,7 +19,6 @@ export const commonLogic = (values: DepositInput) => { ] const vaultContract = contracts.helpers.createVault({ - options: { chainId: options.network }, vaultAddress, }) diff --git a/src/services/vault/transactions/ejectSubVault/checkAccess.ts b/src/services/vault/transactions/ejectSubVault/checkAccess.ts deleted file mode 100644 index 42de5aad..00000000 --- a/src/services/vault/transactions/ejectSubVault/checkAccess.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { checkAdminAccess } from '../util' -import type { EjectSubVaultInput as Input } from './types' - - -type Action = (values: Input) => Promise - -const checkAccess = (action: Action) => ( - async (values: Input) => { - try { - const result = await action(values) - - return result - } - catch (actionError) { - return checkAdminAccess(values) - .then( - () => Promise.reject(actionError), - (error) => Promise.reject(error) - ) - } - } -) - - -export default checkAccess diff --git a/src/services/vault/transactions/ejectSubVault/ejectSubVault.ts b/src/services/vault/transactions/ejectSubVault/ejectSubVault.ts index 80a9c23d..3ddbb9f1 100644 --- a/src/services/vault/transactions/ejectSubVault/ejectSubVault.ts +++ b/src/services/vault/transactions/ejectSubVault/ejectSubVault.ts @@ -1,10 +1,10 @@ import { commonLogic } from './common' -import checkAccess from './checkAccess' +import { checkAccess } from '../util' import type { EjectSubVaultInput } from './types' import { wrapErrorHandler } from '../../../../helpers' -const ejectSubVault = checkAccess(async (values: EjectSubVaultInput) => { +const ejectSubVault = checkAccess(async (values) => { const { provider, userAddress, subVaultAddress } = values const signer = await provider.getSigner(userAddress) diff --git a/src/services/vault/transactions/index.ts b/src/services/vault/transactions/index.ts index 5d1490f0..280f5bb2 100644 --- a/src/services/vault/transactions/index.ts +++ b/src/services/vault/transactions/index.ts @@ -5,12 +5,13 @@ import { multicall, VaultMulticallInput } from './multicall' import { createWithdraw, ExtractWithdraw } from './withdraw' import { createVaultCreator, ExtractCreateVault } from './createVault' import { createAddSubVault, ExtractAddSubVaultInput } from './addSubVault' -import { createRejectSubVault, ExtractRejectSubVaultInput } from './rejectSubVault' -import { createEjectSubVault, ExtractEjectSubVaultInput } from './ejectSubVault' +import { createUpdateState, ExtractUpdateStateInput } from './updateState' import { createClaimExitQueue, ExtractClaimExitQueue } from './claimExitQueue' +import { createEjectSubVault, ExtractEjectSubVaultInput } from './ejectSubVault' +import { createRejectSubVault, ExtractRejectSubVaultInput } from './rejectSubVault' import { createSetDepositDataRoot, ExtractSetDepositDataRoot } from './setDepositDataRoot' -import { createNativeTokenDeposit, createOtherTokenDeposit, ExtractDeposit } from './deposit' import { createSetDepositDataManager, ExtractSetDepositDataManager } from './setDepositDataManager' +import { createNativeTokenDeposit, createOtherTokenDeposit, ExtractDeposit } from './deposit' class VaultTransactions { @@ -77,6 +78,12 @@ class VaultTransactions { */ public ejectSubVault: ExtractEjectSubVaultInput + /** + * @description Update a vault state. + * @see https://docs.stakewise.io/vault/transactions/updatestate + */ + public updateState: ExtractUpdateStateInput + constructor(params: StakeWise.CommonParams) { this.params = params @@ -92,6 +99,7 @@ class VaultTransactions { this.operate = transactionWrapper(params, createOperate(params)) this.withdraw = transactionWrapper(params, createWithdraw(params)) this.create = transactionWrapper(params, createVaultCreator(params)) + this.updateState = transactionWrapper(params, createUpdateState(params)) this.addSubVault = transactionWrapper(params, createAddSubVault(params)) this.rejectSubVault = transactionWrapper(params, createRejectSubVault(params)) this.ejectSubVault = transactionWrapper(params, createEjectSubVault(params)) diff --git a/src/services/vault/transactions/multicall/index.ts b/src/services/vault/transactions/multicall/index.ts index 1f9e7165..a51cda22 100644 --- a/src/services/vault/transactions/multicall/index.ts +++ b/src/services/vault/transactions/multicall/index.ts @@ -7,7 +7,7 @@ export type VaultMulticallInput = Pick & StakeWise.CommonParams export const multicall = async (values: VaultMulticallInput) => { - const { vaultAddress, request, contracts, config } = values + const { vaultAddress, request, contracts } = values const { isBlocklist, isPrivate, version } = await getVault(values) @@ -16,7 +16,6 @@ export const multicall = async (values: VaultMulticallInput) isPrivate, isBlocklist, isDepositWithMint: version >= 3, - chainId: config.network.chainId, }, vaultAddress, }) diff --git a/src/services/vault/transactions/operate/checkAccess.ts b/src/services/vault/transactions/operate/checkAccess.ts deleted file mode 100644 index dd03c81f..00000000 --- a/src/services/vault/transactions/operate/checkAccess.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { OperateTransactionInput as Input } from './types' - -import { - checkAdminAccess, - checkWhitelisterAccess, - checkBlocklistManagerAccess, -} from '../util' - - -type Action = (values: Input) => Promise - -const checkAccess = (action: Action) => ( - async (values: Input) => { - const { - blocklist, whitelist, whitelistManager, feeRecipient, feePercent, - blocklistManager, metadataIpfsHash, validatorsManager, admin, - } = values - - try { - const result = await action(values) - - return result - } - catch (actionError) { - const isAdmin = Boolean( - admin - || feePercent - || feeRecipient - || whitelistManager - || blocklistManager - || metadataIpfsHash - || validatorsManager - ) - const isWhitelistManager = Boolean(whitelist) - const isBlocklistManager = Boolean(blocklist) - - const checkPromises = [] - - if (isAdmin) { - checkPromises.push( - checkAdminAccess(values) - ) - } - if (isWhitelistManager) { - checkPromises.push( - checkWhitelisterAccess(values) - ) - } - if (isBlocklistManager) { - checkPromises.push( - checkBlocklistManagerAccess(values) - ) - } - - return Promise.all(checkPromises) - .then( - () => Promise.reject(actionError), - (error) => Promise.reject(error) - ) - } - } -) - - -export default checkAccess diff --git a/src/services/vault/transactions/operate/common.ts b/src/services/vault/transactions/operate/common.ts index dcda2eef..a0bd7b47 100644 --- a/src/services/vault/transactions/operate/common.ts +++ b/src/services/vault/transactions/operate/common.ts @@ -25,14 +25,12 @@ export const commonLogic = async (values: OperateTransactionInput) => { validateArgs.address({ vaultAddress, userAddress }) - const chainId = options.network const isPrivate = Boolean(whitelist?.length || whitelistManager) const isBlocklist = Boolean(blocklist?.length || blocklistManager) const vaultContract = contracts.helpers.createVault({ vaultAddress, options: { - chainId, isPrivate, isBlocklist, }, diff --git a/src/services/vault/transactions/operate/getRolesList.ts b/src/services/vault/transactions/operate/getRolesList.ts new file mode 100644 index 00000000..648eafeb --- /dev/null +++ b/src/services/vault/transactions/operate/getRolesList.ts @@ -0,0 +1,40 @@ +import type { OperateTransactionInput as Input } from './types' + +import { Role } from '../util' + + +const getRolesList = (values: Input) => { + const { + blocklist, whitelist, whitelistManager, feeRecipient, feePercent, + blocklistManager, metadataIpfsHash, validatorsManager, admin, + } = values + + const isAdmin = Boolean( + admin + || feePercent + || feeRecipient + || whitelistManager + || blocklistManager + || metadataIpfsHash + || validatorsManager + ) + const isWhitelistManager = Boolean(whitelist) + const isBlocklistManager = Boolean(blocklist) + + const rolesList: Role[] = [] + + if (isAdmin) { + rolesList.push('admin') + } + if (isWhitelistManager) { + rolesList.push('whitelister') + } + if (isBlocklistManager) { + rolesList.push('blocklistManager') + } + + return rolesList +} + + +export default getRolesList diff --git a/src/services/vault/transactions/operate/operate.ts b/src/services/vault/transactions/operate/operate.ts index 5d9615aa..db842b99 100644 --- a/src/services/vault/transactions/operate/operate.ts +++ b/src/services/vault/transactions/operate/operate.ts @@ -1,20 +1,23 @@ +import getRolesList from './getRolesList' import { commonLogic } from './common' -import checkAccess from './checkAccess' -import { uploadMetadata } from '../util' -import type { OperateInput } from './types' import { vaultMulticall } from '../../../../contracts' +import type { OperateInput } from './types' +import { checkAccess, uploadMetadata } from '../util' -const operate = checkAccess(async (values: OperateInput) => { - const { image, displayName, description, ...rest } = values +const operate = checkAccess( + async (values: OperateInput) => { + const { image, displayName, description, ...rest } = values - const metadataIpfsHash = await uploadMetadata(values) - const multicallCommonArgs = await commonLogic({ metadataIpfsHash, ...rest }) + const metadataIpfsHash = await uploadMetadata(values) + const multicallCommonArgs = await commonLogic({ metadataIpfsHash, ...rest }) - const result = await vaultMulticall<{ hash: string }>(multicallCommonArgs) + const result = await vaultMulticall<{ hash: string }>(multicallCommonArgs) - return result.hash -}) + return result.hash + }, + getRolesList +) export default operate diff --git a/src/services/vault/transactions/rejectSubVault/checkAccess.ts b/src/services/vault/transactions/rejectSubVault/checkAccess.ts deleted file mode 100644 index 8c5a141f..00000000 --- a/src/services/vault/transactions/rejectSubVault/checkAccess.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { checkAdminAccess } from '../util' -import type { RejectSubVaultInput as Input } from './types' - - -type Action = (values: Input) => Promise - -const checkAccess = (action: Action) => ( - async (values: Input) => { - try { - const result = await action(values) - - return result - } - catch (actionError) { - return checkAdminAccess(values) - .then( - () => Promise.reject(actionError), - (error) => Promise.reject(error) - ) - } - } -) - - -export default checkAccess diff --git a/src/services/vault/transactions/rejectSubVault/rejectSubVault.ts b/src/services/vault/transactions/rejectSubVault/rejectSubVault.ts index 6f0622c8..b14c6b3f 100644 --- a/src/services/vault/transactions/rejectSubVault/rejectSubVault.ts +++ b/src/services/vault/transactions/rejectSubVault/rejectSubVault.ts @@ -1,10 +1,10 @@ import { commonLogic } from './common' -import checkAccess from './checkAccess' +import { checkAccess } from '../util' import type { RejectSubVaultInput } from './types' import { wrapErrorHandler } from '../../../../helpers' -const rejectSubVault = checkAccess(async (values: RejectSubVaultInput) => { +const rejectSubVault = checkAccess(async (values) => { const { provider, userAddress, subVaultAddress } = values const signer = await provider.getSigner(userAddress) diff --git a/src/services/vault/transactions/setDepositDataManager/checkAccess.ts b/src/services/vault/transactions/setDepositDataManager/checkAccess.ts deleted file mode 100644 index a06e3638..00000000 --- a/src/services/vault/transactions/setDepositDataManager/checkAccess.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { checkAdminAccess } from '../util' -import type { SetDepositDataManagerInput as Input } from './types' - - -type Action = (values: Input) => Promise - -const checkAccess = (action: Action) => ( - async (values: Input) => { - try { - const result = await action(values) - - return result - } - catch (actionError) { - return checkAdminAccess(values) - .then( - () => Promise.reject(actionError), - (error) => Promise.reject(error) - ) - } - } -) - - -export default checkAccess diff --git a/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.ts b/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.ts index 7f99df5f..d05d1c9a 100644 --- a/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.ts +++ b/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.ts @@ -1,12 +1,12 @@ import { commonLogic } from './common' -import checkAccess from './checkAccess' +import { checkAccess } from '../util' import type { SetDepositDataManagerInput } from './types' import { wrapErrorHandler } from '../../../../helpers' import getVaultVersion from '../../requests/getVaultVersion' -const setDepositDataManager = checkAccess(async (values: SetDepositDataManagerInput) => { - const { provider, userAddress, managerAddress, vaultAddress, contracts, options } = values +const setDepositDataManager = checkAccess(async (values) => { + const { provider, userAddress, managerAddress, vaultAddress, contracts } = values const signer = await provider.getSigner(userAddress) @@ -15,9 +15,6 @@ const setDepositDataManager = checkAccess(async (values: SetDepositDataM if (isV1Version) { const vaultContract = contracts.helpers.createVault({ vaultAddress, - options: { - chainId: options.network, - }, }) const signedContract = vaultContract.connect(signer) diff --git a/src/services/vault/transactions/setDepositDataRoot/checkAccess.ts b/src/services/vault/transactions/setDepositDataRoot/checkAccess.ts deleted file mode 100644 index 388a9215..00000000 --- a/src/services/vault/transactions/setDepositDataRoot/checkAccess.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { checkDepositDataManagerAccess } from '../util' -import type { SetDepositDataRootInput as Input } from './types' - - -type Action = (values: Input) => Promise - -const checkAccess = (action: Action) => ( - async (values: Input) => { - try { - const result = await action(values) - - return result - } - catch (actionError) { - return checkDepositDataManagerAccess(values) - .then( - () => Promise.reject(actionError), - (error) => Promise.reject(error) - ) - } - } -) - - -export default checkAccess diff --git a/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.ts b/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.ts index 56c4283a..b227a2ba 100644 --- a/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.ts +++ b/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.ts @@ -1,45 +1,45 @@ import { commonLogic } from './common' -import checkAccess from './checkAccess' +import { checkAccess } from '../util' import type { SetDepositDataRootInput } from './types' import { wrapErrorHandler } from '../../../../helpers' import getVaultVersion from '../../requests/getVaultVersion' -const setDepositDataRoot = checkAccess(async (values: SetDepositDataRootInput) => { - const { provider, userAddress, vaultAddress, depositDataRoot, contracts, options } = values +const setDepositDataRoot = checkAccess( + async (values) => { + const { provider, userAddress, vaultAddress, depositDataRoot, contracts } = values - const signer = await provider.getSigner(userAddress) + const signer = await provider.getSigner(userAddress) - const { isV1Version } = await getVaultVersion(values) + const { isV1Version } = await getVaultVersion(values) - if (isV1Version) { - const vaultContract = contracts.helpers.createVault({ - vaultAddress, - options: { - chainId: options.network, - }, - }) + if (isV1Version) { + const vaultContract = contracts.helpers.createVault({ + vaultAddress, + }) - const signedVaultContract = vaultContract.connect(signer) + const signedVaultContract = vaultContract.connect(signer) - const result = await wrapErrorHandler( - signedVaultContract.setValidatorsRoot(depositDataRoot), - 'transaction' - ) + const result = await wrapErrorHandler( + signedVaultContract.setValidatorsRoot(depositDataRoot), + 'transaction' + ) - return result.hash - } + return result.hash + } - const contract = commonLogic(values) - const signedDepositDataRegistryContract = contract.connect(signer) + const contract = commonLogic(values) + const signedDepositDataRegistryContract = contract.connect(signer) - const result = await wrapErrorHandler( - signedDepositDataRegistryContract.setDepositDataRoot(vaultAddress, depositDataRoot), - 'transaction' - ) + const result = await wrapErrorHandler( + signedDepositDataRegistryContract.setDepositDataRoot(vaultAddress, depositDataRoot), + 'transaction' + ) - return result?.hash -}) + return result?.hash + }, + [ 'depositDataManager' ] +) export default setDepositDataRoot diff --git a/src/services/vault/transactions/updateState/common.ts b/src/services/vault/transactions/updateState/common.ts new file mode 100644 index 00000000..22d0baa1 --- /dev/null +++ b/src/services/vault/transactions/updateState/common.ts @@ -0,0 +1,21 @@ +import { getHarvestArgs } from '../../../../contracts/multicall/util' +import { validateArgs } from '../../../../helpers' +import { UpdateStateInput } from './types' + + +export const commonLogic = async (values: UpdateStateInput) => { + const { contracts, vaultAddress, userAddress } = values + + validateArgs.address({ vaultAddress, userAddress }) + + const harvestArgs = await getHarvestArgs(values) + + const vaultContract = contracts.helpers.createVault({ + vaultAddress, + }) + + return { + vaultContract, + harvestArgs, + } +} diff --git a/src/services/vault/transactions/updateState/index.ts b/src/services/vault/transactions/updateState/index.ts new file mode 100644 index 00000000..dd832a62 --- /dev/null +++ b/src/services/vault/transactions/updateState/index.ts @@ -0,0 +1,15 @@ +import updateState from './updateState' +import updateStateGas from './updateStateGas' +import updateStateEncode from './updateStateEncode' +import type { UpdateStateInput, ExtractUpdateStateInput } from './types' + + +export const createUpdateState = (params: StakeWise.CommonParams): ExtractUpdateStateInput => { + const result = (values: StakeWise.ExtractInput) => updateState({ ...params, ...values }) + result.encode = (values: StakeWise.ExtractInput) => updateStateEncode({ ...params, ...values }) + result.estimateGas = (values: StakeWise.ExtractInput) => updateStateGas({ ...params, ...values }) + + return result +} + +export type { ExtractUpdateStateInput } from './types' diff --git a/src/services/vault/transactions/updateState/types.d.ts b/src/services/vault/transactions/updateState/types.d.ts new file mode 100644 index 00000000..dda9df5f --- /dev/null +++ b/src/services/vault/transactions/updateState/types.d.ts @@ -0,0 +1,10 @@ +export type UpdateStateInput = StakeWise.CommonParams & { + userAddress: string + vaultAddress: string +} + +export interface ExtractUpdateStateInput { + (values: StakeWise.ExtractInput): Promise + estimateGas: (values: StakeWise.ExtractInput) => Promise + encode: (values: StakeWise.ExtractInput) => Promise> +} diff --git a/src/services/vault/transactions/updateState/updateState.md b/src/services/vault/transactions/updateState/updateState.md new file mode 100644 index 00000000..3fc4577e --- /dev/null +++ b/src/services/vault/transactions/updateState/updateState.md @@ -0,0 +1,34 @@ +--- +id: updateState +slug: /vault/transactions/updatestate +--- + +#### Description: + +Update the state of a vault if required. This is used to update the state of a vault before a transaction has been executed. + +#### Arguments: + +| Name | Type | Required | Description | +|----------------|----------|----------|---------------------------| +| userAddress | `string` | **Yes** | The user address | +| vaultAddress | `string` | **Yes** | The address of the vault | + +#### Example: + +```ts +const params = { + vaultAddress: '0x...', + userAddress: '0x...', +} + +// Send transaction +// Will return empty string if updateState is not required +const hash = await sdk.vault.updateState(params) +// When you sign transactions on the backend (for custodians) +// Will return empty object if updateState is not required +const { data, to } = await sdk.vault.updateState.encode(params) +// Get an approximate gas per transaction +// Will return 0n if updateState is not required +const gas = await sdk.vault.updateState.estimateGas(params) +``` diff --git a/src/services/vault/transactions/updateState/updateState.ts b/src/services/vault/transactions/updateState/updateState.ts new file mode 100644 index 00000000..f1d321fb --- /dev/null +++ b/src/services/vault/transactions/updateState/updateState.ts @@ -0,0 +1,28 @@ +import { commonLogic } from './common' +import { wrapErrorHandler } from '../../../../helpers' +import type { UpdateStateInput } from './types' + + +const updateState = async (values: UpdateStateInput) => { + const { provider, userAddress } = values + + const { vaultContract, harvestArgs } = await commonLogic(values) + + const signer = await provider.getSigner(userAddress) + + const signedContract = vaultContract.connect(signer) + + if (!harvestArgs) { + return '' + } + + const response = await wrapErrorHandler( + signedContract.updateState(harvestArgs), + 'transaction' + ) + + return response.hash +} + + +export default updateState diff --git a/src/services/vault/transactions/updateState/updateStateEncode.ts b/src/services/vault/transactions/updateState/updateStateEncode.ts new file mode 100644 index 00000000..bf9d96df --- /dev/null +++ b/src/services/vault/transactions/updateState/updateStateEncode.ts @@ -0,0 +1,16 @@ +import { commonLogic } from './common' +import type { UpdateStateInput } from './types' + + +const updateStateEncode = async (values: UpdateStateInput) => { + const { vaultContract, harvestArgs } = await commonLogic(values) + + if (!harvestArgs) { + return {} + } + + return vaultContract.updateState.populateTransaction(harvestArgs) +} + + +export default updateStateEncode diff --git a/src/services/vault/transactions/updateState/updateStateGas.ts b/src/services/vault/transactions/updateState/updateStateGas.ts new file mode 100644 index 00000000..ef865fdd --- /dev/null +++ b/src/services/vault/transactions/updateState/updateStateGas.ts @@ -0,0 +1,27 @@ +import { commonLogic } from './common' +import { getGas, wrapErrorHandler } from '../../../../helpers' +import type { UpdateStateInput } from './types' + + +const updateStateGas = async (values: UpdateStateInput) => { + const { provider, userAddress } = values + + const { vaultContract, harvestArgs } = await commonLogic(values) + + if (!harvestArgs) { + return 0n + } + + const signer = await provider.getSigner(userAddress) + const signedContract = vaultContract.connect(signer) + + const estimatedGas = await wrapErrorHandler( + signedContract.updateState.estimateGas(harvestArgs), + 'gas' + ) + + return getGas({ estimatedGas, provider: values.provider }) +} + + +export default updateStateGas diff --git a/src/services/vault/transactions/util/check/checkAccess.ts b/src/services/vault/transactions/util/check/checkAccess.ts new file mode 100644 index 00000000..bc584350 --- /dev/null +++ b/src/services/vault/transactions/util/check/checkAccess.ts @@ -0,0 +1,35 @@ +import type { CheckInput } from './types' +import roles, { Role } from './roles' + + +type Action = (values: Input) => Promise +type GetRolesList = (values: Input) => Role[] + +const checkAccess = ( + action: Action, + getRolesList: Role[] | GetRolesList = [ 'admin' ] +) => ( + async (values: Input) => { + try { + const result = await action(values) + + return result + } + catch (actionError) { + const roleList: Role[] = typeof getRolesList === 'function' + ? getRolesList(values) + : getRolesList + + const checkPromises = roleList.map((role) => roles[role](values)) + + return Promise.all(checkPromises) + .then( + () => Promise.reject(actionError), + (error) => Promise.reject(error) + ) + } + } +) + + +export default checkAccess diff --git a/src/services/vault/transactions/util/check/index.ts b/src/services/vault/transactions/util/check/index.ts index 36701da3..ed179c33 100644 --- a/src/services/vault/transactions/util/check/index.ts +++ b/src/services/vault/transactions/util/check/index.ts @@ -1,4 +1,2 @@ -export { default as checkAdminAccess } from './checkAdminAccess' -export { default as checkWhitelisterAccess } from './checkWhitelisterAccess' -export { default as checkBlocklistManagerAccess } from './checkBlocklistManagerAccess' -export { default as checkDepositDataManagerAccess } from './checkDepositDataManagerAccess' +export type { Role } from './roles' +export { default as checkAccess } from './checkAccess' diff --git a/src/services/vault/transactions/util/check/checkAdminAccess.ts b/src/services/vault/transactions/util/check/roles/checkAdminAccess.ts similarity index 92% rename from src/services/vault/transactions/util/check/checkAdminAccess.ts rename to src/services/vault/transactions/util/check/roles/checkAdminAccess.ts index 77460cf9..2248a610 100644 --- a/src/services/vault/transactions/util/check/checkAdminAccess.ts +++ b/src/services/vault/transactions/util/check/roles/checkAdminAccess.ts @@ -1,4 +1,4 @@ -import type { CheckInput } from './types' +import type { CheckInput } from '../types' const checkAdminAccess = async ({ userAddress, vaultAddress, contracts }: CheckInput) => { diff --git a/src/services/vault/transactions/util/check/checkBlocklistManagerAccess.ts b/src/services/vault/transactions/util/check/roles/checkBlocklistManagerAccess.ts similarity index 93% rename from src/services/vault/transactions/util/check/checkBlocklistManagerAccess.ts rename to src/services/vault/transactions/util/check/roles/checkBlocklistManagerAccess.ts index cbddbe4f..41054ecd 100644 --- a/src/services/vault/transactions/util/check/checkBlocklistManagerAccess.ts +++ b/src/services/vault/transactions/util/check/roles/checkBlocklistManagerAccess.ts @@ -1,4 +1,4 @@ -import type { CheckInput } from './types' +import type { CheckInput } from '../types' const checkBlocklistManagerAccess = async ({ userAddress, vaultAddress, contracts }: CheckInput) => { diff --git a/src/services/vault/transactions/util/check/checkDepositDataManagerAccess.ts b/src/services/vault/transactions/util/check/roles/checkDepositDataManagerAccess.ts similarity index 88% rename from src/services/vault/transactions/util/check/checkDepositDataManagerAccess.ts rename to src/services/vault/transactions/util/check/roles/checkDepositDataManagerAccess.ts index 5065f35b..e0a65b92 100644 --- a/src/services/vault/transactions/util/check/checkDepositDataManagerAccess.ts +++ b/src/services/vault/transactions/util/check/roles/checkDepositDataManagerAccess.ts @@ -1,5 +1,5 @@ -import getVaultVersion from '../../../requests/getVaultVersion' -import type { CheckInput } from './types' +import getVaultVersion from '../../../../requests/getVaultVersion' +import type { CheckInput } from '../types' const checkDepositDataManagerAccess = async (values: CheckInput) => { diff --git a/src/services/vault/transactions/util/check/checkWhitelisterAccess.ts b/src/services/vault/transactions/util/check/roles/checkWhitelisterAccess.ts similarity index 93% rename from src/services/vault/transactions/util/check/checkWhitelisterAccess.ts rename to src/services/vault/transactions/util/check/roles/checkWhitelisterAccess.ts index ffd33e7f..3a5bb719 100644 --- a/src/services/vault/transactions/util/check/checkWhitelisterAccess.ts +++ b/src/services/vault/transactions/util/check/roles/checkWhitelisterAccess.ts @@ -1,4 +1,4 @@ -import type { CheckInput } from './types' +import type { CheckInput } from '../types' const checkWhitelisterAccess = async ({ userAddress, vaultAddress, contracts }: CheckInput) => { diff --git a/src/services/vault/transactions/util/check/roles/index.ts b/src/services/vault/transactions/util/check/roles/index.ts new file mode 100644 index 00000000..274e5408 --- /dev/null +++ b/src/services/vault/transactions/util/check/roles/index.ts @@ -0,0 +1,16 @@ +import checkAdminAccess from './checkAdminAccess' +import checkWhitelisterAccess from './checkWhitelisterAccess' +import checkBlocklistManagerAccess from './checkBlocklistManagerAccess' +import checkDepositDataManagerAccess from './checkDepositDataManagerAccess' + + +const roles = { + admin: checkAdminAccess, + whitelister: checkWhitelisterAccess, + blocklistManager: checkBlocklistManagerAccess, + depositDataManager: checkDepositDataManagerAccess, +} + +export type Role = keyof typeof roles + +export default roles From 78a39c1e77304f14a1f4caa1cc605d49861d4dca Mon Sep 17 00:00:00 2001 From: Andrey Kopylov Date: Tue, 24 Mar 2026 15:16:48 +0500 Subject: [PATCH 11/27] add replica subgraphs --- .graphqlconfig | 2 +- src/helpers/configs/hoodi.ts | 2 +- src/helpers/configs/mainnet.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.graphqlconfig b/.graphqlconfig index 14330f00..46e91e8a 100644 --- a/.graphqlconfig +++ b/.graphqlconfig @@ -11,7 +11,7 @@ "extensions": { "endpoints": { "Subgraph GraphQL": { - "url": "https://graphs.stakewise.io/hoodi/subgraphs/name/stakewise/stage", + "url": "https://graphs-replica.stakewise.io/hoodi/subgraphs/name/stakewise/stage", "headers": { "user-agent": "JS GraphQL" }, diff --git a/src/helpers/configs/hoodi.ts b/src/helpers/configs/hoodi.ts index a241a123..451e56cd 100644 --- a/src/helpers/configs/hoodi.ts +++ b/src/helpers/configs/hoodi.ts @@ -8,7 +8,7 @@ export default { api: { backend: 'https://hoodi-api.stakewise.io/graphql', // TODO change (+ change .graphqlconfig) - subgraph: 'https://graphs.stakewise.io/hoodi/subgraphs/name/stakewise/stage', + subgraph: 'https://graphs-replica.stakewise.io/hoodi/subgraphs/name/stakewise/stage', }, pages: { beaconchain: 'https://hoodi.beaconcha.in/', diff --git a/src/helpers/configs/mainnet.ts b/src/helpers/configs/mainnet.ts index 3c91cd3b..552b50bb 100644 --- a/src/helpers/configs/mainnet.ts +++ b/src/helpers/configs/mainnet.ts @@ -8,8 +8,8 @@ export default { api: { backend: 'https://mainnet-api.stakewise.io/graphql', subgraph: [ - 'https://graphs.stakewise.io/mainnet-a/subgraphs/name/stakewise/prod', - 'https://graphs.stakewise.io/mainnet-b/subgraphs/name/stakewise/prod', + 'https://graphs.stakewise.io/mainnet/subgraphs/name/stakewise/prod', + 'https://graphs-replica.stakewise.io/mainnet/subgraphs/name/stakewise/prod', ], }, pages: { From 94d3b4b9c6494627e61b91a1af7855d6c1470fc4 Mon Sep 17 00:00:00 2001 From: CAst Date: Tue, 24 Mar 2026 16:44:52 +0500 Subject: [PATCH 12/27] Abort callback (#353) * Docs description (#349) * [docs-description] add description to .md files * [docs-description] fix doc * fix (#350) * [change-docs-links] change slug (#351) * [fix-slug] fixed (#352) * [abort-callback] open AbortCallback --- .github/workflows/sync-docs.yml | 4 ++-- documentation/03-Quick start/boost.md | 1 + documentation/03-Quick start/burn-os-token.md | 1 + documentation/03-Quick start/deposit-to-vault.md | 1 + documentation/03-Quick start/get-user-data.md | 1 + documentation/03-Quick start/get-vault-data.md | 1 + documentation/03-Quick start/mint-os-token.md | 1 + documentation/03-Quick start/unboost.md | 1 + documentation/03-Quick start/unstake.md | 1 + documentation/connecting-wallet.md | 2 ++ documentation/index.md | 1 + documentation/installation-setup.md | 1 + documentation/reference.md | 12 ++++-------- src/index.ts | 2 +- src/modules/gql-module/index.ts | 1 + src/services/boost/requests/getData/getData.md | 3 ++- .../getLeverageStrategyData.md | 3 ++- .../getLeverageStrategyProxy.md | 3 ++- .../requests/getQueuePosition/getQueuePosition.md | 3 ++- .../boost/transactions/claimQueue/claimQueue.md | 3 ++- src/services/boost/transactions/lock/lock.md | 9 +++++---- src/services/boost/transactions/unlock/unlock.md | 5 +++-- .../upgradeLeverageStrategy.md | 3 ++- .../requests/getRewards/getRewards.md | 9 +++++---- .../distributorRewards/transactions/claim/claim.md | 9 +++++---- .../osToken/helpers/getBurnAmount/getBurnAmount.md | 9 +++++---- .../getBurnAmountForUnstake.md | 3 ++- .../helpers/getHealthFactor/getHealthFactor.md | 9 +++++---- .../getAssetsFromShares/getAssetsFromShares.md | 3 ++- .../osToken/requests/getBalance/getBalance.md | 3 ++- .../osToken/requests/getMaxMint/getMaxMint.md | 9 +++++---- .../requests/getMaxMintAmount/getMaxMintAmount.md | 3 ++- .../osToken/requests/getOsTokenAPY/getOsTokenAPY.md | 3 ++- .../requests/getOsTokenRate/getOsTokenRate.md | 3 ++- .../osToken/requests/getPosition/getPosition.md | 9 +++++---- .../getSharesFromAssets/getSharesFromAssets.md | 3 ++- src/services/osToken/transactions/burn/burn.md | 3 ++- src/services/osToken/transactions/mint/mint.md | 5 +++-- .../requests/getClaimAmount/getClaimAmount.md | 3 ++- .../transactions/claimRewards/claimRewards.md | 3 ++- .../createRewardSplitter/createRewardSplitter.md | 3 ++- .../transactions/setClaimer/setClaimer.md | 3 ++- .../updateFeeRecipients/updateFeeRecipients.md | 5 +++-- src/services/utils/getFiatRates/getFiatRates.md | 3 ++- .../utils/getFiatRatesByDay/getFiatRatesByDay.md | 3 ++- .../utils/getPermitSignature/getPermitSignature.md | 3 ++- .../utils/getStakewiseStats/getStakewiseStats.md | 3 ++- .../utils/getTransactions/getTransactions.md | 3 ++- .../vault/requests/getBlocklist/getBlocklist.md | 3 ++- .../getExitQueuePositions/getExitQueuePositions.md | 3 ++- .../requests/getHarvestParams/getHarvestParams.md | 3 ++- .../vault/requests/getMaxWithdraw/getMaxWithdraw.md | 9 +++++---- .../getMaxWithdrawAmount/getMaxWithdrawAmount.md | 3 ++- .../requests/getOsTokenConfig/getOsTokenConfig.md | 3 ++- .../getPeriodicDistributions.md | 3 ++- .../getRewardSplitters/getRewardSplitters.md | 3 ++- .../requests/getStakeBalance/getStakeBalance.md | 3 ++- .../requests/getStakerActions/getStakerActions.md | 3 ++- src/services/vault/requests/getUserApy/getUserApy.md | 3 ++- .../vault/requests/getUserRewards/getUserRewards.md | 3 ++- .../vault/requests/getUserStats/getUserStats.md | 3 ++- .../vault/requests/getValidators/getValidators.md | 3 ++- src/services/vault/requests/getVault/getVault.md | 7 ++++--- .../requests/getVaultFactory/getVaultFactory.md | 3 ++- .../vault/requests/getVaultStats/getVaultStats.md | 3 ++- .../requests/getVaultVersion/getVaultVersion.md | 3 ++- .../vault/requests/getWhitelist/getWhitelist.md | 3 ++- .../transactions/claimExitQueue/claimExitQueue.md | 5 +++-- .../vault/transactions/createVault/createVault.md | 3 ++- src/services/vault/transactions/deposit/deposit.md | 3 ++- src/services/vault/transactions/operate/operate.md | 3 ++- .../setDepositDataManager/setDepositDataManager.md | 3 ++- .../setDepositDataRoot/setDepositDataRoot.md | 3 ++- src/services/vault/transactions/withdraw/withdraw.md | 3 ++- 74 files changed, 168 insertions(+), 100 deletions(-) diff --git a/.github/workflows/sync-docs.yml b/.github/workflows/sync-docs.yml index faad3ab5..c6465813 100644 --- a/.github/workflows/sync-docs.yml +++ b/.github/workflows/sync-docs.yml @@ -39,9 +39,9 @@ jobs: with: ssh-private-key: ${{ secrets.SYNC_DOCS_SSH_KEY }} - - name: Install dependencies securely + - name: Install dependencies run: | - pnpm install --frozen-lockfile --ignore-scripts --audit false --fund false + pnpm install - name: Version check run: pnpm check:version diff --git a/documentation/03-Quick start/boost.md b/documentation/03-Quick start/boost.md index cba792d5..1ac59bf4 100644 --- a/documentation/03-Quick start/boost.md +++ b/documentation/03-Quick start/boost.md @@ -2,6 +2,7 @@ id: boost-os-token title: Boost osToken sidebar_position: 6 +description: Boost staking rewards with StakeWise SDK — leverage osTokens as Aave collateral to amplify your vault staking position. --- # Boost osToken diff --git a/documentation/03-Quick start/burn-os-token.md b/documentation/03-Quick start/burn-os-token.md index 5aaabdee..7dbf0680 100644 --- a/documentation/03-Quick start/burn-os-token.md +++ b/documentation/03-Quick start/burn-os-token.md @@ -2,6 +2,7 @@ id: burn-os-token title: Burn osToken sidebar_position: 5 +description: Burn osETH tokens in a StakeWise vault using the SDK — monitor osToken position health and execute burn transactions safely. --- # Burn osToken diff --git a/documentation/03-Quick start/deposit-to-vault.md b/documentation/03-Quick start/deposit-to-vault.md index 7603fc07..f81ecc0e 100644 --- a/documentation/03-Quick start/deposit-to-vault.md +++ b/documentation/03-Quick start/deposit-to-vault.md @@ -2,6 +2,7 @@ id: deposit-to-vault title: Deposit to vault sidebar_position: 2 +description: Deposit ETH into a StakeWise vault using the SDK — client-side browser wallet and backend custodial wallet integration examples. --- # Deposit to vault diff --git a/documentation/03-Quick start/get-user-data.md b/documentation/03-Quick start/get-user-data.md index 5818bf0e..9f1694a0 100644 --- a/documentation/03-Quick start/get-user-data.md +++ b/documentation/03-Quick start/get-user-data.md @@ -2,6 +2,7 @@ id: get-user-data title: Get user data sidebar_position: 1 +description: Query user staking data from StakeWise vaults — balances, osToken positions, boost amounts, APY, exit queues, and action history. --- # Get user data diff --git a/documentation/03-Quick start/get-vault-data.md b/documentation/03-Quick start/get-vault-data.md index 65edcedf..43b6abdc 100644 --- a/documentation/03-Quick start/get-vault-data.md +++ b/documentation/03-Quick start/get-vault-data.md @@ -2,6 +2,7 @@ id: get-vault-data title: Get vault data sidebar_position: 0 +description: Fetch StakeWise vault data using the SDK — retrieve vault details, stats charts, validators, whitelist, and blocklist information. --- # Get vault data diff --git a/documentation/03-Quick start/mint-os-token.md b/documentation/03-Quick start/mint-os-token.md index 7367789a..52a6f3b5 100644 --- a/documentation/03-Quick start/mint-os-token.md +++ b/documentation/03-Quick start/mint-os-token.md @@ -2,6 +2,7 @@ id: mint-os-token title: Mint osToken sidebar_position: 4 +description: Mint osETH tokens against your StakeWise vault stake using the SDK — check max mintable amounts and execute minting transactions. --- # Mint osToken diff --git a/documentation/03-Quick start/unboost.md b/documentation/03-Quick start/unboost.md index d700a8f2..24bc4231 100644 --- a/documentation/03-Quick start/unboost.md +++ b/documentation/03-Quick start/unboost.md @@ -2,6 +2,7 @@ id: unboost-os-token title: Unboost osToken sidebar_position: 7 +description: Exit a leveraged boost position with the StakeWise SDK — repay Aave debt, unlock osToken collateral, and track the withdrawal queue. --- # Unboost osToken diff --git a/documentation/03-Quick start/unstake.md b/documentation/03-Quick start/unstake.md index 1fe25614..7b8d0ec2 100644 --- a/documentation/03-Quick start/unstake.md +++ b/documentation/03-Quick start/unstake.md @@ -2,6 +2,7 @@ id: unstake-example title: Unstake sidebar_position: 3 +description: Unstake deposits from a StakeWise vault using the SDK — withdraw staked assets, handle osToken burns, and track exit queue positions. --- # Unstake diff --git a/documentation/connecting-wallet.md b/documentation/connecting-wallet.md index 78974662..4d286ba7 100644 --- a/documentation/connecting-wallet.md +++ b/documentation/connecting-wallet.md @@ -2,6 +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. --- # Connecting a Wallet @@ -226,3 +227,4 @@ const setupEventHandlers = (provider: EIP1193Provider) => { setupEventHandlers(eip1193Provider) ``` + diff --git a/documentation/index.md b/documentation/index.md index 9a5caca0..bf2ebe4f 100644 --- a/documentation/index.md +++ b/documentation/index.md @@ -2,6 +2,7 @@ id: overview title: Overview sidebar_position: 0 +description: StakeWise V3 SDK overview for TypeScript developers — vault management, staking transactions, and blockchain data queries. --- # Overview diff --git a/documentation/installation-setup.md b/documentation/installation-setup.md index b91e9580..b34ba53a 100644 --- a/documentation/installation-setup.md +++ b/documentation/installation-setup.md @@ -2,6 +2,7 @@ id: installation-setup title: Installation and Setup sidebar_position: 1 +description: Install the StakeWise V3 SDK via npm or yarn, configure GraphQL loaders for Webpack, Next.js, or Vite, and create an SDK instance. --- ## Installation diff --git a/documentation/reference.md b/documentation/reference.md index 59a7b84f..5a46b109 100644 --- a/documentation/reference.md +++ b/documentation/reference.md @@ -1,7 +1,8 @@ --- -id: types-config-errors -title: Types, Config, Errors -sidebar_position: 3 +id: sdk-reference +title: SDK Reference +sidebar_position: 2 +description: StakeWise SDK reference for network configuration, global TypeScript types, contract access, and built-in ethers helpers. --- # Configuration for the Current Network @@ -47,13 +48,9 @@ You can make calls to the built-in ethers contracts if needed. To access contrac For example, if you want to quickly create a standard ERC20 contract, you can use the helper `sdk.contracts.helpers.createErc20(tokenAddress)`. # Error Handling and Transaction Debugging - Each SDK method validates the arguments passed to it before execution and throws an error if any argument is invalid. For example, if you attempt to send a transaction without providing a provider during SDK initialization, an error will be thrown. - If an error occurs during a transaction, you will see a detailed error logged in the console, including the transaction data. If the error object contains a `solidityError` field, it means the error was successfully parsed and the root cause is immediately visible. - If the `solidityError` field is not present, the error log will still include the `data`, `to`, and `from` fields. Using these values, you can reproduce and debug the transaction with Tenderly: - 1. Open Tenderly and go to the Simulator section. 2. Select the appropriate network. 3. Paste the `to` address into the left column (the contract address field). @@ -61,5 +58,4 @@ If the `solidityError` field is not present, the error log will still include th 5. Paste the `from` address into the From field on the right. 6. Disable Use Pending Block. 7. Enter the current block number into the Block Number field. - After running the simulation, you will see the exact error that occurred in the smart contract, making it significantly easier to understand and resolve the issue. diff --git a/src/index.ts b/src/index.ts index 3796bb28..602b1000 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,7 +6,7 @@ export * from './helpers/enums' export { default as StakeWiseSDK } from './StakeWiseSDK' export { createContract, createErc20Contract } from './contracts' export { default as localStorage } from './modules/local-storage' -export { wrapAbortPromise, AbortPromise, AbortRequest } from './modules/gql-module' +export { wrapAbortPromise, AbortPromise, AbortRequest, AbortCallback } from './modules/gql-module' export { configs, diff --git a/src/modules/gql-module/index.ts b/src/modules/gql-module/index.ts index 19b947c9..24a1b9c7 100644 --- a/src/modules/gql-module/index.ts +++ b/src/modules/gql-module/index.ts @@ -1,5 +1,6 @@ export { default as graphqlFetch } from './graphqlFetch' export { default as AbortPromise } from './abortPromise' export { default as AbortRequest } from './abortRequest' +export { default as AbortCallback } from './abortCallback' export type { FetchCodegenInput, FetchInput } from './types' export { default as wrapAbortPromise } from './wrapAbortPromise' diff --git a/src/services/boost/requests/getData/getData.md b/src/services/boost/requests/getData/getData.md index f2530b97..8553f052 100644 --- a/src/services/boost/requests/getData/getData.md +++ b/src/services/boost/requests/getData/getData.md @@ -1,6 +1,7 @@ --- id: getData -slug: /boost/requests/getdata +slug: /sdk/api/boost/requests/getdata +description: Use the StakeWise SDK boost getData method to retrieve boost and leverage strategy data for a vault user. --- #### Description: diff --git a/src/services/boost/requests/getLeverageStrategyData/getLeverageStrategyData.md b/src/services/boost/requests/getLeverageStrategyData/getLeverageStrategyData.md index ca3e2863..dcc56a08 100644 --- a/src/services/boost/requests/getLeverageStrategyData/getLeverageStrategyData.md +++ b/src/services/boost/requests/getLeverageStrategyData/getLeverageStrategyData.md @@ -1,6 +1,7 @@ --- id: getLeverageStrategyData -slug: /boost/requests/getleveragestrategydata +slug: /sdk/api/boost/requests/getleveragestrategydata +description: Use the StakeWise SDK getLeverageStrategyData method to check the leverage strategy version and upgrade status. --- #### Description: diff --git a/src/services/boost/requests/getLeverageStrategyProxy/getLeverageStrategyProxy.md b/src/services/boost/requests/getLeverageStrategyProxy/getLeverageStrategyProxy.md index 16e1f5ce..6f7cb7bf 100644 --- a/src/services/boost/requests/getLeverageStrategyProxy/getLeverageStrategyProxy.md +++ b/src/services/boost/requests/getLeverageStrategyProxy/getLeverageStrategyProxy.md @@ -1,6 +1,7 @@ --- id: getLeverageStrategyProxy -slug: /boost/requests/getleveragestrategyproxy +slug: /sdk/api/boost/requests/getleveragestrategyproxy +description: Use the StakeWise SDK getLeverageStrategyProxy method to get the leverage strategy proxy contract address for boosting. --- #### Description: diff --git a/src/services/boost/requests/getQueuePosition/getQueuePosition.md b/src/services/boost/requests/getQueuePosition/getQueuePosition.md index 4363a1e6..6917e617 100644 --- a/src/services/boost/requests/getQueuePosition/getQueuePosition.md +++ b/src/services/boost/requests/getQueuePosition/getQueuePosition.md @@ -1,6 +1,7 @@ --- id: getQueuePosition -slug: /boost/requests/getqueueposition +slug: /sdk/api/boost/requests/getqueueposition +description: Use the StakeWise SDK boost getQueuePosition method to retrieve unlock queue position data for a user's boosted osTokens. --- #### Description: diff --git a/src/services/boost/transactions/claimQueue/claimQueue.md b/src/services/boost/transactions/claimQueue/claimQueue.md index 37d3a818..ff55553b 100644 --- a/src/services/boost/transactions/claimQueue/claimQueue.md +++ b/src/services/boost/transactions/claimQueue/claimQueue.md @@ -1,6 +1,7 @@ --- id: claimQueue -slug: /boost/transactions/claimqueue +slug: /sdk/api/boost/transactions/claimqueue +description: Use the StakeWise SDK boost claimQueue method to claim assets from the unboost queue after unlocking osTokens. --- #### Description: diff --git a/src/services/boost/transactions/lock/lock.md b/src/services/boost/transactions/lock/lock.md index bfc18acd..190458c5 100644 --- a/src/services/boost/transactions/lock/lock.md +++ b/src/services/boost/transactions/lock/lock.md @@ -1,6 +1,7 @@ --- id: lock -slug: /boost/transactions/lock +slug: /sdk/api/boost/transactions/lock +description: Use the StakeWise SDK boost lock method to boost osToken APY through leverage staking with a vault's strategy proxy. --- #### Description: @@ -14,10 +15,10 @@ Boost your osToken apy using leverage staking | amount | `bigint` | **Yes** | Boost amount | | userAddress | `string` | **Yes** | The user address | | vaultAddress | `string` | **Yes** | The address of the vault that will mint osTokens for leverage staking | -| boostAddress | `string` | **Yes** | The address of the strategy proxy using the [sdk.boost.getLeverageStrategyProxy](/boost/requests/getleveragestrategyproxy) method | +| boostAddress | `string` | **Yes** | The address of the strategy proxy using the [sdk.boost.getLeverageStrategyProxy](/sdk/api/boost/requests/getleveragestrategyproxy) method | | referrerAddress | `string` | **No** | The address of the referrer | -| permitParams | `PermitParams` | **No** | The permit signature is required if there isn’t enough osToken allowance for the strategy proxy contract.

**For MultiSig**
The permit signature is not necessary for Multi Sig (e.g. Safe Wallet), as it should use `sdk.contracts.mintToken.approve(boostAddress, MaxUint256)` instead of a permit call to set up osToken allowance. This will be called in the action if needed.

**For other wallets**
The permit signature is optional since it will be obtained automatically using the [utils.getPermitSignature](/utils/getpermitsignature) method. | -| leverageStrategyData | `LeverageStrategyData` | **No** | Leverage strategy data from [sdk.boost.getLeverageStrategyData](/boost/requests/getleveragestrategydata). If not provided, it will be fetched automatically during the transaction | +| permitParams | `PermitParams` | **No** | The permit signature is required if there isn’t enough osToken allowance for the strategy proxy contract.

**For MultiSig**
The permit signature is not necessary for Multi Sig (e.g. Safe Wallet), as it should use `sdk.contracts.mintToken.approve(boostAddress, MaxUint256)` instead of a permit call to set up osToken allowance. This will be called in the action if needed.

**For other wallets**
The permit signature is optional since it will be obtained automatically using the [utils.getPermitSignature](/sdk/api/utils/getpermitsignature) method. | +| leverageStrategyData | `LeverageStrategyData` | **No** | Leverage strategy data from [sdk.boost.getLeverageStrategyData](/sdk/api/boost/requests/getleveragestrategydata). If not provided, it will be fetched automatically during the transaction | ```ts type LeverageStrategyData = { diff --git a/src/services/boost/transactions/unlock/unlock.md b/src/services/boost/transactions/unlock/unlock.md index 44c5b1ad..9e44ab29 100644 --- a/src/services/boost/transactions/unlock/unlock.md +++ b/src/services/boost/transactions/unlock/unlock.md @@ -1,6 +1,7 @@ --- id: unlock -slug: /boost/transactions/unlock +slug: /sdk/api/boost/transactions/unlock +description: Use the StakeWise SDK boost unlock method to unboost previously boosted osTokens by specifying a percentage to release. --- #### Description: @@ -14,7 +15,7 @@ Unboost your boosted osToken | percent | `number` | **Yes** | The percent to unboost (100 at max) | | userAddress | `string` | **Yes** | The user address | | vaultAddress | `string` | **Yes** | The address of the vault where the osTokens boosted | -| leverageStrategyData | `LeverageStrategyData` | **No** | Leverage strategy data from [sdk.boost.getLeverageStrategyData](/boost/requests/getleveragestrategydata). If not provided, it will be fetched automatically during the transaction | +| leverageStrategyData | `LeverageStrategyData` | **No** | Leverage strategy data from [sdk.boost.getLeverageStrategyData](/sdk/api/boost/requests/getleveragestrategydata). If not provided, it will be fetched automatically during the transaction | ```ts type LeverageStrategyData = { diff --git a/src/services/boost/transactions/upgradeLeverageStrategy/upgradeLeverageStrategy.md b/src/services/boost/transactions/upgradeLeverageStrategy/upgradeLeverageStrategy.md index fda6d3eb..b5d5f509 100644 --- a/src/services/boost/transactions/upgradeLeverageStrategy/upgradeLeverageStrategy.md +++ b/src/services/boost/transactions/upgradeLeverageStrategy/upgradeLeverageStrategy.md @@ -1,6 +1,7 @@ --- id: upgradeLeverageStrategy -slug: /boost/transactions/upgradeleveragestrategy +slug: /sdk/api/boost/transactions/upgradeleveragestrategy +description: Use the StakeWise SDK upgradeLeverageStrategy method to upgrade the leverage strategy contract for a vault's boost system. --- #### Description: diff --git a/src/services/distributorRewards/requests/getRewards/getRewards.md b/src/services/distributorRewards/requests/getRewards/getRewards.md index d6cd26c8..4390ed29 100644 --- a/src/services/distributorRewards/requests/getRewards/getRewards.md +++ b/src/services/distributorRewards/requests/getRewards/getRewards.md @@ -1,6 +1,7 @@ --- id: getRewards -slug: /distributorRewards/requests/getrewards +slug: /sdk/api/distributorRewards/requests/getrewards +description: Use the StakeWise SDK distributorRewards getRewards method to fetch currently claimable distributor reward tokens for a user. --- #### Description: @@ -27,10 +28,10 @@ type Output = | Name | Description | |---------------------|------------------------------------------------------------------------------------------------------------------------------| -| `proof` | The Merkle tree proof. Used in [sdk.distributorRewards.claim](/distributorRewards/transactions/claim) | -| `tokens` | An array of addresses of the tokens. Used in [sdk.distributorRewards.claim](/distributorRewards/transactions/claim) | +| `proof` | The Merkle tree proof. Used in [sdk.distributorRewards.claim](/sdk/api/distributorRewards/transactions/claim) | +| `tokens` | An array of addresses of the tokens. Used in [sdk.distributorRewards.claim](/sdk/api/distributorRewards/transactions/claim) | | `unclaimedAmounts` | An array of unclaimed amounts of the tokens. A claim is available if at least one amount in the array is greater than zero. | -| `cumulativeAmounts` | An array of cumulative amounts of the tokens. Used in [sdk.distributorRewards.claim](/distributorRewards/transactions/claim) | +| `cumulativeAmounts` | An array of cumulative amounts of the tokens. Used in [sdk.distributorRewards.claim](/sdk/api/distributorRewards/transactions/claim) | #### Example: diff --git a/src/services/distributorRewards/transactions/claim/claim.md b/src/services/distributorRewards/transactions/claim/claim.md index b9316e48..3140def0 100644 --- a/src/services/distributorRewards/transactions/claim/claim.md +++ b/src/services/distributorRewards/transactions/claim/claim.md @@ -1,6 +1,7 @@ --- id: create -slug: /distributorRewards/transactions/claim +slug: /sdk/api/distributorRewards/transactions/claim +description: Use the StakeWise SDK distributorRewards claim method to claim token rewards from the merkle distributor V2 contract. --- ### `claim` @@ -14,9 +15,9 @@ Claims rewards from the merkle distributor V2 contract. | Name | Type | Required | Description | |-------------------|------------|----------|----------------------------------------------------------------------------------------------------------------------------------------| | userAddress | `string` | **Yes** | The address of the user initiating the action. This address will become the owner of the reward splitter and must be the vault admin | -| proof | `string[]` | **Yes** | The Merkle tree proof. Get it from [sdk.distributorRewards.getRewards](/distributorRewards/requests/getrewards) | -| tokens | `string[]` | **Yes** | An array of addresses of the tokens. Get it from [sdk.distributorRewards.getRewards](/distributorRewards/requests/getrewards) | -| cumulativeAmounts | `string[]` | **Yes** | An array of cumulative amounts of the tokens. Get it from [sdk.distributorRewards.getRewards](/distributorRewards/requests/getrewards) | +| proof | `string[]` | **Yes** | The Merkle tree proof. Get it from [sdk.distributorRewards.getRewards](/sdk/api/distributorRewards/requests/getrewards) | +| tokens | `string[]` | **Yes** | An array of addresses of the tokens. Get it from [sdk.distributorRewards.getRewards](/sdk/api/distributorRewards/requests/getrewards) | +| cumulativeAmounts | `string[]` | **Yes** | An array of cumulative amounts of the tokens. Get it from [sdk.distributorRewards.getRewards](/sdk/api/distributorRewards/requests/getrewards) | #### Example: diff --git a/src/services/osToken/helpers/getBurnAmount/getBurnAmount.md b/src/services/osToken/helpers/getBurnAmount/getBurnAmount.md index 9c8bf7f3..c5785066 100644 --- a/src/services/osToken/helpers/getBurnAmount/getBurnAmount.md +++ b/src/services/osToken/helpers/getBurnAmount/getBurnAmount.md @@ -1,7 +1,8 @@ --- id: getBurnAmount title: getBurnAmount -slug: /osToken/helpers/getburnamount +slug: /sdk/api/osToken/helpers/getburnamount +description: "StakeWise SDK getBurnAmount helper (deprecated): calculates how many osTokens to burn to fully withdraw your deposit." --- # Deprecated! @@ -15,9 +16,9 @@ How many osToken burn do you need to make to withdraw all deposit. | Name | Type | Required | Description | |-----------------|----------|----------|--------------------------------------------------------------| | vaultAddress | `string` | **Yes** | The address of the vault | -| ltvPercent | `bigint` | **Yes** | [sdk.vault.getVault](/vault/requests/getvault) | -| mintedAssets | `bigint` | **Yes** | [sdk.osToken.getPosition](/osToken/requests/getposition) | -| stakedAssets | `bigint` | **Yes** | [sdk.vault.getStakeBalance](/vault/requests/getstakebalance) | +| ltvPercent | `bigint` | **Yes** | [sdk.vault.getVault](/sdk/api/vault/requests/getvault) | +| mintedAssets | `bigint` | **Yes** | [sdk.osToken.getPosition](/sdk/api/osToken/requests/getposition) | +| stakedAssets | `bigint` | **Yes** | [sdk.vault.getStakeBalance](/sdk/api/vault/requests/getstakebalance) | | newStakedAssets | `bigint` | **Yes** | The future amount of stake after the deposit | #### Returns: diff --git a/src/services/osToken/helpers/getBurnAmountForUnstake/getBurnAmountForUnstake.md b/src/services/osToken/helpers/getBurnAmountForUnstake/getBurnAmountForUnstake.md index 69a96dd3..e2af85c1 100644 --- a/src/services/osToken/helpers/getBurnAmountForUnstake/getBurnAmountForUnstake.md +++ b/src/services/osToken/helpers/getBurnAmountForUnstake/getBurnAmountForUnstake.md @@ -1,6 +1,7 @@ --- id: getBurnAmountForUnstake -slug: /osToken/helpers/getburnamountforunstake +slug: /sdk/api/osToken/helpers/getburnamountforunstake +description: Use the StakeWise SDK getBurnAmountForUnstake helper to calculate osTokens that must be burned to enable full unstaking. --- #### Description: diff --git a/src/services/osToken/helpers/getHealthFactor/getHealthFactor.md b/src/services/osToken/helpers/getHealthFactor/getHealthFactor.md index 294b34f6..7a1c9d43 100644 --- a/src/services/osToken/helpers/getHealthFactor/getHealthFactor.md +++ b/src/services/osToken/helpers/getHealthFactor/getHealthFactor.md @@ -1,6 +1,7 @@ --- id: getHealthFactor -slug: /osToken/helpers/gethealthfactor +slug: /sdk/api/osToken/helpers/gethealthfactor +description: Use the StakeWise SDK getHealthFactor helper to assess the health of an osToken position relative to liquidation thresholds. --- #### Description: @@ -10,9 +11,9 @@ Get the health of the position #### Arguments: | Name | Type | Required | Description | |------------------|----------|----------|------------------------------------------------------| -| liqThresholdPercent | `bigint` | **Yes** | [sdk.vault.getVault](/vault/requests/getvault) | -| mintedAssets | `bigint` | **Yes** | [sdk.osToken.getPosition](/osToken/requests/getposition) | -| stakedAssets | `bigint` | **Yes** | [sdk.vault.getStakeBalance](/vault/requests/getstakebalance) | +| liqThresholdPercent | `bigint` | **Yes** | [sdk.vault.getVault](/sdk/api/vault/requests/getvault) | +| mintedAssets | `bigint` | **Yes** | [sdk.osToken.getPosition](/sdk/api/osToken/requests/getposition) | +| stakedAssets | `bigint` | **Yes** | [sdk.vault.getStakeBalance](/sdk/api/vault/requests/getstakebalance) | #### Returns: diff --git a/src/services/osToken/requests/getAssetsFromShares/getAssetsFromShares.md b/src/services/osToken/requests/getAssetsFromShares/getAssetsFromShares.md index a731b81c..b6996256 100644 --- a/src/services/osToken/requests/getAssetsFromShares/getAssetsFromShares.md +++ b/src/services/osToken/requests/getAssetsFromShares/getAssetsFromShares.md @@ -1,6 +1,7 @@ --- id: getAssetsFromShares -slug: /osToken/requests/getassetsfromshares +slug: /sdk/api/osToken/requests/getassetsfromshares +description: Use the StakeWise SDK getAssetsFromShares method to convert an osToken share amount to its equivalent ETH value. --- #### Description: diff --git a/src/services/osToken/requests/getBalance/getBalance.md b/src/services/osToken/requests/getBalance/getBalance.md index d7402bbe..a78e6ba6 100644 --- a/src/services/osToken/requests/getBalance/getBalance.md +++ b/src/services/osToken/requests/getBalance/getBalance.md @@ -1,6 +1,7 @@ --- id: getBalance -slug: /osToken/requests/getbalance +slug: /sdk/api/osToken/requests/getbalance +description: Use the StakeWise SDK osToken getBalance method to retrieve a user's osToken balance for a specific vault. --- #### Description: diff --git a/src/services/osToken/requests/getMaxMint/getMaxMint.md b/src/services/osToken/requests/getMaxMint/getMaxMint.md index ffa61e6f..543454ac 100644 --- a/src/services/osToken/requests/getMaxMint/getMaxMint.md +++ b/src/services/osToken/requests/getMaxMint/getMaxMint.md @@ -1,7 +1,8 @@ --- id: getMaxMint title: getMaxMint -slug: /osToken/requests/getmaxmint +slug: /sdk/api/osToken/requests/getmaxmint +description: "StakeWise SDK getMaxMint method (deprecated): returns the maximum number of osToken shares available for minting." --- # Deprecated! @@ -15,9 +16,9 @@ Maximum number of **shares** for minting | Name | Type | Required | Description | |--------------|----------|----------|--------------------------------------------------------------| | vaultAddress | `string` | **Yes** | The address of the vault | -| ltvPercent | `bigint` | **Yes** | [sdk.vault.getVault](/vault/requests/getvault) | -| stakedAssets | `bigint` | **Yes** | [sdk.vault.getStakeBalance](/vault/requests/getstakebalance) | -| mintedAssets | `bigint` | **Yes** | [sdk.osToken.getPosition](/osToken/requests/getposition) | +| ltvPercent | `bigint` | **Yes** | [sdk.vault.getVault](/sdk/api/vault/requests/getvault) | +| stakedAssets | `bigint` | **Yes** | [sdk.vault.getStakeBalance](/sdk/api/vault/requests/getstakebalance) | +| mintedAssets | `bigint` | **Yes** | [sdk.osToken.getPosition](/sdk/api/osToken/requests/getposition) | #### Returns: diff --git a/src/services/osToken/requests/getMaxMintAmount/getMaxMintAmount.md b/src/services/osToken/requests/getMaxMintAmount/getMaxMintAmount.md index 856707b6..f19bc303 100644 --- a/src/services/osToken/requests/getMaxMintAmount/getMaxMintAmount.md +++ b/src/services/osToken/requests/getMaxMintAmount/getMaxMintAmount.md @@ -1,6 +1,7 @@ --- id: getMaxMintAmount -slug: /osToken/requests/getmaxmintamount +slug: /sdk/api/osToken/requests/getmaxmintamount +description: Use the StakeWise SDK getMaxMintAmount method to calculate the maximum number of osToken shares a user can mint. --- #### Description: diff --git a/src/services/osToken/requests/getOsTokenAPY/getOsTokenAPY.md b/src/services/osToken/requests/getOsTokenAPY/getOsTokenAPY.md index 801f0553..d62b443d 100644 --- a/src/services/osToken/requests/getOsTokenAPY/getOsTokenAPY.md +++ b/src/services/osToken/requests/getOsTokenAPY/getOsTokenAPY.md @@ -1,6 +1,7 @@ --- id: getAPY -slug: /osToken/requests/getostokenapy +slug: /sdk/api/osToken/requests/getostokenapy +description: Use the StakeWise SDK getOsTokenAPY method to retrieve the current annual percentage yield and fee for osToken. --- #### Description: diff --git a/src/services/osToken/requests/getOsTokenRate/getOsTokenRate.md b/src/services/osToken/requests/getOsTokenRate/getOsTokenRate.md index d9365a6a..2125283f 100644 --- a/src/services/osToken/requests/getOsTokenRate/getOsTokenRate.md +++ b/src/services/osToken/requests/getOsTokenRate/getOsTokenRate.md @@ -1,6 +1,7 @@ --- id: getRate -slug: /osToken/requests/getostokenrate +slug: /sdk/api/osToken/requests/getostokenrate +description: Use the StakeWise SDK getOsTokenRate method to get the current ETH to osToken exchange rate for conversions. --- #### Description: diff --git a/src/services/osToken/requests/getPosition/getPosition.md b/src/services/osToken/requests/getPosition/getPosition.md index 3f361321..b32cc7a6 100644 --- a/src/services/osToken/requests/getPosition/getPosition.md +++ b/src/services/osToken/requests/getPosition/getPosition.md @@ -1,7 +1,8 @@ --- id: getPosition title: getPosition -slug: /osToken/requests/getposition +slug: /sdk/api/osToken/requests/getposition +description: "StakeWise SDK getPosition method (deprecated): retrieves user osToken position data including minted assets and health factor." --- # Deprecated! @@ -14,8 +15,8 @@ User position data #### Arguments: | Name | Type | Required | Description | |------------------|----------|----------|--------------------------------------------------------------| -| liqThresholdPercent | `bigint` | **Yes** | [sdk.vault.getVault](/vault/requests/getvault) | -| stakedAssets | `bigint` | **Yes** | [sdk.vault.getStakeBalance](/vault/requests/getstakebalance) | +| liqThresholdPercent | `bigint` | **Yes** | [sdk.vault.getVault](/sdk/api/vault/requests/getvault) | +| stakedAssets | `bigint` | **Yes** | [sdk.vault.getStakeBalance](/sdk/api/vault/requests/getstakebalance) | | userAddress | `string` | **Yes** | The user address | | vaultAddress | `string` | **Yes** | The address of the vault | @@ -39,7 +40,7 @@ type Output = { |----------------------|-----------------------------------------------------------------| | `minted.shares` | Balance | | `minted.assets` | Balance in ETH | -| `healthFactor` | [sdk.osToken.getHealthFactor](/osToken/helpers/gethealthfactor) | +| `healthFactor` | [sdk.osToken.getHealthFactor](/sdk/api/osToken/helpers/gethealthfactor) | | `protocolFeePercent` | Usage fee percent | #### Example: diff --git a/src/services/osToken/requests/getSharesFromAssets/getSharesFromAssets.md b/src/services/osToken/requests/getSharesFromAssets/getSharesFromAssets.md index ff41975a..ef057414 100644 --- a/src/services/osToken/requests/getSharesFromAssets/getSharesFromAssets.md +++ b/src/services/osToken/requests/getSharesFromAssets/getSharesFromAssets.md @@ -1,6 +1,7 @@ --- id: getSharesFromAssets -slug: /osToken/requests/getsharesfromassets +slug: /sdk/api/osToken/requests/getsharesfromassets +description: Use the StakeWise SDK getSharesFromAssets method to convert an ETH amount to its equivalent osToken share value. --- #### Description: diff --git a/src/services/osToken/transactions/burn/burn.md b/src/services/osToken/transactions/burn/burn.md index f2be816a..6ce87bf4 100644 --- a/src/services/osToken/transactions/burn/burn.md +++ b/src/services/osToken/transactions/burn/burn.md @@ -1,6 +1,7 @@ --- id: burn -slug: /osToken/transactions/burn +slug: /sdk/api/osToken/transactions/burn +description: Use the StakeWise SDK osToken burn method to burn osTokens and reduce your minted position in a vault. --- #### Description: diff --git a/src/services/osToken/transactions/mint/mint.md b/src/services/osToken/transactions/mint/mint.md index ab08457e..e4322e26 100644 --- a/src/services/osToken/transactions/mint/mint.md +++ b/src/services/osToken/transactions/mint/mint.md @@ -1,12 +1,13 @@ --- id: mint -slug: /osToken/transactions/mint +slug: /sdk/api/osToken/transactions/mint +description: Use the StakeWise SDK osToken mint method to mint osTokens based on your vault deposit, with health factor checks. --- #### Description: Getting osToken. The amount of token you can get depends on the user's current deposit in the vault. -Use data from methods [sdk.osToken.getMaxMint](/osToken/requests/getmaxmint) and [sdk.osToken.getHealthFactor](/osToken/helpers/gethealthfactor) to block a call to mint() if the number of shares is greater than what getMaxMint returns or if the number of osToken after the transaction would make the position unhealthy +Use data from methods [sdk.osToken.getMaxMint](/sdk/api/osToken/requests/getmaxmint) and [sdk.osToken.getHealthFactor](/sdk/api/osToken/helpers/gethealthfactor) to block a call to mint() if the number of shares is greater than what getMaxMint returns or if the number of osToken after the transaction would make the position unhealthy #### Arguments: diff --git a/src/services/rewardSplitter/requests/getClaimAmount/getClaimAmount.md b/src/services/rewardSplitter/requests/getClaimAmount/getClaimAmount.md index 80e615dc..4a72052e 100644 --- a/src/services/rewardSplitter/requests/getClaimAmount/getClaimAmount.md +++ b/src/services/rewardSplitter/requests/getClaimAmount/getClaimAmount.md @@ -1,6 +1,7 @@ --- id: getClaimAmount -slug: /rewardSplitter/requests/getclaimamount +slug: /sdk/api/rewardSplitter/requests/getclaimamount +description: Use the StakeWise SDK getClaimAmount method to calculate claimable assets from active and inactive reward splitters. --- #### Description: diff --git a/src/services/rewardSplitter/transactions/claimRewards/claimRewards.md b/src/services/rewardSplitter/transactions/claimRewards/claimRewards.md index 66e40e82..5549cd4e 100644 --- a/src/services/rewardSplitter/transactions/claimRewards/claimRewards.md +++ b/src/services/rewardSplitter/transactions/claimRewards/claimRewards.md @@ -1,6 +1,7 @@ --- id: claimRewards -slug: /rewardSplitter/transactions/claimrewards +slug: /sdk/api/rewardSplitter/transactions/claimrewards +description: Use the StakeWise SDK rewardSplitter claimRewards method to claim accumulated rewards from a reward splitter contract. --- #### Description: diff --git a/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.md b/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.md index b6939b89..58260f1a 100644 --- a/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.md +++ b/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.md @@ -1,6 +1,7 @@ --- id: create -slug: /rewardSplitter/transactions/createrewardsplitter +slug: /sdk/api/rewardSplitter/transactions/createrewardsplitter +description: Use the StakeWise SDK createRewardSplitter method to deploy a contract that distributes vault rewards among fee recipients. --- ### `create` diff --git a/src/services/rewardSplitter/transactions/setClaimer/setClaimer.md b/src/services/rewardSplitter/transactions/setClaimer/setClaimer.md index 7b15dd22..559318cf 100644 --- a/src/services/rewardSplitter/transactions/setClaimer/setClaimer.md +++ b/src/services/rewardSplitter/transactions/setClaimer/setClaimer.md @@ -1,6 +1,7 @@ --- id: setClaimer -slug: /rewardSplitter/transactions/setclaimer +slug: /sdk/api/rewardSplitter/transactions/setclaimer +description: Use the StakeWise SDK setClaimer method to authorize an address to claim vault fees on behalf of reward splitter shareholders. --- #### Description: diff --git a/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.md b/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.md index 9cb36400..a9834d2c 100644 --- a/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.md +++ b/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.md @@ -1,6 +1,7 @@ --- id: updateFeeRecipients -slug: /rewardSplitter/transactions/updatefeerecipients +slug: /sdk/api/rewardSplitter/transactions/updatefeerecipients +description: Use the StakeWise SDK updateFeeRecipients method to modify reward splitter fee recipients and their share proportions. --- #### Description: @@ -17,7 +18,7 @@ Please note that only the vault admin, who is also the owner of the reward split | vaultAddress | `string` | **Yes** | The address of the vault | | rewardSplitterAddress | `string` | **Yes** | The address of the reward splitter | | feeRecipients | `Array<{ address: string, shares: bigint }>` | **Yes** | The list of the vault fee recipients with their addresses and shares amount. For simplicity, we suggest setting the amount as a percentage converted to a BigInt value. For example, for 100% shares: `parseEther('100')` | -| oldFeeRecipients | `Array<{ address: string, shares: bigint }>` | **No** | The current list of the vault fee recipients that will be updated within this action. It is needed to calculate how many shares will be added or removed from each fee recipient. If not provided, it will be requested from the [sdk.vault.getRewardSplitters](/vault/requests/getrewardsplitters) action | +| oldFeeRecipients | `Array<{ address: string, shares: bigint }>` | **No** | The current list of the vault fee recipients that will be updated within this action. It is needed to calculate how many shares will be added or removed from each fee recipient. If not provided, it will be requested from the [sdk.vault.getRewardSplitters](/sdk/api/vault/requests/getrewardsplitters) action | #### Example: diff --git a/src/services/utils/getFiatRates/getFiatRates.md b/src/services/utils/getFiatRates/getFiatRates.md index bf96af45..46724ba8 100644 --- a/src/services/utils/getFiatRates/getFiatRates.md +++ b/src/services/utils/getFiatRates/getFiatRates.md @@ -1,6 +1,7 @@ --- id: getFiatRates -slug: /utils/getfiatrates +slug: /sdk/api/utils/getfiatrates +description: Use the StakeWise SDK getFiatRates utility to retrieve current fiat exchange rates (USD, EUR, GBP, CNY, JPY, KRW, AUD). --- #### Description: diff --git a/src/services/utils/getFiatRatesByDay/getFiatRatesByDay.md b/src/services/utils/getFiatRatesByDay/getFiatRatesByDay.md index 79e25cb8..52ffe9eb 100644 --- a/src/services/utils/getFiatRatesByDay/getFiatRatesByDay.md +++ b/src/services/utils/getFiatRatesByDay/getFiatRatesByDay.md @@ -1,6 +1,7 @@ --- id: getFiatRatesByDay -slug: /utils/getfiatratesbyday +slug: /sdk/api/utils/getfiatratesbyday +description: Use the StakeWise SDK getFiatRatesByDay utility to retrieve historical daily fiat exchange rates for a date range. --- #### Description: diff --git a/src/services/utils/getPermitSignature/getPermitSignature.md b/src/services/utils/getPermitSignature/getPermitSignature.md index 9cf0bb74..69ec0766 100644 --- a/src/services/utils/getPermitSignature/getPermitSignature.md +++ b/src/services/utils/getPermitSignature/getPermitSignature.md @@ -1,6 +1,7 @@ --- id: getPermitSignature -slug: /utils/getpermitsignature +slug: /sdk/api/utils/getpermitsignature +description: Use the StakeWise SDK getPermitSignature utility to generate an ERC20 permit signature for gasless token approvals. --- #### Description: diff --git a/src/services/utils/getStakewiseStats/getStakewiseStats.md b/src/services/utils/getStakewiseStats/getStakewiseStats.md index 7be9a670..6e099c1a 100644 --- a/src/services/utils/getStakewiseStats/getStakewiseStats.md +++ b/src/services/utils/getStakewiseStats/getStakewiseStats.md @@ -1,6 +1,7 @@ --- id: getStakewiseStats -slug: /utils/getstakewisestats +slug: /sdk/api/utils/getstakewisestats +description: Use the StakeWise SDK getStakewiseStats utility to fetch protocol-wide statistics including TVL, user count, and total rewards. --- #### Description: diff --git a/src/services/utils/getTransactions/getTransactions.md b/src/services/utils/getTransactions/getTransactions.md index f78bc630..706b0765 100644 --- a/src/services/utils/getTransactions/getTransactions.md +++ b/src/services/utils/getTransactions/getTransactions.md @@ -1,6 +1,7 @@ --- id: getTransactions -slug: /utils/gettransactions +slug: /sdk/api/utils/gettransactions +description: Use the StakeWise SDK getTransactions utility to verify that a transaction has been indexed by the subgraph. --- #### Description: diff --git a/src/services/vault/requests/getBlocklist/getBlocklist.md b/src/services/vault/requests/getBlocklist/getBlocklist.md index ef3616f7..0819ea8a 100644 --- a/src/services/vault/requests/getBlocklist/getBlocklist.md +++ b/src/services/vault/requests/getBlocklist/getBlocklist.md @@ -1,6 +1,7 @@ --- id: getBlocklist -slug: /vault/requests/getblocklist +slug: /sdk/api/vault/requests/getblocklist +description: Use the StakeWise SDK getBlocklist method to fetch the list of blocked addresses for blocklisted vaults. --- #### Description: diff --git a/src/services/vault/requests/getExitQueuePositions/getExitQueuePositions.md b/src/services/vault/requests/getExitQueuePositions/getExitQueuePositions.md index aac86851..e01e7ea6 100644 --- a/src/services/vault/requests/getExitQueuePositions/getExitQueuePositions.md +++ b/src/services/vault/requests/getExitQueuePositions/getExitQueuePositions.md @@ -1,6 +1,7 @@ --- id: getExitQueuePositions -slug: /vault/requests/getexitqueuepositions +slug: /sdk/api/vault/requests/getexitqueuepositions +description: Use the StakeWise SDK getExitQueuePositions method to retrieve the withdrawal queue positions for a specific user. --- #### Description: diff --git a/src/services/vault/requests/getHarvestParams/getHarvestParams.md b/src/services/vault/requests/getHarvestParams/getHarvestParams.md index 8e0703a6..92e2e4bb 100644 --- a/src/services/vault/requests/getHarvestParams/getHarvestParams.md +++ b/src/services/vault/requests/getHarvestParams/getHarvestParams.md @@ -1,6 +1,7 @@ --- id: getHarvestParams -slug: /vault/requests/getharvestparams +slug: /sdk/api/vault/requests/getharvestparams +description: Use the StakeWise SDK getHarvestParams method to fetch the parameters needed to update vault state and harvest rewards. --- #### Description: diff --git a/src/services/vault/requests/getMaxWithdraw/getMaxWithdraw.md b/src/services/vault/requests/getMaxWithdraw/getMaxWithdraw.md index 4b6ae73d..03b1f1ff 100644 --- a/src/services/vault/requests/getMaxWithdraw/getMaxWithdraw.md +++ b/src/services/vault/requests/getMaxWithdraw/getMaxWithdraw.md @@ -1,7 +1,8 @@ --- id: getMaxWithdraw title: getMaxWithdraw -slug: /vault/requests/getmaxwithdraw +slug: /sdk/api/vault/requests/getmaxwithdraw +description: "StakeWise SDK getMaxWithdraw method (deprecated): calculates the maximum withdrawal amount based on staked and minted assets." --- # Deprecated! @@ -16,9 +17,9 @@ How much a user can withdraw. Use this method if the user has mintedAssets, if m | Name | Type | Required | Info | |--------------|----------|----------|--------------------------------------------------------------| | vaultAddress | `string` | **Yes** | The address of the vault | -| ltvPercent | `bigint` | **Yes** | [sdk.vault.getVault](/vault/requests/getvault) | -| mintedAssets | `bigint` | **Yes** | [sdk.osToken.getPosition](/osToken/requests/getposition) | -| stakedAssets | `bigint` | **Yes** | [sdk.vault.getStakeBalance](/vault/requests/getstakebalance) | +| ltvPercent | `bigint` | **Yes** | [sdk.vault.getVault](/sdk/api/vault/requests/getvault) | +| mintedAssets | `bigint` | **Yes** | [sdk.osToken.getPosition](/sdk/api/osToken/requests/getposition) | +| stakedAssets | `bigint` | **Yes** | [sdk.vault.getStakeBalance](/sdk/api/vault/requests/getstakebalance) | #### Returns: diff --git a/src/services/vault/requests/getMaxWithdrawAmount/getMaxWithdrawAmount.md b/src/services/vault/requests/getMaxWithdrawAmount/getMaxWithdrawAmount.md index 5baa0a27..36be73a5 100644 --- a/src/services/vault/requests/getMaxWithdrawAmount/getMaxWithdrawAmount.md +++ b/src/services/vault/requests/getMaxWithdrawAmount/getMaxWithdrawAmount.md @@ -1,6 +1,7 @@ --- id: getMaxWithdrawAmount -slug: /vault/requests/getmaxwithdrawamount +slug: /sdk/api/vault/requests/getmaxwithdrawamount +description: Use the StakeWise SDK getMaxWithdrawAmount method to calculate the maximum amount a user can withdraw from a vault. --- #### Description: diff --git a/src/services/vault/requests/getOsTokenConfig/getOsTokenConfig.md b/src/services/vault/requests/getOsTokenConfig/getOsTokenConfig.md index 2d8ea6a6..e8b4201b 100644 --- a/src/services/vault/requests/getOsTokenConfig/getOsTokenConfig.md +++ b/src/services/vault/requests/getOsTokenConfig/getOsTokenConfig.md @@ -1,6 +1,7 @@ --- id: getOsTokenConfig -slug: /vault/getostokenconfig +slug: /sdk/api/vault/getostokenconfig +description: Use the StakeWise SDK getOsTokenConfig method to retrieve osToken collateral parameters like LTV and liquidation threshold. --- #### Description: diff --git a/src/services/vault/requests/getPeriodicDistributions/getPeriodicDistributions.md b/src/services/vault/requests/getPeriodicDistributions/getPeriodicDistributions.md index b885ac3e..576a9b68 100644 --- a/src/services/vault/requests/getPeriodicDistributions/getPeriodicDistributions.md +++ b/src/services/vault/requests/getPeriodicDistributions/getPeriodicDistributions.md @@ -1,6 +1,7 @@ --- id: getPeriodicDistributions -slug: /vault/requests/getperiodicdistributions +slug: /sdk/api/vault/requests/getperiodicdistributions +description: Use the StakeWise SDK getPeriodicDistributions method to fetch periodic distribution data for additional vault incentives. --- #### Description: diff --git a/src/services/vault/requests/getRewardSplitters/getRewardSplitters.md b/src/services/vault/requests/getRewardSplitters/getRewardSplitters.md index 7db99528..3fb3e459 100644 --- a/src/services/vault/requests/getRewardSplitters/getRewardSplitters.md +++ b/src/services/vault/requests/getRewardSplitters/getRewardSplitters.md @@ -1,6 +1,7 @@ --- id: getRewardSplitters -slug: /vault/requests/getrewardsplitters +slug: /sdk/api/vault/requests/getrewardsplitters +description: Use the StakeWise SDK getRewardSplitters method to fetch reward splitter contracts that distribute vault rewards among recipients. --- #### Description: diff --git a/src/services/vault/requests/getStakeBalance/getStakeBalance.md b/src/services/vault/requests/getStakeBalance/getStakeBalance.md index 5d94cdc4..07db931c 100644 --- a/src/services/vault/requests/getStakeBalance/getStakeBalance.md +++ b/src/services/vault/requests/getStakeBalance/getStakeBalance.md @@ -1,6 +1,7 @@ --- id: getStakeBalance -slug: /vault/requests/getstakebalance +slug: /sdk/api/vault/requests/getstakebalance +description: Use the StakeWise SDK getStakeBalance method to retrieve a user's staked balance and related data in a specific vault. --- #### Description: diff --git a/src/services/vault/requests/getStakerActions/getStakerActions.md b/src/services/vault/requests/getStakerActions/getStakerActions.md index 4571c104..0b8bf9ce 100644 --- a/src/services/vault/requests/getStakerActions/getStakerActions.md +++ b/src/services/vault/requests/getStakerActions/getStakerActions.md @@ -1,6 +1,7 @@ --- id: getStakerActions -slug: /vault/requests/getstakeractions +slug: /sdk/api/vault/requests/getstakeractions +description: Use the StakeWise SDK getStakerActions method to fetch a paginated list of user interactions and events for a vault. --- #### Description: diff --git a/src/services/vault/requests/getUserApy/getUserApy.md b/src/services/vault/requests/getUserApy/getUserApy.md index 2b9d7358..a96a7fb0 100644 --- a/src/services/vault/requests/getUserApy/getUserApy.md +++ b/src/services/vault/requests/getUserApy/getUserApy.md @@ -1,6 +1,7 @@ --- id: getUserApy -slug: /vault/requests/getuserapy +slug: /sdk/api/vault/requests/getuserapy +description: Use the StakeWise SDK getUserApy method to get a user's current APY in a vault, accounting for minting and boost. --- #### Description: diff --git a/src/services/vault/requests/getUserRewards/getUserRewards.md b/src/services/vault/requests/getUserRewards/getUserRewards.md index 79f59749..9ea235cb 100644 --- a/src/services/vault/requests/getUserRewards/getUserRewards.md +++ b/src/services/vault/requests/getUserRewards/getUserRewards.md @@ -1,6 +1,7 @@ --- id: getUserRewards -slug: /vault/requests/getuserrewards +slug: /sdk/api/vault/requests/getuserrewards +description: Use the StakeWise SDK getUserRewards method to fetch daily staking rewards for a user within a specified date range. --- #### Description: diff --git a/src/services/vault/requests/getUserStats/getUserStats.md b/src/services/vault/requests/getUserStats/getUserStats.md index 7208c025..f6e23965 100644 --- a/src/services/vault/requests/getUserStats/getUserStats.md +++ b/src/services/vault/requests/getUserStats/getUserStats.md @@ -1,6 +1,7 @@ --- id: getUserStats -slug: /vault/requests/getuserstats +slug: /sdk/api/vault/requests/getuserstats +description: Use the StakeWise SDK getUserStats method to retrieve user stats for a vault, useful for building performance charts. --- #### Description: diff --git a/src/services/vault/requests/getValidators/getValidators.md b/src/services/vault/requests/getValidators/getValidators.md index 06b12606..9576f1d4 100644 --- a/src/services/vault/requests/getValidators/getValidators.md +++ b/src/services/vault/requests/getValidators/getValidators.md @@ -1,6 +1,7 @@ --- id: getValidators -slug: /vault/requests/getvalidators +slug: /sdk/api/vault/requests/getvalidators +description: Use the StakeWise SDK getValidators method to retrieve the list of running validators for a specific vault. --- #### Description: diff --git a/src/services/vault/requests/getVault/getVault.md b/src/services/vault/requests/getVault/getVault.md index 429dc9f7..fcb90e61 100644 --- a/src/services/vault/requests/getVault/getVault.md +++ b/src/services/vault/requests/getVault/getVault.md @@ -1,6 +1,7 @@ --- id: getVault -slug: /vault/requests/getvault +slug: /sdk/api/vault/requests/getvault +description: Use the StakeWise SDK getVault method to retrieve master data for a vault including APY, TVL, and configuration details. --- #### Description: @@ -81,8 +82,8 @@ type Output = { | `whitelistManager` | Whitelist manager | | `vaultAddress` | Address of vault | | `mevRecipient` | Validator fee recipient | -| `whitelistCount` | Number of addresses in the [whitelist](/vault/requests/getwhitelist) | -| `blocklistCount` | Number of addresses in the [blocklist](/vault/requests/getblocklist) | +| `whitelistCount` | Number of addresses in the [whitelist](/sdk/api/vault/requests/getwhitelist) | +| `blocklistCount` | Number of addresses in the [blocklist](/sdk/api/vault/requests/getblocklist) | | `imageUrl` | Link for vault logo | | `blocklistManager` | Blocklist manager | | `depositDataManager` | Keys manager address | diff --git a/src/services/vault/requests/getVaultFactory/getVaultFactory.md b/src/services/vault/requests/getVaultFactory/getVaultFactory.md index aecb900f..10f5b701 100644 --- a/src/services/vault/requests/getVaultFactory/getVaultFactory.md +++ b/src/services/vault/requests/getVaultFactory/getVaultFactory.md @@ -1,6 +1,7 @@ --- id: getVaultFactory -slug: /vault/requests/getvaultfactory +slug: /sdk/api/vault/requests/getvaultfactory +description: Use the StakeWise SDK getVaultFactory method to get the vault factory contract address needed for vault creation. --- #### Description: diff --git a/src/services/vault/requests/getVaultStats/getVaultStats.md b/src/services/vault/requests/getVaultStats/getVaultStats.md index 2baf24b4..346405cf 100644 --- a/src/services/vault/requests/getVaultStats/getVaultStats.md +++ b/src/services/vault/requests/getVaultStats/getVaultStats.md @@ -1,6 +1,7 @@ --- id: getVaultStats -slug: /vault/requests/getvaultstats +slug: /sdk/api/vault/requests/getvaultstats +description: Use the StakeWise SDK getVaultStats method to fetch vault performance statistics over time for building charts. --- #### Description: diff --git a/src/services/vault/requests/getVaultVersion/getVaultVersion.md b/src/services/vault/requests/getVaultVersion/getVaultVersion.md index 75f24930..48ebd56e 100644 --- a/src/services/vault/requests/getVaultVersion/getVaultVersion.md +++ b/src/services/vault/requests/getVaultVersion/getVaultVersion.md @@ -1,6 +1,7 @@ --- id: getVaultVersion -slug: /vault/requests/getvaultversion +slug: /sdk/api/vault/requests/getvaultversion +description: Use the StakeWise SDK getVaultVersion method to retrieve the current version number of a specific vault contract. --- #### Description: diff --git a/src/services/vault/requests/getWhitelist/getWhitelist.md b/src/services/vault/requests/getWhitelist/getWhitelist.md index 4e9356ca..8f9d7779 100644 --- a/src/services/vault/requests/getWhitelist/getWhitelist.md +++ b/src/services/vault/requests/getWhitelist/getWhitelist.md @@ -1,6 +1,7 @@ --- id: getWhitelist -slug: /vault/requests/getwhitelist +slug: /sdk/api/vault/requests/getwhitelist +description: Use the StakeWise SDK getWhitelist method to fetch the list of whitelisted addresses eligible to stake in private vaults. --- #### Description: diff --git a/src/services/vault/transactions/claimExitQueue/claimExitQueue.md b/src/services/vault/transactions/claimExitQueue/claimExitQueue.md index e8f094aa..4774f71d 100644 --- a/src/services/vault/transactions/claimExitQueue/claimExitQueue.md +++ b/src/services/vault/transactions/claimExitQueue/claimExitQueue.md @@ -1,6 +1,7 @@ --- id: claimExitQueue -slug: /vault/transactions/claimexitqueue +slug: /sdk/api/vault/transactions/claimexitqueue +description: Use the StakeWise SDK claimExitQueue method to withdraw exited assets from the vault exit queue for a specific user. --- #### Description: @@ -11,7 +12,7 @@ Withdraws exited assets from the queue. | Name | Type | Required | Description | |--------------|----------|----------|------------------------------------------------------------------------------------------| -| positions | `string` | **Yes** | `postions` from [sdk.vault.getExitQueuePositions](/vault/requests/getexitqueuepositions) | +| positions | `string` | **Yes** | `postions` from [sdk.vault.getExitQueuePositions](/sdk/api/vault/requests/getexitqueuepositions) | | userAddress | `string` | **Yes** | The user address | | vaultAddress | `string` | **Yes** | The address of the vault | diff --git a/src/services/vault/transactions/createVault/createVault.md b/src/services/vault/transactions/createVault/createVault.md index 49dcdcbb..e43c9c94 100644 --- a/src/services/vault/transactions/createVault/createVault.md +++ b/src/services/vault/transactions/createVault/createVault.md @@ -1,6 +1,7 @@ --- id: create -slug: /vault/transactions/create +slug: /sdk/api/vault/transactions/create +description: Use the StakeWise SDK createVault method to deploy a new staking vault with custom configuration, fees, and metadata. --- #### Description: diff --git a/src/services/vault/transactions/deposit/deposit.md b/src/services/vault/transactions/deposit/deposit.md index f20b482f..f33bda5c 100644 --- a/src/services/vault/transactions/deposit/deposit.md +++ b/src/services/vault/transactions/deposit/deposit.md @@ -1,6 +1,7 @@ --- id: deposit -slug: /vault/transactions/deposit +slug: /sdk/api/vault/transactions/deposit +description: Use the StakeWise SDK deposit method to stake assets into a vault. Includes arguments, example code, and encoding support. --- #### Description: diff --git a/src/services/vault/transactions/operate/operate.md b/src/services/vault/transactions/operate/operate.md index 8d3d491f..69faeaf5 100644 --- a/src/services/vault/transactions/operate/operate.md +++ b/src/services/vault/transactions/operate/operate.md @@ -1,6 +1,7 @@ --- id: operate -slug: /vault/transactions/operate +slug: /sdk/api/vault/transactions/operate +description: Use the StakeWise SDK operate method to update vault settings such as whitelist, blocklist, validators manager, and metadata. --- #### Description: diff --git a/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.md b/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.md index cd2b2ecf..3ecdf0c4 100644 --- a/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.md +++ b/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.md @@ -1,6 +1,7 @@ --- id: setDepositDataManager -slug: /vault/transactions/setdepositdatamanager +slug: /sdk/api/vault/transactions/setdepositdatamanager +description: Use the StakeWise SDK setDepositDataManager method to assign a deposit data manager to v2+ vaults. --- #### Description: diff --git a/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.md b/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.md index 4c95fb1c..c389a8df 100644 --- a/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.md +++ b/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.md @@ -1,6 +1,7 @@ --- id: setDepositDataRoot -slug: /vault/transactions/setdepositdataroot +slug: /sdk/api/vault/transactions/setdepositdataroot +description: Use the StakeWise SDK setDepositDataRoot method to set the validators merkle tree root for v2+ vaults. --- #### Description: diff --git a/src/services/vault/transactions/withdraw/withdraw.md b/src/services/vault/transactions/withdraw/withdraw.md index 36fa00d2..01aa4453 100644 --- a/src/services/vault/transactions/withdraw/withdraw.md +++ b/src/services/vault/transactions/withdraw/withdraw.md @@ -1,6 +1,7 @@ --- id: withdraw -slug: /vault/transactions/withdraw +slug: /sdk/api/vault/transactions/withdraw +description: Use the StakeWise SDK withdraw method to unstake and withdraw funds from a vault, with health factor validation. --- #### Description: From 4abc61d219ed2e5084d82d5fbe04dfc0dc39952d Mon Sep 17 00:00:00 2001 From: Kadyr Dzhemaledinov Date: Tue, 7 Apr 2026 10:55:23 +0300 Subject: [PATCH 13/27] Link checker (#355) * Remove sync docs git action (#354) * [remove-sync-docs] remove git action and change script * change git action * add link checker script and update documentation references * fix broken links * add md files to check * small improve * update GitHub Actions to use latest checkout and cache actions (#356) Co-authored-by: github-actions[bot] * add script to check documentation links and update pre-commit hook * update * update * update * add warning for slug changes in staged md files * rename markdown files and update slug checking logic in link checker * Add script to check documentation links (#357) * add script to check documentation links * fix after review * rename documentation files and improve slug validation in checkDocLinks * add category configuration for Quick Start * improve slug processing and include _category_.json in documentation file search * 4.2.3 (#358) * merge --------- Co-authored-by: CAst Co-authored-by: github-actions[bot] --- .github/workflows/build-check.yml | 6 +- .github/workflows/sync-docs.yml | 56 ------- .github/workflows/unit-tests.yml | 6 +- .husky/pre-commit | 4 +- changelog/next-release.md | 12 +- documentation/03-quick-start/_category_.json | 3 + .../boost.md | 0 .../burn-os-token.md | 0 .../deposit-to-vault.md | 0 .../get-user-data.md | 0 .../get-vault-data.md | 0 .../mint-os-token.md | 0 .../unboost.md | 0 .../unstake.md | 0 package.json | 3 +- scripts/checkDocLinks.js | 144 ++++++++++++++++++ scripts/syncDocs/index.ts | 59 ++++--- scripts/syncDocs/sendDiscordNotification.ts | 76 --------- src/services/boost/index.ts | 8 +- src/services/boost/transactions/index.ts | 8 +- src/services/distributorRewards/index.ts | 2 +- .../distributorRewards/transactions/index.ts | 2 +- src/services/osToken/index.ts | 22 +-- src/services/osToken/transactions/index.ts | 4 +- src/services/rewardSplitter/index.ts | 2 +- .../rewardSplitter/transactions/index.ts | 8 +- src/services/utils/index.ts | 10 +- src/services/vault/index.ts | 40 ++--- .../getOsTokenConfig/getOsTokenConfig.md | 2 +- .../requests/getSubVaults/getSubVaults.md | 2 +- .../vault/requests/getVault/getVault.md | 1 + .../transactions/addSubVault/addSubVault.md | 2 +- .../ejectSubVault/ejectSubVault.md | 2 +- src/services/vault/transactions/index.ts | 23 ++- .../rejectSubVault/rejectSubVault.md | 2 +- .../transactions/updateState/updateState.md | 2 +- 36 files changed, 274 insertions(+), 237 deletions(-) delete mode 100644 .github/workflows/sync-docs.yml create mode 100644 documentation/03-quick-start/_category_.json rename documentation/{03-Quick start => 03-quick-start}/boost.md (100%) rename documentation/{03-Quick start => 03-quick-start}/burn-os-token.md (100%) rename documentation/{03-Quick start => 03-quick-start}/deposit-to-vault.md (100%) rename documentation/{03-Quick start => 03-quick-start}/get-user-data.md (100%) rename documentation/{03-Quick start => 03-quick-start}/get-vault-data.md (100%) rename documentation/{03-Quick start => 03-quick-start}/mint-os-token.md (100%) rename documentation/{03-Quick start => 03-quick-start}/unboost.md (100%) rename documentation/{03-Quick start => 03-quick-start}/unstake.md (100%) create mode 100644 scripts/checkDocLinks.js delete mode 100644 scripts/syncDocs/sendDiscordNotification.ts diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml index 0f4f9b82..edde6d16 100644 --- a/.github/workflows/build-check.yml +++ b/.github/workflows/build-check.yml @@ -13,15 +13,15 @@ jobs: packages: read steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 with: version: 10.25.0 - name: Setup Node - uses: actions/setup-node@v6 + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f with: node-version: '24.12.0' diff --git a/.github/workflows/sync-docs.yml b/.github/workflows/sync-docs.yml deleted file mode 100644 index c6465813..00000000 --- a/.github/workflows/sync-docs.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Sync docs to StakeWise Docs - -on: - push: - branches: - - main - paths: - - 'src/**/*.md' - - 'src/**/*.mdx' - - 'documentation/**/*.md' - -permissions: - contents: read - pull-requests: read - -jobs: - sync-docs: - runs-on: ubuntu-latest - - steps: - - name: Checkout repo - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 10.25.0 - - - name: Setup Node.js - uses: actions/setup-node@v6 - with: - node-version: '24' - cache: 'pnpm' - - - name: Setup SSH key for docs repository - uses: webfactory/ssh-agent@v0.9.0 - with: - ssh-private-key: ${{ secrets.SYNC_DOCS_SSH_KEY }} - - - name: Install dependencies - run: | - pnpm install - - - name: Version check - run: pnpm check:version - continue-on-error: false - - - name: Run docs sync - env: - SYNC_DOCS_TOKEN: ${{ secrets.SYNC_DOCS_TOKEN }} - DISCORD_USERS_JSON: ${{ secrets.DISCORD_USERS_JSON }} - DISCORD_WEBHOOK_URL: ${{ secrets.SYNC_DOCS_DISCORD_WEBHOOK_URL }} - COMMIT_AUTHOR: ${{ github.actor }} - run: pnpm sync:docs diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 8f0e95ee..0afa42c8 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -13,15 +13,15 @@ jobs: packages: read steps: - name: Checkout 🛎️ - uses: actions/checkout@v4 + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 with: version: 10.25.0 - name: Setup Node - uses: actions/setup-node@v6 + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f with: cache: pnpm scope: '@stakewise' diff --git a/.husky/pre-commit b/.husky/pre-commit index 8504f951..74c0ea0a 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,3 +1,3 @@ sh ./scripts/pre-push.sh - -npm run lint +pnpm run check:docLinks +pnpm run lint diff --git a/changelog/next-release.md b/changelog/next-release.md index 37789ce7..2c16cdfe 100644 --- a/changelog/next-release.md +++ b/changelog/next-release.md @@ -1,14 +1,14 @@ ## Added methods -- [sdk.vault.getSubVaults](https://docs.stakewise.io/vault/requests/getsubvaults) -- [sdk.vault.addSubVault](https://docs.stakewise.io/vault/transactions/addsubvault) -- [sdk.vault.rejectSubVault](https://docs.stakewise.io/vault/transactions/rejectsubvault) -- [sdk.vault.ejectSubVault](https://docs.stakewise.io/vault/transactions/ejectsubvault) -- [sdk.vault.updateState](https://docs.stakewise.io/vault/transactions/updatestate) +- [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/vault/requests/getvault) +### 1. [sdk.vault.getVault](https://docs.stakewise.io/sdk/api/vault/requests/getvault) #### Add output field: ```ts diff --git a/documentation/03-quick-start/_category_.json b/documentation/03-quick-start/_category_.json new file mode 100644 index 00000000..867b92db --- /dev/null +++ b/documentation/03-quick-start/_category_.json @@ -0,0 +1,3 @@ +{ + "label": "Quick Start" +} diff --git a/documentation/03-Quick start/boost.md b/documentation/03-quick-start/boost.md similarity index 100% rename from documentation/03-Quick start/boost.md rename to documentation/03-quick-start/boost.md diff --git a/documentation/03-Quick start/burn-os-token.md b/documentation/03-quick-start/burn-os-token.md similarity index 100% rename from documentation/03-Quick start/burn-os-token.md rename to documentation/03-quick-start/burn-os-token.md diff --git a/documentation/03-Quick start/deposit-to-vault.md b/documentation/03-quick-start/deposit-to-vault.md similarity index 100% rename from documentation/03-Quick start/deposit-to-vault.md rename to documentation/03-quick-start/deposit-to-vault.md diff --git a/documentation/03-Quick start/get-user-data.md b/documentation/03-quick-start/get-user-data.md similarity index 100% rename from documentation/03-Quick start/get-user-data.md rename to documentation/03-quick-start/get-user-data.md diff --git a/documentation/03-Quick start/get-vault-data.md b/documentation/03-quick-start/get-vault-data.md similarity index 100% rename from documentation/03-Quick start/get-vault-data.md rename to documentation/03-quick-start/get-vault-data.md diff --git a/documentation/03-Quick start/mint-os-token.md b/documentation/03-quick-start/mint-os-token.md similarity index 100% rename from documentation/03-Quick start/mint-os-token.md rename to documentation/03-quick-start/mint-os-token.md diff --git a/documentation/03-Quick start/unboost.md b/documentation/03-quick-start/unboost.md similarity index 100% rename from documentation/03-Quick start/unboost.md rename to documentation/03-quick-start/unboost.md diff --git a/documentation/03-Quick start/unstake.md b/documentation/03-quick-start/unstake.md similarity index 100% rename from documentation/03-Quick start/unstake.md rename to documentation/03-quick-start/unstake.md diff --git a/package.json b/package.json index f90625be..ee8d2c9b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "type": "module", - "version": "4.2.2", + "version": "4.2.3", "sideEffects": false, "main": "dist/index.js", "types": "dist/index.d.ts", @@ -20,6 +20,7 @@ "graphql": "graphql-codegen && tsx ./scripts/generateGraphqlExports/index.ts", "rollup": "rollup --config rollup.config.js", "check:version": "node ./scripts/checkVersion.js", + "check:docLinks": "node ./scripts/checkDocLinks.js", "lint": "eslint ./src --ext .ts,.tsx,.js,.jsx", "release": "pnpm build && pnpm publish --tag=latest", "sync:docs": "tsx ./scripts/syncDocs/index.ts" diff --git a/scripts/checkDocLinks.js b/scripts/checkDocLinks.js new file mode 100644 index 00000000..61bbdce9 --- /dev/null +++ b/scripts/checkDocLinks.js @@ -0,0 +1,144 @@ +import path from 'path' +import https from 'https' +import { fileURLToPath } from 'url' +import { execSync } from 'child_process' + + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +// eslint-disable-next-line no-restricted-syntax +const docsUrl = 'https://docs.stakewise.io' + +const srcDir = path.resolve(__dirname, '../src') + +const fetchSitemap = () => { + const sitemapUrl = `${docsUrl}/sitemap.xml` + + return new Promise((resolve, reject) => { + https + .get(sitemapUrl, (res) => { + let data = '' + + res.on('data', (chunk) => data += chunk) + res.on('end', () => { + const matches = data.match(/([^<]+)/g) || [] + + const urls = matches.map((match) => { + return match + .replace('', '') + .replace(/\/$/, '') + .toLowerCase() + }) + + resolve(urls) + }) + }) + .on('error', reject) + }) +} + +const getSdkApiSlugs = () => { + try { + const output = execSync( + `grep -r "^slug:" "${srcDir}" --include="*.md"`, + { encoding: 'utf-8' } + ) + + const slugs = output + .split('\n') + .filter(Boolean) + .map((line) => line.replace(/.*slug:\s*/, '').trim().replace(/\/$/, '').toLowerCase()) + + const brokenSlugs = slugs.filter((slug) => !slug.startsWith('/')) + + if (brokenSlugs.length) { + console.log('🚫 Slugs must start with /:') + brokenSlugs.forEach((slug) => console.log(`${slug}`)) + process.exit(1) + } + + return slugs.filter((slug) => slug.startsWith('/sdk/api/')) + } + catch { + return [] + } +} + +const getUrls = () => { + const rootDir = path.resolve(__dirname, '..') + + try { + const output = execSync( + `grep -roh "https://docs\\.stakewise\\.io/[^\\"' )\\\`>]*" "${rootDir}" ` + + '--include="*.ts" --include="*.tsx" --include="*.md" --include="*.mdx" ' + + '--exclude-dir=node_modules', + { encoding: 'utf-8' } + ) + + return [ ...new Set( + output + .split('\n') + .map((url) => url.replace(/[.,;)]+$/, '')) + .filter((url) => url && url !== docsUrl && url !== `${docsUrl}/`) + )] + } + catch { + return [] + } +} + +const checkDocLinks = async () => { + const urls = getUrls() + + if (!urls.length) { + console.log('No docs links found.') + + return + } + + const slugs = getSdkApiSlugs() + const broken = [] + + let sitemap = null + + for (const url of urls) { + const urlPath = url.replace(docsUrl, '').replace(/[#?].*$/, '').replace(/\/$/, '').toLowerCase() + + if (slugs.includes(urlPath)) { + continue + } + + // Not found in local slugs — check against live sitemap + if (!sitemap) { + sitemap = await fetchSitemap() + } + + if (!sitemap.includes(`${docsUrl}${urlPath}`)) { + broken.push(url) + } + } + + if (broken.length) { + broken.forEach((url) => console.log(url)) + console.log(`\n🚫 Found ${broken.length} broken link(s)!`) + process.exit(1) + } + + console.log('✅ All docs links are valid.') + + // Warn if staged md files were changed + try { + const stagedMd = execSync('git diff --cached --name-only -- "src/**/*.md" "documentation/**/*.md"', { encoding: 'utf-8' }).trim() + + if (stagedMd) { + const warn = (text) => console.log(`\x1b[33m${text}\x1b[0m`) + + console.log() + warn('⚠️SDK docs were changed! ⚠️') + warn("Don't forget to run: pnpm sync:docs") + } + } + catch {} +} + +checkDocLinks() diff --git a/scripts/syncDocs/index.ts b/scripts/syncDocs/index.ts index 6a9e1f16..a720ac33 100644 --- a/scripts/syncDocs/index.ts +++ b/scripts/syncDocs/index.ts @@ -2,10 +2,10 @@ import path from 'path' import fs from 'fs-extra' import { glob } from 'glob' import simpleGit from 'simple-git' +import { execSync } from 'child_process' import log from './log' import createPullRequest from './createPullRequest' -import sendDiscordNotification from './sendDiscordNotification' const branchName = 'sync-sdk' @@ -15,9 +15,32 @@ const docsRepoPath = `${process.cwd()}/docs` const documentationPath = `${process.cwd()}/documentation` const docsRepoUrl = 'git@github.com:stakewise/stakewise-docs.git' -const commitAuthor = process.env.COMMIT_AUTHOR || 'unknown' -const syncDocsToken = process.env.SYNC_DOCS_TOKEN -const discordWebhookUrl = process.env.DISCORD_WEBHOOK_URL +const getGitUserName = () => { + try { + return execSync('git config user.name', { encoding: 'utf-8' }).trim() + } + catch { + return 'unknown' + } +} + +const getGitHubToken = () => { + try { + const output = execSync( + 'echo "protocol=https\nhost=github.com" | git credential fill', + { encoding: 'utf-8', shell: '/bin/sh' }, + ) + const match = output.match(/password=(.+)/) + + return match?.[1]?.trim() + } + catch { + return undefined + } +} + +const commitAuthor = getGitUserName() +const syncDocsToken = getGitHubToken() const changeTargetPath = (path: string) => path .replace('services/', 'API/') @@ -37,6 +60,11 @@ const changeTargetPath = (path: string) => path log.info('🤖 Start of documentation synchronization...') + if (!syncDocsToken) { + log.error('GitHub token not found. Make sure your git credentials for github.com are configured.') + process.exit(1) + } + try { const isExist = await fs.pathExists(docsRepoPath) @@ -54,7 +82,7 @@ const changeTargetPath = (path: string) => path cwd: srcPath }) - const documentationFiles = await glob(['**/*.md', '**/*.mdx'], { + const documentationFiles = await glob(['**/*.md', '**/*.mdx', '**/_category_.json'], { cwd: documentationPath }) @@ -99,15 +127,11 @@ const changeTargetPath = (path: string) => path await fs.ensureDir(path.dirname(targetFile)) await fs.copy(sourceFile, targetFile) - } + } log.success('Files are copied') - await git - .addConfig('user.name', 'github-actions[bot]') - .addConfig('user.email', 'github-actions[bot]@users.noreply.github.com') - - log.success(`GitHub Commit signer is set.`) + log.info(`👤 Commit author: ${commitAuthor}`) await git.add('.') @@ -122,7 +146,7 @@ const changeTargetPath = (path: string) => path log.success(`Changes are pushed to '${branchName}' branch.`) - const prData = await createPullRequest({ + await createPullRequest({ authToken: syncDocsToken, repo: 'stakewise-docs', owner: 'stakewise', @@ -131,15 +155,12 @@ const changeTargetPath = (path: string) => path title, }) - await sendDiscordNotification({ - discordWebhookUrl, - author: commitAuthor, - prUrl: prData.html_url, - filesCount: filesCount, - }) + await fs.remove(docsRepoPath) + log.success('🧹 Cloned docs repository has been cleaned up.') } catch (error) { log.error(`${error}`) + await fs.remove(docsRepoPath) process.exit(1) - } + } })() diff --git a/scripts/syncDocs/sendDiscordNotification.ts b/scripts/syncDocs/sendDiscordNotification.ts deleted file mode 100644 index c7ce3116..00000000 --- a/scripts/syncDocs/sendDiscordNotification.ts +++ /dev/null @@ -1,76 +0,0 @@ -import log from './log' - - -type Input = { - prUrl: string - author: string - filesCount: number - discordWebhookUrl?: string -} - -const sendDiscordNotification = async (values: Input) => { - const { prUrl, author, filesCount, discordWebhookUrl } = values - - if (!discordWebhookUrl) { - log.info('Discord webhook URL not provided, skipping notification.') - - return - } - - try { - const users = JSON.parse(process.env.DISCORD_USERS_JSON || '{}') - - const user = users[author] - - const mention = user ? `**<@${user}>**` : 'Unknown author' - - const discordMessage = { - username: 'SDK Docs Sync', - avatar_url: 'https://github.com/github.png', - embeds: [ - { - title: '📚 SDK Documentation Synced', - description: `${mention} Documentation has been automatically synchronized and a PR is ready for review.`, - color: 0x00ff00, - fields: [ - { - name: '🔗 Pull Request', - value: `**[View PR](${prUrl})**`, - inline: true - }, - { - name: '📁 Files Synced', - value: `${filesCount} files`, - inline: true - } - ], - timestamp: new Date().toISOString(), - footer: { - text: 'StakeWise Docs Sync' - } - } - ] - } - - const response = await fetch(discordWebhookUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(discordMessage), - }) - - if (response.ok) { - log.success('📢 Discord notification sent successfully.') - } - else { - log.error(`Failed to send Discord notification: ${response.statusText}`) - } - } - catch (error) { - log.error(`Error sending Discord notification: ${error}`) - } -} - - -export default sendDiscordNotification diff --git a/src/services/boost/index.ts b/src/services/boost/index.ts index 69148882..df9e7121 100644 --- a/src/services/boost/index.ts +++ b/src/services/boost/index.ts @@ -25,7 +25,7 @@ class Boost extends BoostTransactions { /** * @description Get basic boost data for the user. - * @see https://docs.stakewise.io/boost/requests/getdata + * @see https://docs.stakewise.io/sdk/api/boost/requests/getdata */ public getData(values: StakeWise.ExtractInput) { return getData({ ...this.params, ...values }) @@ -33,7 +33,7 @@ class Boost extends BoostTransactions { /** * @description Get unlock position data. - * @see https://docs.stakewise.io/boost/requests/getqueueposition + * @see https://docs.stakewise.io/sdk/api/boost/requests/getqueueposition */ public getQueuePosition(values: StakeWise.ExtractInput) { return getQueuePosition({ ...this.params, ...values }) @@ -41,7 +41,7 @@ class Boost extends BoostTransactions { /** * @description Get Aave leverage strategy contract data - * @see https://docs.stakewise.io/boost/requests/getleveragestrategydata + * @see https://docs.stakewise.io/sdk/api/boost/requests/getleveragestrategydata */ public getLeverageStrategyData(values: StakeWise.ExtractInput) { return getLeverageStrategyData({ ...this.params, ...values }) @@ -49,7 +49,7 @@ class Boost extends BoostTransactions { /** * @description Get Aave leverage strategy proxy contract address - * @see https://docs.stakewise.io/boost/requests/getleveragestrategyproxy + * @see https://docs.stakewise.io/sdk/api/boost/requests/getleveragestrategyproxy */ public getLeverageStrategyProxy(values: StakeWise.ExtractInput) { return getLeverageStrategyProxy({ ...this.params, ...values }) diff --git a/src/services/boost/transactions/index.ts b/src/services/boost/transactions/index.ts index 5e0d68e0..94df5ed4 100644 --- a/src/services/boost/transactions/index.ts +++ b/src/services/boost/transactions/index.ts @@ -10,25 +10,25 @@ class BoostTransactions { /** * @description Lock your osToken to increase apy - * @see https://docs.stakewise.io/boost/transactions/lock + * @see https://docs.stakewise.io/sdk/api/boost/transactions/lock */ public lock: ExtractLock /** * @description Unlock your boosted osToken - * @see https://docs.stakewise.io/boost/transactions/unlock + * @see https://docs.stakewise.io/sdk/api/boost/transactions/unlock */ public unlock: ExtractUnlock /** * @description Claim your boosted osTokens and accumulated rewards - * @see https://docs.stakewise.io/boost/transactions/claimqueue + * @see https://docs.stakewise.io/sdk/api/boost/transactions/claimqueue */ public claimQueue: ExtractClaimQueue /** * @description Upgrade leverage strategy contract version - * @see https://docs.stakewise.io/boost/transactions/upgradeleveragestrategy + * @see https://docs.stakewise.io/sdk/api/boost/transactions/upgradeleveragestrategy */ public upgradeLeverageStrategy: ExtractUpgradeLeverageStrategy diff --git a/src/services/distributorRewards/index.ts b/src/services/distributorRewards/index.ts index e130145f..40a49eff 100644 --- a/src/services/distributorRewards/index.ts +++ b/src/services/distributorRewards/index.ts @@ -12,7 +12,7 @@ class DistributorRewards extends DistributorRewardsTransactions { /** * @description Returns the set of distributor rewards tokens that are currently claimable. - * @see https://docs.stakewise.io/distributorRewards/requests/getrewards + * @see https://docs.stakewise.io/sdk/api/distributorRewards/requests/getrewards */ public getRewards(values: StakeWise.ExtractInput) { return getRewards({ ...this.params, ...values }) diff --git a/src/services/distributorRewards/transactions/index.ts b/src/services/distributorRewards/transactions/index.ts index 0547644e..6a10083b 100644 --- a/src/services/distributorRewards/transactions/index.ts +++ b/src/services/distributorRewards/transactions/index.ts @@ -6,7 +6,7 @@ import { createClaim, ExtractClaim } from './claim' class DistributorRewardsTransactions { /** * @description Claims rewards from the merkle distributor V2 contract. - * @see https://docs.stakewise.io/distributorRewards/transactions/claim + * @see https://docs.stakewise.io/sdk/api/distributorRewards/transactions/claim */ public claim: ExtractClaim diff --git a/src/services/osToken/index.ts b/src/services/osToken/index.ts index 01538a48..1f0c7fa4 100644 --- a/src/services/osToken/index.ts +++ b/src/services/osToken/index.ts @@ -45,7 +45,7 @@ class OsToken extends OsTokenTransactions { /** * @description Current osToken APY. - * @see https://docs.stakewise.io/osToken/requests/getostokenapy + * @see https://docs.stakewise.io/sdk/api/osToken/requests/getostokenapy */ public getAPY() { return getAPY(this.params) @@ -53,7 +53,7 @@ class OsToken extends OsTokenTransactions { /** * @description Current osToken rate. - * @see https://docs.stakewise.io/osToken/requests/getostokenrate + * @see https://docs.stakewise.io/sdk/api/osToken/requests/getostokenrate */ public getRate() { return getRate(this.params) @@ -62,7 +62,7 @@ class OsToken extends OsTokenTransactions { /** * @description Maximum number of **shares** for minting. * @deprecated Use new getMaxMintAmount method. - * @see https://docs.stakewise.io/osToken/requests/getmaxmint + * @see https://docs.stakewise.io/sdk/api/osToken/requests/getmaxmint */ public getMaxMint(values: StakeWise.ExtractInput) { return getMaxMint({ ...this.params, ...values }) @@ -70,7 +70,7 @@ class OsToken extends OsTokenTransactions { /** * @description Maximum number of **shares** for minting. - * @see https://docs.stakewise.io/osToken/requests/getmaxmintamount + * @see https://docs.stakewise.io/sdk/api/osToken/requests/getmaxmintamount */ public getMaxMintAmount(values: StakeWise.ExtractInput) { return getMaxMintAmount({ ...this.params, ...values }) @@ -79,7 +79,7 @@ class OsToken extends OsTokenTransactions { /** * @description User position data * @deprecated Use osToken.getHealthFactor and osToken.getBalance - * @see https://docs.stakewise.io/osToken/requests/getposition + * @see https://docs.stakewise.io/sdk/api/osToken/requests/getposition */ public getPosition(values: StakeWise.ExtractInput) { return getPosition({ ...this.params, ...values }) @@ -87,7 +87,7 @@ class OsToken extends OsTokenTransactions { /** * @description User osToken balance - * @see https://docs.stakewise.io/osToken/helpers/getbalance + * @see https://docs.stakewise.io/sdk/api/osToken/requests/getbalance */ public getBalance(values: StakeWise.ExtractInput) { return getBalance({ ...this.params, ...values }) @@ -95,7 +95,7 @@ class OsToken extends OsTokenTransactions { /** * @description Convert ETH (assets) → osToken (shares) - * @see https://docs.stakewise.io/osToken/requests/getsharesfromassets + * @see https://docs.stakewise.io/sdk/api/osToken/requests/getsharesfromassets */ public getSharesFromAssets(values: StakeWise.ExtractInput) { return getSharesFromAssets({ ...this.params, ...values }) @@ -103,7 +103,7 @@ class OsToken extends OsTokenTransactions { /** * @description Convert osToken (shares) → ETH (assets) - * @see https://docs.stakewise.io/osToken/requests/getassetsfromshares + * @see https://docs.stakewise.io/sdk/api/osToken/requests/getassetsfromshares */ public getAssetsFromShares(values: StakeWise.ExtractInput) { return getAssetsFromShares({ ...this.params, ...values }) @@ -112,7 +112,7 @@ class OsToken extends OsTokenTransactions { /** * @description How many osToken burn do you need to make to withdraw all deposit. * @deprecated use new getBurnAmountForUnstake method - * @see https://docs.stakewise.io/osToken/helpers/getburnamount + * @see https://docs.stakewise.io/sdk/api/osToken/helpers/getburnamount */ public getBurnAmount(values: StakeWise.ExtractInput) { return getBurnAmount({ ...this.params, ...values }) @@ -120,7 +120,7 @@ class OsToken extends OsTokenTransactions { /** * @description Returns the amount of osToken to burn for full unstake. - * @see https://docs.stakewise.io/osToken/helpers/getburnamountforunstake + * @see https://docs.stakewise.io/sdk/api/osToken/helpers/getburnamountforunstake */ public getBurnAmountForUnstake(values: StakeWise.ExtractInput) { return getBurnAmountForUnstake({ ...this.params, ...values }) @@ -128,7 +128,7 @@ class OsToken extends OsTokenTransactions { /** * @description Get the health of osETH position - * @see https://docs.stakewise.io/osToken/helpers/gethealthfactor + * @see https://docs.stakewise.io/sdk/api/osToken/helpers/gethealthfactor */ public getHealthFactor(values: StakeWise.ExtractInput) { return getHealthFactor({ ...this.params, ...values }) diff --git a/src/services/osToken/transactions/index.ts b/src/services/osToken/transactions/index.ts index 357cdb37..f593d378 100644 --- a/src/services/osToken/transactions/index.ts +++ b/src/services/osToken/transactions/index.ts @@ -10,13 +10,13 @@ class OsTokenTransactions { * Use data from methods osToken.getMaxMint and osToken.getHealthFactor to block a call to mint() * if the number of shares is greater than what getMaxMint returns or if the number of osToken after the transaction * would make the position unhealthy - * @see https://docs.stakewise.io/osToken/transactions/mint + * @see https://docs.stakewise.io/sdk/api/osToken/transactions/mint */ public mint: ExtractMint /** * @description Burns your osToken - * @see https://docs.stakewise.io/osToken/transactions/burn + * @see https://docs.stakewise.io/sdk/api/osToken/transactions/burn */ public burn: ExtractBurn diff --git a/src/services/rewardSplitter/index.ts b/src/services/rewardSplitter/index.ts index 625430b7..001598eb 100644 --- a/src/services/rewardSplitter/index.ts +++ b/src/services/rewardSplitter/index.ts @@ -13,7 +13,7 @@ class RewardSplitter extends RewardSplitterTransactions { /** * @description Calculates the amount of assets that the user can claim from the reward splitter. - * @see https://docs.stakewise.io/rewardSplitter/requests/getclaimamount + * @see https://docs.stakewise.io/sdk/api/rewardSplitter/requests/getclaimamount */ public getClaimAmount(values: StakeWise.ExtractInput) { return getClaimAmount({ ...this.params, ...values }) diff --git a/src/services/rewardSplitter/transactions/index.ts b/src/services/rewardSplitter/transactions/index.ts index dec83510..800ddb17 100644 --- a/src/services/rewardSplitter/transactions/index.ts +++ b/src/services/rewardSplitter/transactions/index.ts @@ -10,20 +10,20 @@ class RewardSplitterTransactions { /** * @description Allows the reward splitter owner to set a claimer * that can claim vault fees on behalf of the shareholders. - * @see https://docs.stakewise.io/rewardSplitter/transactions/setclaimer + * @see https://docs.stakewise.io/sdk/api/rewardSplitter/transactions/setclaimer */ public setClaimer: ExtractSetClaimer /** * @description Claims rewards from the reward splitter contract. - * @see https://docs.stakewise.io/rewardSplitter/transactions/claimrewards + * @see https://docs.stakewise.io/sdk/api/rewardSplitter/transactions/claimrewards */ public claimRewards: ExtractClaimRewards /** * @description Updates the reward splitter fee recipients and predefined fee splitting proportions. * Please note that only the vault admin, who is also the owner of the reward splitter, is permitted to perform this action. - * @see https://docs.stakewise.io/rewardSplitter/transactions/updatefeerecipients + * @see https://docs.stakewise.io/sdk/api/rewardSplitter/transactions/updatefeerecipients */ public updateFeeRecipients: ExtractUpdateFeeRecipients @@ -32,7 +32,7 @@ class RewardSplitterTransactions { * recipients in predefined proportions. Subsequently, the address of the created reward splitter * must be added to the vault as a fee recipient in order to utilize it. Please note that only vault * admin is permitted to perform this action. - * @see https://docs.stakewise.io/rewardSplitter/transactions/createrewardsplitter + * @see https://docs.stakewise.io/sdk/api/rewardSplitter/transactions/createrewardsplitter */ public create: ExtractCreateRewardSplitter diff --git a/src/services/utils/index.ts b/src/services/utils/index.ts index bd957e49..5d498de9 100644 --- a/src/services/utils/index.ts +++ b/src/services/utils/index.ts @@ -17,7 +17,7 @@ class Utils { /** * @description Returns the USD, EUR, GBP, CNY, JPY, KRW, AUD, SWISE exchange rates for the current network asset - * @see https://docs.stakewise.io/utils/getfiatrates + * @see https://docs.stakewise.io/sdk/api/utils/getfiatrates */ public getFiatRates() { return getFiatRates(this.params) @@ -25,7 +25,7 @@ class Utils { /** * @description TVL statistics, number of users, rewards earned - * @see https://docs.stakewise.io/utils/getstakewisestats + * @see https://docs.stakewise.io/sdk/api/utils/getstakewisestats */ public getStakewiseStats() { return getStakewiseStats(this.params) @@ -33,7 +33,7 @@ class Utils { /** * @description Retrieving a transaction to verify that the data went into the subgraph after the transaction - * @see https://docs.stakewise.io/utils/gettransactions + * @see https://docs.stakewise.io/sdk/api/utils/gettransactions */ public getTransactions(values: StakeWise.ExtractInput) { return getTransactions({ ...this.params, ...values }) @@ -41,7 +41,7 @@ class Utils { /** * @description Get fiat data by day - * @see https://docs.stakewise.io/utils/getfiatratesbyday + * @see https://docs.stakewise.io/sdk/api/utils/getfiatratesbyday */ public getFiatRatesByDay(values: StakeWise.ExtractInput) { return getFiatRatesByDay({ ...this.params, ...values }) @@ -49,7 +49,7 @@ class Utils { /** * @description Get permit signature (used in leverage staking). - * @see https://docs.stakewise.io/utils/getpermitsignature + * @see https://docs.stakewise.io/sdk/api/utils/getpermitsignature */ public getPermitSignature(values: StakeWise.ExtractInput) { return getPermitSignature({ ...this.params, ...values }) diff --git a/src/services/vault/index.ts b/src/services/vault/index.ts index 9c7256c8..42c1367f 100644 --- a/src/services/vault/index.ts +++ b/src/services/vault/index.ts @@ -34,7 +34,7 @@ class Vault extends VaultTransactions { /** * @description Returns the master data of the vault. - * @see https://docs.stakewise.io/vault/requests/getvault + * @see https://docs.stakewise.io/sdk/api/vault/requests/getvault */ public getVault(values: StakeWise.ExtractInput) { return getVault({ ...this.params, ...values }) @@ -42,7 +42,7 @@ class Vault extends VaultTransactions { /** * @description Necessary to update the vault state. - * @see https://docs.stakewise.io/vault/requests/getharvestparams + * @see https://docs.stakewise.io/sdk/api/vault/requests/getharvestparams */ public getHarvestParams(values: StakeWise.ExtractInput) { return getHarvestParams({ ...this.params, ...values }) @@ -50,7 +50,7 @@ class Vault extends VaultTransactions { /** * @description Getting user's exit queue positions. - * @see https://docs.stakewise.io/vault/requests/getexitqueuepositions + * @see https://docs.stakewise.io/sdk/api/vault/requests/getexitqueuepositions */ public getExitQueuePositions(values: StakeWise.ExtractInput) { return getExitQueuePositions({ ...this.params, ...values }) @@ -58,7 +58,7 @@ class Vault extends VaultTransactions { /** * @description Fetch the list of created reward splitters. - * @see https://docs.stakewise.io/vault/requests/getrewardsplitters + * @see https://docs.stakewise.io/sdk/api/vault/requests/getrewardsplitters */ public getRewardSplitters(values: StakeWise.ExtractInput) { return getRewardSplitters({ ...this.params, ...values }) @@ -66,7 +66,7 @@ class Vault extends VaultTransactions { /** * @description Get a list of interactions with the vault. - * @see https://docs.stakewise.io/vault/requests/getstakeractions + * @see https://docs.stakewise.io/sdk/api/vault/requests/getstakeractions */ public getStakerActions(values: StakeWise.ExtractInput) { return getStakerActions({ ...this.params, ...values }) @@ -74,7 +74,7 @@ class Vault extends VaultTransactions { /** * @description Getting user's balance in the vault. - * @see https://docs.stakewise.io/vault/requests/getstakebalance + * @see https://docs.stakewise.io/sdk/api/vault/requests/getstakebalance */ public getStakeBalance(values: StakeWise.ExtractInput) { return getStakeBalance({ ...this.params, ...values }) @@ -82,7 +82,7 @@ class Vault extends VaultTransactions { /** * @description Daily rewards for the user. - * @see https://docs.stakewise.io/vault/requests/getuserrewards + * @see https://docs.stakewise.io/sdk/api/vault/requests/getuserrewards */ public getUserRewards(values: StakeWise.ExtractInput) { return getUserRewards({ ...this.params, ...values }) @@ -91,7 +91,7 @@ class Vault extends VaultTransactions { /** * @description How much a user can withdraw. Deprecated. * @deprecated Use new getMaxWithdrawAmount method - * @see https://docs.stakewise.io/vault/requests/getmaxwithdraw + * @see https://docs.stakewise.io/sdk/api/vault/requests/getmaxwithdraw */ public getMaxWithdraw(values: StakeWise.ExtractInput) { return getMaxWithdraw({ ...this.params, ...values }) @@ -99,7 +99,7 @@ class Vault extends VaultTransactions { /** * @description Getting the vault current version. - * @see https://docs.stakewise.io/vault/requests/getvaultversion + * @see https://docs.stakewise.io/sdk/api/vault/requests/getvaultversion */ public getVaultVersion(values: StakeWise.ExtractInput) { return getVaultVersion({ ...this.params, ...values }) @@ -107,7 +107,7 @@ class Vault extends VaultTransactions { /** * @description Getting the factory to vault creation. - * @see https://docs.stakewise.io/vault/requests/getvaultfactory + * @see https://docs.stakewise.io/sdk/api/vault/requests/getvaultfactory */ public getVaultFactory(values: StakeWise.ExtractInput) { return getVaultFactory({ ...this.params, ...values }) @@ -115,7 +115,7 @@ class Vault extends VaultTransactions { /** * @description How much a user can withdraw. - * @see https://docs.stakewise.io/vault/requests/getmaxwithdrawamount + * @see https://docs.stakewise.io/sdk/api/vault/requests/getmaxwithdrawamount */ public getMaxWithdrawAmount(values: StakeWise.ExtractInput) { return getMaxWithdrawAmount({ ...this.params, ...values }) @@ -123,7 +123,7 @@ class Vault extends VaultTransactions { /** * @description Returns the running vault validators. - * @see https://docs.stakewise.io/vault/requests/getvalidators + * @see https://docs.stakewise.io/sdk/api/vault/requests/getvalidators */ public getValidators(values: StakeWise.ExtractInput) { return getValidators({ ...this.params, ...values }) @@ -131,7 +131,7 @@ class Vault extends VaultTransactions { /** * @description Fetch the whitelist for private vaults. - * @see https://docs.stakewise.io/vault/requests/getwhitelist + * @see https://docs.stakewise.io/sdk/api/vault/requests/getwhitelist */ public getWhitelist(values: StakeWise.ExtractInput) { return getWhitelist({ ...this.params, ...values }) @@ -139,7 +139,7 @@ class Vault extends VaultTransactions { /** * @description Fetch the blocklist for blocklisted vaults. - * @see https://docs.stakewise.io/vault/requests/getblocklist + * @see https://docs.stakewise.io/sdk/api/vault/requests/getblocklist */ public getBlocklist(values: StakeWise.ExtractInput) { return getBlocklist({ ...this.params, ...values }) @@ -147,7 +147,7 @@ class Vault extends VaultTransactions { /** * @description Returns the vault stats collection. - * @see https://docs.stakewise.io/vault/requests/getvaultstats + * @see https://docs.stakewise.io/sdk/api/vault/requests/getvaultstats */ public getVaultStats(values: StakeWise.ExtractInput) { return getVaultStats({ ...this.params, ...values }) @@ -155,7 +155,7 @@ class Vault extends VaultTransactions { /** * @description Returns the user stats collection. - * @see https://docs.stakewise.io/vault/requests/getuserstats + * @see https://docs.stakewise.io/sdk/api/vault/requests/getuserstats */ public getUserStats(values: StakeWise.ExtractInput) { return getUserStats({ ...this.params, ...values }) @@ -163,7 +163,7 @@ class Vault extends VaultTransactions { /** * @description Get the current APY of the user. - * @see https://docs.stakewise.io/vault/requests/getuserapy + * @see https://docs.stakewise.io/sdk/api/vault/requests/getuserapy */ public getUserApy(values: StakeWise.ExtractInput) { return getUserApy({ ...this.params, ...values }) @@ -171,7 +171,7 @@ class Vault extends VaultTransactions { /** * @description Getting the periodic distribution of additional incentives. - * @see https://docs.stakewise.io/vault/requests/getperiodicdistributions + * @see https://docs.stakewise.io/sdk/api/vault/requests/getperiodicdistributions */ public getPeriodicDistributions(values: StakeWise.ExtractInput) { return getPeriodicDistributions({ ...this.params, ...values }) @@ -179,7 +179,7 @@ class Vault extends VaultTransactions { /** * @description Returns osToken collateral parameters. - * @see https://docs.stakewise.io/vault/requests/getostokenconfig + * @see https://docs.stakewise.io/sdk/api/vault/requests/getostokenconfig */ public getOsTokenConfig(values: StakeWise.ExtractInput) { return getOsTokenConfig({ ...this.params, ...values }) @@ -187,7 +187,7 @@ class Vault extends VaultTransactions { /** * @description Returns the list of sub vaults. - * @see https://docs.stakewise.io/vault/requests/getsubvaults + * @see https://docs.stakewise.io/sdk/api/vault/requests/getsubvaults */ public getSubVaults(values: StakeWise.ExtractInput) { return getSubVaults({ ...this.params, ...values }) diff --git a/src/services/vault/requests/getOsTokenConfig/getOsTokenConfig.md b/src/services/vault/requests/getOsTokenConfig/getOsTokenConfig.md index e8b4201b..b22ba897 100644 --- a/src/services/vault/requests/getOsTokenConfig/getOsTokenConfig.md +++ b/src/services/vault/requests/getOsTokenConfig/getOsTokenConfig.md @@ -1,6 +1,6 @@ --- id: getOsTokenConfig -slug: /sdk/api/vault/getostokenconfig +slug: /sdk/api/vault/requests/getostokenconfig description: Use the StakeWise SDK getOsTokenConfig method to retrieve osToken collateral parameters like LTV and liquidation threshold. --- diff --git a/src/services/vault/requests/getSubVaults/getSubVaults.md b/src/services/vault/requests/getSubVaults/getSubVaults.md index d1d4c544..c17f2144 100644 --- a/src/services/vault/requests/getSubVaults/getSubVaults.md +++ b/src/services/vault/requests/getSubVaults/getSubVaults.md @@ -1,6 +1,6 @@ --- id: getSubVaults -slug: /vault/requests/getsubvaults +slug: /sdk/api/vault/requests/getsubvaults --- #### Description: diff --git a/src/services/vault/requests/getVault/getVault.md b/src/services/vault/requests/getVault/getVault.md index fcb90e61..fa103e7c 100644 --- a/src/services/vault/requests/getVault/getVault.md +++ b/src/services/vault/requests/getVault/getVault.md @@ -111,3 +111,4 @@ type Output = { ```ts await sdk.vault.getVault({ vaultAddress: '0x...' }) ``` +# test diff --git a/src/services/vault/transactions/addSubVault/addSubVault.md b/src/services/vault/transactions/addSubVault/addSubVault.md index 83a2f336..711b61a6 100644 --- a/src/services/vault/transactions/addSubVault/addSubVault.md +++ b/src/services/vault/transactions/addSubVault/addSubVault.md @@ -1,6 +1,6 @@ --- id: addSubVault -slug: /vault/transactions/addsubvault +slug: /sdk/api/vault/transactions/addsubvault --- #### Description: diff --git a/src/services/vault/transactions/ejectSubVault/ejectSubVault.md b/src/services/vault/transactions/ejectSubVault/ejectSubVault.md index 5becc786..1063d460 100644 --- a/src/services/vault/transactions/ejectSubVault/ejectSubVault.md +++ b/src/services/vault/transactions/ejectSubVault/ejectSubVault.md @@ -1,6 +1,6 @@ --- id: ejectSubVault -slug: /vault/transactions/ejectsubvault +slug: /sdk/api/vault/transactions/ejectsubvault --- #### Description: diff --git a/src/services/vault/transactions/index.ts b/src/services/vault/transactions/index.ts index 280f5bb2..3abd40a1 100644 --- a/src/services/vault/transactions/index.ts +++ b/src/services/vault/transactions/index.ts @@ -19,68 +19,68 @@ class VaultTransactions { /** * @description Deposit (stake) in a vault. - * @see https://docs.stakewise.io/vault/transactions/deposit + * @see https://docs.stakewise.io/sdk/api/vault/transactions/deposit */ public deposit: ExtractDeposit /** * @description Withdrawal of funds from a vault. - * @see https://docs.stakewise.io/vault/transactions/withdraw + * @see https://docs.stakewise.io/sdk/api/vault/transactions/withdraw */ public withdraw: ExtractWithdraw /** * @description Create vault. - * @see https://docs.stakewise.io/vault/transactions/create + * @see https://docs.stakewise.io/sdk/api/vault/transactions/create */ public create: ExtractCreateVault /** * @description Updates the vault by authorized personnel such as the vault admin, whitelist manager, * blocklist manager, validators manager, or deposit-data manager. - * @see https://docs.stakewise.io/vault/transactions/operate + * @see https://docs.stakewise.io/sdk/api/vault/transactions/operate */ public operate: ExtractOperate /** * @description Claim user's exit queue. - * @see https://docs.stakewise.io/vault/transactions/claimexitqueue + * @see https://docs.stakewise.io/sdk/api/vault/transactions/claimexitqueue */ public claimExitQueue: ExtractClaimExitQueue /** * @description Adding root validators to vault. Supports only vault v2. - * @see https://docs.stakewise.io/vault/transactions/setdepositdataroot + * @see https://docs.stakewise.io/sdk/api/vault/transactions/setdepositdataroot */ public setDepositDataRoot: ExtractSetDepositDataRoot /** * @description Adding deposit data manager. Supports only vault v2. - * @see https://docs.stakewise.io/vault/transactions/setdepositdatamanager + * @see https://docs.stakewise.io/sdk/api/vault/transactions/setdepositdatamanager */ public setDepositDataManager: ExtractSetDepositDataManager /** * @description Adding new sub-vault. Supports only in metaVault. - * @see https://docs.stakewise.io/vault/transactions/addsubvault + * @see https://docs.stakewise.io/sdk/api/vault/transactions/addsubvault */ public addSubVault: ExtractAddSubVaultInput /** * @description Rejecting a sub-vault. Supports only in metaVault. - * @see https://docs.stakewise.io/vault/transactions/rejectsubvault + * @see https://docs.stakewise.io/sdk/api/vault/transactions/rejectsubvault */ public rejectSubVault: ExtractRejectSubVaultInput /** * @description Ejecting a sub-vault. Supports only in metaVault. - * @see https://docs.stakewise.io/vault/transactions/ejectsubvault + * @see https://docs.stakewise.io/sdk/api/vault/transactions/ejectsubvault */ public ejectSubVault: ExtractEjectSubVaultInput /** * @description Update a vault state. - * @see https://docs.stakewise.io/vault/transactions/updatestate + * @see https://docs.stakewise.io/sdk/api/vault/transactions/updatestate */ public updateState: ExtractUpdateStateInput @@ -110,7 +110,6 @@ class VaultTransactions { /** * @description Assistant function for custom multi-query requests to the vault. - * @see https://docs.stakewise.io/vault/transactions/multicall */ public multicall(values: StakeWise.ExtractInput) { return multicall({ ...this.params, ...values }) diff --git a/src/services/vault/transactions/rejectSubVault/rejectSubVault.md b/src/services/vault/transactions/rejectSubVault/rejectSubVault.md index c8f3ca1e..4534e08d 100644 --- a/src/services/vault/transactions/rejectSubVault/rejectSubVault.md +++ b/src/services/vault/transactions/rejectSubVault/rejectSubVault.md @@ -1,6 +1,6 @@ --- id: rejectSubVault -slug: /vault/transactions/rejectsubvault +slug: /sdk/api/vault/transactions/rejectsubvault --- #### Description: diff --git a/src/services/vault/transactions/updateState/updateState.md b/src/services/vault/transactions/updateState/updateState.md index 3fc4577e..7182f410 100644 --- a/src/services/vault/transactions/updateState/updateState.md +++ b/src/services/vault/transactions/updateState/updateState.md @@ -1,6 +1,6 @@ --- id: updateState -slug: /vault/transactions/updatestate +slug: /sdk/api/vault/transactions/updatestate --- #### Description: From 5b52db227227e82ff97cfbec28f91bb18fc15e9d Mon Sep 17 00:00:00 2001 From: Kadyr Dzhemaledinov Date: Wed, 8 Apr 2026 10:57:03 +0300 Subject: [PATCH 14/27] refactor gas & encode in setDepositData transactions (#359) --- .../setDepositDataManagerEncode.ts | 13 ++++++++- .../setDepositDataManagerGas.ts | 27 ++++++++++++++----- .../setDepositDataRootEncode.ts | 13 ++++++++- .../setDepositDataRootGas.ts | 27 ++++++++++++++----- 4 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/services/vault/transactions/setDepositDataManager/setDepositDataManagerEncode.ts b/src/services/vault/transactions/setDepositDataManager/setDepositDataManagerEncode.ts index 73292292..3084a784 100644 --- a/src/services/vault/transactions/setDepositDataManager/setDepositDataManagerEncode.ts +++ b/src/services/vault/transactions/setDepositDataManager/setDepositDataManagerEncode.ts @@ -1,11 +1,22 @@ import { commonLogic } from './common' import type { SetDepositDataManagerInput } from './types' +import getVaultVersion from '../../requests/getVaultVersion' const setDepositDataManagerEncode = async (values: SetDepositDataManagerInput) => { + const { vaultAddress, managerAddress, contracts } = values + + const { isV1Version } = await getVaultVersion(values) + + if (isV1Version) { + const vaultContract = contracts.helpers.createVault({ vaultAddress }) + + return vaultContract.setKeysManager.populateTransaction(managerAddress) + } + const contract = commonLogic(values) - return contract.setDepositDataManager.populateTransaction(values.vaultAddress, values.managerAddress) + return contract.setDepositDataManager.populateTransaction(vaultAddress, managerAddress) } diff --git a/src/services/vault/transactions/setDepositDataManager/setDepositDataManagerGas.ts b/src/services/vault/transactions/setDepositDataManager/setDepositDataManagerGas.ts index 93d62af4..e3b21f37 100644 --- a/src/services/vault/transactions/setDepositDataManager/setDepositDataManagerGas.ts +++ b/src/services/vault/transactions/setDepositDataManager/setDepositDataManagerGas.ts @@ -1,22 +1,37 @@ import { commonLogic } from './common' -import { getGas, wrapErrorHandler } from '../../../../helpers' import type { SetDepositDataManagerInput } from './types' +import getVaultVersion from '../../requests/getVaultVersion' +import { getGas, wrapErrorHandler } from '../../../../helpers' const setDepositDataManagerGas = async (values: SetDepositDataManagerInput) => { - const { provider, userAddress, vaultAddress, managerAddress } = values - - const contract = commonLogic(values) + const { provider, userAddress, vaultAddress, managerAddress, contracts } = values const signer = await provider.getSigner(userAddress) + + const { isV1Version } = await getVaultVersion(values) + + if (isV1Version) { + const vaultContract = contracts.helpers.createVault({ vaultAddress }) + const signedContract = vaultContract.connect(signer) + + const estimatedGas = await wrapErrorHandler( + signedContract.setKeysManager.estimateGas(managerAddress), + 'gas' + ) + + return getGas({ estimatedGas, provider }) + } + + const contract = commonLogic(values) const signedContract = contract.connect(signer) const estimatedGas = await wrapErrorHandler( signedContract.setDepositDataManager.estimateGas(vaultAddress, managerAddress), - 'transaction' + 'gas' ) - return getGas({ estimatedGas, provider: values.provider }) + return getGas({ estimatedGas, provider }) } diff --git a/src/services/vault/transactions/setDepositDataRoot/setDepositDataRootEncode.ts b/src/services/vault/transactions/setDepositDataRoot/setDepositDataRootEncode.ts index 6de81b88..30e0f041 100644 --- a/src/services/vault/transactions/setDepositDataRoot/setDepositDataRootEncode.ts +++ b/src/services/vault/transactions/setDepositDataRoot/setDepositDataRootEncode.ts @@ -1,11 +1,22 @@ import { commonLogic } from './common' import type { SetDepositDataRootInput } from './types' +import getVaultVersion from '../../requests/getVaultVersion' const setDepositDataRootEncode = async (values: SetDepositDataRootInput) => { + const { vaultAddress, depositDataRoot, contracts } = values + + const { isV1Version } = await getVaultVersion(values) + + if (isV1Version) { + const vaultContract = contracts.helpers.createVault({ vaultAddress }) + + return vaultContract.setValidatorsRoot.populateTransaction(depositDataRoot) + } + const contract = commonLogic(values) - return contract.setDepositDataRoot.populateTransaction(values.vaultAddress, values.depositDataRoot) + return contract.setDepositDataRoot.populateTransaction(vaultAddress, depositDataRoot) } diff --git a/src/services/vault/transactions/setDepositDataRoot/setDepositDataRootGas.ts b/src/services/vault/transactions/setDepositDataRoot/setDepositDataRootGas.ts index a8d58750..7e746609 100644 --- a/src/services/vault/transactions/setDepositDataRoot/setDepositDataRootGas.ts +++ b/src/services/vault/transactions/setDepositDataRoot/setDepositDataRootGas.ts @@ -1,22 +1,37 @@ import { commonLogic } from './common' import type { SetDepositDataRootInput } from './types' +import getVaultVersion from '../../requests/getVaultVersion' import { getGas, wrapErrorHandler } from '../../../../helpers' const setDepositDataRootGas = async (values: SetDepositDataRootInput) => { - const { provider, userAddress, vaultAddress, depositDataRoot } = values - - const contract = commonLogic(values) + const { provider, userAddress, vaultAddress, depositDataRoot, contracts } = values const signer = await provider.getSigner(userAddress) - const signedDepositDataRegistryContract = contract.connect(signer) + + const { isV1Version } = await getVaultVersion(values) + + if (isV1Version) { + const vaultContract = contracts.helpers.createVault({ vaultAddress }) + const signedContract = vaultContract.connect(signer) + + const estimatedGas = await wrapErrorHandler( + signedContract.setValidatorsRoot.estimateGas(depositDataRoot), + 'gas' + ) + + return getGas({ estimatedGas, provider }) + } + + const contract = commonLogic(values) + const signedContract = contract.connect(signer) const estimatedGas = await wrapErrorHandler( - signedDepositDataRegistryContract.setDepositDataRoot.estimateGas(vaultAddress, depositDataRoot), + signedContract.setDepositDataRoot.estimateGas(vaultAddress, depositDataRoot), 'gas' ) - return getGas({ estimatedGas, provider: values.provider }) + return getGas({ estimatedGas, provider }) } From bceb1cd0c004ac46e5639840524286213bef160f Mon Sep 17 00:00:00 2001 From: Mike Diamond Date: Tue, 21 Apr 2026 12:41:16 +0300 Subject: [PATCH 15/27] [subgraph updates] update sub vaults request (#362) * [subgraph updates] update sub vaults request Signed-off-by: MikeDiam * [subgraph updates] update cancellable type Signed-off-by: MikeDiam * [subgraph updates] refactor sub vaults query and mapping logic Signed-off-by: MikeDiam --------- Signed-off-by: MikeDiam --- changelog/next-release.md | 2 +- .../subgraph/exitQueue/exitQueueQuery.graphql | 2 +- .../rewardSplittersQuery.graphql | 2 +- .../subgraph/vault/subVaultsQuery.graphql | 20 ++++- src/graphql/subgraph/vault/vaultQuery.graphql | 1 + src/modules/gql-module/index.ts | 16 ++++ src/services/assertCancellable.ts | 36 ++++++++ .../boost/requests/getQueuePosition/index.tsx | 2 +- src/services/index.ts | 3 + .../requests/getExitQueuePositions/index.ts | 3 +- .../modifyExitRequests.ts | 2 +- .../vault/requests/getOsTokenConfig/index.ts | 2 +- .../requests/getSubVaults/getSubVaults.md | 23 +++-- .../vault/requests/getSubVaults/index.ts | 87 +++---------------- .../requests/getSubVaults/modifySubVaults.ts | 36 ++++++++ .../vault/requests/getVaultVersion/index.ts | 5 +- 16 files changed, 141 insertions(+), 101 deletions(-) create mode 100644 src/services/assertCancellable.ts create mode 100644 src/services/vault/requests/getSubVaults/modifySubVaults.ts diff --git a/changelog/next-release.md b/changelog/next-release.md index 2c16cdfe..ab91a5e0 100644 --- a/changelog/next-release.md +++ b/changelog/next-release.md @@ -13,7 +13,7 @@ #### Add output field: ```ts type Output = { - canHarvest: boolen + canHarvest: boolean exitingAssets: string exitingTickets: string ejectingSubVault: string diff --git a/src/graphql/subgraph/exitQueue/exitQueueQuery.graphql b/src/graphql/subgraph/exitQueue/exitQueueQuery.graphql index ddffca0b..403f457c 100644 --- a/src/graphql/subgraph/exitQueue/exitQueueQuery.graphql +++ b/src/graphql/subgraph/exitQueue/exitQueueQuery.graphql @@ -1,5 +1,5 @@ query exitQueue($where: ExitRequest_filter) { - exitRequests(where: $where) { + exitRequests(where: $where, first: 1000) { receiver isClaimed timestamp diff --git a/src/graphql/subgraph/rewardSplitters/rewardSplittersQuery.graphql b/src/graphql/subgraph/rewardSplitters/rewardSplittersQuery.graphql index 90d89d36..0ac7629c 100644 --- a/src/graphql/subgraph/rewardSplitters/rewardSplittersQuery.graphql +++ b/src/graphql/subgraph/rewardSplitters/rewardSplittersQuery.graphql @@ -5,7 +5,7 @@ query RewardSplitters($where: RewardSplitter_filter!) { version claimer totalShares - shareHolders(orderBy: shares, orderDirection: desc, where: { shares_gt: 0 }) { + shareHolders(orderBy: shares, orderDirection: desc, first: 1000, where: { shares_gt: 0 }) { id shares address diff --git a/src/graphql/subgraph/vault/subVaultsQuery.graphql b/src/graphql/subgraph/vault/subVaultsQuery.graphql index d7aa27d4..c458fd5f 100644 --- a/src/graphql/subgraph/vault/subVaultsQuery.graphql +++ b/src/graphql/subgraph/vault/subVaultsQuery.graphql @@ -2,12 +2,24 @@ query SubVaults( $skip: Int! $first: Int! $where: SubVault_filter! + $metaVaultAddress: Bytes! ) { subVaults( - skip: $skip, - first: $first, - where: $where, + skip: $skip + first: $first + where: $where ) { - subVault + subVault { + id + imageUrl + displayName + allocators(where: { address: $metaVaultAddress }) { + apy + assets + } + exitRequests(where: { receiver: $metaVaultAddress, isClaimed: false }) { + totalAssets + } + } } } diff --git a/src/graphql/subgraph/vault/vaultQuery.graphql b/src/graphql/subgraph/vault/vaultQuery.graphql index 91ea4013..dd13f504 100644 --- a/src/graphql/subgraph/vault/vaultQuery.graphql +++ b/src/graphql/subgraph/vault/vaultQuery.graphql @@ -22,6 +22,7 @@ query Vault($address: ID!) { canHarvest feePercent isMetaVault + subVaultsCount totalAssets isBlocklist displayName diff --git a/src/modules/gql-module/index.ts b/src/modules/gql-module/index.ts index 24a1b9c7..04b4da8a 100644 --- a/src/modules/gql-module/index.ts +++ b/src/modules/gql-module/index.ts @@ -4,3 +4,19 @@ export { default as AbortRequest } from './abortRequest' export { default as AbortCallback } from './abortCallback' export type { FetchCodegenInput, FetchInput } from './types' export { default as wrapAbortPromise } from './wrapAbortPromise' + +export type Cancellable = { + then: (onSuccess: (value: T) => any, onError?: (error: any) => any) => any + catch: (callback: (error: any) => any) => any + finally: (callback: () => void) => any + abort: () => void +} + + +export type AssertCancellable = { + [K in keyof T]: T[K] extends (...args: any[]) => infer R + ? [R] extends [Promise] + ? [R] extends [Cancellable] ? T[K] : never + : T[K] + : T[K] +} diff --git a/src/services/assertCancellable.ts b/src/services/assertCancellable.ts new file mode 100644 index 00000000..9e802a85 --- /dev/null +++ b/src/services/assertCancellable.ts @@ -0,0 +1,36 @@ +import type { AssertCancellable } from '../modules/gql-module' + +import Vault from './vault' +import Boost from './boost' +import Utils from './utils' +import OsToken from './osToken' +import RewardSplitter from './rewardSplitter' +import VaultTransactions from './vault/transactions' +import BoostTransactions from './boost/transactions' +import DistributorRewards from './distributorRewards' +import OsTokenTransactions from './osToken/transactions' +import RewardSplitterTransactions from './rewardSplitter/transactions' +import DistributorRewardsTransactions from './distributorRewards/transactions' + + +// Requests methods must be cancellable according to docs +type Requests = Pick> + +// Wallet signing cannot be aborted, gas estimation is part of tx send +type UtilsTxHelpers = 'getVaultMulticallGas' | 'getVaultMulticallEncode' | 'getPermitSignature' + +const assertCancellable: { + utils: AssertCancellable> + vault: AssertCancellable> + boost: AssertCancellable> + osToken: AssertCancellable> + rewardSplitter: AssertCancellable> + distributorRewards: AssertCancellable> +} = { + utils: {} as Requests, + vault: {} as Requests, + boost: {} as Requests, + osToken: {} as Requests, + rewardSplitter: {} as Requests, + distributorRewards: {} as Requests, +} diff --git a/src/services/boost/requests/getQueuePosition/index.tsx b/src/services/boost/requests/getQueuePosition/index.tsx index 77796f9a..cb8921ba 100644 --- a/src/services/boost/requests/getQueuePosition/index.tsx +++ b/src/services/boost/requests/getQueuePosition/index.tsx @@ -11,7 +11,7 @@ export type GetQueuePositionInput = StakeWise.CommonParams & { export type Output = ParseBoostQueueOutput -const getQueuePosition = async (input: GetQueuePositionInput): Promise => { +const getQueuePosition = (input: GetQueuePositionInput) => { const { options, vaultAddress, userAddress } = input validateArgs.address({ vaultAddress, userAddress }) diff --git a/src/services/index.ts b/src/services/index.ts index 4e41fd3c..f2e53839 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -1,3 +1,6 @@ +import './assertCancellable' + + export { default as Vault } from './vault' export { default as Boost } from './boost' export { default as Utils } from './utils' diff --git a/src/services/vault/requests/getExitQueuePositions/index.ts b/src/services/vault/requests/getExitQueuePositions/index.ts index 3515e1d9..fabb2e1d 100644 --- a/src/services/vault/requests/getExitQueuePositions/index.ts +++ b/src/services/vault/requests/getExitQueuePositions/index.ts @@ -1,7 +1,6 @@ import graphql from '../../../../graphql' import { apiUrls, validateArgs } from '../../../../helpers' import modifyExitRequests from './modifyExitRequests' -import type { ParseExitRequestsOutput } from './modifyExitRequests' export type GetExitQueuePositionsInput = StakeWise.CommonParams & { @@ -10,7 +9,7 @@ export type GetExitQueuePositionsInput = StakeWise.CommonParams & { isClaimed?: boolean } -const getExitQueuePositions = async (input: GetExitQueuePositionsInput): Promise => { +const getExitQueuePositions = (input: GetExitQueuePositionsInput) => { const { options, vaultAddress, userAddress, isClaimed } = input validateArgs.address({ vaultAddress, userAddress }) diff --git a/src/services/vault/requests/getExitQueuePositions/modifyExitRequests.ts b/src/services/vault/requests/getExitQueuePositions/modifyExitRequests.ts index 73ffb53a..ef43a38f 100644 --- a/src/services/vault/requests/getExitQueuePositions/modifyExitRequests.ts +++ b/src/services/vault/requests/getExitQueuePositions/modifyExitRequests.ts @@ -30,7 +30,7 @@ export type ParseExitRequestsOutput = { requests: OutputExitRequest[] } -const modifyExitRequests = async (values: ParseExitRequestsInput): Promise => { +const modifyExitRequests = (values: ParseExitRequestsInput): ParseExitRequestsOutput => { const { exitRequests } = values if (!exitRequests.length) { diff --git a/src/services/vault/requests/getOsTokenConfig/index.ts b/src/services/vault/requests/getOsTokenConfig/index.ts index ba44bc00..17dc80d5 100644 --- a/src/services/vault/requests/getOsTokenConfig/index.ts +++ b/src/services/vault/requests/getOsTokenConfig/index.ts @@ -6,7 +6,7 @@ export type GetOsTokenConfigInput = StakeWise.CommonParams & { vaultAddress: string } -const getOsTokenConfig = async (input: GetOsTokenConfigInput) => { +const getOsTokenConfig = (input: GetOsTokenConfigInput) => { const { options, vaultAddress } = input validateArgs.address({ vaultAddress }) diff --git a/src/services/vault/requests/getSubVaults/getSubVaults.md b/src/services/vault/requests/getSubVaults/getSubVaults.md index c17f2144..fa1ffc47 100644 --- a/src/services/vault/requests/getSubVaults/getSubVaults.md +++ b/src/services/vault/requests/getSubVaults/getSubVaults.md @@ -5,45 +5,44 @@ slug: /sdk/api/vault/requests/getsubvaults #### Description: -Returns the list of sub vaults. +Returns the list of sub vaults for a given meta vault. #### Arguments: | Name | Type | Required | Description | |------|------|----------|-----------------------------------------------------------| | vaultAddress | `string` | **Yes** | The address of the meta vault | -| search | `string` | **No** | Filters results by the address field | -| limit | `number` | **No** | Limits the number of sub vaults returned. Defaults to 100 | -| skip | `number` | **No** | Skips the specified number of sub vaults. Defaults to 0 | +| limit | `number` | **Yes** | Limits the number of sub vaults returned | +| skip | `number` | **Yes** | Skips the specified number of sub vaults | #### Returns: ```ts -type Output = { +type Output = Array<{ id: string apy: string imageUrl: string displayName: string stakingAssets: bigint exitingAssets: bigint -} +}> ``` | Name | Description | |------|-------------| -| `id` | Vault address | -| `imageUrl` | The image URL extracted from the metadata IPFS file. Will be `null` if the vault does not have an image. | +| `id` | Address of vault | +| `apy` | Current vault apy | +| `imageUrl` | Link for vault logo | | `displayName` | Name of vault | -| `stakingAssets` | The amount of assets staking in the sub-vault. | -| `exitingAssets` | The amount of assets exiting the sub-vault. | -| `apy` | The sub-vault average weekly APY | +| `stakingAssets` | The amount of assets staking in the sub vault | +| `exitingAssets` | The total number of assets that are exiting the sub vault | #### Example: ```ts await sdk.vault.getSubVaults({ skip: 0, - limit: 5, + limit: 20, vaultAddress: '0x...' }) ``` diff --git a/src/services/vault/requests/getSubVaults/index.ts b/src/services/vault/requests/getSubVaults/index.ts index 37635dad..8dc41e85 100644 --- a/src/services/vault/requests/getSubVaults/index.ts +++ b/src/services/vault/requests/getSubVaults/index.ts @@ -1,99 +1,34 @@ -import type { SubVaultsQueryPayload, SubVaultsQueryVariables } from '../../../../graphql/subgraph/vault' +import type { SubVaultsQueryVariables, SubVaultsQueryPayload } from '../../../../graphql/subgraph/vault' import { apiUrls, validateArgs } from '../../../../helpers' - -import getVault from '../getVault' -import getExitQueuePositions from '../getExitQueuePositions' - import graphql from '../../../../graphql' +import modifySubVaults from './modifySubVaults' + export type GetSubVaultsInput = StakeWise.CommonParams & { - search?: string + vaultAddress: string skip: SubVaultsQueryVariables['skip'] limit: SubVaultsQueryVariables['first'] - vaultAddress: SubVaultsQueryVariables['where']['metaVault'] -} - -type OutputSubVault = { - id: string - apy: string - imageUrl: string - displayName: string - stakingAssets: bigint - exitingAssets: bigint } -const getSubVaults = async (input: GetSubVaultsInput): Promise => { - const { skip, limit, search, vaultAddress, ...commonParams } = input +const getSubVaults = (input: GetSubVaultsInput) => { + const { options, vaultAddress, skip, limit } = input validateArgs.address({ vaultAddress }) validateArgs.number({ skip, limit }) - if (typeof search !== 'undefined') { - validateArgs.string({ search }) - } - - const url = apiUrls.getSubgraphqlUrl(commonParams.options) - const metaVaultId = vaultAddress.toLowerCase() - const where = search - ? { metaVault_: { id: metaVaultId }, subVault_contains: search.toLowerCase() } - : { metaVault_: { id: metaVaultId } } - - const subVaults = await graphql.subgraph.vault.fetchSubVaultsQuery({ - url, + return graphql.subgraph.vault.fetchSubVaultsQuery({ + url: apiUrls.getSubgraphqlUrl(options), variables: { skip, first: limit, - where: where as SubVaultsQueryVariables['where'], + where: { metaVault: metaVaultId } as SubVaultsQueryVariables['where'], + metaVaultAddress: metaVaultId, }, - modifyResult:(data: SubVaultsQueryPayload) => data.subVaults.map(((vault) => vault.subVault)), + modifyResult: modifySubVaults, }) - - const results = await Promise.all( - subVaults.map(async (subVaultId) => { - const vaultId = subVaultId.toLowerCase() - - const [ allocatorData, vaultData, exitQueue ] = await Promise.all([ - graphql.subgraph.allocator.fetchAllocatorsQuery({ - url, - variables: { - address: metaVaultId, - vaultAddress: vaultId, - }, - modifyResult: (data) => { - const first = data?.allocators?.[0] - - return { - assets: BigInt(first?.assets || 0), - apy: (Number(first?.apy) || 0).toFixed(2), - } - }, - }), - - getVault({ ...commonParams, vaultAddress: vaultId }), - - getExitQueuePositions({ - ...commonParams, - isClaimed: false, - vaultAddress: vaultId, - userAddress: metaVaultId, - }), - ]) - - return { - id: vaultId, - apy: allocatorData.apy, - imageUrl: vaultData.imageUrl, - exitingAssets: exitQueue.total, - displayName: vaultData.displayName, - stakingAssets: allocatorData.assets, - } - }) - ) - - return results } diff --git a/src/services/vault/requests/getSubVaults/modifySubVaults.ts b/src/services/vault/requests/getSubVaults/modifySubVaults.ts new file mode 100644 index 00000000..3c342896 --- /dev/null +++ b/src/services/vault/requests/getSubVaults/modifySubVaults.ts @@ -0,0 +1,36 @@ +import type { SubVaultsQueryPayload } from '../../../../graphql/subgraph/vault' + + +type ModifiedSubVault = { + id: string + apy: string + imageUrl: string + displayName: string + stakingAssets: bigint + exitingAssets: bigint +} + +const modifySubVaults = (data: SubVaultsQueryPayload): ModifiedSubVault[] => { + return data.subVaults.map(({ subVault }) => { + const { id, imageUrl, displayName, allocators, exitRequests } = subVault + + const [ allocator ] = allocators + const exitingAssets = exitRequests.reduce((acc, { totalAssets }) => ( + acc + BigInt(totalAssets) + ), 0n) + + const apy = Number(allocator?.apy) || 0 + + return { + id, + apy: apy.toFixed(2), + imageUrl: imageUrl || '', + displayName: displayName || '', + stakingAssets: BigInt(allocator?.assets || 0), + exitingAssets, + } + }) +} + + +export default modifySubVaults diff --git a/src/services/vault/requests/getVaultVersion/index.ts b/src/services/vault/requests/getVaultVersion/index.ts index f6c643fb..00fa8b0f 100644 --- a/src/services/vault/requests/getVaultVersion/index.ts +++ b/src/services/vault/requests/getVaultVersion/index.ts @@ -1,3 +1,6 @@ +import { wrapAbortPromise } from '../../../../modules/gql-module' + + export type GetVaultVersionInput = StakeWise.CommonParams & { vaultAddress: string } @@ -24,4 +27,4 @@ const getVaultVersion = async (values: GetVaultVersionInput) => { } -export default getVaultVersion +export default wrapAbortPromise(getVaultVersion) From e904379ee277e46bb1319a11923889eac35b8e5e Mon Sep 17 00:00:00 2001 From: Kadyr Dzhemaledinov Date: Wed, 22 Apr 2026 11:03:35 +0300 Subject: [PATCH 16/27] update factories addresses (#365) --- src/helpers/configs/gnosis.ts | 2 +- src/helpers/configs/hoodi.ts | 8 ++++---- src/helpers/configs/mainnet.ts | 9 +++++---- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/helpers/configs/gnosis.ts b/src/helpers/configs/gnosis.ts index 707c3fe8..29f564c7 100644 --- a/src/helpers/configs/gnosis.ts +++ b/src/helpers/configs/gnosis.ts @@ -44,7 +44,7 @@ export default { blocklistVault: '0x608d8Ca6916b96edf63Dd429e62Fe1366ae6f3B5', erc20BlocklistVault: '0x39c6eef5f955bcC280966504bc5c82F2394Fa368', - metavault: ZeroAddress, + metavault: '0x75E6f7640137c128c91dE4Ee62F6f30b542e5f1B', erc20Metavault: ZeroAddress, privateMetavault: ZeroAddress, erc20PrivateMetavault: ZeroAddress, diff --git a/src/helpers/configs/hoodi.ts b/src/helpers/configs/hoodi.ts index 451e56cd..459488dd 100644 --- a/src/helpers/configs/hoodi.ts +++ b/src/helpers/configs/hoodi.ts @@ -45,11 +45,11 @@ export default { blocklistVault: '0x608d8Ca6916b96edf63Dd429e62Fe1366ae6f3B5', erc20BlocklistVault: '0x39c6eef5f955bcC280966504bc5c82F2394Fa368', - metavault: '0x721C63fc53C432FC0feA4e0775e7ABFd29983347', - erc20Metavault: '0x0aca1A126d0636bf74086DD077b47366a1353D4D', + metavault: '0xFC10dB96A7724Fa3Efb47C5304b29d3C01004b47', + erc20Metavault: '0xd21e8401c2DBbb180C621E8B3B22a842Ea73e487', - privateMetavault: '0xa11f61D2687993CF29B6aEb8f9EFb3147F34Dbb6', - erc20PrivateMetavault: '0xCCf6D110181330fB8b62de8FA37fd0a905665376', + privateMetavault: '0xD13BB2fD02fA060Dc82c439724dC9c4bc59957B7', + erc20PrivateMetavault: '0xAc31856e2A81B9Af8b83424817C3bc0770F40a01', }, special: { balancedCurator: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', diff --git a/src/helpers/configs/mainnet.ts b/src/helpers/configs/mainnet.ts index 552b50bb..72b7f028 100644 --- a/src/helpers/configs/mainnet.ts +++ b/src/helpers/configs/mainnet.ts @@ -47,10 +47,11 @@ export default { blocklistVault: '0x608d8Ca6916b96edf63Dd429e62Fe1366ae6f3B5', erc20BlocklistVault: '0x39c6eef5f955bcC280966504bc5c82F2394Fa368', - metavault: ZeroAddress, - erc20Metavault: ZeroAddress, - privateMetavault: ZeroAddress, - erc20PrivateMetavault: ZeroAddress, + metavault: '0x76D90928645065b4D4212eE62ce1ba8f90718f14', + erc20Metavault: '0x4E3dE90882B3d10D067b8954909D4A4b0Bb390D0', + + privateMetavault: '0x1e86e620567bb877F5ED13607A1a7B7DBcb6BE66', + erc20PrivateMetavault: '0xE14FA9bBdb7813025309f71DdC0FA8fAae1B9141', }, special: { balancedCurator: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', From e4b1cf8d403fd20f05e03dcdbace5a3c627f09af Mon Sep 17 00:00:00 2001 From: Kadyr Dzhemaledinov Date: Fri, 24 Apr 2026 12:47:43 +0300 Subject: [PATCH 17/27] Merge main sdk (#366) * Remove sync docs git action (#354) * [remove-sync-docs] remove git action and change script * change git action * update GitHub Actions to use latest checkout and cache actions (#356) Co-authored-by: github-actions[bot] * Add script to check documentation links (#357) * add script to check documentation links * fix after review * rename documentation files and improve slug validation in checkDocLinks * add category configuration for Quick Start * improve slug processing and include _category_.json in documentation file search * 4.2.3 (#358) * [fix-encode] fix transactionWrapper (#360) * up-version (#361) * [handle-429] add retry-after header support (#364) * fix --------- Co-authored-by: CAst Co-authored-by: github-actions[bot] --- package.json | 2 +- src/helpers/createProvider/getFetchRequest.ts | 51 ++++++++++++++++--- src/helpers/transactionWrapper.ts | 19 +++++-- .../requests/getMaxWithdrawAmount/index.ts | 4 +- 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index ee8d2c9b..def31329 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "type": "module", - "version": "4.2.3", + "version": "4.2.4", "sideEffects": false, "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/helpers/createProvider/getFetchRequest.ts b/src/helpers/createProvider/getFetchRequest.ts index bac85904..7b4f0166 100644 --- a/src/helpers/createProvider/getFetchRequest.ts +++ b/src/helpers/createProvider/getFetchRequest.ts @@ -1,6 +1,9 @@ -import { FetchRequest, FetchResponse } from 'ethers' +import { FetchRequest } from 'ethers' +const baseCooldownMs = 10_000 +const maxCooldownMs = 60_000 + const getFetchRequest = (_url: string | StakeWise.UrlWithHeaders) => { const url = typeof _url === 'string' ? _url : _url.url const headers = typeof _url === 'string' ? {} : _url.headers @@ -20,20 +23,52 @@ const getFetchRequest = (_url: string | StakeWise.UrlWithHeaders) => { maxAttempts: 2, }) + // Throttle state: on 429 we set a cooldown that doubles + // (10s, 20s, 40s, 60s max) and resets on a successful request. + // If the server sends a Retry-After header, we use that value instead. + let throttledUntil = 0 + let cooldownMs = baseCooldownMs + + fetchRequest.preflightFunc = async (request) => { + const remaining = throttledUntil - Date.now() + + if (remaining > 0) { + await new Promise((resolve) => setTimeout(resolve, remaining)) + } + + return request + } + + // processFunc is called after retryFunc, including for 429 when retryFunc returns false fetchRequest.processFunc = async (_, response) => { - if (response.statusCode === 429) { - // mutate the response to 500 to start an additional node - // https://github.com/ethers-io/ethers.js/blob/main/src.ts/utils/fetch.ts#L519 - return new FetchResponse(500, '', response.headers, null) + if (response.statusCode !== 429) { + throttledUntil = 0 + cooldownMs = baseCooldownMs } return response } fetchRequest.retryFunc = async (_, response) => { - // stop retry attempts - // https://github.com/ethers-io/ethers.js/blob/main/src.ts/utils/fetch.ts#L556 - return response.statusCode !== 429 + if (response.statusCode === 429) { + const retryAfter = response.headers['retry-after'] + + const retryAfterMs = retryAfter + ? Number(retryAfter) * 1_000 + : 0 + + if (retryAfterMs > 0) { + throttledUntil = Date.now() + retryAfterMs + } + else { + throttledUntil = Date.now() + cooldownMs + cooldownMs = Math.min(maxCooldownMs, cooldownMs * 2) + } + + return false + } + + return true } return fetchRequest diff --git a/src/helpers/transactionWrapper.ts b/src/helpers/transactionWrapper.ts index 970bd649..012db6d0 100644 --- a/src/helpers/transactionWrapper.ts +++ b/src/helpers/transactionWrapper.ts @@ -1,13 +1,26 @@ +interface TransactionLike { + (...args: any[]): any + encode: (...args: any[]) => any + estimateGas: (...args: any[]) => Promise +} + /** * @description Prevents transaction invocation if provider is not passed to the SDK instance */ -const transactionWrapper = (params: StakeWise.CommonParams, method: T): T => { +const transactionWrapper = (params: StakeWise.CommonParams, method: T): T => { const isReadOnlyProvider = !params.options.provider if (isReadOnlyProvider) { - return (() => { + const block = () => { throw new Error('To send this transaction, please provide BrowserProvider to the StakeWiseSDK') - }) as T + } + + const newMethod = block as unknown as T + + newMethod.estimateGas = block as T['estimateGas'] + newMethod.encode = method.encode + + return newMethod } return method diff --git a/src/services/vault/requests/getMaxWithdrawAmount/index.ts b/src/services/vault/requests/getMaxWithdrawAmount/index.ts index 08a164e4..a723b918 100644 --- a/src/services/vault/requests/getMaxWithdrawAmount/index.ts +++ b/src/services/vault/requests/getMaxWithdrawAmount/index.ts @@ -13,7 +13,7 @@ export type GetMaxWithdrawAmountInput = StakeWise.CommonParams & { const min = parseEther('0.00001') -const getMaxWithdraw = async (values: GetMaxWithdrawAmountInput) => { +const getMaxWithdrawAmount = async (values: GetMaxWithdrawAmountInput) => { const { contracts, vaultAddress } = values validateArgs.address({ vaultAddress }) @@ -43,4 +43,4 @@ const getMaxWithdraw = async (values: GetMaxWithdrawAmountInput) => { } -export default wrapAbortPromise(getMaxWithdraw) +export default wrapAbortPromise(getMaxWithdrawAmount) From 42a9bd7e3cf01eabc8727dc7ba9491e4a929f69c Mon Sep 17 00:00:00 2001 From: CAst Date: Mon, 27 Apr 2026 15:19:02 +0500 Subject: [PATCH 18/27] [expand-sub-vaults-registry] change abi (#367) --- src/contracts/abis/SubVaultsRegistryAbi.json | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/contracts/abis/SubVaultsRegistryAbi.json b/src/contracts/abis/SubVaultsRegistryAbi.json index 83e825cb..b93409ec 100644 --- a/src/contracts/abis/SubVaultsRegistryAbi.json +++ b/src/contracts/abis/SubVaultsRegistryAbi.json @@ -37,5 +37,31 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "curator", + "type": "address" + } + ], + "name": "setSubVaultsCurator", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "subVaultsCurator", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" } ] From b873d54cb6548084b2902322032746c8066dc416 Mon Sep 17 00:00:00 2001 From: CAst Date: Wed, 29 Apr 2026 11:35:33 +0500 Subject: [PATCH 19/27] [curator-v2] add v2 curator for vault creation (#368) --- src/helpers/configs/gnosis.ts | 4 ++++ src/helpers/configs/hoodi.ts | 5 ++++- src/helpers/configs/mainnet.ts | 5 ++++- .../vault/transactions/createVault/helpers/getEncodeBytes.ts | 4 ++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/helpers/configs/gnosis.ts b/src/helpers/configs/gnosis.ts index 29f564c7..d50dee09 100644 --- a/src/helpers/configs/gnosis.ts +++ b/src/helpers/configs/gnosis.ts @@ -33,6 +33,10 @@ export default { depositDataRegistry: '0x58e16621B5c0786D6667D2d54E28A20940269E16', mintTokenController: '0x60B2053d7f2a0bBa70fe6CDd88FB47b579B9179a', rewardSplitterFactory: '0xd12Df8543e0522CCbF12d231e822B7264c634775', + curator: { + v1: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', + v2: '0x5dd9e7e355509Bd5d29018D0Af4927251d82Ab9E', + }, }, factories: { vault: '0x7A8cbBf690084E43De778173cfAcf7313c9122DD', diff --git a/src/helpers/configs/hoodi.ts b/src/helpers/configs/hoodi.ts index 459488dd..8be6c6d3 100644 --- a/src/helpers/configs/hoodi.ts +++ b/src/helpers/configs/hoodi.ts @@ -34,6 +34,10 @@ export default { depositDataRegistry: '0x93a3f880E07B27dacA6Ef2d3C23E77DBd6294487', mintTokenController: '0x140Fc69Eabd77fFF91d9852B612B2323256f7Ac1', rewardSplitterFactory: '0xd12Df8543e0522CCbF12d231e822B7264c634775', + curator: { + v1: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', + v2: '0x59EdC6edA87885e4A3e2beb9B55AF535a363b306', + }, }, factories: { vault: '0x7A8cbBf690084E43De778173cfAcf7313c9122DD', @@ -52,7 +56,6 @@ export default { erc20PrivateMetavault: '0xAc31856e2A81B9Af8b83424817C3bc0770F40a01', }, special: { - balancedCurator: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', stakeCalculator: '0xaE9A192Ed2030444eB9323C592F1b85801EA0Ec3', leverageStrategy: '0x154628AC72533aad39aBdcaE2055Dced0b4Eef4D', leverageStrategyV2: '0xe382BD0c48A7dd435bE911e0f663cbCAa94AF965', diff --git a/src/helpers/configs/mainnet.ts b/src/helpers/configs/mainnet.ts index 72b7f028..9d6a1e79 100644 --- a/src/helpers/configs/mainnet.ts +++ b/src/helpers/configs/mainnet.ts @@ -36,6 +36,10 @@ export default { depositDataRegistry: '0x75AB6DdCe07556639333d3Df1eaa684F5735223e', mintTokenController: '0x2A261e60FB14586B474C208b1B7AC6D0f5000306', rewardSplitterFactory: '0xd12Df8543e0522CCbF12d231e822B7264c634775', + curator: { + v1: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', + v2: '0xe01351f866C118FbD04d222f9262A470F1d44d90', + }, }, factories: { vault: '0x7A8cbBf690084E43De778173cfAcf7313c9122DD', @@ -54,7 +58,6 @@ export default { erc20PrivateMetavault: '0xE14FA9bBdb7813025309f71DdC0FA8fAae1B9141', }, special: { - balancedCurator: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', stakeCalculator: '0x75c57bd50A3EB7291Da3429956D3566E0153A38f', leverageStrategy: '0x48cD14FDB8e72A03C8D952af081DBB127D6281fc', leverageStrategyV2: '0x7575BC9E5168f27B97F9028905A2Adf91d2fF53d', diff --git a/src/services/vault/transactions/createVault/helpers/getEncodeBytes.ts b/src/services/vault/transactions/createVault/helpers/getEncodeBytes.ts index c7c3e599..43900b11 100644 --- a/src/services/vault/transactions/createVault/helpers/getEncodeBytes.ts +++ b/src/services/vault/transactions/createVault/helpers/getEncodeBytes.ts @@ -1,4 +1,4 @@ -import { AbiCoder, MaxUint256 } from 'ethers' +import { AbiCoder, MaxUint256, getAddress } from 'ethers' import { configs } from '../../../../../helpers' import type { CreateVaultTransactionInput } from '../types' @@ -68,7 +68,7 @@ const getEncodeBytes = (values: EncodeBytesInput) => { if (isMetaVault) { encodedParams.push({ type: 'curator', - value: configs[options.network].addresses.special.balancedCurator, + value: configs[options.network].addresses.base.curator.v2, }) } From e3c6dc2b5b3999a0c1ca54e60953f484654a5c7a Mon Sep 17 00:00:00 2001 From: Kadyr Dzhemaledinov Date: Mon, 4 May 2026 16:12:37 +0300 Subject: [PATCH 20/27] add endpoints file (#369) * add endpoints file * update position * update endpoints docs --- documentation/endpoints.md | 56 +++++++++++++++++++ documentation/installation-setup.md | 21 ------- .../_category_.json | 1 + .../{03-quick-start => quick-start}/boost.md | 0 .../burn-os-token.md | 0 .../deposit-to-vault.md | 0 .../get-user-data.md | 0 .../get-vault-data.md | 0 .../mint-os-token.md | 0 .../unboost.md | 0 .../unstake.md | 0 documentation/reference.md | 2 +- 12 files changed, 58 insertions(+), 22 deletions(-) create mode 100644 documentation/endpoints.md rename documentation/{03-quick-start => quick-start}/_category_.json (63%) rename documentation/{03-quick-start => quick-start}/boost.md (100%) rename documentation/{03-quick-start => quick-start}/burn-os-token.md (100%) rename documentation/{03-quick-start => quick-start}/deposit-to-vault.md (100%) rename documentation/{03-quick-start => quick-start}/get-user-data.md (100%) rename documentation/{03-quick-start => quick-start}/get-vault-data.md (100%) rename documentation/{03-quick-start => quick-start}/mint-os-token.md (100%) rename documentation/{03-quick-start => quick-start}/unboost.md (100%) rename documentation/{03-quick-start => quick-start}/unstake.md (100%) diff --git a/documentation/endpoints.md b/documentation/endpoints.md new file mode 100644 index 00000000..9689f2d7 --- /dev/null +++ b/documentation/endpoints.md @@ -0,0 +1,56 @@ +--- +id: endpoints +title: Available Endpoints +sidebar_position: 4 +description: RPC, API and Subgraph endpoints for Mainnet, Gnosis and Hoodi networks. +--- + +# Available Endpoints + +--- + +## 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` | diff --git a/documentation/installation-setup.md b/documentation/installation-setup.md index b34ba53a..9e81f4f6 100644 --- a/documentation/installation-setup.md +++ b/documentation/installation-setup.md @@ -17,27 +17,6 @@ yarn add @stakewise/v3-sdk --- -## GraphQL Loader Setup - -The SDK includes `.graphql` queries. If your build tool does not natively support importing `.graphql` files, you’ll need to install and configure a corresponding plugin. - -### `Webpack Configuration` - -```ts -// webpack.config.js -module.exports = { - module: { - rules: [ - { - test: /\.(graphql|gql)$/, - exclude: /node_modules/, - loader: 'graphql-tag/loader' - } - ] - } -} -``` - ### `Next.js Configuration` ```ts diff --git a/documentation/03-quick-start/_category_.json b/documentation/quick-start/_category_.json similarity index 63% rename from documentation/03-quick-start/_category_.json rename to documentation/quick-start/_category_.json index 867b92db..78dfab50 100644 --- a/documentation/03-quick-start/_category_.json +++ b/documentation/quick-start/_category_.json @@ -1,3 +1,4 @@ { + "position": 5, "label": "Quick Start" } diff --git a/documentation/03-quick-start/boost.md b/documentation/quick-start/boost.md similarity index 100% rename from documentation/03-quick-start/boost.md rename to documentation/quick-start/boost.md diff --git a/documentation/03-quick-start/burn-os-token.md b/documentation/quick-start/burn-os-token.md similarity index 100% rename from documentation/03-quick-start/burn-os-token.md rename to documentation/quick-start/burn-os-token.md diff --git a/documentation/03-quick-start/deposit-to-vault.md b/documentation/quick-start/deposit-to-vault.md similarity index 100% rename from documentation/03-quick-start/deposit-to-vault.md rename to documentation/quick-start/deposit-to-vault.md diff --git a/documentation/03-quick-start/get-user-data.md b/documentation/quick-start/get-user-data.md similarity index 100% rename from documentation/03-quick-start/get-user-data.md rename to documentation/quick-start/get-user-data.md diff --git a/documentation/03-quick-start/get-vault-data.md b/documentation/quick-start/get-vault-data.md similarity index 100% rename from documentation/03-quick-start/get-vault-data.md rename to documentation/quick-start/get-vault-data.md diff --git a/documentation/03-quick-start/mint-os-token.md b/documentation/quick-start/mint-os-token.md similarity index 100% rename from documentation/03-quick-start/mint-os-token.md rename to documentation/quick-start/mint-os-token.md diff --git a/documentation/03-quick-start/unboost.md b/documentation/quick-start/unboost.md similarity index 100% rename from documentation/03-quick-start/unboost.md rename to documentation/quick-start/unboost.md diff --git a/documentation/03-quick-start/unstake.md b/documentation/quick-start/unstake.md similarity index 100% rename from documentation/03-quick-start/unstake.md rename to documentation/quick-start/unstake.md diff --git a/documentation/reference.md b/documentation/reference.md index 5a46b109..50760696 100644 --- a/documentation/reference.md +++ b/documentation/reference.md @@ -1,7 +1,7 @@ --- id: sdk-reference title: SDK Reference -sidebar_position: 2 +sidebar_position: 3 description: StakeWise SDK reference for network configuration, global TypeScript types, contract access, and built-in ethers helpers. --- From 01b26e70e329b36ef14bdd5013f9086e8882b618 Mon Sep 17 00:00:00 2001 From: CAst Date: Wed, 6 May 2026 17:16:47 +0500 Subject: [PATCH 21/27] Merge main (#371) * Remove sync docs git action (#354) * [remove-sync-docs] remove git action and change script * change git action * update GitHub Actions to use latest checkout and cache actions (#356) Co-authored-by: github-actions[bot] * Add script to check documentation links (#357) * add script to check documentation links * fix after review * rename documentation files and improve slug validation in checkDocLinks * add category configuration for Quick Start * improve slug processing and include _category_.json in documentation file search * 4.2.3 (#358) * [fix-encode] fix transactionWrapper (#360) * up-version (#361) * [handle-429] add retry-after header support (#364) * add context7 public key (#370) * remove old files --------- Co-authored-by: Kadyr Dzhemaledinov Co-authored-by: github-actions[bot] --- context7.json | 4 ++++ scripts/syncDocs/index.ts | 1 + 2 files changed, 5 insertions(+) create mode 100644 context7.json diff --git a/context7.json b/context7.json new file mode 100644 index 00000000..c9c38326 --- /dev/null +++ b/context7.json @@ -0,0 +1,4 @@ +{ + "url": "https://context7.com/stakewise/v3-sdk", + "public_key": "pk_wpaUy9UwJWjviJip1LFYx" +} diff --git a/scripts/syncDocs/index.ts b/scripts/syncDocs/index.ts index a720ac33..f6b12a1d 100644 --- a/scripts/syncDocs/index.ts +++ b/scripts/syncDocs/index.ts @@ -1,6 +1,7 @@ import path from 'path' import fs from 'fs-extra' import { glob } from 'glob' +import { execSync } from 'child_process' import simpleGit from 'simple-git' import { execSync } from 'child_process' From d9a66b5d151c831655ca4dea8ba6cb78a9970554 Mon Sep 17 00:00:00 2001 From: Mike Diamond Date: Mon, 11 May 2026 09:21:27 +0300 Subject: [PATCH 22/27] Context7 (#374) * Remove sync docs git action (#354) * [remove-sync-docs] remove git action and change script * change git action * Add script to check documentation links (#357) * add script to check documentation links * fix after review * rename documentation files and improve slug validation in checkDocLinks * add category configuration for Quick Start * improve slug processing and include _category_.json in documentation file search * [context7] test Signed-off-by: MikeDiam * [context7] test Signed-off-by: MikeDiam * [context7] update context7.json Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update context Signed-off-by: MikeDiam * [context7] update structure Signed-off-by: MikeDiam --------- Signed-off-by: MikeDiam Co-authored-by: CAst Co-authored-by: Kadyr Dzhemaledinov --- .gitignore | 2 + context7.json | 39 ++++- documentation/connecting-wallet.md | 4 +- documentation/endpoints.md | 25 ++- documentation/fundamentals/_category_.json | 4 + .../fundamentals/aggregate-queries.md | 58 +++++++ documentation/fundamentals/concepts.md | 112 ++++++++++++++ .../fundamentals/custom-contracts.md | 127 ++++++++++++++++ documentation/fundamentals/error-handling.md | 54 +++++++ .../fundamentals/network-switching.md | 77 ++++++++++ .../fundamentals/subgraph-indexing.md | 89 +++++++++++ documentation/index.md | 33 ++-- documentation/quick-start/boost.md | 10 +- documentation/quick-start/burn-os-token.md | 4 +- documentation/quick-start/deposit-to-vault.md | 10 +- documentation/quick-start/get-user-data.md | 2 +- documentation/quick-start/get-vault-data.md | 2 +- documentation/quick-start/mint-os-token.md | 4 +- documentation/quick-start/unboost.md | 4 +- documentation/quick-start/unstake.md | 8 +- documentation/reference.md | 64 +++++++- scripts/syncDocs/index.ts | 1 - src/helpers/validateArgs.ts | 11 +- .../transactions/claimQueue/claimQueue.md | 5 + src/services/boost/transactions/lock/lock.md | 7 +- .../boost/transactions/unlock/unlock.md | 7 +- .../upgradeLeverageStrategy.md | 5 + .../transactions/claim/claim.md | 5 + .../osToken/transactions/burn/burn.md | 5 + .../osToken/transactions/mint/mint.md | 5 + .../transactions/claimRewards/claimRewards.md | 5 + .../createRewardSplitter.md | 5 + .../transactions/setClaimer/setClaimer.md | 5 + .../updateFeeRecipients.md | 5 + src/services/utils/index.ts | 9 ++ src/services/utils/waitForSubgraph/index.ts | 64 ++++++++ .../utils/waitForSubgraph/waitForSubgraph.md | 27 ++++ .../requests/getSubVaults/getSubVaults.md | 1 + .../transactions/addSubVault/addSubVault.md | 43 +++++- .../claimExitQueue/claimExitQueue.md | 5 + .../transactions/createVault/createVault.md | 143 ++++++++++++++++-- .../vault/transactions/deposit/deposit.md | 5 + .../ejectSubVault/ejectSubVault.md | 6 + .../vault/transactions/operate/operate.md | 11 ++ .../rejectSubVault/rejectSubVault.md | 6 + .../setDepositDataManager.md | 5 + .../setDepositDataRoot/setDepositDataRoot.md | 5 + .../transactions/updateState/updateState.md | 8 + .../vault/transactions/withdraw/withdraw.md | 5 + 49 files changed, 1098 insertions(+), 48 deletions(-) create mode 100644 documentation/fundamentals/_category_.json create mode 100644 documentation/fundamentals/aggregate-queries.md create mode 100644 documentation/fundamentals/concepts.md create mode 100644 documentation/fundamentals/custom-contracts.md create mode 100644 documentation/fundamentals/error-handling.md create mode 100644 documentation/fundamentals/network-switching.md create mode 100644 documentation/fundamentals/subgraph-indexing.md create mode 100644 src/services/utils/waitForSubgraph/index.ts create mode 100644 src/services/utils/waitForSubgraph/waitForSubgraph.md diff --git a/.gitignore b/.gitignore index 438ea144..1700e82a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ schema.graphql src/types/graphql src/contracts/types src/contracts/vault/types + +CLAUDE.md diff --git a/context7.json b/context7.json index c9c38326..517a1421 100644 --- a/context7.json +++ b/context7.json @@ -1,4 +1,41 @@ { + "$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" + "public_key": "pk_wpaUy9UwJWjviJip1LFYx", + "branch": "context7", + "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` 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`; call `.abort()` to cancel. `.then`/`.catch` are silently suppressed after abort.", + "Contracts outside `sdk.contracts`: import top-level `createContract(address, abi, sdk.provider)` from `@stakewise/v3-sdk`.", + "Batch independent reads with `Promise.all` / `AbortPromise.all`. Never parallelise writes; wallets serialise signing." + ], + "previousVersions": [] } diff --git a/documentation/connecting-wallet.md b/documentation/connecting-wallet.md index 4d286ba7..6b85eecb 100644 --- a/documentation/connecting-wallet.md +++ b/documentation/connecting-wallet.md @@ -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 @@ -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. diff --git a/documentation/endpoints.md b/documentation/endpoints.md index 9689f2d7..68a65f28 100644 --- a/documentation/endpoints.md +++ b/documentation/endpoints.md @@ -9,13 +9,32 @@ description: RPC, API and Subgraph endpoints for Mainnet, Gnosis and Hoodi netwo --- +## 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: +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. +✅ **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. --- @@ -47,7 +66,7 @@ Use the **`prod`** endpoint for production environments. ### Stage -Mirrors the production schema but tracks the staging deployment — use it only when reproducing issues against a non-production environment. +Mirrors the production schema but tracks the staging deployment - use it only when reproducing issues against a non-production environment. | Network | Endpoint | |---------|----------| diff --git a/documentation/fundamentals/_category_.json b/documentation/fundamentals/_category_.json new file mode 100644 index 00000000..d0b3a51d --- /dev/null +++ b/documentation/fundamentals/_category_.json @@ -0,0 +1,4 @@ +{ + "position": 2, + "label": "Fundamentals" +} diff --git a/documentation/fundamentals/aggregate-queries.md b/documentation/fundamentals/aggregate-queries.md new file mode 100644 index 00000000..04462ad8 --- /dev/null +++ b/documentation/fundamentals/aggregate-queries.md @@ -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`) +``` diff --git a/documentation/fundamentals/concepts.md b/documentation/fundamentals/concepts.md new file mode 100644 index 00000000..253f55a8 --- /dev/null +++ b/documentation/fundamentals/concepts.md @@ -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 }) +``` diff --git a/documentation/fundamentals/custom-contracts.md b/documentation/fundamentals/custom-contracts.md new file mode 100644 index 00000000..5cef7d8d --- /dev/null +++ b/documentation/fundamentals/custom-contracts.md @@ -0,0 +1,127 @@ +--- +id: custom-contracts +title: Call arbitrary contracts +sidebar_position: 5 +description: Interact with any StakeWise V3-compatible contract not yet integrated into the SDK's default StakeWise.Contracts namespace. Pass the contract address, ABI, and sdk.provider (which carries the SDK's network configuration and RPC endpoints) to createContract from @stakewise/v3-sdk to get a typed ethers Contract bound to the same chain as the SDK instance. +--- + +# Call arbitrary contracts + + +The default `StakeWise.Contracts` namespace, exposed at `sdk.contracts`, ships with built-ins (Keeper, RewardSplitter, MintTokenController, etc.). For any contract that is not yet integrated there - a freshly deployed StakeWise V3-compatible contract, a Chainlink oracle, a partner protocol - use the top-level `createContract` helper exported from `@stakewise/v3-sdk`. Pass the contract address, its ABI, and `sdk.provider` (which carries the SDK's network configuration and fallback RPC endpoints) to get a typed ethers `Contract` bound to the same chain as the SDK instance. + +## Interact with a StakeWise V3-compatible contract not in the default namespace + +Suppose a new StakeWise V3-compatible contract is deployed and is not yet integrated into the SDK's default `StakeWise.Contracts`. To interact with it, reuse the SDK's provider and configuration via `createContract`: + +```typescript +import { createContract, StakeWiseSDK, Network } from '@stakewise/v3-sdk' + +const sdk = new StakeWiseSDK({ + network: Network.Mainnet, + endpoints: { web3: 'https://main-rpc.io' }, +}) + +const customAbi = [ + 'function getValue() view returns (uint256)', +] as const + +type CustomContract = { + getValue(): Promise +} + +const custom = createContract( + '0xCustomContractAddress', + customAbi, + sdk.provider, +) + +const value = await custom.getValue() +``` + +`sdk.provider` carries the network the SDK was initialized for and any fallback RPC endpoints, so the custom contract talks to the same chain (Mainnet, Hoodi, or Gnosis) as the rest of the SDK calls. + +## Read from a Chainlink oracle + +```typescript +import { createContract, StakeWiseSDK, Network } from '@stakewise/v3-sdk' + +const sdk = new StakeWiseSDK({ + network: Network.Mainnet, + endpoints: { web3: 'https://main-rpc.io' }, +}) + +const aggregatorV3Abi = [ + 'function latestRoundData() view returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)', + 'function decimals() view returns (uint8)', +] as const + +type ChainlinkOracle = { + latestRoundData(): Promise + decimals(): Promise +} + +const ethUsdOracle = createContract( + '0xChainlinkETHUSDFeedAddress', + aggregatorV3Abi, + sdk.provider, +) + +const [ , answer ] = await ethUsdOracle.latestRoundData() +const decimals = await ethUsdOracle.decimals() + +console.log(`ETH/USD = ${Number(answer) / 10 ** decimals}`) +``` + +Passing `sdk.provider` reuses the SDK's RPC configuration (network, fallback rotation), so a Gnosis-configured SDK automatically talks to Gnosis RPC. + +## Write through a custom contract + +For state-changing calls you need a signer-connected SDK. Build the contract, fetch a signer with `sdk.provider.getSigner()`, then `connect(signer)` on the returned contract: + +```typescript +import { BrowserProvider } from 'ethers' +import { createContract, StakeWiseSDK, Network } from '@stakewise/v3-sdk' + +const sdk = new StakeWiseSDK({ + network: Network.Mainnet, + provider: new BrowserProvider(window.ethereum), +}) + +const partnerEscrowAbi = [ + 'function claim(address recipient) returns (uint256)', +] as const + +type PartnerEscrow = { + claim(recipient: string): Promise<{ hash: string }> +} + +const escrow = createContract( + '0xPartnerEscrowAddress', + partnerEscrowAbi, + sdk.provider, +) + +const signer = await sdk.provider.getSigner() +const signedEscrow = escrow.connect(signer) as PartnerEscrow + +const tx = await signedEscrow.claim('0xRecipientAddress') +console.log('tx hash:', tx.hash) +``` + +## Using a different provider + +`createContract` accepts any ethers provider, not just `sdk.provider`. Useful for archive nodes or cross-chain reads that bypass the SDK's RPC config: + +```typescript +import { JsonRpcProvider } from 'ethers' +import { createContract } from '@stakewise/v3-sdk' + +const archiveProvider = new JsonRpcProvider('https://archive-rpc.io') + +const erc20 = createContract( + '0xTokenAddress', + [ 'function balanceOf(address) view returns (uint256)' ], + archiveProvider, +) +``` diff --git a/documentation/fundamentals/error-handling.md b/documentation/fundamentals/error-handling.md new file mode 100644 index 00000000..f13bbd47 --- /dev/null +++ b/documentation/fundamentals/error-handling.md @@ -0,0 +1,54 @@ +--- +id: error-handling +title: Error handling +sidebar_position: 4 +description: Catch SDK errors, decode contract reverts via error.name, debug failed transactions with the JSON payload in error.message, and inspect pre-flight argument validation errors. +--- + +# Error handling + + +Every SDK method validates arguments synchronously before any network call. Network errors (RPC, subgraph) and Solidity reverts come back as rejections from the returned promise. + +## Catching transaction reverts + +When a write reverts, the SDK wraps the underlying error in a `ContractError`. If the SDK can decode the Solidity revert reason, `error.name` becomes the contract error name (e.g. `ZeroSharesAmount`); `error.message` contains a JSON dump of `{ solidityError, to, from, data }` for debugging. + +```typescript +import { parseEther } from 'ethers' +import { StakeWiseSDK, Network } from '@stakewise/v3-sdk' + +const sdk = new StakeWiseSDK({ + network: Network.Mainnet, + provider: browserProvider, +}) + +try { + await sdk.vault.deposit({ + vaultAddress: '0x...', + userAddress: '0x...', + assets: parseEther('1.0'), + referrerAddress: '0x0000000000000000000000000000000000000000', + }) +} +catch (error: any) { + console.error('revert reason:', error.name) + console.error('debug payload:', error.message) +} +``` + +If the revert cannot be decoded (unknown error selector), `error.message` keeps the original payload. Copy `to` / `data` / `from` from there into Tenderly's [Simulator](https://dashboard.tenderly.co/explorer) for a human-readable call trace. + +## Pre-flight argument validation + +User-input mistakes throw synchronously before any network call: + +| Symptom | Cause | +|---|---| +| `Provider or endpoints.web3 should be provided` | Init without a provider AND without `endpoints.web3` | +| `The "" argument must be a valid address` | Address malformed | +| `The "" argument must be of type bigint` | Number/string passed where bigint expected | +| `The "" argument must be a valid 32-byte hex hash` | Tx hash malformed (e.g. wrong length) | +| `To send this transaction, please provide BrowserProvider to the StakeWiseSDK` | Calling default-form write on a read-only SDK | + +For read-only flows, use `sdk.vault..encode(...)` (returns calldata) instead of the default form. diff --git a/documentation/fundamentals/network-switching.md b/documentation/fundamentals/network-switching.md new file mode 100644 index 00000000..e970f273 --- /dev/null +++ b/documentation/fundamentals/network-switching.md @@ -0,0 +1,77 @@ +--- +id: network-switching +title: Switch networks at runtime +sidebar_position: 4 +description: SDK instances are immutable per network. To switch from Mainnet to Gnosis (or back) at runtime, construct a new SDK and cache one instance per chain via a singleton factory. Listen on EIP-1193 chainChanged to react to wallet network changes. +--- + +# Switch networks at runtime + + +A `StakeWiseSDK` instance is bound to a single network for its lifetime. `sdk.network`, `sdk.config`, `sdk.provider`, and `sdk.contracts` are derived from the constructor's `network` argument. To switch from Mainnet to Gnosis at runtime construct a new instance. + +## Singleton factory + +Recreating the SDK on every render is wasteful and breaks request caching. Cache one instance per chain: + +```typescript +import { BrowserProvider } from 'ethers' +import { StakeWiseSDK, Network } from '@stakewise/v3-sdk' + +const sdkCache = new Map() + +const rpcUrls: Record = { + [Network.Mainnet]: 'https://main-rpc.io', + [Network.Gnosis]: 'https://gnosis-rpc.io', + [Network.Hoodi]: 'https://hoodi-rpc.io', +} + +export const getSDK = (network: Network, provider?: BrowserProvider): StakeWiseSDK => { + if (provider) { + return new StakeWiseSDK({ network, provider }) + } + + const cached = sdkCache.get(network) + if (cached) { + return cached + } + + const sdk = new StakeWiseSDK({ + network, + endpoints: { web3: rpcUrls[network] }, + }) + + sdkCache.set(network, sdk) + + return sdk +} +``` + +## Reacting to wallet `chainChanged` + +When the user switches chains in MetaMask, listen on the EIP-1193 provider and rebuild the SDK on the new chain: + +```typescript +import { BrowserProvider } from 'ethers' +import { StakeWiseSDK, Network } from '@stakewise/v3-sdk' + +let sdk: StakeWiseSDK = new StakeWiseSDK({ + network: Network.Mainnet, + provider: new BrowserProvider(window.ethereum), +}) + +const supportedNetworks = new Set([ Network.Mainnet, Network.Gnosis, Network.Hoodi ]) + +const handleChainChanged = (chainIdHex: string) => { + const chainId = Number.parseInt(chainIdHex, 16) + + if (!supportedNetworks.has(chainId)) return + + sdk = new StakeWiseSDK({ + network: chainId, + provider: new BrowserProvider(window.ethereum), + }) +} + +window.ethereum?.on('chainChanged', handleChainChanged) +``` diff --git a/documentation/fundamentals/subgraph-indexing.md b/documentation/fundamentals/subgraph-indexing.md new file mode 100644 index 00000000..61b6e319 --- /dev/null +++ b/documentation/fundamentals/subgraph-indexing.md @@ -0,0 +1,89 @@ +--- +id: subgraph-indexing +title: Wait for subgraph indexing +sidebar_position: 1 +description: After every write transaction (deposit, withdraw, mint, burn, lock, unlock, createVault), poll the StakeWise subgraph with sdk.utils.waitForSubgraph before refetching read methods - otherwise data is stale. +--- + +# Wait for subgraph indexing + + +The SDK reads on-chain state from a subgraph (Graph Protocol indexer), which lags blockchain finality by 1-5 seconds. Calling any read method (`getVault`, `getStakeBalance`, `getExitQueuePositions`, etc.) right after a write returns stale data. + +`sdk.utils.waitForSubgraph` polls until the tx is indexed, then resolves. Always await it between write and refetch. + +## The canonical post-write flow + +```typescript +import { BrowserProvider, parseEther } from 'ethers' +import { StakeWiseSDK, Network } from '@stakewise/v3-sdk' + +const sdk = new StakeWiseSDK({ + network: Network.Mainnet, + provider: new BrowserProvider(window.ethereum), +}) + +const txHash = await sdk.vault.deposit({ + vaultAddress: '0x...', + userAddress: '0x...', + assets: parseEther('1.0'), + referrerAddress: '0x0000000000000000000000000000000000000000', +}) + +// 1. Wait for subgraph to index the tx (also covers receipt confirmation) +await sdk.utils.waitForSubgraph({ hash: txHash }) + +// 2. Now safe to refetch - subgraph reflects the deposit +const stake = await sdk.vault.getStakeBalance({ + vaultAddress: '0x...', + userAddress: '0x...', +}) +``` + +The helper polls `sdk.utils.getTransactions({ hash })` once per second until the tx is indexed. Subgraph fallback / retry on transient errors is handled by the SDK's own GraphQL fetch layer. + +The returned object is an `AbortPromise` (same shape as every other read in the SDK). Call `.abort()` on it to stop polling, the call is a no-op if the helper has already resolved. + +## Cancelling on unmount (React) + +Use the same ref-based pattern as the rest of the SDK - see [`useFetchList.ts`](https://github.com/stakewise/frontwise/blob/master/apps/web/src/views/VaultView/Modals/access/ListModal/util/useFetchList.ts) for the canonical example. + +```typescript +import { useEffect, useRef, useState } from 'react' +import { StakeWiseSDK, Network } from '@stakewise/v3-sdk' + +const sdk = new StakeWiseSDK({ + network: Network.Mainnet, + endpoints: { web3: 'https://main-rpc.io' }, +}) + +const useDepositFlow = (txHash: string | null) => { + const promiseRef = useRef | null>(null) + const [ ready, setReady ] = useState(false) + + useEffect(() => { + if (!txHash) { + return + } + + promiseRef.current?.abort() + promiseRef.current = sdk.utils.waitForSubgraph({ hash: txHash }) + + promiseRef.current + .then(() => setReady(true)) + .catch((error) => console.error(error)) + + return () => promiseRef.current?.abort() + }, [ txHash ]) + + return ready +} +``` + +`.abort()` suppresses any pending success/failure callbacks, your `.then` / `.catch` will never fire after it, so you don't need a separate `if (!aborted)` check inside them. + +## Common pitfalls + +- **Calling `getStakeBalance` immediately after `sdk.vault.deposit()` returns the *old* balance.** Always await `waitForSubgraph` between the two. +- **Network changes during waiting.** When the user switches chains mid-poll, the SDK is bound to the previous network and the helper may keep polling the old subgraph. Call `.abort()` on the wait promise and recreate the SDK on the new chain. +- **`sdk.provider.waitForTransaction(hash)` is not enough.** That waits for receipt confirmation (block inclusion) but does not wait for subgraph indexing, there is typically a 1–5 second additional gap. diff --git a/documentation/index.md b/documentation/index.md index bf2ebe4f..3d0f965d 100644 --- a/documentation/index.md +++ b/documentation/index.md @@ -2,14 +2,14 @@ id: overview title: Overview sidebar_position: 0 -description: StakeWise V3 SDK overview for TypeScript developers — vault management, staking transactions, and blockchain data queries. +description: StakeWise V3 SDK overview for TypeScript developers - vault management, staking transactions, and blockchain data queries. --- # Overview The SDK provides an API for interacting with a **Vault**, allowing you to create and manage vaults, fetch user balances for stakers, and send blockchain transactions related to the vault. With this SDK, you can easily build and integrate your own vault interface. -The SDK is written in **TypeScript** and is designed to remain lightweight — we carefully avoid adding unnecessary dependencies. +The SDK is written in **TypeScript** and is designed to remain lightweight - we carefully avoid adding unnecessary dependencies. To use the SDK, you must have the **ethers** library installed, version **6.14.3 or higher**. The SDK retrieves data from both **subgraphs** and **on-chain smart contracts**, and it can also **send transactions** if you pass a provider instance connected to the user's wallet. @@ -25,13 +25,24 @@ The SDK retrieves data from both **subgraphs** and **on-chain smart contracts**, ## Supported Networks -The SDK currently supports: +| Network | `Network` enum | Chain ID | Native asset | osToken symbol | +|---|---|---|---|---| +| Ethereum Mainnet | `Network.Mainnet` | `1` | ETH | osETH | +| Gnosis | `Network.Gnosis` | `100` | xDAI | osGNO | +| Hoodi Testnet | `Network.Hoodi` | `560048` | ETH | osETH | -- **Ethereum Mainnet** -- **Hoodi Testnet** -- **Gnosis Network** +You specify the target network when creating the SDK instance: -You can specify the target network when creating the SDK instance. +```ts +import { StakeWiseSDK, Network } from '@stakewise/v3-sdk' + +const sdk = new StakeWiseSDK({ + network: Network.Mainnet, + endpoints: { web3: 'https://main-rpc.io' }, +}) +``` + +> SDK instances are immutable per network. To switch networks at runtime, construct a new instance. --- @@ -46,7 +57,7 @@ You can provide endpoints in several formats: * An array of objects to include custom headers (e.g., for authenticated RPC endpoints). -```typescript +```ts import { StakeWiseSDK, Network } from '@stakewise/v3-sdk' const sdk = new StakeWiseSDK({ @@ -71,7 +82,7 @@ const sdk = new StakeWiseSDK({ ## Transaction Flexibility -The SDK supports both **client-side** (browser wallet) and **backend** (custodial) transaction execution. Each write method provides three execution patterns: +The SDK supports both **client-side** (browser wallet) and **backend** (custodial) transaction execution. Each write method provides three execution patterns (with one exception - see below): | Method | Description | Use Case | |--------|-------------|----------| @@ -79,13 +90,15 @@ The SDK supports both **client-side** (browser wallet) and **backend** (custodia | `sdk.vault.method.encode(...)` | Returns encoded calldata | Custom transaction building & custodial wallets | | `sdk.vault.method.estimateGas(...)` | Estimates gas costs | cost calculation | +> **Exception:** `sdk.vault.multicall(values)` is a plain function with no `.encode` / `.estimateGas` siblings. It batches several vault operations into a single transaction and returns `Promise` where `T` is a user-typed tuple of per-operation results. + --- ## Aborting Data Requests Most data-fetching methods in the SDK return a **promise-like object** that includes built-in control methods such as `abort()`. -This allows you to safely cancel network requests that are no longer relevant — for example, when a user changes a filter or input before the previous request completes. +This allows you to safely cancel network requests that are no longer relevant - for example, when a user changes a filter or input before the previous request completes. When `abort()` is called, the ongoing network request is **canceled**, and the associated promise will **not resolve or reject**. If the request has already finished, calling `abort()` has **no effect**. diff --git a/documentation/quick-start/boost.md b/documentation/quick-start/boost.md index 1ac59bf4..886bcd74 100644 --- a/documentation/quick-start/boost.md +++ b/documentation/quick-start/boost.md @@ -2,13 +2,17 @@ id: boost-os-token title: Boost osToken sidebar_position: 6 -description: Boost staking rewards with StakeWise SDK — leverage osTokens as Aave collateral to amplify your vault staking position. +description: Boost staking rewards with StakeWise SDK - leverage osTokens as Aave collateral to amplify your vault staking position. --- # Boost osToken StakeWise Boost enhances staking rewards by leveraging your osTokens as collateral to borrow additional assets from Aave. The borrowed funds are then restaked, creating a compounding effect that amplifies your staking position. +## How to lock osToken into the Boost leverage strategy + +To boost a user's osToken position, look up the leverage strategy proxy with `sdk.boost.getLeverageStrategyProxy`, ensure the proxy has osToken allowance (via permit signature for EOAs or `approve` for multisig wallets), then call `sdk.boost.lock`. The full flow below covers both wallet types. + ```ts import { BrowserProvider, parseEther } from 'ethers' import { StakeWiseSDK, Network, OsTokenPositionHealth } from '@stakewise/v3-sdk' @@ -70,6 +74,8 @@ const boost = async (values: Input) => { const { hash } = await signedContract.approve(permitAddress, shares) await sdk.provider.waitForTransaction(hash) + + await sdk.utils.waitForSubgraph({ hash }) } else { // Use gasless permit for EOAs @@ -98,6 +104,8 @@ const boost = async (values: Input) => { }) await sdk.provider.waitForTransaction(hash) + + await sdk.utils.waitForSubgraph({ hash }) } catch (error) { console.error(error) diff --git a/documentation/quick-start/burn-os-token.md b/documentation/quick-start/burn-os-token.md index 7dbf0680..947ac334 100644 --- a/documentation/quick-start/burn-os-token.md +++ b/documentation/quick-start/burn-os-token.md @@ -2,7 +2,7 @@ id: burn-os-token title: Burn osToken sidebar_position: 5 -description: Burn osETH tokens in a StakeWise vault using the SDK — monitor osToken position health and execute burn transactions safely. +description: Burn osETH tokens in a StakeWise vault using the SDK - monitor osToken position health and execute burn transactions safely. --- # Burn osToken @@ -68,6 +68,8 @@ const burn = async (values: Input) => { }) await sdk.provider.waitForTransaction(hash) + + await sdk.utils.waitForSubgraph({ hash }) } catch (error) { console.error(error) diff --git a/documentation/quick-start/deposit-to-vault.md b/documentation/quick-start/deposit-to-vault.md index f81ecc0e..6cef3fc7 100644 --- a/documentation/quick-start/deposit-to-vault.md +++ b/documentation/quick-start/deposit-to-vault.md @@ -2,14 +2,14 @@ id: deposit-to-vault title: Deposit to vault sidebar_position: 2 -description: Deposit ETH into a StakeWise vault using the SDK — client-side browser wallet and backend custodial wallet integration examples. +description: Deposit ETH into a StakeWise vault using the SDK - client-side browser wallet and backend custodial wallet integration examples. --- # Deposit to vault This guide demonstrates two different approaches for depositing into a vault: -### 1. Client-Side (Browser Wallet) +## How to deposit from a browser wallet Use this method when users connect their non-custodial wallet (like MetaMask) directly in the browser. @@ -48,6 +48,8 @@ const deposit = async (values: Input) => { const hash = await sdk.vault.deposit(params) await sdk.provider.waitForTransaction(hash) + + await sdk.utils.waitForSubgraph({ hash }) } catch (error) { console.error(error) @@ -62,7 +64,7 @@ deposit({ ``` --- -### 2. Backend-Side (Custodial Wallet) +## How to deposit from a backend or custodial wallet Use this method when you manage private keys on your backend server. @@ -95,6 +97,8 @@ const deposit = async (values: Input) => { const { hash } = await yourSigningService.sendTransaction() await sdk.provider.waitForTransaction(hash) + + await sdk.utils.waitForSubgraph({ hash }) } catch (error) { console.error(error) diff --git a/documentation/quick-start/get-user-data.md b/documentation/quick-start/get-user-data.md index 9f1694a0..16e34472 100644 --- a/documentation/quick-start/get-user-data.md +++ b/documentation/quick-start/get-user-data.md @@ -2,7 +2,7 @@ id: get-user-data title: Get user data sidebar_position: 1 -description: Query user staking data from StakeWise vaults — balances, osToken positions, boost amounts, APY, exit queues, and action history. +description: Query user staking data from StakeWise vaults - balances, osToken positions, boost amounts, APY, exit queues, and action history. --- # Get user data diff --git a/documentation/quick-start/get-vault-data.md b/documentation/quick-start/get-vault-data.md index 43b6abdc..f3c2db3b 100644 --- a/documentation/quick-start/get-vault-data.md +++ b/documentation/quick-start/get-vault-data.md @@ -2,7 +2,7 @@ id: get-vault-data title: Get vault data sidebar_position: 0 -description: Fetch StakeWise vault data using the SDK — retrieve vault details, stats charts, validators, whitelist, and blocklist information. +description: Fetch StakeWise vault data using the SDK - retrieve vault details, stats charts, validators, whitelist, and blocklist information. --- # Get vault data diff --git a/documentation/quick-start/mint-os-token.md b/documentation/quick-start/mint-os-token.md index 52a6f3b5..f79ffae9 100644 --- a/documentation/quick-start/mint-os-token.md +++ b/documentation/quick-start/mint-os-token.md @@ -2,7 +2,7 @@ id: mint-os-token title: Mint osToken sidebar_position: 4 -description: Mint osETH tokens against your StakeWise vault stake using the SDK — check max mintable amounts and execute minting transactions. +description: Mint osETH tokens against your StakeWise vault stake using the SDK - check max mintable amounts and execute minting transactions. --- # Mint osToken @@ -57,6 +57,8 @@ const mint = async (values: Input) => { }) await sdk.provider.waitForTransaction(hash) + + await sdk.utils.waitForSubgraph({ hash }) } catch (error) { console.error(error) diff --git a/documentation/quick-start/unboost.md b/documentation/quick-start/unboost.md index 24bc4231..151d2c64 100644 --- a/documentation/quick-start/unboost.md +++ b/documentation/quick-start/unboost.md @@ -2,7 +2,7 @@ id: unboost-os-token title: Unboost osToken sidebar_position: 7 -description: Exit a leveraged boost position with the StakeWise SDK — repay Aave debt, unlock osToken collateral, and track the withdrawal queue. +description: Exit a leveraged boost position with the StakeWise SDK - repay Aave debt, unlock osToken collateral, and track the withdrawal queue. --- # Unboost osToken @@ -62,6 +62,8 @@ const unboost = async (values: Input) => { await sdk.provider.waitForTransaction(hash) + await sdk.utils.waitForSubgraph({ hash }) + const unboostQueue = await sdk.boost.getQueuePosition({ userAddress, vaultAddress }) // After you have unboosted, your funds are placed in the withdrawal queue. diff --git a/documentation/quick-start/unstake.md b/documentation/quick-start/unstake.md index 7b8d0ec2..97205b54 100644 --- a/documentation/quick-start/unstake.md +++ b/documentation/quick-start/unstake.md @@ -2,13 +2,17 @@ id: unstake-example title: Unstake sidebar_position: 3 -description: Unstake deposits from a StakeWise vault using the SDK — withdraw staked assets, handle osToken burns, and track exit queue positions. +description: Unstake deposits from a StakeWise vault using the SDK - withdraw staked assets, handle osToken burns, and track exit queue positions. --- # Unstake This guide outlines the implementation approach for unstaking user deposits. +## How to unstake from a StakeWise V3 vault + +To unstake (withdraw) user assets from a vault, fetch the current stake balance and the maximum withdrawable amount, check whether any osToken must be burned first via `getBurnAmountForUnstake`, then call `sdk.vault.withdraw`. The withdrawal lands in the vault's exit queue, which you can read with `sdk.vault.getExitQueuePositions` after the subgraph has indexed the transaction. + ```ts import { BrowserProvider, parseEther, formatEther } from 'ethers' import { StakeWiseSDK, Network } from '@stakewise/v3-sdk' @@ -65,6 +69,8 @@ const unstake = async (values: Input) => { await sdk.provider.waitForTransaction(hash) + await sdk.utils.waitForSubgraph({ hash }) + const positions = await sdk.vault.getExitQueuePositions({ userAddress, vaultAddress }) // After unstaking, the withdrawal of funds will be added to the exit queue, which can be obtained using the SDK. diff --git a/documentation/reference.md b/documentation/reference.md index 50760696..6e5aff0e 100644 --- a/documentation/reference.md +++ b/documentation/reference.md @@ -5,7 +5,9 @@ sidebar_position: 3 description: StakeWise SDK reference for network configuration, global TypeScript types, contract access, and built-in ethers helpers. --- -# Configuration for the Current Network +# SDK Reference + +## Configuration for the Current Network For each network, the SDK stores configuration containing essential data for working with the current network. @@ -21,7 +23,7 @@ The configuration contains the following data: - **addresses** - addresses of main contracts operating in the network - **tokens** - token symbols for the current network -# Global Types +## Global Types The SDK adds the `StakeWise` namespace to the global scope, from which you can access necessary data types. @@ -34,6 +36,13 @@ The SDK adds the `StakeWise` namespace to the global scope, from which you can a To get the return type of the `sdk.boost.getData` method, you can use two approaches: ```typescript +import { StakeWiseSDK, Network } from '@stakewise/v3-sdk' + +const sdk = new StakeWiseSDK({ + network: Network.Mainnet, + endpoints: { web3: 'https://main-rpc.io' }, +}) + // First approach type BoostData = Awaited> @@ -41,16 +50,60 @@ type BoostData = Awaited> type BoostData = Awaited> ``` -# Contracts +## Built-in Contracts You can make calls to the built-in ethers contracts if needed. To access contracts for the current network, use `sdk.contracts`. -For example, if you want to quickly create a standard ERC20 contract, you can use the helper `sdk.contracts.helpers.createErc20(tokenAddress)`. +For a standard ERC20 contract at any address, use `sdk.contracts.helpers.createErc20(tokenAddress)`. + +The osToken (osETH on Mainnet/Hoodi, osGNO on Gnosis) is the StakeWise V3 staking token. Its ERC20 address lives at `sdk.config.addresses.tokens.mintToken`: + +```typescript +import { StakeWiseSDK, Network } from '@stakewise/v3-sdk' + +const sdk = new StakeWiseSDK({ + network: Network.Mainnet, + endpoints: { web3: 'https://main-rpc.io' }, +}) + +const osTokenAddress = sdk.config.addresses.tokens.mintToken +const osToken = sdk.contracts.helpers.createErc20(osTokenAddress) + +const totalSupply = await osToken.totalSupply() +``` + +## How to read osETH ERC20 balance and total supply + +osETH (osGNO on Gnosis) is the StakeWise V3 liquid staking token. The SDK exposes its ERC20 contract pre-instantiated at `sdk.contracts.tokens.mintToken` - call `balanceOf`, `totalSupply`, `allowance`, etc. directly without wrapping the address yourself: + +```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 [ totalSupply, userBalance ] = await Promise.all([ + sdk.contracts.tokens.mintToken.totalSupply(), + sdk.contracts.tokens.mintToken.balanceOf('0xUserAddress'), +]) + +console.log(`osETH supply: ${formatEther(totalSupply)}`) +console.log(`User osETH balance: ${formatEther(userBalance)}`) +``` + +On Gnosis, swap `Network.Mainnet` for `Network.Gnosis` and the same `sdk.contracts.tokens.mintToken` returns osGNO supply and balance values. + +## Error Handling and Transaction Debugging -# Error Handling and Transaction Debugging Each SDK method validates the arguments passed to it before execution and throws an error if any argument is invalid. For example, if you attempt to send a transaction without providing a provider during SDK initialization, an error will be thrown. + If an error occurs during a transaction, you will see a detailed error logged in the console, including the transaction data. If the error object contains a `solidityError` field, it means the error was successfully parsed and the root cause is immediately visible. + If the `solidityError` field is not present, the error log will still include the `data`, `to`, and `from` fields. Using these values, you can reproduce and debug the transaction with Tenderly: + 1. Open Tenderly and go to the Simulator section. 2. Select the appropriate network. 3. Paste the `to` address into the left column (the contract address field). @@ -58,4 +111,5 @@ If the `solidityError` field is not present, the error log will still include th 5. Paste the `from` address into the From field on the right. 6. Disable Use Pending Block. 7. Enter the current block number into the Block Number field. + After running the simulation, you will see the exact error that occurred in the smart contract, making it significantly easier to understand and resolve the issue. diff --git a/scripts/syncDocs/index.ts b/scripts/syncDocs/index.ts index f6b12a1d..a720ac33 100644 --- a/scripts/syncDocs/index.ts +++ b/scripts/syncDocs/index.ts @@ -1,7 +1,6 @@ import path from 'path' import fs from 'fs-extra' import { glob } from 'glob' -import { execSync } from 'child_process' import simpleGit from 'simple-git' import { execSync } from 'child_process' diff --git a/src/helpers/validateArgs.ts b/src/helpers/validateArgs.ts index 4b6f196c..1dbd3639 100644 --- a/src/helpers/validateArgs.ts +++ b/src/helpers/validateArgs.ts @@ -1,4 +1,4 @@ -import { isAddress } from 'ethers' +import { isAddress, isHexString } from 'ethers' const image = (value: string) => { @@ -28,6 +28,14 @@ const address = (values: Record) => { }) } +const hash = (values: Record) => { + Object.keys(values).forEach((key) => { + if (!isHexString(values[key], 32)) { + throw new Error(`The "${key}" argument must be a valid 32-byte hex hash (0x + 64 hex chars)`) + } + }) +} + const string = (values: Record) => { Object.keys(values).forEach((key) => { if (typeof values[key] !== 'string') { @@ -82,6 +90,7 @@ const maxLength = (values: Record) => export default { + hash, image, array, object, diff --git a/src/services/boost/transactions/claimQueue/claimQueue.md b/src/services/boost/transactions/claimQueue/claimQueue.md index ff55553b..b58a1f7e 100644 --- a/src/services/boost/transactions/claimQueue/claimQueue.md +++ b/src/services/boost/transactions/claimQueue/claimQueue.md @@ -39,6 +39,11 @@ const params = { // Send transaction const hash = await sdk.boost.claimQueue(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to, value } = await sdk.boost.claimQueue.encode(params) // Get an approximate gas per transaction diff --git a/src/services/boost/transactions/lock/lock.md b/src/services/boost/transactions/lock/lock.md index 190458c5..7f598059 100644 --- a/src/services/boost/transactions/lock/lock.md +++ b/src/services/boost/transactions/lock/lock.md @@ -17,7 +17,7 @@ Boost your osToken apy using leverage staking | vaultAddress | `string` | **Yes** | The address of the vault that will mint osTokens for leverage staking | | boostAddress | `string` | **Yes** | The address of the strategy proxy using the [sdk.boost.getLeverageStrategyProxy](/sdk/api/boost/requests/getleveragestrategyproxy) method | | referrerAddress | `string` | **No** | The address of the referrer | -| permitParams | `PermitParams` | **No** | The permit signature is required if there isn’t enough osToken allowance for the strategy proxy contract.

**For MultiSig**
The permit signature is not necessary for Multi Sig (e.g. Safe Wallet), as it should use `sdk.contracts.mintToken.approve(boostAddress, MaxUint256)` instead of a permit call to set up osToken allowance. This will be called in the action if needed.

**For other wallets**
The permit signature is optional since it will be obtained automatically using the [utils.getPermitSignature](/sdk/api/utils/getpermitsignature) method. | +| permitParams | `PermitParams` | **No** | The permit signature is required if there isn’t enough osToken allowance for the strategy proxy contract.

**For MultiSig**
The permit signature is not necessary for Multi Sig (e.g. Safe Wallet), as it should use `sdk.contracts.tokens.mintToken.approve(boostAddress, MaxUint256)` instead of a permit call to set up osToken allowance. This will be called in the action if needed.

**For other wallets**
The permit signature is optional since it will be obtained automatically using the [utils.getPermitSignature](/sdk/api/utils/getpermitsignature) method. | | leverageStrategyData | `LeverageStrategyData` | **No** | Leverage strategy data from [sdk.boost.getLeverageStrategyData](/sdk/api/boost/requests/getleveragestrategydata). If not provided, it will be fetched automatically during the transaction | ```ts @@ -54,6 +54,11 @@ const params = { // Send transaction const hash = await sdk.boost.lock(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) // `lockTxData` will always be returned, while `approveTxData` will only be returned for MultiSig e.g. Safe Wallet // if there isn’t enough osToken allowance, otherwise it will be null diff --git a/src/services/boost/transactions/unlock/unlock.md b/src/services/boost/transactions/unlock/unlock.md index 9e44ab29..c5be4155 100644 --- a/src/services/boost/transactions/unlock/unlock.md +++ b/src/services/boost/transactions/unlock/unlock.md @@ -12,7 +12,7 @@ Unboost your boosted osToken | Name | Type | Required | Description | |----------------------|------------|----------|-----------------------------------------------------| -| percent | `number` | **Yes** | The percent to unboost (100 at max) | +| percent | `number` | **Yes** | The percent of the boosted position to unboost. Must be in the range `(0, 100]` - strictly greater than 0 and at most 100. The SDK throws before sending the transaction if `percent` is `0` or below, or above `100`. | | userAddress | `string` | **Yes** | The user address | | vaultAddress | `string` | **Yes** | The address of the vault where the osTokens boosted | | leverageStrategyData | `LeverageStrategyData` | **No** | Leverage strategy data from [sdk.boost.getLeverageStrategyData](/sdk/api/boost/requests/getleveragestrategydata). If not provided, it will be fetched automatically during the transaction | @@ -41,6 +41,11 @@ const params = { // Send transaction const hash = await sdk.boost.unlock(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) // `lockTxData` will always be returned, while `upgradeLeverageStrategyTxData` will be returned if the leverage strategy contract upgrade is required const { lockTxData, upgradeLeverageStrategyTxData } = await sdk.boost.unlock.encode(params) diff --git a/src/services/boost/transactions/upgradeLeverageStrategy/upgradeLeverageStrategy.md b/src/services/boost/transactions/upgradeLeverageStrategy/upgradeLeverageStrategy.md index b5d5f509..30ff8566 100644 --- a/src/services/boost/transactions/upgradeLeverageStrategy/upgradeLeverageStrategy.md +++ b/src/services/boost/transactions/upgradeLeverageStrategy/upgradeLeverageStrategy.md @@ -26,6 +26,11 @@ const params = { // Send transaction const hash = await sdk.boost.upgradeLeverageStrategy(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to, value } = await sdk.boost.unlock.encode(params) // Get an approximate gas per transaction diff --git a/src/services/distributorRewards/transactions/claim/claim.md b/src/services/distributorRewards/transactions/claim/claim.md index 3140def0..e8e05b21 100644 --- a/src/services/distributorRewards/transactions/claim/claim.md +++ b/src/services/distributorRewards/transactions/claim/claim.md @@ -40,6 +40,11 @@ const params = { // Send transaction const hash = await sdk.distributorRewards.claim(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.distributorRewards.claim.encode(params) // Get an approximate gas per transaction diff --git a/src/services/osToken/transactions/burn/burn.md b/src/services/osToken/transactions/burn/burn.md index 6ce87bf4..c5a1cee8 100644 --- a/src/services/osToken/transactions/burn/burn.md +++ b/src/services/osToken/transactions/burn/burn.md @@ -27,6 +27,11 @@ const params = { // Send transaction const hash = await sdk.osToken.burn(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to, value } = await sdk.osToken.burn.encode(params) // Get an approximate gas per transaction diff --git a/src/services/osToken/transactions/mint/mint.md b/src/services/osToken/transactions/mint/mint.md index e4322e26..062ad353 100644 --- a/src/services/osToken/transactions/mint/mint.md +++ b/src/services/osToken/transactions/mint/mint.md @@ -81,6 +81,11 @@ const params = { // Send transaction const hash = await sdk.osToken.mint(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.osToken.mint.encode(params) // Get an approximate gas per transaction diff --git a/src/services/rewardSplitter/transactions/claimRewards/claimRewards.md b/src/services/rewardSplitter/transactions/claimRewards/claimRewards.md index 5549cd4e..dc8f8e4e 100644 --- a/src/services/rewardSplitter/transactions/claimRewards/claimRewards.md +++ b/src/services/rewardSplitter/transactions/claimRewards/claimRewards.md @@ -28,6 +28,11 @@ const params = { // Send transaction const hash = await sdk.rewardSplitter.claimRewards(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.rewardSplitter.claimRewards.encode(params) // Get an approximate gas per transaction diff --git a/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.md b/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.md index 58260f1a..6336dbd1 100644 --- a/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.md +++ b/src/services/rewardSplitter/transactions/createRewardSplitter/createRewardSplitter.md @@ -29,6 +29,11 @@ const params = { // Send transaction const hash = await sdk.rewardSplitter.create(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.rewardSplitter.create.encode(params) // Get an approximate gas per transaction diff --git a/src/services/rewardSplitter/transactions/setClaimer/setClaimer.md b/src/services/rewardSplitter/transactions/setClaimer/setClaimer.md index 559318cf..cfe581d7 100644 --- a/src/services/rewardSplitter/transactions/setClaimer/setClaimer.md +++ b/src/services/rewardSplitter/transactions/setClaimer/setClaimer.md @@ -26,6 +26,11 @@ const params = { // Send transaction const hash = await sdk.rewardSplitter.setClaimer(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.rewardSplitter.setClaimer.encode(params) // Get an approximate gas per transaction diff --git a/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.md b/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.md index a9834d2c..afb485a1 100644 --- a/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.md +++ b/src/services/rewardSplitter/transactions/updateFeeRecipients/updateFeeRecipients.md @@ -55,6 +55,11 @@ const params = { // Send transaction const hash = await sdk.rewardSplitter.updateFeeRecipients(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.rewardSplitter.updateFeeRecipients.encode(params) // Get an approximate gas per transaction diff --git a/src/services/utils/index.ts b/src/services/utils/index.ts index 5d498de9..f70cff6d 100644 --- a/src/services/utils/index.ts +++ b/src/services/utils/index.ts @@ -1,5 +1,6 @@ import { getFiatRates } from './getFiatRates' import { getStakewiseStats } from './getStakewiseStats' +import { waitForSubgraph, WaitForSubgraphInput } from './waitForSubgraph' import { getTransactions, GetTransactionsInput } from './getTransactions' import { getListVariables, GetListVariablesInput } from './getListVariables' import { getFiatRatesByDay, GetFiatRatesByDayInput } from './getFiatRatesByDay' @@ -39,6 +40,14 @@ class Utils { return getTransactions({ ...this.params, ...values }) } + /** + * @description Polls the subgraph until a transaction with the given hash is indexed. Required after every write before refetching reads. + * @see https://docs.stakewise.io/sdk/api/utils/waitforsubgraph + */ + public waitForSubgraph(values: StakeWise.ExtractInput) { + return waitForSubgraph({ ...this.params, ...values }) + } + /** * @description Get fiat data by day * @see https://docs.stakewise.io/sdk/api/utils/getfiatratesbyday diff --git a/src/services/utils/waitForSubgraph/index.ts b/src/services/utils/waitForSubgraph/index.ts new file mode 100644 index 00000000..a8ba62e6 --- /dev/null +++ b/src/services/utils/waitForSubgraph/index.ts @@ -0,0 +1,64 @@ +import { validateArgs } from '../../../helpers' +import { getTransactions } from '../getTransactions' +import AbortPromise from '../../../modules/gql-module/abortPromise' + + +export type WaitForSubgraphInput = StakeWise.CommonParams & { + hash: string +} + +export const waitForSubgraph = (input: WaitForSubgraphInput): AbortPromise => { + const { hash, config, options, provider, contracts } = input + + validateArgs.hash({ hash }) + + const commonParams: StakeWise.CommonParams = { config, options, provider, contracts } + + let isAborted = false + + const fetchCount = async (attempt: number = 0): Promise => { + try { + const transactions = await getTransactions({ ...commonParams, hash }) + + return transactions.length + } + catch (error) { + if (attempt < 10) { + await new Promise((resolve) => setTimeout(resolve, attempt * 100)) + + return fetchCount(attempt + 1) + } + + return Promise.reject(error) + } + } + + const poll = async (): Promise => { + if (isAborted) { + return + } + + const count = await fetchCount() + + if (!count) { + await new Promise((resolve) => setTimeout(resolve, 1000)) + + return poll() + } + } + + return new AbortPromise( + (resolve, reject) => { + poll() + .then(() => resolve()) + .catch((error) => { + if (!isAborted) { + reject(error) + } + }) + }, + () => { + isAborted = true + } + ) +} diff --git a/src/services/utils/waitForSubgraph/waitForSubgraph.md b/src/services/utils/waitForSubgraph/waitForSubgraph.md new file mode 100644 index 00000000..6d8733d1 --- /dev/null +++ b/src/services/utils/waitForSubgraph/waitForSubgraph.md @@ -0,0 +1,27 @@ +--- +id: waitForSubgraph +slug: /sdk/api/utils/waitforsubgraph +description: Use the StakeWise SDK waitForSubgraph utility to poll the subgraph after a write transaction until indexing catches up, so the next read returns fresh data instead of pre-tx state. +--- + +#### Description: + +Polls the subgraph until a transaction with the given hash is indexed. Required after every write operation (`deposit`, `withdraw`, `mint`, `burn`, `lock`, `unlock`, `createVault`) before refetching read methods - otherwise the subgraph returns stale data because it indexes blocks asynchronously. + +`sdk.provider.waitForTransaction(hash)` waits for the receipt only, not for subgraph indexing. There is typically a 1 to 5 second additional gap. + +#### Arguments: + +| Name | Type | Required | Description | +|--------|----------|----------|---------------------------------------------| +| `hash` | `string` | **Yes** | Transaction hash returned by the write call | + +#### Returns: + +`AbortPromise`. Call `.abort()` to stop polling on unmount or navigation. + +#### Example: + +```ts +await sdk.utils.waitForSubgraph({ hash: '0x...' }) +``` diff --git a/src/services/vault/requests/getSubVaults/getSubVaults.md b/src/services/vault/requests/getSubVaults/getSubVaults.md index fa1ffc47..3bd891ab 100644 --- a/src/services/vault/requests/getSubVaults/getSubVaults.md +++ b/src/services/vault/requests/getSubVaults/getSubVaults.md @@ -1,6 +1,7 @@ --- id: getSubVaults slug: /sdk/api/vault/requests/getsubvaults +description: Use the StakeWise SDK getSubVaults method to list sub-vaults of a StakeWise V3 meta vault with paging support. Returns per-vault APY, display name, image URL, staking and exiting assets. --- #### Description: diff --git a/src/services/vault/transactions/addSubVault/addSubVault.md b/src/services/vault/transactions/addSubVault/addSubVault.md index 711b61a6..442adbdd 100644 --- a/src/services/vault/transactions/addSubVault/addSubVault.md +++ b/src/services/vault/transactions/addSubVault/addSubVault.md @@ -1,11 +1,47 @@ --- id: addSubVault slug: /sdk/api/vault/transactions/addsubvault +description: Use the StakeWise SDK addSubVault method to add a sub-vault to a StakeWise V3 meta vault registry on Mainnet, Hoodi, or Gnosis. Called by the meta vault curator to extend the registry of underlying vaults receiving routed deposits. --- #### Description: -Adding a new sub-vault to the vault registry. +Adds a new sub-vault to a meta vault's registry. Called by the meta vault admin (curator). + +#### Prerequisites before calling addSubVault + +The contract reverts if the sub-vault is unreachable for the meta vault. Pre-check on the frontend so the user gets an informative error instead of a generic revert: + +- If the sub-vault is **private** (`isPrivate: true` from `sdk.vault.getVault`), the meta vault address must be in the sub-vault's whitelist. Read the whitelist with `sdk.vault.getWhitelist({ vaultAddress: subVaultAddress })` and skip or warn the user if the meta vault is not present. +- If the sub-vault has a **blocklist** (`isBlocklist: true`), the meta vault address must not be on the blocklist. Read it with `sdk.vault.getBlocklist({ vaultAddress: subVaultAddress })`. +- The sub-vault itself must not be a meta vault (`isMetaVault: false`). Nesting meta vaults is not supported. +- The sub-vault should not already be in the meta vault's registry. Check the current list with `sdk.vault.getSubVaults({ vaultAddress })`. + +```ts +const subVault = await sdk.vault.getVault({ vaultAddress: subVaultAddress }) + +if (subVault.isMetaVault) { + throw new Error('Cannot add a meta vault as a sub-vault') +} + +if (subVault.isPrivate) { + const whitelist = await sdk.vault.getWhitelist({ vaultAddress: subVaultAddress, limit: 1000, skip: 0 }) + const isWhitelisted = whitelist.some(({ address }) => address.toLowerCase() === metaVaultAddress.toLowerCase()) + + if (!isWhitelisted) { + throw new Error('Meta vault must be on the sub-vault whitelist before it can be added') + } +} + +if (subVault.isBlocklist) { + const blocklist = await sdk.vault.getBlocklist({ vaultAddress: subVaultAddress, limit: 1000, skip: 0 }) + const isBlocked = blocklist.some(({ address }) => address.toLowerCase() === metaVaultAddress.toLowerCase()) + + if (isBlocked) { + throw new Error('Meta vault is on the sub-vault blocklist and cannot be added') + } +} +``` #### Arguments: @@ -26,6 +62,11 @@ const params = { // Send transaction const hash = await sdk.vault.addSubVault(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.vault.addSubVault.encode(params) // Get an approximate gas per transaction diff --git a/src/services/vault/transactions/claimExitQueue/claimExitQueue.md b/src/services/vault/transactions/claimExitQueue/claimExitQueue.md index 4774f71d..e5b2ea20 100644 --- a/src/services/vault/transactions/claimExitQueue/claimExitQueue.md +++ b/src/services/vault/transactions/claimExitQueue/claimExitQueue.md @@ -42,6 +42,11 @@ const params = { // Send transaction const hash = await sdk.vault.claimExitQueue(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.vault.claimExitQueue.encode(params) // Get an approximate gas per transaction diff --git a/src/services/vault/transactions/createVault/createVault.md b/src/services/vault/transactions/createVault/createVault.md index e43c9c94..aecdb543 100644 --- a/src/services/vault/transactions/createVault/createVault.md +++ b/src/services/vault/transactions/createVault/createVault.md @@ -6,15 +6,15 @@ description: Use the StakeWise SDK createVault method to deploy a new staking va #### Description: -Create a vault. When the transaction is executed, one gwei of the deposit token must be stored in the vault to avoid [inflation attack](https://blog.openzeppelin.com/a-novel-defense-against-erc4626-inflation-attacks). +How to deploy a StakeWise V3 vault: call `sdk.vault.create({ userAddress, type, ... })` on a write-capable SDK (browser wallet or backend signer). The simplest case is `VaultType.Default` with no `vaultToken`, no `capacity`, no `keysManagerFee` - the SDK applies sensible defaults and the returned hash points at a fully working open vault. -Pay attention to chains where the deposit token is not a native token such as Gnosis. -On these chains before creating the vault, ensure that you call the `approve` function on the deposit token contract, -allowing the vault factory address to spend one gwei. +The optional `vaultToken: { name, symbol }` argument toggles between an **ERC20 vault** (vault mints a transferable share token) and a **non-ERC20 vault** (shares tracked internally). The `type` argument selects `Default`, `Private`, `Blocklist`, `MetaVault`, or `PrivateMetaVault` access. Regular vault types combine with the ERC20 toggle into six factories; meta vault types add their own factories. The SDK picks the right factory automatically. -You can retrieve the vault factory contract using the helper function: `sdk.getVaultFactory({ vaultType: params.type, isErc20: params.isErc20 })`. +When the transaction is executed, one gwei of the deposit token must be stored in the vault to avoid [inflation attack](https://blog.openzeppelin.com/a-novel-defense-against-erc4626-inflation-attacks). +On Mainnet and Hoodi the deposit token is the native asset (ETH) and the SDK attaches the 1 gwei automatically. +On Gnosis the deposit token is GNO, so before calling `sdk.vault.create` you must call `approve` on GNO to allow the vault factory to spend 1 gwei. Retrieve the factory address with `sdk.vault.getVaultFactory({ vaultType: params.type, isErc20: Boolean(params.vaultToken) })`. -**Important**: When creating a metavault on Gnosis, only the default vault type is supported. ERC20 tokens and private vaults are not available. Additionally, all metavaults do not support the `isOwnMevEscrow` parameter. +**Important**: When creating a meta vault on Gnosis, only `VaultType.MetaVault` is supported (open access). `VaultType.PrivateMetaVault` is Mainnet and Hoodi only. ERC20 share tokens (`vaultToken`) are not available for meta vaults on Gnosis. All meta vaults reject the `isOwnMevEscrow` parameter on every chain. @@ -23,7 +23,7 @@ You can retrieve the vault factory contract using the helper function: `sdk.getV | Name | Type | Required | Description | |----------------|------------------------------------|----------|------------------------------------------------------------------------------------------------------------------------------------------------------------| | userAddress | `string` | **Yes** | The address of the user initiating the action. This address will become the vault admin | -| type | `VaultType` | **No** | Allowed vault types: Default, Private and Blocklist. Available vault types can be found in the `enum VaultType` which you can be imported from the library | +| type | `VaultType` | **No** | One of: `Default`, `Private`, `Blocklist`, `MetaVault`, `PrivateMetaVault`. Imported from the library: `import { VaultType } from '@stakewise/v3-sdk'`. Use `MetaVault` / `PrivateMetaVault` to deploy a meta vault that holds a registry of sub-vaults; `PrivateMetaVault` is Mainnet/Hoodi only. | | vaultToken | `{ name: string, symbol: string }` | **No** | If provided, the vault will be created with its own ERC20 token | | capacity | `bigint` | **No** | If provided, should be defined in gwei. By default, capacity is `MaxUint256`; the minimum allowed capacity is `parseEther('32')`| | keysManagerFee | `number` | **No** | If provided, should be between `0` and `100`, inclusive with a maximum of two decimal digits allowed (e.g., `15.35`). By default, the fee is `0`| @@ -32,9 +32,12 @@ You can retrieve the vault factory contract using the helper function: `sdk.getV | displayName | `string` | **No** | The vault display name (will be uploaded to IPFS; maximum size is 30 characters)| | description | `string` | **No** | The vault description (will be uploaded to IPFS; maximum size is 1000 characters)| -#### Example: +#### Example: ERC20 vault on Mainnet ```ts +import { MaxUint256 } from 'ethers' +import { VaultType } from '@stakewise/v3-sdk' + const params = { userAddress: '0x...', type: VaultType.Default, @@ -50,11 +53,127 @@ const params = { description: 'Example description', } -// Transaction example -// Send transaction to create a vault +// Send transaction const hash = await sdk.vault.create(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) -const { data, to, value } = await sdk.vault.deposit.encode(params) +const { data, to, value } = await sdk.vault.create.encode(params) // Get an approximate gas per transaction -const gas = await sdk.vault.deposit.estimateGas(params) +const gas = await sdk.vault.create.estimateGas(params) +``` + +#### Example: non-ERC20 Private vault + +Omit `vaultToken` to deploy a non-ERC20 vault and switch `type` to restrict access: + +```ts +import { VaultType } from '@stakewise/v3-sdk' + +const hash = await sdk.vault.create({ + userAddress: '0x...', + type: VaultType.Private, + isOwnMevEscrow: false, + keysManagerFee: 5, + displayName: 'Private vault', +}) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) +``` + +#### Example: ERC20 vault on Gnosis (with GNO approve) + +On Gnosis the 1 gwei security deposit is GNO, not native xDAI. Approve the vault factory before `sdk.vault.create`: + +```ts +import { MaxUint256 } from 'ethers' +import { VaultType } from '@stakewise/v3-sdk' + +const userAddress = '0x...' +const isErc20 = true + +const factoryAddress = await sdk.vault.getVaultFactory({ + vaultType: VaultType.Default, + isErc20, +}) + +const depositTokenAddress = sdk.config.addresses.tokens.depositToken +const gno = sdk.contracts.helpers.createErc20(depositTokenAddress) +const signer = await sdk.provider.getSigner(userAddress) + +const approveTx = await gno.connect(signer).approve(factoryAddress, MaxUint256) +await approveTx.wait() + +const hash = await sdk.vault.create({ + userAddress, + type: VaultType.Default, + vaultToken: { name: 'Gnosis Vault Share', symbol: 'GVS' }, + isOwnMevEscrow: false, + keysManagerFee: 5, + displayName: 'Gnosis ERC20 vault', +}) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) +``` + +#### Example: meta vault on Gnosis + +On Gnosis a meta vault uses `VaultType.MetaVault` (open) - `PrivateMetaVault` is not supported. Meta vaults do not accept `vaultToken` (no ERC20 share token on Gnosis meta vaults) and never accept `isOwnMevEscrow`. The sub-vaults underneath the meta vault keep their own MEV configuration. + +```ts +import { MaxUint256 } from 'ethers' +import { VaultType } from '@stakewise/v3-sdk' + +const userAddress = '0x...' + +const factoryAddress = await sdk.vault.getVaultFactory({ + vaultType: VaultType.MetaVault, + isErc20: false, +}) + +const depositTokenAddress = sdk.config.addresses.tokens.depositToken +const gno = sdk.contracts.helpers.createErc20(depositTokenAddress) +const signer = await sdk.provider.getSigner(userAddress) + +const approveTx = await gno.connect(signer).approve(factoryAddress, MaxUint256) +await approveTx.wait() + +const hash = await sdk.vault.create({ + userAddress, + type: VaultType.MetaVault, + keysManagerFee: 5, + displayName: 'Gnosis Meta Vault', +}) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) +``` + +After deploying the meta vault, the curator (the `userAddress` above) populates its registry by calling `sdk.vault.addSubVault({ vaultAddress: metaVaultAddress, subVaultAddress, userAddress })` for each sub-vault. + +#### Example: private meta vault on Mainnet + +On Mainnet and Hoodi, `VaultType.PrivateMetaVault` is supported. Mainnet does not require an approve step (the 1 gwei security deposit is native ETH and the SDK attaches it automatically): + +```ts +import { VaultType } from '@stakewise/v3-sdk' + +const hash = await sdk.vault.create({ + userAddress: '0x...', + type: VaultType.PrivateMetaVault, + keysManagerFee: 5, + displayName: 'Private Meta Vault', +}) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) ``` diff --git a/src/services/vault/transactions/deposit/deposit.md b/src/services/vault/transactions/deposit/deposit.md index f33bda5c..d48c6aaf 100644 --- a/src/services/vault/transactions/deposit/deposit.md +++ b/src/services/vault/transactions/deposit/deposit.md @@ -27,6 +27,11 @@ const params = { // Send transaction const hash = await sdk.vault.deposit(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to, value } = await sdk.vault.deposit.encode(params) // Get an approximate gas per transaction diff --git a/src/services/vault/transactions/ejectSubVault/ejectSubVault.md b/src/services/vault/transactions/ejectSubVault/ejectSubVault.md index 1063d460..f609f09e 100644 --- a/src/services/vault/transactions/ejectSubVault/ejectSubVault.md +++ b/src/services/vault/transactions/ejectSubVault/ejectSubVault.md @@ -1,6 +1,7 @@ --- id: ejectSubVault slug: /sdk/api/vault/transactions/ejectsubvault +description: Use the StakeWise SDK ejectSubVault method to remove an active sub-vault from a StakeWise V3 meta vault registry. Called by the meta vault curator to drop an in-use sub-vault from the registry. --- #### Description: @@ -26,6 +27,11 @@ const params = { // Send transaction const hash = await sdk.vault.ejectSubVault(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.vault.ejectSubVault.encode(params) // Get an approximate gas per transaction diff --git a/src/services/vault/transactions/operate/operate.md b/src/services/vault/transactions/operate/operate.md index 69faeaf5..0b651416 100644 --- a/src/services/vault/transactions/operate/operate.md +++ b/src/services/vault/transactions/operate/operate.md @@ -8,6 +8,12 @@ description: Use the StakeWise SDK operate method to update vault settings such Updates the vault by authorized personnel such as the vault admin, whitelistManager, blocklist manager, validators manager. +#### Constraints + +- **One access mode per call.** The vault is either Private (whitelist) or Blocklist, never both. Passing `whitelist` / `whitelistManager` together with `blocklist` / `blocklistManager` in the same call throws an error before sending the transaction. Update one mode at a time. +- **700-address chunk limit.** `whitelist` and `blocklist` arrays are capped at 700 entries per call. Larger lists must be split across multiple sequential transactions; the SDK throws before sending if the limit is exceeded. +- **No vault-type pre-check.** The SDK does not verify that the target vault matches the access mode you are updating. Calling `whitelist` updates on a Default vault reverts at execution. Pre-check the vault type with `sdk.vault.getVault({ vaultAddress })` (`isPrivate`, `isBlocklist`) before calling `operate`. + #### Arguments: | Name | Type | Required | Access | Description | @@ -87,6 +93,11 @@ const blocklistParams = { // Send transaction const hash = await sdk.vault.operate(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.vault.operate.encode(params) // Get an approximate gas per transaction diff --git a/src/services/vault/transactions/rejectSubVault/rejectSubVault.md b/src/services/vault/transactions/rejectSubVault/rejectSubVault.md index 4534e08d..416c053f 100644 --- a/src/services/vault/transactions/rejectSubVault/rejectSubVault.md +++ b/src/services/vault/transactions/rejectSubVault/rejectSubVault.md @@ -1,6 +1,7 @@ --- id: rejectSubVault slug: /sdk/api/vault/transactions/rejectsubvault +description: Use the StakeWise SDK rejectSubVault method to reject a proposed sub-vault from a StakeWise V3 meta vault registry before it becomes active. Called by the meta vault curator to discard a pending sub-vault proposal. --- #### Description: @@ -26,6 +27,11 @@ const params = { // Send transaction const hash = await sdk.vault.rejectSubVault(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.vault.rejectSubVault.encode(params) // Get an approximate gas per transaction diff --git a/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.md b/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.md index 3ecdf0c4..6e913e52 100644 --- a/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.md +++ b/src/services/vault/transactions/setDepositDataManager/setDepositDataManager.md @@ -27,6 +27,11 @@ const params = { // Send transaction const hash = await sdk.vault.setDepositDataManager(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.vault.setDepositDataManager.encode(params) // Get an approximate gas per transaction diff --git a/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.md b/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.md index c389a8df..3deb43e2 100644 --- a/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.md +++ b/src/services/vault/transactions/setDepositDataRoot/setDepositDataRoot.md @@ -27,6 +27,11 @@ const params = { // Send transaction const hash = await sdk.vault.setDepositDataRoot(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.vault.setDepositDataRoot.encode(params) // Get an approximate gas per transaction diff --git a/src/services/vault/transactions/updateState/updateState.md b/src/services/vault/transactions/updateState/updateState.md index 7182f410..8072a0d0 100644 --- a/src/services/vault/transactions/updateState/updateState.md +++ b/src/services/vault/transactions/updateState/updateState.md @@ -1,6 +1,7 @@ --- id: updateState slug: /sdk/api/vault/transactions/updatestate +description: Use the StakeWise SDK updateState method to update the on-chain state of a StakeWise V3 vault before reading state-dependent data or sending a follow-up transaction. Returns an empty hash when the vault is already up to date. --- #### Description: @@ -25,6 +26,13 @@ const params = { // Send transaction // Will return empty string if updateState is not required const hash = await sdk.vault.updateState(params) + +if (hash) { + // Wait for the transaction to be confirmed and indexed + await sdk.provider.waitForTransaction(hash) + await sdk.utils.waitForSubgraph({ hash }) +} + // When you sign transactions on the backend (for custodians) // Will return empty object if updateState is not required const { data, to } = await sdk.vault.updateState.encode(params) diff --git a/src/services/vault/transactions/withdraw/withdraw.md b/src/services/vault/transactions/withdraw/withdraw.md index 01aa4453..0de3ffcb 100644 --- a/src/services/vault/transactions/withdraw/withdraw.md +++ b/src/services/vault/transactions/withdraw/withdraw.md @@ -62,6 +62,11 @@ const params = { // Send transaction const hash = await sdk.vault.withdraw(params) + +// Wait for the transaction to be confirmed and indexed +await sdk.provider.waitForTransaction(hash) +await sdk.utils.waitForSubgraph({ hash }) + // When you sign transactions on the backend (for custodians) const { data, to } = await sdk.vault.withdraw.encode(params) // Get an approximate gas per transaction From 2032beeb63395fae777ef331b54a503da2c933b1 Mon Sep 17 00:00:00 2001 From: MikeDiam Date: Mon, 11 May 2026 09:23:21 +0300 Subject: [PATCH 23/27] [context7] update branch Signed-off-by: MikeDiam --- context7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context7.json b/context7.json index 517a1421..06cf9902 100644 --- a/context7.json +++ b/context7.json @@ -4,7 +4,7 @@ "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": "context7", + "branch": "sub-vaults", "folders": ["documentation", "src/services"], "excludeFolders": [ "scripts", From 8db20ea880d86a4142b2ff3e9b17808ae384df85 Mon Sep 17 00:00:00 2001 From: CAst Date: Wed, 20 May 2026 14:51:42 +0500 Subject: [PATCH 24/27] [small-improves] fixes (#377) --- src/contracts/multicall/{types.d.ts => types.ts} | 6 +++++- src/helpers/configs/gnosis.ts | 1 - .../transactions/claimQueue/{types.d.ts => types.ts} | 0 src/services/boost/transactions/lock/lock.ts | 6 +++++- .../boost/transactions/lock/{types.d.ts => types.ts} | 0 .../boost/transactions/unlock/{types.d.ts => types.ts} | 0 .../upgradeLeverageStrategy/{types.d.ts => types.ts} | 0 .../distributorRewards/transactions/claim/claimGas.ts | 7 +++++-- .../transactions/claim/{types.d.ts => types.ts} | 0 .../osToken/transactions/burn/{types.d.ts => types.ts} | 0 .../osToken/transactions/mint/{types.d.ts => types.ts} | 0 .../transactions/claimRewards/{types.d.ts => types.ts} | 0 .../createRewardSplitter/{types.d.ts => types.ts} | 0 .../transactions/setClaimer/{types.d.ts => types.ts} | 0 .../updateFeeRecipients/{types.d.ts => types.ts} | 0 src/services/utils/index.ts | 9 +++++++++ .../requests/getRewardSplitters/{types.d.ts => types.ts} | 0 .../transactions/addSubVault/{types.d.ts => types.ts} | 0 .../transactions/claimExitQueue/{types.d.ts => types.ts} | 0 .../transactions/createVault/{types.d.ts => types.ts} | 0 .../vault/transactions/deposit/{types.d.ts => types.ts} | 0 .../transactions/ejectSubVault/{types.d.ts => types.ts} | 0 .../vault/transactions/operate/{types.d.ts => types.ts} | 0 .../transactions/rejectSubVault/{types.d.ts => types.ts} | 0 .../setDepositDataManager/{types.d.ts => types.ts} | 0 .../setDepositDataRoot/{types.d.ts => types.ts} | 0 .../transactions/updateState/{types.d.ts => types.ts} | 0 .../transactions/util/check/{types.d.ts => types.ts} | 0 .../vault/transactions/withdraw/{types.d.ts => types.ts} | 0 29 files changed, 24 insertions(+), 5 deletions(-) rename src/contracts/multicall/{types.d.ts => types.ts} (66%) rename src/services/boost/transactions/claimQueue/{types.d.ts => types.ts} (100%) rename src/services/boost/transactions/lock/{types.d.ts => types.ts} (100%) rename src/services/boost/transactions/unlock/{types.d.ts => types.ts} (100%) rename src/services/boost/transactions/upgradeLeverageStrategy/{types.d.ts => types.ts} (100%) rename src/services/distributorRewards/transactions/claim/{types.d.ts => types.ts} (100%) rename src/services/osToken/transactions/burn/{types.d.ts => types.ts} (100%) rename src/services/osToken/transactions/mint/{types.d.ts => types.ts} (100%) rename src/services/rewardSplitter/transactions/claimRewards/{types.d.ts => types.ts} (100%) rename src/services/rewardSplitter/transactions/createRewardSplitter/{types.d.ts => types.ts} (100%) rename src/services/rewardSplitter/transactions/setClaimer/{types.d.ts => types.ts} (100%) rename src/services/rewardSplitter/transactions/updateFeeRecipients/{types.d.ts => types.ts} (100%) rename src/services/vault/requests/getRewardSplitters/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/addSubVault/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/claimExitQueue/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/createVault/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/deposit/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/ejectSubVault/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/operate/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/rejectSubVault/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/setDepositDataManager/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/setDepositDataRoot/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/updateState/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/util/check/{types.d.ts => types.ts} (100%) rename src/services/vault/transactions/withdraw/{types.d.ts => types.ts} (100%) diff --git a/src/contracts/multicall/types.d.ts b/src/contracts/multicall/types.ts similarity index 66% rename from src/contracts/multicall/types.d.ts rename to src/contracts/multicall/types.ts index ab5fe131..76ee7ee1 100644 --- a/src/contracts/multicall/types.d.ts +++ b/src/contracts/multicall/types.ts @@ -13,4 +13,8 @@ export type MulticallRequestInput = { transactionData?: boolean } -export type ContractAbi = ReturnType | RewardSplitterAbi | EigenPodOwnerAbi | LeverageStrategyAbi +export type ContractAbi = + | ReturnType + | RewardSplitterAbi + | EigenPodOwnerAbi + | LeverageStrategyAbi diff --git a/src/helpers/configs/gnosis.ts b/src/helpers/configs/gnosis.ts index d50dee09..34227085 100644 --- a/src/helpers/configs/gnosis.ts +++ b/src/helpers/configs/gnosis.ts @@ -54,7 +54,6 @@ export default { erc20PrivateMetavault: ZeroAddress, }, special: { - balancedCurator: '0xD30E7e4bDbd396cfBe72Ad2f4856769C54eA6b0b', stakeCalculator: '0x2A415b65207049AC7481BF69ff9fc1B3Def97c9A', leverageStrategy: ZeroAddress, leverageStrategyV2: ZeroAddress, diff --git a/src/services/boost/transactions/claimQueue/types.d.ts b/src/services/boost/transactions/claimQueue/types.ts similarity index 100% rename from src/services/boost/transactions/claimQueue/types.d.ts rename to src/services/boost/transactions/claimQueue/types.ts diff --git a/src/services/boost/transactions/lock/lock.ts b/src/services/boost/transactions/lock/lock.ts index b401c00f..4f9855cd 100644 --- a/src/services/boost/transactions/lock/lock.ts +++ b/src/services/boost/transactions/lock/lock.ts @@ -1,5 +1,6 @@ import { commonLogic } from './common' import type { LockInput } from './types' +import { wrapErrorHandler } from '../../../../helpers' import { boostMulticall } from '../../../../contracts' import upgradeLeverageStrategy from '../upgradeLeverageStrategy/upgradeLeverageStrategy' @@ -17,7 +18,10 @@ const lock = async (values: LockInput) => { const signer = await provider.getSigner(userAddress) const signedContract = multiSigData.contract.connect(signer) - const { hash } = await signedContract.approve(...multiSigData.approveArgs) + const { hash } = await wrapErrorHandler( + signedContract.approve(...multiSigData.approveArgs), + 'transaction' + ) await provider.waitForTransaction(hash) } diff --git a/src/services/boost/transactions/lock/types.d.ts b/src/services/boost/transactions/lock/types.ts similarity index 100% rename from src/services/boost/transactions/lock/types.d.ts rename to src/services/boost/transactions/lock/types.ts diff --git a/src/services/boost/transactions/unlock/types.d.ts b/src/services/boost/transactions/unlock/types.ts similarity index 100% rename from src/services/boost/transactions/unlock/types.d.ts rename to src/services/boost/transactions/unlock/types.ts diff --git a/src/services/boost/transactions/upgradeLeverageStrategy/types.d.ts b/src/services/boost/transactions/upgradeLeverageStrategy/types.ts similarity index 100% rename from src/services/boost/transactions/upgradeLeverageStrategy/types.d.ts rename to src/services/boost/transactions/upgradeLeverageStrategy/types.ts diff --git a/src/services/distributorRewards/transactions/claim/claimGas.ts b/src/services/distributorRewards/transactions/claim/claimGas.ts index 6224f6b7..be4d9ef7 100644 --- a/src/services/distributorRewards/transactions/claim/claimGas.ts +++ b/src/services/distributorRewards/transactions/claim/claimGas.ts @@ -1,6 +1,6 @@ import { commonLogic } from './common' -import { getGas } from '../../../../helpers' import type { ClaimInput } from './types' +import { getGas, wrapErrorHandler } from '../../../../helpers' const claimGas = async (values: ClaimInput) => { @@ -8,7 +8,10 @@ const claimGas = async (values: ClaimInput) => { const { merkleDistributorV2, params } = await commonLogic(values) - const estimatedGas = await merkleDistributorV2.claim.estimateGas(...params) + const estimatedGas = await wrapErrorHandler( + merkleDistributorV2.claim.estimateGas(...params), + 'gas' + ) return getGas({ estimatedGas, provider }) } diff --git a/src/services/distributorRewards/transactions/claim/types.d.ts b/src/services/distributorRewards/transactions/claim/types.ts similarity index 100% rename from src/services/distributorRewards/transactions/claim/types.d.ts rename to src/services/distributorRewards/transactions/claim/types.ts diff --git a/src/services/osToken/transactions/burn/types.d.ts b/src/services/osToken/transactions/burn/types.ts similarity index 100% rename from src/services/osToken/transactions/burn/types.d.ts rename to src/services/osToken/transactions/burn/types.ts diff --git a/src/services/osToken/transactions/mint/types.d.ts b/src/services/osToken/transactions/mint/types.ts similarity index 100% rename from src/services/osToken/transactions/mint/types.d.ts rename to src/services/osToken/transactions/mint/types.ts diff --git a/src/services/rewardSplitter/transactions/claimRewards/types.d.ts b/src/services/rewardSplitter/transactions/claimRewards/types.ts similarity index 100% rename from src/services/rewardSplitter/transactions/claimRewards/types.d.ts rename to src/services/rewardSplitter/transactions/claimRewards/types.ts diff --git a/src/services/rewardSplitter/transactions/createRewardSplitter/types.d.ts b/src/services/rewardSplitter/transactions/createRewardSplitter/types.ts similarity index 100% rename from src/services/rewardSplitter/transactions/createRewardSplitter/types.d.ts rename to src/services/rewardSplitter/transactions/createRewardSplitter/types.ts diff --git a/src/services/rewardSplitter/transactions/setClaimer/types.d.ts b/src/services/rewardSplitter/transactions/setClaimer/types.ts similarity index 100% rename from src/services/rewardSplitter/transactions/setClaimer/types.d.ts rename to src/services/rewardSplitter/transactions/setClaimer/types.ts diff --git a/src/services/rewardSplitter/transactions/updateFeeRecipients/types.d.ts b/src/services/rewardSplitter/transactions/updateFeeRecipients/types.ts similarity index 100% rename from src/services/rewardSplitter/transactions/updateFeeRecipients/types.d.ts rename to src/services/rewardSplitter/transactions/updateFeeRecipients/types.ts diff --git a/src/services/utils/index.ts b/src/services/utils/index.ts index f70cff6d..8c75bb7c 100644 --- a/src/services/utils/index.ts +++ b/src/services/utils/index.ts @@ -64,14 +64,23 @@ class Utils { return getPermitSignature({ ...this.params, ...values }) } + /** + * @description Estimate gas for a custom vault multicall (auto-injects `updateState` when needed). + */ public getVaultMulticallGas(values: StakeWise.ExtractInput) { return getVaultMulticallGas({ ...this.params, ...values }) } + /** + * @description Build `{ skip, limit, orderBy, orderDirection }` variables for paginated subgraph list queries. + */ public getListVariables(values: StakeWise.ExtractInput) { return getListVariables({ ...this.params, ...values }) } + /** + * @description Get encoded calldata (`{ data, to }`) for a custom vault multicall — for custodial signing flows. + */ public getVaultMulticallEncode(values: StakeWise.ExtractInput) { return getVaultMulticallEncode({ ...this.params, ...values }) } diff --git a/src/services/vault/requests/getRewardSplitters/types.d.ts b/src/services/vault/requests/getRewardSplitters/types.ts similarity index 100% rename from src/services/vault/requests/getRewardSplitters/types.d.ts rename to src/services/vault/requests/getRewardSplitters/types.ts diff --git a/src/services/vault/transactions/addSubVault/types.d.ts b/src/services/vault/transactions/addSubVault/types.ts similarity index 100% rename from src/services/vault/transactions/addSubVault/types.d.ts rename to src/services/vault/transactions/addSubVault/types.ts diff --git a/src/services/vault/transactions/claimExitQueue/types.d.ts b/src/services/vault/transactions/claimExitQueue/types.ts similarity index 100% rename from src/services/vault/transactions/claimExitQueue/types.d.ts rename to src/services/vault/transactions/claimExitQueue/types.ts diff --git a/src/services/vault/transactions/createVault/types.d.ts b/src/services/vault/transactions/createVault/types.ts similarity index 100% rename from src/services/vault/transactions/createVault/types.d.ts rename to src/services/vault/transactions/createVault/types.ts diff --git a/src/services/vault/transactions/deposit/types.d.ts b/src/services/vault/transactions/deposit/types.ts similarity index 100% rename from src/services/vault/transactions/deposit/types.d.ts rename to src/services/vault/transactions/deposit/types.ts diff --git a/src/services/vault/transactions/ejectSubVault/types.d.ts b/src/services/vault/transactions/ejectSubVault/types.ts similarity index 100% rename from src/services/vault/transactions/ejectSubVault/types.d.ts rename to src/services/vault/transactions/ejectSubVault/types.ts diff --git a/src/services/vault/transactions/operate/types.d.ts b/src/services/vault/transactions/operate/types.ts similarity index 100% rename from src/services/vault/transactions/operate/types.d.ts rename to src/services/vault/transactions/operate/types.ts diff --git a/src/services/vault/transactions/rejectSubVault/types.d.ts b/src/services/vault/transactions/rejectSubVault/types.ts similarity index 100% rename from src/services/vault/transactions/rejectSubVault/types.d.ts rename to src/services/vault/transactions/rejectSubVault/types.ts diff --git a/src/services/vault/transactions/setDepositDataManager/types.d.ts b/src/services/vault/transactions/setDepositDataManager/types.ts similarity index 100% rename from src/services/vault/transactions/setDepositDataManager/types.d.ts rename to src/services/vault/transactions/setDepositDataManager/types.ts diff --git a/src/services/vault/transactions/setDepositDataRoot/types.d.ts b/src/services/vault/transactions/setDepositDataRoot/types.ts similarity index 100% rename from src/services/vault/transactions/setDepositDataRoot/types.d.ts rename to src/services/vault/transactions/setDepositDataRoot/types.ts diff --git a/src/services/vault/transactions/updateState/types.d.ts b/src/services/vault/transactions/updateState/types.ts similarity index 100% rename from src/services/vault/transactions/updateState/types.d.ts rename to src/services/vault/transactions/updateState/types.ts diff --git a/src/services/vault/transactions/util/check/types.d.ts b/src/services/vault/transactions/util/check/types.ts similarity index 100% rename from src/services/vault/transactions/util/check/types.d.ts rename to src/services/vault/transactions/util/check/types.ts diff --git a/src/services/vault/transactions/withdraw/types.d.ts b/src/services/vault/transactions/withdraw/types.ts similarity index 100% rename from src/services/vault/transactions/withdraw/types.d.ts rename to src/services/vault/transactions/withdraw/types.ts From 982a1f3efef6a0516428d9dee0234c299adf5d60 Mon Sep 17 00:00:00 2001 From: CAst Date: Thu, 21 May 2026 14:59:30 +0500 Subject: [PATCH 25/27] Merge main 2 (#379) * Remove sync docs git action (#354) * [remove-sync-docs] remove git action and change script * change git action * update GitHub Actions to use latest checkout and cache actions (#356) Co-authored-by: github-actions[bot] * Add script to check documentation links (#357) * add script to check documentation links * fix after review * rename documentation files and improve slug validation in checkDocLinks * add category configuration for Quick Start * improve slug processing and include _category_.json in documentation file search * 4.2.3 (#358) * [fix-encode] fix transactionWrapper (#360) * up-version (#361) * [handle-429] add retry-after header support (#364) * add context7 public key (#370) * [publish] add yml (#372) * up version (#373) * up version * remove check version * only main branch (#375) * improve-docs-check * fix --------- Co-authored-by: Kadyr Dzhemaledinov Co-authored-by: github-actions[bot] --- .github/workflows/publish.yml | 68 +++++++++++++++++++++++++++++++++++ package.json | 9 +++-- scripts/checkDocLinks.js | 2 +- scripts/checkVersion.js | 20 ----------- 4 files changed, 75 insertions(+), 24 deletions(-) create mode 100644 .github/workflows/publish.yml delete mode 100644 scripts/checkVersion.js diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..e8e04470 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,68 @@ +name: Publish to npm + +on: + push: + tags: + - '[0-9]+.[0-9]+.[0-9]+' + +permissions: {} + +jobs: + publish: + name: Publish + runs-on: ubuntu-latest + environment: + name: npm-publish + url: https://www.npmjs.com/package/@stakewise/v3-sdk + permissions: + contents: read + id-token: write + steps: + - name: Checkout code + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd + with: + persist-credentials: false + + - name: Setup pnpm + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 + with: + version: 10.25.0 + + - name: Setup Node + uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f + with: + cache: pnpm + node-version: '24.12.0' + registry-url: 'https://registry.npmjs.org' + cache-dependency-path: pnpm-lock.yaml + + - name: Verify tag matches package.json version + run: | + PKG_VERSION=$(node -p "require('./package.json').version") + if [ "$GITHUB_REF_NAME" != "$PKG_VERSION" ]; then + echo "::error::Tag $GITHUB_REF_NAME does not match package.json version $PKG_VERSION" + exit 1 + fi + + - name: Verify tag is on main + run: | + git fetch origin main --depth=1 + if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then + echo "::error::Tag $GITHUB_REF_NAME points to commit $GITHUB_SHA which is not on main branch" + exit 1 + fi + + - name: Install dependencies + run: pnpm install --frozen-lockfile --ignore-scripts + + - name: Generate typechain & graphql artifacts + run: pnpm typechain && pnpm graphql + + - name: Run unit tests + run: pnpm test + + - name: Build + run: rm -rf ./dist && pnpm rollup + + - name: Publish to npm with provenance + run: npm publish --provenance --access public --ignore-scripts --tag latest diff --git a/package.json b/package.json index def31329..1cb37a13 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "type": "module", - "version": "4.2.4", + "version": "4.2.5", "sideEffects": false, "main": "dist/index.js", "types": "dist/index.d.ts", @@ -10,16 +10,19 @@ "module": "dist/index.esm.js", "description": "StakeWise v3 SDK", "homepage": "https://github.com/stakewise/v3-sdk", + "repository": { + "type": "git", + "url": "git+https://github.com/stakewise/v3-sdk.git" + }, "scripts": { "test": "jest --clearCache && jest --all", - "prepare": "husky && pnpm typechain && pnpm graphql && pnpm check:version", + "prepare": "husky && pnpm typechain && pnpm graphql", "build": "pnpm test && pnpm prepare && rm -rf ./dist && pnpm rollup", "typechain:vault": "typechain --target ethers-v6 --out-dir src/contracts/vault/types 'src/contracts/vault/abis/*.json'", "typechain:base": "typechain --target ethers-v6 --out-dir src/contracts/types 'src/contracts/abis/*.json'", "typechain": "pnpm typechain:base && pnpm typechain:vault", "graphql": "graphql-codegen && tsx ./scripts/generateGraphqlExports/index.ts", "rollup": "rollup --config rollup.config.js", - "check:version": "node ./scripts/checkVersion.js", "check:docLinks": "node ./scripts/checkDocLinks.js", "lint": "eslint ./src --ext .ts,.tsx,.js,.jsx", "release": "pnpm build && pnpm publish --tag=latest", diff --git a/scripts/checkDocLinks.js b/scripts/checkDocLinks.js index 61bbdce9..d78af142 100644 --- a/scripts/checkDocLinks.js +++ b/scripts/checkDocLinks.js @@ -71,7 +71,7 @@ const getUrls = () => { const output = execSync( `grep -roh "https://docs\\.stakewise\\.io/[^\\"' )\\\`>]*" "${rootDir}" ` + '--include="*.ts" --include="*.tsx" --include="*.md" --include="*.mdx" ' - + '--exclude-dir=node_modules', + + '--exclude-dir=node_modules --exclude-dir=dist', { encoding: 'utf-8' } ) diff --git a/scripts/checkVersion.js b/scripts/checkVersion.js deleted file mode 100644 index d1750f0f..00000000 --- a/scripts/checkVersion.js +++ /dev/null @@ -1,20 +0,0 @@ -import { execSync } from 'child_process' -import pkg from '../package.json' with { type: 'json' } - - -const check = async () => { - const npmVersion = pkg.version - const releaseVersion = execSync(`git ls-remote https://github.com/stakewise/v3-sdk refs/tags/${npmVersion}`, { encoding: 'utf8' }) - .replace(/.*\//, '') - .trim() - - if (npmVersion !== releaseVersion || !releaseVersion) { - console.error(`Please add ${npmVersion} release to Github https://github.com/stakewise/v3-sdk/releases/new`) - process.exit(1) - } - else { - process.exit(0) - } -} - -check() From 8d89cd8b46d11eda4a12e718af6241a3d6bc652f Mon Sep 17 00:00:00 2001 From: Kadyr Dzhemaledinov Date: Thu, 21 May 2026 15:22:57 +0300 Subject: [PATCH 26/27] Merge main (#380) * Remove sync docs git action (#354) * [remove-sync-docs] remove git action and change script * change git action * update GitHub Actions to use latest checkout and cache actions (#356) Co-authored-by: github-actions[bot] * Add script to check documentation links (#357) * add script to check documentation links * fix after review * rename documentation files and improve slug validation in checkDocLinks * add category configuration for Quick Start * improve slug processing and include _category_.json in documentation file search * 4.2.3 (#358) * [fix-encode] fix transactionWrapper (#360) * up-version (#361) * [handle-429] add retry-after header support (#364) * add context7 public key (#370) * [publish] add yml (#372) * up version (#373) * up version * remove check version * only main branch (#375) --------- Co-authored-by: CAst Co-authored-by: github-actions[bot] --- context7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context7.json b/context7.json index 06cf9902..420bb794 100644 --- a/context7.json +++ b/context7.json @@ -4,7 +4,7 @@ "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": "sub-vaults", + "branch": "main", "folders": ["documentation", "src/services"], "excludeFolders": [ "scripts", From 3d6d8dd1a79732adc64b8f10bb8e2a4a4b983900 Mon Sep 17 00:00:00 2001 From: Kadyr Dzhemaledinov Date: Thu, 21 May 2026 15:51:27 +0300 Subject: [PATCH 27/27] New merge 1 (#382) * Remove sync docs git action (#354) * [remove-sync-docs] remove git action and change script * change git action * update GitHub Actions to use latest checkout and cache actions (#356) Co-authored-by: github-actions[bot] * Add script to check documentation links (#357) * add script to check documentation links * fix after review * rename documentation files and improve slug validation in checkDocLinks * add category configuration for Quick Start * improve slug processing and include _category_.json in documentation file search * 4.2.3 (#358) * [fix-encode] fix transactionWrapper (#360) * up-version (#361) * [handle-429] add retry-after header support (#364) * add context7 public key (#370) * [publish] add yml (#372) * up version (#373) * up version * remove check version * only main branch (#375) --------- Co-authored-by: CAst Co-authored-by: github-actions[bot]