Skip to content

Commit 9fad3c8

Browse files
authored
Merge pull request #5 from BootNodeDev/fix/getPosition-return
fix: position error handling and type consistency
2 parents 2588db6 + 22561bf commit 9fad3c8

File tree

6 files changed

+92
-71
lines changed

6 files changed

+92
-71
lines changed

src/hooks/useGetPosition.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export function useGetPosition({
4141
unknown[]
4242
>({
4343
queryKey: ["position", tokenId, chainId],
44-
queryFn: () => getPosition(tokenId, chainId),
44+
queryFn: () => getPosition({ tokenId }, chainId),
4545
...queryOptions,
4646
});
4747
}

src/test/hooks/useGetPosition.test.ts

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,18 @@ describe("useGetPosition", () => {
4444
"WETH",
4545
"Wrapped Ether",
4646
),
47-
amounts: {
48-
amount0: "1000000",
49-
amount1: "1000000000000000000",
47+
position: {
48+
amounts: {
49+
amount0: "1000000",
50+
amount1: "1000000000000000000",
51+
},
52+
tickLower: -100,
53+
tickUpper: 100,
54+
liquidity: BigInt("1000000000000000000"),
5055
},
51-
tickLower: -100,
52-
tickUpper: 100,
53-
liquidity: BigInt("1000000000000000000"),
56+
pool: {},
5457
poolId: "0x1234567890123456789012345678901234567890",
58+
tokenId: "123",
5559
};
5660

5761
(getPosition as unknown as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
@@ -75,7 +79,7 @@ describe("useGetPosition", () => {
7579
});
7680

7781
expect(result.current.data).toEqual(mockPosition);
78-
expect(getPosition).toHaveBeenCalledWith("123", 1);
82+
expect(getPosition).toHaveBeenCalledWith({ tokenId: "123" }, 1);
7983
});
8084

8185
it("should handle errors", async () => {
@@ -122,14 +126,18 @@ describe("useGetPosition", () => {
122126
"WETH",
123127
"Wrapped Ether",
124128
),
125-
amounts: {
126-
amount0: "1000000",
127-
amount1: "1000000000000000000",
129+
position: {
130+
amounts: {
131+
amount0: "1000000",
132+
amount1: "1000000000000000000",
133+
},
134+
tickLower: -100,
135+
tickUpper: 100,
136+
liquidity: BigInt("1000000000000000000"),
128137
},
129-
tickLower: -100,
130-
tickUpper: 100,
131-
liquidity: BigInt("1000000000000000000"),
138+
pool: {},
132139
poolId: "0x1234567890123456789012345678901234567890",
140+
tokenId: "123",
133141
};
134142

135143
(getPosition as unknown as ReturnType<typeof vi.fn>).mockResolvedValueOnce(

src/test/utils/getPosition.test.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ describe("getPosition", () => {
3131

3232
it("should throw error if SDK instance not found", async () => {
3333
mockGetInstance.mockReturnValueOnce(undefined);
34-
await expect(getPosition(mockTokenId, mockChainId)).rejects.toThrow(
35-
"SDK not initialized",
36-
);
34+
await expect(
35+
getPosition({ tokenId: mockTokenId }, mockChainId),
36+
).rejects.toThrow("SDK not found. Please create an instance first.");
3737
});
3838

3939
it("should throw error if tokens not found", async () => {
@@ -59,9 +59,9 @@ describe("getPosition", () => {
5959
});
6060
mockGetTokens.mockResolvedValueOnce(null);
6161

62-
await expect(getPosition(mockTokenId, mockChainId)).rejects.toThrow(
63-
"Tokens not found",
64-
);
62+
await expect(
63+
getPosition({ tokenId: mockTokenId }, mockChainId),
64+
).rejects.toThrow("Tokens not found");
6565
});
6666

6767
it("should throw error if liquidity is 0", async () => {
@@ -91,9 +91,9 @@ describe("getPosition", () => {
9191
new Token(1, mockTokens[1], 18, "WETH", "Wrapped Ether"),
9292
]);
9393

94-
await expect(getPosition(mockTokenId, mockChainId)).rejects.toThrow(
95-
"Liquidity is 0",
96-
);
94+
await expect(
95+
getPosition({ tokenId: mockTokenId }, mockChainId),
96+
).rejects.toThrow("Liquidity is 0");
9797
});
9898

9999
it("should return position data when position exists", async () => {
@@ -137,15 +137,14 @@ describe("getPosition", () => {
137137

138138
mockGetTokens.mockResolvedValueOnce(mockTokenInstances);
139139

140-
const result = await getPosition(mockTokenId, mockChainId);
140+
const result = await getPosition({ tokenId: mockTokenId }, mockChainId);
141141

142142
expect(result).toBeDefined();
143143
expect(result?.token0).toEqual(mockTokenInstances[0]);
144144
expect(result?.token1).toEqual(mockTokenInstances[1]);
145-
expect(result?.liquidity).toBe(BigInt("1000000000000000000"));
146-
expect(result?.amounts).toBeDefined();
147-
expect(result?.tickLower).toBeDefined();
148-
expect(result?.tickUpper).toBeDefined();
145+
expect(result?.position).toBeDefined();
146+
expect(result?.pool).toBeDefined();
149147
expect(result?.poolId).toBeDefined();
148+
expect(result?.tokenId).toBe(mockTokenId);
150149
});
151150
});

src/types/hooks/useGetPosition.ts

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,23 @@
11
import type { UseQueryOptions } from "@tanstack/react-query";
22
import type { Token } from "@uniswap/sdk-core";
3+
import type { Pool, Position } from "@uniswap/v4-sdk";
34

45
/**
56
* Result type for position data
67
*/
78
export interface PositionResult {
9+
/** The position instance */
10+
position: Position;
11+
/** The pool instance associated with the position */
12+
pool: Pool;
813
/** First token in the pair */
914
token0: Token;
1015
/** Second token in the pair */
1116
token1: Token;
12-
/** Token amounts in the position */
13-
amounts: {
14-
/** Amount of token0 */
15-
amount0: string;
16-
/** Amount of token1 */
17-
amount1: string;
18-
};
19-
/** Lower tick boundary of the position */
20-
tickLower: number;
21-
/** Upper tick boundary of the position */
22-
tickUpper: number;
23-
/** Total liquidity in the position */
24-
liquidity: bigint;
2517
/** Unique identifier for the pool */
2618
poolId: `0x${string}`;
19+
/** The unique identifier of the position */
20+
tokenId: string;
2721
}
2822

2923
/**

src/types/utils/getPosition.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { Token } from "@uniswap/sdk-core";
2+
import type { Pool, Position } from "@uniswap/v4-sdk";
3+
4+
/**
5+
* Parameters required for retrieving a Uniswap V4 position instance.
6+
*/
7+
export interface GetPositionParams {
8+
/** The unique identifier of the position */
9+
tokenId: string;
10+
}
11+
12+
/**
13+
* Response structure for retrieving a Uniswap V4 position instance.
14+
*/
15+
export interface GetPositionResponse {
16+
/** The position instance */
17+
position: Position;
18+
/** The pool instance associated with the position */
19+
pool: Pool;
20+
/** The first token in the pool pair */
21+
token0: Token;
22+
/** The second token in the pool pair */
23+
token1: Token;
24+
/** The unique identifier of the pool */
25+
poolId: `0x${string}`;
26+
/** The unique identifier of the position */
27+
tokenId: string;
28+
}

src/utils/getPosition.ts

Lines changed: 22 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,55 @@ import { V4PositionManagerAbi } from "@/constants/abis/V4PositionMananger";
22
import { V4StateViewAbi } from "@/constants/abis/V4StateView";
33
import { getInstance } from "@/core/uniDevKitV4Factory";
44
import { decodePositionInfo } from "@/helpers/positions";
5+
import type {
6+
GetPositionParams,
7+
GetPositionResponse,
8+
} from "@/types/utils/getPosition";
59
import { getTokens } from "@/utils/getTokens";
6-
import type { Token } from "@uniswap/sdk-core";
710
import { Pool, Position as V4Position } from "@uniswap/v4-sdk";
811

9-
interface PositionResult {
10-
token0: Token;
11-
token1: Token;
12-
amounts: {
13-
amount0: string;
14-
amount1: string;
15-
};
16-
tickLower: number;
17-
tickUpper: number;
18-
liquidity: bigint;
19-
poolId: `0x${string}`;
20-
}
21-
12+
/**
13+
* Retrieves a Uniswap V4 position instance for a given token ID.
14+
* @param params Position parameters including token ID
15+
* @param chainId Optional chain ID where the position exists
16+
* @returns Promise resolving to position data
17+
* @throws Error if SDK instance is not found or if position data is invalid
18+
*/
2219
export async function getPosition(
23-
tokenId: string,
20+
params: GetPositionParams,
2421
chainId?: number,
25-
): Promise<PositionResult | undefined> {
22+
): Promise<GetPositionResponse> {
2623
const sdk = getInstance(chainId);
27-
if (!sdk) throw new Error("SDK not initialized");
24+
if (!sdk) {
25+
throw new Error("SDK not found. Please create an instance first.");
26+
}
2827

2928
const client = sdk.getClient();
3029
const positionManager = sdk.getContractAddress("positionManager");
3130
const stateView = sdk.getContractAddress("stateView");
3231

32+
// Fetch poolKey and raw position info
3333
const [poolAndPositionInfo, liquidity] = await client.multicall({
3434
allowFailure: false,
3535
contracts: [
3636
{
3737
address: positionManager,
3838
abi: V4PositionManagerAbi,
3939
functionName: "getPoolAndPositionInfo",
40-
args: [BigInt(tokenId)],
40+
args: [BigInt(params.tokenId)],
4141
},
4242
{
4343
address: positionManager,
4444
abi: V4PositionManagerAbi,
4545
functionName: "getPositionLiquidity",
46-
args: [BigInt(tokenId)],
46+
args: [BigInt(params.tokenId)],
4747
},
4848
],
4949
});
5050

5151
const [poolKey, rawInfo] = poolAndPositionInfo;
52-
5352
const { currency0, currency1, fee, tickSpacing, hooks } = poolKey;
5453

55-
console.log("poolKey", poolKey);
56-
console.log("rawInfo", rawInfo);
57-
5854
if (liquidity === 0n) {
5955
throw new Error("Liquidity is 0");
6056
}
@@ -119,15 +115,11 @@ export async function getPosition(
119115
});
120116

121117
return {
118+
position,
119+
pool,
122120
token0,
123121
token1,
124-
amounts: {
125-
amount0: position.amount0.toSignificant(6),
126-
amount1: position.amount1.toSignificant(6),
127-
},
128-
tickLower,
129-
tickUpper,
130-
liquidity,
131122
poolId,
123+
tokenId: params.tokenId,
132124
};
133125
}

0 commit comments

Comments
 (0)