diff --git a/.graphqlconfig b/.graphqlconfig index b69777b2..24ac2b47 100644 --- a/.graphqlconfig +++ b/.graphqlconfig @@ -11,7 +11,7 @@ "extensions": { "endpoints": { "Subgraph GraphQL": { - "url": "https://graph-testnet.stakewise.io/subgraphs/name/stakewise/stakewise", + "url": "https://holesky-graph.stakewise.io/subgraphs/name/stakewise/stakewise/graphql", "headers": { "user-agent": "JS GraphQL" }, diff --git a/README.md b/README.md index 24f55af7..bcc8e2ba 100644 --- a/README.md +++ b/README.md @@ -84,17 +84,19 @@ const sdk = new StakeWiseSDK({ network: Network.Mainnet }) ## Quick Links ##### Request table: -| **Vault** | **osToken** | **Utils** | -|------|-------------|------| -| [sdk.vault.getStakerActions](#sdkvaultgetstakeractions) | [sdk.osToken.getBurnAmount](#sdkostokengetburnamount) | [sdk.utils.getSwiseUsdPrice](#sdkutilsgetswiseusdprice) | -| [sdk.vault.getSnapshots](#sdkvaultgetsnapshots) | [sdk.osToken.getHealthFactor](#sdkostokengethealthfactor) | [sdk.utils.getTransactions](#sdkutilsgettransactions) | +| **Vault** | **osToken** | **Utils** | +|-------------------------------------------------------------------|-------------|------| +| [sdk.vault.getStakerActions](#sdkvaultgetstakeractions) | [sdk.osToken.getBurnAmount](#sdkostokengetburnamount) | [sdk.utils.getSwiseUsdPrice](#sdkutilsgetswiseusdprice) | +| [sdk.vault.getSnapshots](#sdkvaultgetsnapshots) | [sdk.osToken.getHealthFactor](#sdkostokengethealthfactor) | [sdk.utils.getTransactions](#sdkutilsgettransactions) | | [sdk.vault.getExitQueuePositions](#sdkvaultgetexitqueuepositions) | [sdk.osToken.getAPY](#sdkostokengetapy) | -| [sdk.vault.getValidators](#sdkvaultgetvalidators) | [sdk.osToken.getPosition](#sdkostokengetposition) | -| [sdk.vault.getVault](#sdkvaultgetvault) | [sdk.osToken.getMaxMint](#sdkostokengetmaxmint) | -| [sdk.vault.getMaxWithdraw](#sdkvaultgetmaxwithdraw) | [sdk.osToken.getBaseData](#sdkostokengetbasedata) | -| [sdk.vault.getHarvestParams](#sdkvaultgetharvestparams) | [sdk.osToken.getSharesFromAssets](#sdkostokengetsharesfromassets) | -| [sdk.vault.getStakeBalance](#sdkvaultgetstakebalance) | [sdk.osToken.getAssetsFromShares](#sdkostokengetassetsfromshares) | -|[sdk.vault.getUserRewards](#sdkvaultgetuserrewards) | [sdk.vault.getScorePercentiles](#sdkvaultgetscorepercentiles) +| [sdk.vault.getValidators](#sdkvaultgetvalidators) | [sdk.osToken.getPosition](#sdkostokengetposition) | +| [sdk.vault.getVault](#sdkvaultgetvault) | [sdk.osToken.getMaxMint](#sdkostokengetmaxmint) | +| [sdk.vault.getMaxWithdraw](#sdkvaultgetmaxwithdraw) | [sdk.osToken.getBaseData](#sdkostokengetbasedata) | +| [sdk.vault.getHarvestParams](#sdkvaultgetharvestparams) | [sdk.osToken.getSharesFromAssets](#sdkostokengetsharesfromassets) | +| [sdk.vault.getStakeBalance](#sdkvaultgetstakebalance) | [sdk.osToken.getAssetsFromShares](#sdkostokengetassetsfromshares) | +| [sdk.vault.getUserRewards](#sdkvaultgetuserrewards) | [sdk.vault.getScorePercentiles](#sdkvaultgetscorepercentiles) +| [sdk.vault.getWhitelist](#sdkvaultgetwhitelist) +| [sdk.vault.getBlocklist](#sdkvaultgetblocklist) ##### Table of transactions: | **Vault** | **osToken** | @@ -283,6 +285,90 @@ await sdk.vault.getUserRewards({ }) ``` --- +### `sdk.vault.getWhitelist` + +#### Description: + +Fetch the whitelist for private vaults. Only addresses included in this list are eligible to stake in the private vault. The number of addresses in this list is indicated by the vault whitelistCount field. + + +#### Arguments: + +| Name | Type | Type | Description | +|------|-------------------|-------------|---| +| vaultAddress | `string` | **Require** | - | +| orderDirection | `'asc' \| 'desc'` | **Optional** | Sort, by default `desc` (descending order) | +| search | `string` | **Optional** | Filters results by the address field | +| limit | `number` | **Optional** | Limit the number of addresses, default is 100 | +| skip | `number` | **Optional** | Skip the number of addresses, default is 0 | + +#### Returns: + +```ts +type List = { + createdAt: number + address: string +} + +type Output = { + whitelist: List[] +} +``` + +| Name | Description | +|------|-------------| +| `whitelist` | An array of objects representing the result of the query based on your parameters | + +#### Example: + +```ts +await sdk.vault.getWhitelist({ + vaultAddress: '0x...', +}) +``` +--- +### `sdk.vault.getBlocklist` + +#### Description: + +Fetch the blocklist for blocklisted vaults. Addresses included in this list are not eligible to stake in the blocklisted vault. The number of addresses in this list is indicated by the vault blocklistCount field. + + +#### Arguments: + +| Name | Type | Type | Description | +|------|---------------|-------------|---| +| vaultAddress | `string` | **Require** | - | +| orderDirection | `'asc' \| 'desc'` | **Optional** | Sort, by default `desc` (descending order) | +| search | `string` | **Optional** | Filters results by the address field | +| limit | `number` | **Optional** | Limit the number of addresses, default is 100 | +| skip | `number` | **Optional** | Skip the number of addresses, default is 0 | + +#### Returns: + +```ts +type List = { + createdAt: number + address: string +} + +type Output = { + blocklist: List[] +} +``` + +| Name | Description | +|------|-------------| +| `blocklist` | An array of objects representing the result of the query based on your parameters | + +#### Example: + +```ts +await sdk.vault.getBlocklist({ + vaultAddress: '0x...', +}) +``` +--- ### `sdk.vault.getExitQueuePositions` #### Description: @@ -399,6 +485,8 @@ type Output = { whitelister: string vaultAddress: string mevRecipient: string + whitelistCount: number + blocklistCount: number imageUrl: string | null blocklistManager: string vaultKeysManager: string @@ -407,44 +495,38 @@ type Output = { tokenSymbol: string | null displayName: string | null description: string | null - whitelist: Array<{ - createdAt: number - address: string - }> | null - blocklist: Array<{ - createdAt: number - address: string - }> | null performance: number } ``` -| Name | Description | -|--------------------|-----------------------------------------| -| `apy` | Current vault apy | -| `isErc20` | Does the vault have its own ERC20 token | -| `capacity` | Maximum TVL of Vault | -| `createdAt` | Date of Creation | -| `feePercent` | Commission rate | -| `isPrivate` | Whether the storage is private | -| `isBlocklist` | Whether the storage has blocklist | -| `vaultAdmin` | Vault administrator address | -| `totalAssets` | TVL of Vault | -| `feeRecipient` | Vault fee address | -| `whitelister` | Whitelist manager | -| `vaultAddress` | Address of vault | -| `mevRecipient` | Validator fee recipient | -| `imageUrl` | Link for vault logo | -| `blocklistManager` | Blocklist manager | -| `vaultKeysManager` | Keys manager address | -| `isSmoothingPool` | Smoothing poll or Vault escrow | -| `tokenName` | ERC20 token name | -| `tokenSymbol` | ERC20 token symbol | -| `displayName` | Name of vault | -| `description` | Description of vault | -| `whitelist` | List of authorized users for deposits | -| `blocklist` | List of blocked users for deposits | -| `performance` | Vault performance indicator (percent) | +| Name | Description | +|--------------------|---------------------------------------------------------------| +| `apy` | Current vault apy | +| `isErc20` | Does the vault have its own ERC20 token | +| `capacity` | Maximum TVL of Vault | +| `createdAt` | Date of Creation | +| `feePercent` | Commission rate | +| `isPrivate` | Whether the storage is private | +| `isBlocklist` | Whether the storage has blocklist | +| `vaultAdmin` | Vault administrator address | +| `totalAssets` | TVL of Vault | +| `feeRecipient` | Vault fee address | +| `whitelister` | Whitelist manager | +| `vaultAddress` | Address of vault | +| `mevRecipient` | Validator fee recipient | +| `whitelistCount` | Number of addresses in the [whitelist](#sdkvaultgetwhitelist) | +| `blocklistCount` | Number of addresses in the [blocklist](#sdkvaultgetblocklist) | +| `imageUrl` | Link for vault logo | +| `blocklistManager` | Blocklist manager | +| `vaultKeysManager` | Keys manager address | +| `isSmoothingPool` | Smoothing poll or Vault escrow | +| `tokenName` | ERC20 token name | +| `tokenSymbol` | ERC20 token symbol | +| `displayName` | Name of vault | +| `description` | Description of vault | +| `whitelist` | List of authorized users for deposits | +| `blocklist` | List of blocked users for deposits | +| `performance` | Vault performance indicator (percent) | #### Example: diff --git a/src/graphql/subgraph/vault/blocklistAccountsQuery.graphql b/src/graphql/subgraph/vault/blocklistAccountsQuery.graphql new file mode 100644 index 00000000..10584a29 --- /dev/null +++ b/src/graphql/subgraph/vault/blocklistAccountsQuery.graphql @@ -0,0 +1,6 @@ +query BlocklistAccounts($where: VaultBlockedAccount_filter, $limit: Int, $skip: Int, $orderDirection: OrderDirection) { + vaultBlockedAccounts(where: $where, first: $limit, skip: $skip, orderDirection: $orderDirection, orderBy: createdAt) { + createdAt + address + } +} diff --git a/src/graphql/subgraph/vault/index.ts b/src/graphql/subgraph/vault/index.ts index 47edabe5..77ef49f7 100644 --- a/src/graphql/subgraph/vault/index.ts +++ b/src/graphql/subgraph/vault/index.ts @@ -3,3 +3,9 @@ export type { VaultQueryPayload, VaultQueryVariables } from './vaultQuery.graphq export { fetchHarvestParamsQuery } from './harvestParamsQuery.graphql' export type { HarvestParamsQueryPayload, HarvestParamsQueryVariables } from './harvestParamsQuery.graphql' + +export { fetchWhitelistAccountsQuery } from './whitelistAccountsQuery.graphql' +export type { WhitelistAccountsQueryPayload, WhitelistAccountsQueryVariables } from './whitelistAccountsQuery.graphql' + +export { fetchBlocklistAccountsQuery } from './blocklistAccountsQuery.graphql' +export type { BlocklistAccountsQueryPayload, BlocklistAccountsQueryVariables } from './blocklistAccountsQuery.graphql' diff --git a/src/graphql/subgraph/vault/vaultQuery.graphql b/src/graphql/subgraph/vault/vaultQuery.graphql index 7226ab33..35d86c98 100644 --- a/src/graphql/subgraph/vault/vaultQuery.graphql +++ b/src/graphql/subgraph/vault/vaultQuery.graphql @@ -23,13 +23,7 @@ query Vault($address: ID!) { validatorsRoot blocklistManager weeklyApy - } - privateVaultAccounts(where: { vault: $address }, first: 1000) { - createdAt - address - } - vaultBlockedAccounts(where: { vault: $address }, first: 1000) { - createdAt - address + blocklistCount + whitelistCount } } diff --git a/src/graphql/subgraph/vault/whitelistAccountsQuery.graphql b/src/graphql/subgraph/vault/whitelistAccountsQuery.graphql new file mode 100644 index 00000000..e7a0e5b1 --- /dev/null +++ b/src/graphql/subgraph/vault/whitelistAccountsQuery.graphql @@ -0,0 +1,6 @@ +query WhitelistAccounts($where: PrivateVaultAccount_filter, $limit: Int, $skip: Int, $orderDirection: OrderDirection) { + privateVaultAccounts(where: $where, first: $limit, skip: $skip, orderDirection: $orderDirection, orderBy: createdAt) { + createdAt + address + } +} diff --git a/src/methods/vault/index.ts b/src/methods/vault/index.ts index 1faef0fc..5d7dc01d 100644 --- a/src/methods/vault/index.ts +++ b/src/methods/vault/index.ts @@ -1,6 +1,8 @@ // Requests import getVault from './requests/getVault' import getSnapshots from './requests/getSnapshots' +import getWhitelist from './requests/getWhitelist' +import getBlocklist from './requests/getBlocklist' import getValidators from './requests/getValidators' import getUserRewards from './requests/getUserRewards' import getMaxWithdraw from './requests/getMaxWithdraw' @@ -27,6 +29,8 @@ export default { getMaxWithdraw, getValidators, getSnapshots, + getWhitelist, + getBlocklist, getVault, }, transactions: { diff --git a/src/methods/vault/requests/getBlocklist/index.ts b/src/methods/vault/requests/getBlocklist/index.ts new file mode 100644 index 00000000..6772ba27 --- /dev/null +++ b/src/methods/vault/requests/getBlocklist/index.ts @@ -0,0 +1,66 @@ +import type { BlocklistAccountsQueryVariables, BlocklistAccountsQueryPayload } from '../../../../graphql/subgraph/vault' +import { apiUrls, validateArgs } from '../../../../utils' +import graphql from '../../../../graphql' +import { ModifiedBlocklist } from './types' +import modifyBlocklist from './modifyBlocklist' + + +type GetBlocklistInput = { + vaultAddress: string + orderDirection?: BlocklistAccountsQueryVariables['orderDirection'] + search?: string + limit?: number + skip?: number + options: StakeWise.Options +} + +type GetBlocklistOutput = { + blocklist: { + createdAt: number + address: string + }[] +} + +const getBlocklist = async (input: GetBlocklistInput): Promise => { + const { vaultAddress, orderDirection, search, limit, skip, options } = input + + validateArgs.address({ vaultAddress }) + + if (typeof skip !== 'undefined') { + validateArgs.number({ skip }) + } + + if (typeof limit !== 'undefined') { + validateArgs.number({ limit }) + } + + if (typeof search !== 'undefined') { + validateArgs.string({ search }) + } + + if (typeof orderDirection !== 'undefined') { + if (![ 'asc', 'desc' ].includes(orderDirection)) { + throw new Error(`The "orderDirection" argument must be "asc" or "desc"`) + } + } + + const vault = vaultAddress.toLowerCase() + + const where = search + ? { vault, address_contains: search.toLowerCase() } as BlocklistAccountsQueryVariables['where'] + : { vault } as BlocklistAccountsQueryVariables['where'] + + return graphql.subgraph.vault.fetchBlocklistAccountsQuery({ + url: apiUrls.getSubgraphqlUrl(options), + variables: { + where, + skip: skip || 0, + limit: limit || 100, + orderDirection: orderDirection || 'desc', + }, + modifyResult: (data: BlocklistAccountsQueryPayload) => modifyBlocklist({ data }), + }) +} + + +export default getBlocklist diff --git a/src/methods/vault/requests/getBlocklist/modifyBlocklist.spec.ts b/src/methods/vault/requests/getBlocklist/modifyBlocklist.spec.ts new file mode 100644 index 00000000..2c1e93cd --- /dev/null +++ b/src/methods/vault/requests/getBlocklist/modifyBlocklist.spec.ts @@ -0,0 +1,43 @@ +import modifyBlocklist from './modifyBlocklist' +import type { BlocklistAccountsQueryPayload } from '../../../../graphql/subgraph/vault' + + +describe('modifyBlocklist', () => { + const mockBlocklistQueryPayload: BlocklistAccountsQueryPayload = { + vaultBlockedAccounts: [ + { createdAt: '1693395816', address: '0xeefffd4c23d2e8c845870e273861e7d60df49663' }, + { createdAt: '1693395816', address: '0xeefffd4c23d2e8c845870e273861e7d60df49663' }, + ], + } + + it('should correctly transform the whitelist data', () => { + const expectedModifiedVault = [ + { + createdAt: 1693395816000, + address: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', + }, + { + createdAt: 1693395816000, + address: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', + }, + ] + + const result = modifyBlocklist({ + data: mockBlocklistQueryPayload, + }) + + expect(result).toEqual(expectedModifiedVault) + }) + + it('should handle empty privateVaultAccounts correctly', () => { + const mockDataWithoutBlockedAccounts: BlocklistAccountsQueryPayload = { + vaultBlockedAccounts: [], + } + + const result = modifyBlocklist({ + data: mockDataWithoutBlockedAccounts, + }) + + expect(result).toEqual([]) + }) +}) diff --git a/src/methods/vault/requests/getBlocklist/modifyBlocklist.ts b/src/methods/vault/requests/getBlocklist/modifyBlocklist.ts new file mode 100644 index 00000000..bdbbec9b --- /dev/null +++ b/src/methods/vault/requests/getBlocklist/modifyBlocklist.ts @@ -0,0 +1,26 @@ +import { getAddress } from 'ethers' + +import { ModifiedBlocklist } from './types' +import type { BlocklistAccountsQueryPayload } from '../../../../graphql/subgraph/vault' + + +type ModifyBlocklistInput = { + data: BlocklistAccountsQueryPayload +} + +const modifyAddress = ({ createdAt, address }: { createdAt: string, address: string }) => ({ + createdAt: Number(createdAt) * 1000, + address: getAddress(address), +}) + +const modifyBlocklist = (input: ModifyBlocklistInput): ModifiedBlocklist => { + const { data } = input + const { vaultBlockedAccounts } = data + + return { + blocklist: vaultBlockedAccounts.map(modifyAddress), + } +} + + +export default modifyBlocklist diff --git a/src/methods/vault/requests/getBlocklist/types.ts b/src/methods/vault/requests/getBlocklist/types.ts new file mode 100644 index 00000000..15e30734 --- /dev/null +++ b/src/methods/vault/requests/getBlocklist/types.ts @@ -0,0 +1,8 @@ +type ListItem = { + createdAt: number + address: string +} + +export type ModifiedBlocklist = { + blocklist: ListItem[] +} diff --git a/src/methods/vault/requests/getVault/modifyVault.spec.ts b/src/methods/vault/requests/getVault/modifyVault.spec.ts index 7a20ccd4..04ccb0a1 100644 --- a/src/methods/vault/requests/getVault/modifyVault.spec.ts +++ b/src/methods/vault/requests/getVault/modifyVault.spec.ts @@ -21,6 +21,8 @@ describe('modifyVault', () => { createdAt: '1693395816', displayName: 'Mock Vault', weeklyApy: '2.80', + blocklistCount: '0', + whitelistCount: '0', totalAssets: '150000000000', capacity: '1000000000000000', validatorsRoot: 'mockValidators', @@ -33,14 +35,6 @@ describe('modifyVault', () => { feeRecipient: '0xeefffd4c23d2e8c845870e273861e7d60df49663', blocklistManager: '0xeefffd4c23d2e8c845870e273861e7d60df49663', }, - privateVaultAccounts: [ - { createdAt: '1693395816', address: '0xeefffd4c23d2e8c845870e273861e7d60df49663' }, - { createdAt: '1693395816', address: '0xeefffd4c23d2e8c845870e273861e7d60df49663' }, - ], - vaultBlockedAccounts: [ - { createdAt: '1693395817', address: '0xeefffd4c23d2e8c845870e273861e7d60df49663' }, - { createdAt: '1693395817', address: '0xeefffd4c23d2e8c845870e273861e7d60df49663' }, - ], } it('should correctly transform the vault data', () => { @@ -51,6 +45,8 @@ describe('modifyVault', () => { performance: 10, isPrivate: false, isBlocklist: false, + blocklistCount: 0, + whitelistCount: 0, capacity: '0.001', tokenSymbol: 'mTKN', imageUrl: 'mockUrl', @@ -68,26 +64,6 @@ describe('modifyVault', () => { mevRecipient: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', vaultKeysManager: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', blocklistManager: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', - whitelist: [ - { - createdAt: 1693395816000, - address: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', - }, - { - createdAt: 1693395816000, - address: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', - }, - ], - blocklist: [ - { - createdAt: 1693395817000, - address: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', - }, - { - createdAt: 1693395817000, - address: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', - }, - ], } const result = modifyVault({ @@ -115,34 +91,6 @@ describe('modifyVault', () => { expect(result.mevRecipient).toEqual(configs[network].addresses.base.sharedMevEscrow) }) - it('should handle empty privateVaultAccounts correctly', () => { - const mockDataWithoutPrivateAccounts: VaultQueryPayload = { - ...mockVaultQueryPayload, - privateVaultAccounts: [], - } - - const result = modifyVault({ - data: mockDataWithoutPrivateAccounts, - network, - }) - - expect(result.whitelist).toEqual([]) - }) - - it('should handle empty vaultBlockedAccounts correctly', () => { - const mockDataWithoutBlockedAccounts: VaultQueryPayload = { - ...mockVaultQueryPayload, - vaultBlockedAccounts: [], - } - - const result = modifyVault({ - data: mockDataWithoutBlockedAccounts, - network, - }) - - expect(result.blocklist).toEqual([]) - }) - it('should handle feePercent being 0', () => { const mockDataWithZeroFee: VaultQueryPayload = { ...mockVaultQueryPayload, diff --git a/src/methods/vault/requests/getVault/modifyVault.ts b/src/methods/vault/requests/getVault/modifyVault.ts index ba2717da..e08ae507 100644 --- a/src/methods/vault/requests/getVault/modifyVault.ts +++ b/src/methods/vault/requests/getVault/modifyVault.ts @@ -10,14 +10,9 @@ type ModifyVaultInput = { network: Network } -const modifyAddress = ({ createdAt, address }: { createdAt: string, address: string }) => ({ - createdAt: Number(createdAt) * 1000, - address: getAddress(address), -}) - const modifyVault = (input: ModifyVaultInput): ModifiedVault => { const { data, network } = input - const { vault, privateVaultAccounts, vaultBlockedAccounts } = data + const { vault } = data const { admin, @@ -29,6 +24,8 @@ const modifyVault = (input: ModifyVaultInput): ModifiedVault => { keysManager, totalAssets, feeRecipient, + blocklistCount, + whitelistCount, weeklyApy, ...rest } = vault @@ -45,10 +42,10 @@ const modifyVault = (input: ModifyVaultInput): ModifiedVault => { feeRecipient: getAddress(feeRecipient), vaultKeysManager: getAddress(keysManager), apy: Number(weeklyApy), + blocklistCount: Number(blocklistCount), + whitelistCount: Number(whitelistCount), whitelister: vault.whitelister ? getAddress(vault.whitelister) : '', blocklistManager: vault.blocklistManager ? getAddress(vault.blocklistManager) : '', - whitelist: privateVaultAccounts.map(modifyAddress), - blocklist: vaultBlockedAccounts.map(modifyAddress), mevRecipient: mevEscrow ? getAddress(mevEscrow) : configs[network].addresses.base.sharedMevEscrow, diff --git a/src/methods/vault/requests/getVault/types.ts b/src/methods/vault/requests/getVault/types.ts index 998b1bf6..61fab980 100644 --- a/src/methods/vault/requests/getVault/types.ts +++ b/src/methods/vault/requests/getVault/types.ts @@ -1,14 +1,9 @@ import type { VaultQueryPayload } from '../../../../graphql/subgraph/vault' -type ListItem = { - createdAt: number - address: string -} - export type ModifiedVault = Omit< VaultQueryPayload['vault'], - 'admin' | 'address' | 'mevEscrow' | 'keysManager' | 'weeklyApy' | 'performance' | 'createdAt' + 'admin' | 'address' | 'mevEscrow' | 'keysManager' | 'weeklyApy' | 'performance' | 'createdAt' | 'blocklistCount' | 'whitelistCount' > & { apy: number createdAt: number @@ -16,8 +11,8 @@ export type ModifiedVault = Omit< performance: number vaultAddress: string mevRecipient: string + blocklistCount: number + whitelistCount: number vaultKeysManager: string isSmoothingPool: boolean - whitelist: ListItem[] - blocklist: ListItem[] } diff --git a/src/methods/vault/requests/getWhitelist/index.ts b/src/methods/vault/requests/getWhitelist/index.ts new file mode 100644 index 00000000..901e8947 --- /dev/null +++ b/src/methods/vault/requests/getWhitelist/index.ts @@ -0,0 +1,66 @@ +import type { WhitelistAccountsQueryVariables, WhitelistAccountsQueryPayload } from '../../../../graphql/subgraph/vault' +import { apiUrls, validateArgs } from '../../../../utils' +import graphql from '../../../../graphql' +import { ModifiedWhitelist } from './types' +import modifyWhitelist from './modifyWhitelist' + + +type GetWhitelistInput = { + vaultAddress: string + orderDirection?: WhitelistAccountsQueryVariables['orderDirection'] + search?: string + limit?: number + skip?: number + options: StakeWise.Options +} + +type GetWhitelistOutput = { + whitelist: { + createdAt: number + address: string + }[] +} + +const getWhitelist = async (input: GetWhitelistInput): Promise => { + const { vaultAddress, orderDirection, search, limit, skip, options } = input + + validateArgs.address({ vaultAddress }) + + if (typeof skip !== 'undefined') { + validateArgs.number({ skip }) + } + + if (typeof limit !== 'undefined') { + validateArgs.number({ limit }) + } + + if (typeof search !== 'undefined') { + validateArgs.string({ search }) + } + + if (typeof orderDirection !== 'undefined') { + if (![ 'asc', 'desc' ].includes(orderDirection)) { + throw new Error(`The "orderDirection" argument must be "asc" or "desc"`) + } + } + + const vault = vaultAddress.toLowerCase() + + const where = search + ? { vault, address_contains: search.toLowerCase() } as WhitelistAccountsQueryVariables['where'] + : { vault } as WhitelistAccountsQueryVariables['where'] + + return graphql.subgraph.vault.fetchWhitelistAccountsQuery({ + url: apiUrls.getSubgraphqlUrl(options), + variables: { + where, + skip: skip || 0, + limit: limit || 100, + orderDirection: orderDirection || 'desc', + }, + modifyResult: (data: WhitelistAccountsQueryPayload) => modifyWhitelist({ data }), + }) +} + + +export default getWhitelist diff --git a/src/methods/vault/requests/getWhitelist/modifyWhitelist.spec.ts b/src/methods/vault/requests/getWhitelist/modifyWhitelist.spec.ts new file mode 100644 index 00000000..3d912b4b --- /dev/null +++ b/src/methods/vault/requests/getWhitelist/modifyWhitelist.spec.ts @@ -0,0 +1,43 @@ +import modifyWhitelist from './modifyWhitelist' +import type { WhitelistAccountsQueryPayload } from '../../../../graphql/subgraph/vault' + + +describe('modifyWhitelist', () => { + const mockWhitelistQueryPayload: WhitelistAccountsQueryPayload = { + privateVaultAccounts: [ + { createdAt: '1693395816', address: '0xeefffd4c23d2e8c845870e273861e7d60df49663' }, + { createdAt: '1693395816', address: '0xeefffd4c23d2e8c845870e273861e7d60df49663' }, + ], + } + + it('should correctly transform the whitelist data', () => { + const expectedModifiedVault = [ + { + createdAt: 1693395816000, + address: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', + }, + { + createdAt: 1693395816000, + address: '0xeEFFFD4C23D2E8c845870e273861e7d60Df49663', + }, + ] + + const result = modifyWhitelist({ + data: mockWhitelistQueryPayload, + }) + + expect(result).toEqual(expectedModifiedVault) + }) + + it('should handle empty privateVaultAccounts correctly', () => { + const mockDataWithoutPrivateAccounts: WhitelistAccountsQueryPayload = { + privateVaultAccounts: [], + } + + const result = modifyWhitelist({ + data: mockDataWithoutPrivateAccounts, + }) + + expect(result).toEqual([]) + }) +}) diff --git a/src/methods/vault/requests/getWhitelist/modifyWhitelist.ts b/src/methods/vault/requests/getWhitelist/modifyWhitelist.ts new file mode 100644 index 00000000..9a56fcdf --- /dev/null +++ b/src/methods/vault/requests/getWhitelist/modifyWhitelist.ts @@ -0,0 +1,26 @@ +import { getAddress } from 'ethers' + +import { ModifiedWhitelist } from './types' +import type { WhitelistAccountsQueryPayload } from '../../../../graphql/subgraph/vault' + + +type ModifyWhitelistInput = { + data: WhitelistAccountsQueryPayload +} + +const modifyAddress = ({ createdAt, address }: { createdAt: string, address: string }) => ({ + createdAt: Number(createdAt) * 1000, + address: getAddress(address), +}) + +const modifyWhitelist = (input: ModifyWhitelistInput): ModifiedWhitelist => { + const { data } = input + const { privateVaultAccounts } = data + + return { + whitelist: privateVaultAccounts.map(modifyAddress), + } +} + + +export default modifyWhitelist diff --git a/src/methods/vault/requests/getWhitelist/types.ts b/src/methods/vault/requests/getWhitelist/types.ts new file mode 100644 index 00000000..552e706f --- /dev/null +++ b/src/methods/vault/requests/getWhitelist/types.ts @@ -0,0 +1,8 @@ +type ListItem = { + createdAt: number + address: string +} + +export type ModifiedWhitelist = { + whitelist: ListItem[] +}