diff --git a/src/hooks/useGetPosition.ts b/src/hooks/useGetPosition.ts index dff5992..4f9a0b1 100644 --- a/src/hooks/useGetPosition.ts +++ b/src/hooks/useGetPosition.ts @@ -41,7 +41,7 @@ export function useGetPosition({ unknown[] >({ queryKey: ["position", tokenId, chainId], - queryFn: () => getPosition(tokenId, chainId), + queryFn: () => getPosition({ tokenId }, chainId), ...queryOptions, }); } diff --git a/src/test/hooks/useGetPosition.test.ts b/src/test/hooks/useGetPosition.test.ts index 79b1dec..258a9d7 100644 --- a/src/test/hooks/useGetPosition.test.ts +++ b/src/test/hooks/useGetPosition.test.ts @@ -44,14 +44,18 @@ describe("useGetPosition", () => { "WETH", "Wrapped Ether", ), - amounts: { - amount0: "1000000", - amount1: "1000000000000000000", + position: { + amounts: { + amount0: "1000000", + amount1: "1000000000000000000", + }, + tickLower: -100, + tickUpper: 100, + liquidity: BigInt("1000000000000000000"), }, - tickLower: -100, - tickUpper: 100, - liquidity: BigInt("1000000000000000000"), + pool: {}, poolId: "0x1234567890123456789012345678901234567890", + tokenId: "123", }; (getPosition as unknown as ReturnType).mockResolvedValueOnce( @@ -75,7 +79,7 @@ describe("useGetPosition", () => { }); expect(result.current.data).toEqual(mockPosition); - expect(getPosition).toHaveBeenCalledWith("123", 1); + expect(getPosition).toHaveBeenCalledWith({ tokenId: "123" }, 1); }); it("should handle errors", async () => { @@ -122,14 +126,18 @@ describe("useGetPosition", () => { "WETH", "Wrapped Ether", ), - amounts: { - amount0: "1000000", - amount1: "1000000000000000000", + position: { + amounts: { + amount0: "1000000", + amount1: "1000000000000000000", + }, + tickLower: -100, + tickUpper: 100, + liquidity: BigInt("1000000000000000000"), }, - tickLower: -100, - tickUpper: 100, - liquidity: BigInt("1000000000000000000"), + pool: {}, poolId: "0x1234567890123456789012345678901234567890", + tokenId: "123", }; (getPosition as unknown as ReturnType).mockResolvedValueOnce( diff --git a/src/test/utils/getPosition.test.ts b/src/test/utils/getPosition.test.ts index 9117a89..6eb5d3a 100644 --- a/src/test/utils/getPosition.test.ts +++ b/src/test/utils/getPosition.test.ts @@ -31,9 +31,9 @@ describe("getPosition", () => { it("should throw error if SDK instance not found", async () => { mockGetInstance.mockReturnValueOnce(undefined); - await expect(getPosition(mockTokenId, mockChainId)).rejects.toThrow( - "SDK not initialized", - ); + await expect( + getPosition({ tokenId: mockTokenId }, mockChainId), + ).rejects.toThrow("SDK not found. Please create an instance first."); }); it("should throw error if tokens not found", async () => { @@ -59,9 +59,9 @@ describe("getPosition", () => { }); mockGetTokens.mockResolvedValueOnce(null); - await expect(getPosition(mockTokenId, mockChainId)).rejects.toThrow( - "Tokens not found", - ); + await expect( + getPosition({ tokenId: mockTokenId }, mockChainId), + ).rejects.toThrow("Tokens not found"); }); it("should throw error if liquidity is 0", async () => { @@ -91,9 +91,9 @@ describe("getPosition", () => { new Token(1, mockTokens[1], 18, "WETH", "Wrapped Ether"), ]); - await expect(getPosition(mockTokenId, mockChainId)).rejects.toThrow( - "Liquidity is 0", - ); + await expect( + getPosition({ tokenId: mockTokenId }, mockChainId), + ).rejects.toThrow("Liquidity is 0"); }); it("should return position data when position exists", async () => { @@ -137,15 +137,14 @@ describe("getPosition", () => { mockGetTokens.mockResolvedValueOnce(mockTokenInstances); - const result = await getPosition(mockTokenId, mockChainId); + const result = await getPosition({ tokenId: mockTokenId }, mockChainId); expect(result).toBeDefined(); expect(result?.token0).toEqual(mockTokenInstances[0]); expect(result?.token1).toEqual(mockTokenInstances[1]); - expect(result?.liquidity).toBe(BigInt("1000000000000000000")); - expect(result?.amounts).toBeDefined(); - expect(result?.tickLower).toBeDefined(); - expect(result?.tickUpper).toBeDefined(); + expect(result?.position).toBeDefined(); + expect(result?.pool).toBeDefined(); expect(result?.poolId).toBeDefined(); + expect(result?.tokenId).toBe(mockTokenId); }); }); diff --git a/src/types/hooks/useGetPosition.ts b/src/types/hooks/useGetPosition.ts index dba2aac..115741a 100644 --- a/src/types/hooks/useGetPosition.ts +++ b/src/types/hooks/useGetPosition.ts @@ -1,29 +1,23 @@ import type { UseQueryOptions } from "@tanstack/react-query"; import type { Token } from "@uniswap/sdk-core"; +import type { Pool, Position } from "@uniswap/v4-sdk"; /** * Result type for position data */ export interface PositionResult { + /** The position instance */ + position: Position; + /** The pool instance associated with the position */ + pool: Pool; /** First token in the pair */ token0: Token; /** Second token in the pair */ token1: Token; - /** Token amounts in the position */ - amounts: { - /** Amount of token0 */ - amount0: string; - /** Amount of token1 */ - amount1: string; - }; - /** Lower tick boundary of the position */ - tickLower: number; - /** Upper tick boundary of the position */ - tickUpper: number; - /** Total liquidity in the position */ - liquidity: bigint; /** Unique identifier for the pool */ poolId: `0x${string}`; + /** The unique identifier of the position */ + tokenId: string; } /** diff --git a/src/types/utils/getPosition.ts b/src/types/utils/getPosition.ts new file mode 100644 index 0000000..25513c9 --- /dev/null +++ b/src/types/utils/getPosition.ts @@ -0,0 +1,28 @@ +import type { Token } from "@uniswap/sdk-core"; +import type { Pool, Position } from "@uniswap/v4-sdk"; + +/** + * Parameters required for retrieving a Uniswap V4 position instance. + */ +export interface GetPositionParams { + /** The unique identifier of the position */ + tokenId: string; +} + +/** + * Response structure for retrieving a Uniswap V4 position instance. + */ +export interface GetPositionResponse { + /** The position instance */ + position: Position; + /** The pool instance associated with the position */ + pool: Pool; + /** The first token in the pool pair */ + token0: Token; + /** The second token in the pool pair */ + token1: Token; + /** The unique identifier of the pool */ + poolId: `0x${string}`; + /** The unique identifier of the position */ + tokenId: string; +} diff --git a/src/utils/getPosition.ts b/src/utils/getPosition.ts index 54b5bf6..5a5324b 100644 --- a/src/utils/getPosition.ts +++ b/src/utils/getPosition.ts @@ -2,34 +2,34 @@ import { V4PositionManagerAbi } from "@/constants/abis/V4PositionMananger"; import { V4StateViewAbi } from "@/constants/abis/V4StateView"; import { getInstance } from "@/core/uniDevKitV4Factory"; import { decodePositionInfo } from "@/helpers/positions"; +import type { + GetPositionParams, + GetPositionResponse, +} from "@/types/utils/getPosition"; import { getTokens } from "@/utils/getTokens"; -import type { Token } from "@uniswap/sdk-core"; import { Pool, Position as V4Position } from "@uniswap/v4-sdk"; -interface PositionResult { - token0: Token; - token1: Token; - amounts: { - amount0: string; - amount1: string; - }; - tickLower: number; - tickUpper: number; - liquidity: bigint; - poolId: `0x${string}`; -} - +/** + * Retrieves a Uniswap V4 position instance for a given token ID. + * @param params Position parameters including token ID + * @param chainId Optional chain ID where the position exists + * @returns Promise resolving to position data + * @throws Error if SDK instance is not found or if position data is invalid + */ export async function getPosition( - tokenId: string, + params: GetPositionParams, chainId?: number, -): Promise { +): Promise { const sdk = getInstance(chainId); - if (!sdk) throw new Error("SDK not initialized"); + if (!sdk) { + throw new Error("SDK not found. Please create an instance first."); + } const client = sdk.getClient(); const positionManager = sdk.getContractAddress("positionManager"); const stateView = sdk.getContractAddress("stateView"); + // Fetch poolKey and raw position info const [poolAndPositionInfo, liquidity] = await client.multicall({ allowFailure: false, contracts: [ @@ -37,24 +37,20 @@ export async function getPosition( address: positionManager, abi: V4PositionManagerAbi, functionName: "getPoolAndPositionInfo", - args: [BigInt(tokenId)], + args: [BigInt(params.tokenId)], }, { address: positionManager, abi: V4PositionManagerAbi, functionName: "getPositionLiquidity", - args: [BigInt(tokenId)], + args: [BigInt(params.tokenId)], }, ], }); const [poolKey, rawInfo] = poolAndPositionInfo; - const { currency0, currency1, fee, tickSpacing, hooks } = poolKey; - console.log("poolKey", poolKey); - console.log("rawInfo", rawInfo); - if (liquidity === 0n) { throw new Error("Liquidity is 0"); } @@ -119,15 +115,11 @@ export async function getPosition( }); return { + position, + pool, token0, token1, - amounts: { - amount0: position.amount0.toSignificant(6), - amount1: position.amount1.toSignificant(6), - }, - tickLower, - tickUpper, - liquidity, poolId, + tokenId: params.tokenId, }; }