diff --git a/README.md b/README.md index ce2e5c97..81f0b6f6 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The official SDK designed for effortless data retrieval from the StakeWise platform. This SDK provides a streamlined interface over GraphQL requests and contract interactions. -![Version](https://img.shields.io/badge/version-1.3.0-blue) +![Version](https://img.shields.io/badge/version-1.4.0-blue) ![Unit Tests](https://github.com/stakewise/v3-sdk/actions/workflows/unit-tests.yml/badge.svg) ![GitHub issues](https://img.shields.io/github/issues-raw/stakewise/v3-sdk) ![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/stakewise/v3-sdk) diff --git a/src/methods/vault/requests/getExitQueuePositions/index.ts b/src/methods/vault/requests/getExitQueuePositions/index.ts index adb2ff3a..378d2f1e 100644 --- a/src/methods/vault/requests/getExitQueuePositions/index.ts +++ b/src/methods/vault/requests/getExitQueuePositions/index.ts @@ -6,6 +6,7 @@ import type { FetchExitQueuePositionsInput } from './fetchExitQueuePositions' type GetExitQueuePositionsInput = FetchExitQueuePositionsInput & { contracts: StakeWise.Contracts + provider: StakeWise.Provider options: StakeWise.Options } @@ -16,7 +17,7 @@ const mock = { } const getExitQueuePositions = async (input: GetExitQueuePositionsInput) => { - const { options, contracts, vaultAddress, userAddress } = input + const { options, contracts, provider, vaultAddress, userAddress } = input validateArgs.address({ vaultAddress, userAddress }) @@ -30,6 +31,7 @@ const getExitQueuePositions = async (input: GetExitQueuePositionsInput) => { const exitQueue = await parseExitRequests({ options, + provider, contracts, userAddress, totalShares, diff --git a/src/methods/vault/requests/getExitQueuePositions/parseExitRequests.spec.ts b/src/methods/vault/requests/getExitQueuePositions/parseExitRequests.spec.ts index e4837e81..8fbaf6d1 100644 --- a/src/methods/vault/requests/getExitQueuePositions/parseExitRequests.spec.ts +++ b/src/methods/vault/requests/getExitQueuePositions/parseExitRequests.spec.ts @@ -8,6 +8,14 @@ import parseExitRequests, { ParseExitRequestsInput } from './parseExitRequests' jest.mock('../../../../contracts/vaultMulticall') +const getMockProvider = (timestamp: number) => ({ + getBlock() { + return { + timestamp, + } + }, +}) as unknown as StakeWise.Provider + describe('parseExitRequests function', () => { const network = Network.Goerli const config = configs[network] @@ -21,6 +29,7 @@ describe('parseExitRequests function', () => { totalShares: 1000n, userAddress: ZeroAddress, vaultAddress: ZeroAddress, + provider: getMockProvider(9999999999), exitRequests: [ { positionTicket: 'positionTicket-1', @@ -69,13 +78,11 @@ describe('parseExitRequests function', () => { positions: [ { exitQueueIndex: 1n, - totalShares: '100', timestamp: '123456', positionTicket: 'positionTicket-1', }, { exitQueueIndex: 2n, - totalShares: '200', timestamp: '123456', positionTicket: 'positionTicket-2', }, @@ -85,6 +92,30 @@ describe('parseExitRequests function', () => { }) }) + it('should hide the position if it hasn\'t been 24 hours', async () => { + (vaultMulticall as jest.Mock) + .mockResolvedValueOnce([ + [ 1n ], + [ 2n ], + ]) + .mockResolvedValueOnce([ + { assets: 100n }, + ]) + + const result = await parseExitRequests({ + ...input, + provider: getMockProvider(1), + }) + + expect(vaultMulticall).toHaveBeenCalledTimes(2) + + expect(result).toEqual({ + total: 100n, + positions: [], + withdrawable: 0n, + }) + }) + it('should handle -1 indexes from getExitQueueIndex', async () => { (vaultMulticall as jest.Mock) .mockResolvedValueOnce([ @@ -122,7 +153,6 @@ describe('parseExitRequests function', () => { expect(result).toEqual({ positions: [ { exitQueueIndex: 1n, - totalShares: '200', timestamp: '123456', positionTicket: 'positionTicket-2', } ], @@ -149,13 +179,11 @@ describe('parseExitRequests function', () => { positions: [ { exitQueueIndex: 0n, - totalShares: '100', timestamp: '123456', positionTicket: 'positionTicket-1', }, { exitQueueIndex: 1n, - totalShares: '200', timestamp: '123456', positionTicket: 'positionTicket-2', }, @@ -182,13 +210,11 @@ describe('parseExitRequests function', () => { positions: [ { exitQueueIndex: 0n, - totalShares: '100', timestamp: '123456', positionTicket: 'positionTicket-1', }, { exitQueueIndex: 1n, - totalShares: '200', timestamp: '123456', positionTicket: 'positionTicket-2', }, diff --git a/src/methods/vault/requests/getExitQueuePositions/parseExitRequests.ts b/src/methods/vault/requests/getExitQueuePositions/parseExitRequests.ts index 0e5efd23..968504d0 100644 --- a/src/methods/vault/requests/getExitQueuePositions/parseExitRequests.ts +++ b/src/methods/vault/requests/getExitQueuePositions/parseExitRequests.ts @@ -3,6 +3,7 @@ import vaultMulticall from '../../../../contracts/vaultMulticall' export type ParseExitRequestsInput = { contracts: StakeWise.Contracts + provider: StakeWise.Provider options: StakeWise.Options userAddress: string vaultAddress: string @@ -32,8 +33,20 @@ type ExitedAssetsResponse = Array<{ claimedAssets: bigint }> +const _checkTimestamp = async (timestamp: string, provider: StakeWise.Provider) => { + const lastBlock = await provider.getBlock('latest') + + const current = lastBlock + ? lastBlock.timestamp + : Number((new Date().getTime() / 1000).toFixed(0)) + + const diff = Number(current) - Number(timestamp) + + return diff > 86_400 // 24 hours +} + const parseExitRequests = async (values: ParseExitRequestsInput): Promise => { - const { options, contracts, userAddress, vaultAddress, totalShares, exitRequests } = values + const { options, contracts, provider, userAddress, vaultAddress, totalShares, exitRequests } = values const keeperContract = contracts.base.keeper const vaultContract = contracts.helpers.createVault(vaultAddress) @@ -59,19 +72,25 @@ const parseExitRequests = async (values: ParseExitRequestsInput): Promise { - const exitQueueIndex = item[0] + const claims: Position[] = [] + const indexes = (indexesResponse || []) + + for (let i = 0; i < indexes.length; i++) { + const exitQueueIndex = indexes[i][0] + const { positionTicket, timestamp } = exitRequests[i] + + // 24 hours must have elapsed since the position was created + const is24HoursPassed = await _checkTimestamp(timestamp, provider) // If the index is -1 then we cannot claim anything. Otherwise, the value is >= 0. - if (exitQueueIndex > -1n) { - const item = { exitQueueIndex, ...exitRequests[index] } + const isValid = exitQueueIndex > -1n - return [ ...acc, item ] - } + if (isValid && is24HoursPassed) { + const item = { exitQueueIndex, positionTicket, timestamp } - return acc - }, [] as Position[]) + claims.push(item) + } + } let exitedAssetsResponse: ExitedAssetsResponse = [] diff --git a/src/types/global.ts b/src/types/global.ts index 6c69c461..23cd6922 100644 --- a/src/types/global.ts +++ b/src/types/global.ts @@ -43,7 +43,7 @@ declare global { type Options = { network: Network - provider?: any + provider?: Provider endpoints?: { api?: string web3?: string