@gala-chain/launchpad-mcp-server 1.22.3 → 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/CHANGELOG.md +161 -0
  2. package/README.md +83 -8
  3. package/dist/constants/mcpToolNames.d.ts +69 -11
  4. package/dist/constants/mcpToolNames.d.ts.map +1 -1
  5. package/dist/constants/mcpToolNames.js +47 -9
  6. package/dist/constants/mcpToolNames.js.map +1 -1
  7. package/dist/generated/version.d.ts +1 -1
  8. package/dist/generated/version.js +1 -1
  9. package/dist/prompts/balances.d.ts +24 -0
  10. package/dist/prompts/balances.d.ts.map +1 -0
  11. package/dist/prompts/balances.js +191 -0
  12. package/dist/prompts/balances.js.map +1 -0
  13. package/dist/prompts/creation-utils.d.ts +20 -0
  14. package/dist/prompts/creation-utils.d.ts.map +1 -0
  15. package/dist/prompts/creation-utils.js +115 -0
  16. package/dist/prompts/creation-utils.js.map +1 -0
  17. package/dist/prompts/index.d.ts +9 -2
  18. package/dist/prompts/index.d.ts.map +1 -1
  19. package/dist/prompts/index.js +23 -2
  20. package/dist/prompts/index.js.map +1 -1
  21. package/dist/prompts/pools.d.ts +64 -0
  22. package/dist/prompts/pools.d.ts.map +1 -0
  23. package/dist/prompts/pools.js +548 -0
  24. package/dist/prompts/pools.js.map +1 -0
  25. package/dist/prompts/social.d.ts +16 -0
  26. package/dist/prompts/social.d.ts.map +1 -0
  27. package/dist/prompts/social.js +97 -0
  28. package/dist/prompts/social.js.map +1 -0
  29. package/dist/prompts/trading-calculations.d.ts +52 -0
  30. package/dist/prompts/trading-calculations.d.ts.map +1 -0
  31. package/dist/prompts/trading-calculations.js +479 -0
  32. package/dist/prompts/trading-calculations.js.map +1 -0
  33. package/dist/prompts/transfers.d.ts +16 -0
  34. package/dist/prompts/transfers.d.ts.map +1 -0
  35. package/dist/prompts/transfers.js +100 -0
  36. package/dist/prompts/transfers.js.map +1 -0
  37. package/dist/prompts/utility-tools.d.ts +56 -0
  38. package/dist/prompts/utility-tools.d.ts.map +1 -0
  39. package/dist/prompts/utility-tools.js +338 -0
  40. package/dist/prompts/utility-tools.js.map +1 -0
  41. package/dist/prompts/utility.d.ts +8 -0
  42. package/dist/prompts/utility.d.ts.map +1 -1
  43. package/dist/prompts/utility.js +49 -2
  44. package/dist/prompts/utility.js.map +1 -1
  45. package/dist/server.d.ts +17 -0
  46. package/dist/server.d.ts.map +1 -1
  47. package/dist/server.js +81 -3
  48. package/dist/server.js.map +1 -1
  49. package/dist/tools/index.d.ts +9 -1
  50. package/dist/tools/index.d.ts.map +1 -1
  51. package/dist/tools/index.js +10 -2
  52. package/dist/tools/index.js.map +1 -1
  53. package/dist/tools/utils/getConfig.d.ts +2 -0
  54. package/dist/tools/utils/getConfig.d.ts.map +1 -1
  55. package/dist/tools/utils/getConfig.js +12 -3
  56. package/dist/tools/utils/getConfig.js.map +1 -1
  57. package/dist/tools/utils/getEnvironment.d.ts +8 -0
  58. package/dist/tools/utils/getEnvironment.d.ts.map +1 -0
  59. package/dist/tools/utils/getEnvironment.js +19 -0
  60. package/dist/tools/utils/getEnvironment.js.map +1 -0
  61. package/dist/tools/utils/index.d.ts.map +1 -1
  62. package/dist/tools/utils/index.js +4 -0
  63. package/dist/tools/utils/index.js.map +1 -1
  64. package/dist/tools/utils/switchEnvironment.d.ts +8 -0
  65. package/dist/tools/utils/switchEnvironment.d.ts.map +1 -0
  66. package/dist/tools/utils/switchEnvironment.js +30 -0
  67. package/dist/tools/utils/switchEnvironment.js.map +1 -0
  68. package/dist/types/mcp.d.ts +1 -1
  69. package/dist/types/mcp.d.ts.map +1 -1
  70. package/dist/utils/tool-factory.d.ts +30 -0
  71. package/dist/utils/tool-factory.d.ts.map +1 -1
  72. package/dist/utils/tool-factory.js +31 -0
  73. package/dist/utils/tool-factory.js.map +1 -1
  74. package/docs/AI-AGENT-PATTERNS.md +555 -0
  75. package/docs/CONSTRAINTS-REFERENCE.md +454 -0
  76. package/docs/PROMPT-TOOL-MAPPING.md +352 -0
  77. package/docs/examples/default-values-pattern.md +240 -0
  78. package/docs/examples/tool-factory-pattern.md +217 -0
  79. package/jest.config.js +94 -0
  80. package/package.json +1 -1
  81. package/src/__tests__/integration/fetchTokenDetails.integration.test.ts +258 -0
  82. package/src/__tests__/integration/poolTools.integration.test.ts +185 -0
  83. package/src/__tests__/server.test.ts +256 -0
  84. package/src/constants/mcpToolNames.ts +181 -0
  85. package/src/index.ts +19 -0
  86. package/src/prompts/__tests__/promptStructure.test.ts +137 -0
  87. package/src/prompts/__tests__/registry.test.ts +359 -0
  88. package/src/prompts/analysis.ts +429 -0
  89. package/src/prompts/balances.ts +198 -0
  90. package/src/prompts/create-token.ts +123 -0
  91. package/src/prompts/creation-utils.ts +118 -0
  92. package/src/prompts/dex-trading.ts +86 -0
  93. package/src/prompts/discover-tokens.ts +86 -0
  94. package/src/prompts/index.ts +175 -0
  95. package/src/prompts/liquidity-positions.ts +270 -0
  96. package/src/prompts/pools.ts +571 -0
  97. package/src/prompts/portfolio.ts +242 -0
  98. package/src/prompts/social.ts +100 -0
  99. package/src/prompts/trading-calculations.ts +499 -0
  100. package/src/prompts/trading.ts +191 -0
  101. package/src/prompts/transfers.ts +103 -0
  102. package/src/prompts/utility-tools.ts +349 -0
  103. package/src/prompts/utility.ts +92 -0
  104. package/src/prompts/utils/workflowTemplates.ts +511 -0
  105. package/src/schemas/common-schemas.ts +393 -0
  106. package/src/scripts/test-all-prompts.ts +184 -0
  107. package/src/server.ts +367 -0
  108. package/src/tools/__tests__/dex-tools.test.ts +562 -0
  109. package/src/tools/__tests__/liquidity-positions.test.ts +673 -0
  110. package/src/tools/balance/index.ts +174 -0
  111. package/src/tools/creation/index.ts +182 -0
  112. package/src/tools/dex/index.ts +226 -0
  113. package/src/tools/dex/liquidity-positions.ts +547 -0
  114. package/src/tools/index.ts +94 -0
  115. package/src/tools/pools/fetchAllPools.ts +47 -0
  116. package/src/tools/pools/fetchAllPriceHistory.ts +119 -0
  117. package/src/tools/pools/fetchPoolDetails.ts +27 -0
  118. package/src/tools/pools/fetchPoolDetailsForCalculation.ts +22 -0
  119. package/src/tools/pools/fetchPools.ts +47 -0
  120. package/src/tools/pools/fetchPriceHistory.ts +124 -0
  121. package/src/tools/pools/fetchTokenDetails.ts +77 -0
  122. package/src/tools/pools/index.ts +284 -0
  123. package/src/tools/social/index.ts +64 -0
  124. package/src/tools/trading/index.ts +605 -0
  125. package/src/tools/transfers/index.ts +75 -0
  126. package/src/tools/utils/clearCache.ts +36 -0
  127. package/src/tools/utils/createWallet.ts +19 -0
  128. package/src/tools/utils/explainSdkUsage.ts +1446 -0
  129. package/src/tools/utils/getAddress.ts +12 -0
  130. package/src/tools/utils/getCacheInfo.ts +14 -0
  131. package/src/tools/utils/getConfig.ts +21 -0
  132. package/src/tools/utils/getEnvironment.ts +17 -0
  133. package/src/tools/utils/getEthereumAddress.ts +12 -0
  134. package/src/tools/utils/getUrlByTokenName.ts +12 -0
  135. package/src/tools/utils/getVersion.ts +25 -0
  136. package/src/tools/utils/getWallet.ts +25 -0
  137. package/src/tools/utils/hasWallet.ts +15 -0
  138. package/src/tools/utils/index.ts +37 -0
  139. package/src/tools/utils/isTokenGraduated.ts +16 -0
  140. package/src/tools/utils/setWallet.ts +41 -0
  141. package/src/tools/utils/switchEnvironment.ts +28 -0
  142. package/src/types/mcp.ts +72 -0
  143. package/src/utils/__tests__/validation.test.ts +147 -0
  144. package/src/utils/constraints.ts +155 -0
  145. package/src/utils/default-values.ts +208 -0
  146. package/src/utils/error-handler.ts +69 -0
  147. package/src/utils/error-templates.ts +273 -0
  148. package/src/utils/response-formatter.ts +51 -0
  149. package/src/utils/tool-factory.ts +303 -0
  150. package/src/utils/tool-registry.ts +296 -0
  151. package/src/utils/validation.ts +371 -0
  152. package/tests/wallet-management-integration.test.ts +284 -0
  153. package/tsconfig.json +23 -0
@@ -0,0 +1,673 @@
1
+ /**
2
+ * Unit Tests for Liquidity Position Management MCP Tools
3
+ *
4
+ * Tests the MCP tools for managing GalaSwap liquidity positions including:
5
+ * - Fetching user positions (all, by ID, by token pair)
6
+ * - Creating liquidity positions (by price or tick)
7
+ * - Estimating and removing liquidity
8
+ * - Collecting accumulated fees
9
+ */
10
+
11
+ import {
12
+ getUserLiquidityPositionsTool,
13
+ getLiquidityPositionByIdTool,
14
+ getLiquidityPositionTool,
15
+ addLiquidityByPriceTool,
16
+ addLiquidityByTicksTool,
17
+ estimateRemoveLiquidityTool,
18
+ removeLiquidityTool,
19
+ collectPositionFeesTool,
20
+ } from '../dex/liquidity-positions';
21
+
22
+ /**
23
+ * Mock LaunchpadSDK with all liquidity position methods
24
+ */
25
+ const mockSdk = {
26
+ getSwapUserLiquidityPositions: jest.fn(),
27
+ getSwapLiquidityPositionById: jest.fn(),
28
+ getSwapLiquidityPosition: jest.fn(),
29
+ addSwapLiquidityByPrice: jest.fn(),
30
+ addSwapLiquidityByTicks: jest.fn(),
31
+ getSwapEstimateRemoveLiquidity: jest.fn(),
32
+ removeSwapLiquidity: jest.fn(),
33
+ collectSwapPositionFees: jest.fn(),
34
+ getAddress: jest.fn(() => 'eth|0x1234567890abcdef1234567890abcdef12345678'),
35
+ };
36
+
37
+ describe('Liquidity Position Management MCP Tools', () => {
38
+ beforeEach(() => {
39
+ jest.clearAllMocks();
40
+ });
41
+
42
+ describe('getUserLiquidityPositionsTool', () => {
43
+ it('should be properly configured tool', () => {
44
+ expect(getUserLiquidityPositionsTool).toBeDefined();
45
+ expect(getUserLiquidityPositionsTool.name).toBe('gala_launchpad_get_user_liquidity_positions');
46
+ expect(getUserLiquidityPositionsTool.description).toContain('liquidity positions');
47
+ });
48
+
49
+ it('should have correct input schema', () => {
50
+ const schema = getUserLiquidityPositionsTool.inputSchema as any;
51
+ expect(schema.type).toBe('object');
52
+ expect(schema.properties).toHaveProperty('ownerAddress');
53
+ expect(schema.required).toContain('ownerAddress');
54
+ });
55
+
56
+ it('should return formatted positions response', async () => {
57
+ const mockPositions = [
58
+ {
59
+ positionId: 'pos-1',
60
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
61
+ token0: 'GALA|Unit|none|none',
62
+ token1: 'GUSDC|Unit|none|none',
63
+ feeTier: 3000,
64
+ liquidity: '1000000000',
65
+ amount0: '5000',
66
+ amount1: '5000',
67
+ tickLower: -276320,
68
+ tickUpper: -276000,
69
+ feeAmount0: '50',
70
+ feeAmount1: '50',
71
+ },
72
+ ];
73
+
74
+ mockSdk.getSwapUserLiquidityPositions.mockResolvedValueOnce(mockPositions);
75
+
76
+ const handler = getUserLiquidityPositionsTool.handler as any;
77
+ const result = await handler(mockSdk, {
78
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
79
+ limit: 10,
80
+ });
81
+
82
+ expect(result).toBeDefined();
83
+ expect(result.content).toBeDefined();
84
+ expect(result.content[0].type).toBe('text');
85
+ expect(result.content[0].text).toContain('1');
86
+ });
87
+
88
+ it('should handle empty positions list', async () => {
89
+ mockSdk.getSwapUserLiquidityPositions.mockResolvedValueOnce([]);
90
+
91
+ const handler = getUserLiquidityPositionsTool.handler as any;
92
+ const result = await handler(mockSdk, {
93
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
94
+ });
95
+
96
+ expect(result).toBeDefined();
97
+ expect(result.content[0].text).toContain('0');
98
+ });
99
+
100
+ it('should handle position query errors', async () => {
101
+ mockSdk.getSwapUserLiquidityPositions.mockRejectedValueOnce(
102
+ new Error('Network error')
103
+ );
104
+
105
+ const handler = getUserLiquidityPositionsTool.handler as any;
106
+
107
+ try {
108
+ await handler(mockSdk, {
109
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
110
+ });
111
+ throw new Error('Should have thrown error');
112
+ } catch (error) {
113
+ expect(error).toBeDefined();
114
+ }
115
+ });
116
+ });
117
+
118
+ describe('getLiquidityPositionByIdTool', () => {
119
+ it('should be properly configured tool', () => {
120
+ expect(getLiquidityPositionByIdTool).toBeDefined();
121
+ expect(getLiquidityPositionByIdTool.name).toBe('gala_launchpad_get_liquidity_position_by_id');
122
+ expect(getLiquidityPositionByIdTool.description).toContain('position');
123
+ });
124
+
125
+ it('should have correct input schema with ownerAddress and positionId', () => {
126
+ const schema = getLiquidityPositionByIdTool.inputSchema as any;
127
+ expect(schema.properties).toHaveProperty('ownerAddress');
128
+ expect(schema.properties).toHaveProperty('positionId');
129
+ expect(schema.required).toEqual(['ownerAddress', 'positionId']);
130
+ });
131
+
132
+ it('should return specific position by ID', async () => {
133
+ const mockPosition = {
134
+ positionId: 'pos-123',
135
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
136
+ token0: 'GALA|Unit|none|none',
137
+ token1: 'GUSDC|Unit|none|none',
138
+ feeTier: 3000,
139
+ liquidity: '1000000000',
140
+ amount0: '5000',
141
+ amount1: '5000',
142
+ tickLower: -276320,
143
+ tickUpper: -276000,
144
+ feeAmount0: '50',
145
+ feeAmount1: '50',
146
+ };
147
+
148
+ mockSdk.getSwapLiquidityPositionById.mockResolvedValueOnce(mockPosition);
149
+
150
+ const handler = getLiquidityPositionByIdTool.handler as any;
151
+ const result = await handler(mockSdk, {
152
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
153
+ positionId: 'pos-123',
154
+ });
155
+
156
+ expect(result).toBeDefined();
157
+ expect(result.content[0].text).toContain('pos-123');
158
+ });
159
+
160
+ it('should handle position not found error', async () => {
161
+ mockSdk.getSwapLiquidityPositionById.mockRejectedValueOnce(
162
+ new Error('Position not found')
163
+ );
164
+
165
+ const handler = getLiquidityPositionByIdTool.handler as any;
166
+
167
+ try {
168
+ await handler(mockSdk, {
169
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
170
+ positionId: 'invalid-id',
171
+ });
172
+ throw new Error('Should have thrown error');
173
+ } catch (error) {
174
+ expect(error).toBeDefined();
175
+ }
176
+ });
177
+ });
178
+
179
+ describe('getLiquidityPositionTool', () => {
180
+ it('should be properly configured tool', () => {
181
+ expect(getLiquidityPositionTool).toBeDefined();
182
+ expect(getLiquidityPositionTool.name).toBe('gala_launchpad_get_liquidity_position');
183
+ });
184
+
185
+ it('should have correct input schema with position details', () => {
186
+ const schema = getLiquidityPositionTool.inputSchema as any;
187
+ expect(schema.properties).toHaveProperty('ownerAddress');
188
+ expect(schema.properties).toHaveProperty('token0');
189
+ expect(schema.properties).toHaveProperty('token1');
190
+ expect(schema.properties).toHaveProperty('fee');
191
+ expect(schema.properties).toHaveProperty('tickLower');
192
+ expect(schema.properties).toHaveProperty('tickUpper');
193
+ });
194
+
195
+ it('should return position by token pair and tick range', async () => {
196
+ const mockPosition = {
197
+ positionId: 'pos-456',
198
+ token0: 'GALA|Unit|none|none',
199
+ token1: 'GUSDC|Unit|none|none',
200
+ feeTier: 3000,
201
+ liquidity: '1000000000',
202
+ };
203
+
204
+ mockSdk.getSwapLiquidityPosition.mockResolvedValueOnce(mockPosition);
205
+
206
+ const handler = getLiquidityPositionTool.handler as any;
207
+ const result = await handler(mockSdk, {
208
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
209
+ token0: 'GALA',
210
+ token1: 'GUSDC',
211
+ fee: 3000,
212
+ tickLower: -276320,
213
+ tickUpper: -276000,
214
+ });
215
+
216
+ expect(result).toBeDefined();
217
+ expect(result.content[0].text).toContain('GALA');
218
+ });
219
+ });
220
+
221
+ describe('estimateRemoveLiquidityTool', () => {
222
+ it('should be properly configured tool', () => {
223
+ expect(estimateRemoveLiquidityTool).toBeDefined();
224
+ expect(estimateRemoveLiquidityTool.name).toBe('gala_launchpad_estimate_remove_liquidity');
225
+ expect(estimateRemoveLiquidityTool.description).toMatch(/[Ee]stimate/);
226
+ });
227
+
228
+ it('should have correct input schema', () => {
229
+ const schema = estimateRemoveLiquidityTool.inputSchema as any;
230
+ expect(schema.properties).toHaveProperty('token0');
231
+ expect(schema.properties).toHaveProperty('token1');
232
+ expect(schema.properties).toHaveProperty('fee');
233
+ expect(schema.properties).toHaveProperty('liquidity');
234
+ expect(schema.properties).toHaveProperty('tickLower');
235
+ expect(schema.properties).toHaveProperty('tickUpper');
236
+ });
237
+
238
+ it('should return estimated removal amounts', async () => {
239
+ const mockEstimate = {
240
+ amount0: '5000',
241
+ amount1: '5000',
242
+ fee0: '50',
243
+ fee1: '50',
244
+ };
245
+
246
+ mockSdk.getSwapEstimateRemoveLiquidity.mockResolvedValueOnce(mockEstimate);
247
+
248
+ const handler = estimateRemoveLiquidityTool.handler as any;
249
+ const result = await handler(mockSdk, {
250
+ token0: 'GALA',
251
+ token1: 'GUSDC',
252
+ fee: 3000,
253
+ liquidity: '1000000000',
254
+ tickLower: -276320,
255
+ tickUpper: -276000,
256
+ });
257
+
258
+ expect(result).toBeDefined();
259
+ expect(result.content[0].text).toContain('5000');
260
+ });
261
+
262
+ it('should handle estimation with partial removal', async () => {
263
+ const mockEstimate = {
264
+ amount0: '2500',
265
+ amount1: '2500',
266
+ fee0: '25',
267
+ fee1: '25',
268
+ };
269
+
270
+ mockSdk.getSwapEstimateRemoveLiquidity.mockResolvedValueOnce(mockEstimate);
271
+
272
+ const handler = estimateRemoveLiquidityTool.handler as any;
273
+ const result = await handler(mockSdk, {
274
+ token0: 'GALA',
275
+ token1: 'GUSDC',
276
+ fee: 3000,
277
+ liquidity: '500000000', // Half the original
278
+ tickLower: -276320,
279
+ tickUpper: -276000,
280
+ });
281
+
282
+ expect(result).toBeDefined();
283
+ expect(result.content[0].text).toContain('2500');
284
+ });
285
+
286
+ it('should handle estimation errors', async () => {
287
+ mockSdk.getSwapEstimateRemoveLiquidity.mockRejectedValueOnce(
288
+ new Error('Invalid position')
289
+ );
290
+
291
+ const handler = estimateRemoveLiquidityTool.handler as any;
292
+
293
+ try {
294
+ await handler(mockSdk, {
295
+ token0: 'INVALID',
296
+ token1: 'INVALID',
297
+ fee: 3000,
298
+ liquidity: '1000000000',
299
+ tickLower: -276320,
300
+ tickUpper: -276000,
301
+ });
302
+ throw new Error('Should have thrown error');
303
+ } catch (error) {
304
+ expect(error).toBeDefined();
305
+ }
306
+ });
307
+ });
308
+
309
+ describe('addLiquidityByPriceTool', () => {
310
+ it('should be properly configured tool', () => {
311
+ expect(addLiquidityByPriceTool).toBeDefined();
312
+ expect(addLiquidityByPriceTool.name).toBe('gala_launchpad_add_liquidity_by_price');
313
+ expect(addLiquidityByPriceTool.description).toContain('price');
314
+ });
315
+
316
+ it('should have correct input schema with price range parameters', () => {
317
+ const schema = addLiquidityByPriceTool.inputSchema as any;
318
+ expect(schema.properties).toHaveProperty('token0');
319
+ expect(schema.properties).toHaveProperty('token1');
320
+ expect(schema.properties).toHaveProperty('fee');
321
+ expect(schema.properties).toHaveProperty('minPrice');
322
+ expect(schema.properties).toHaveProperty('maxPrice');
323
+ expect(schema.properties).toHaveProperty('amount0Desired');
324
+ expect(schema.properties).toHaveProperty('amount1Desired');
325
+ });
326
+
327
+ it('should create liquidity position using price range', async () => {
328
+ const mockResult = {
329
+ transactionId: 'tx-123',
330
+ positionId: 'pos-789',
331
+ token0: 'GALA',
332
+ token1: 'GUSDC',
333
+ amount0: '5000',
334
+ amount1: '5000',
335
+ };
336
+
337
+ mockSdk.addSwapLiquidityByPrice.mockResolvedValueOnce(mockResult);
338
+
339
+ const handler = addLiquidityByPriceTool.handler as any;
340
+ const result = await handler(mockSdk, {
341
+ token0: 'GALA',
342
+ token1: 'GUSDC',
343
+ fee: 3000,
344
+ minPrice: '0.95',
345
+ maxPrice: '1.05',
346
+ amount0Desired: '5000',
347
+ amount1Desired: '5000',
348
+ });
349
+
350
+ expect(result).toBeDefined();
351
+ expect(result.content[0].text).toContain('tx-123');
352
+ });
353
+
354
+ it('should handle slippage protection in liquidity creation', async () => {
355
+ const mockResult = {
356
+ transactionId: 'tx-456',
357
+ positionId: 'pos-101112',
358
+ };
359
+
360
+ mockSdk.addSwapLiquidityByPrice.mockResolvedValueOnce(mockResult);
361
+
362
+ const handler = addLiquidityByPriceTool.handler as any;
363
+ const result = await handler(mockSdk, {
364
+ token0: 'GALA',
365
+ token1: 'GUSDC',
366
+ fee: 3000,
367
+ minPrice: '0.90',
368
+ maxPrice: '1.10',
369
+ amount0Desired: '10000',
370
+ amount1Desired: '10000',
371
+ amount0Min: '9000',
372
+ amount1Min: '9000',
373
+ });
374
+
375
+ expect(result).toBeDefined();
376
+ expect(result.content[0].text).toContain('tx-456');
377
+ });
378
+
379
+ it('should handle liquidity creation errors', async () => {
380
+ mockSdk.addSwapLiquidityByPrice.mockRejectedValueOnce(
381
+ new Error('Insufficient balance')
382
+ );
383
+
384
+ const handler = addLiquidityByPriceTool.handler as any;
385
+
386
+ try {
387
+ await handler(mockSdk, {
388
+ token0: 'GALA',
389
+ token1: 'GUSDC',
390
+ fee: 3000,
391
+ minPrice: '0.95',
392
+ maxPrice: '1.05',
393
+ amount0Desired: '1000000000', // Too large
394
+ amount1Desired: '1000000000',
395
+ });
396
+ throw new Error('Should have thrown error');
397
+ } catch (error) {
398
+ expect(error).toBeDefined();
399
+ }
400
+ });
401
+ });
402
+
403
+ describe('addLiquidityByTicksTool', () => {
404
+ it('should be properly configured tool', () => {
405
+ expect(addLiquidityByTicksTool).toBeDefined();
406
+ expect(addLiquidityByTicksTool.name).toBe('gala_launchpad_add_liquidity_by_ticks');
407
+ expect(addLiquidityByTicksTool.description).toContain('tick');
408
+ });
409
+
410
+ it('should have correct input schema with tick parameters', () => {
411
+ const schema = addLiquidityByTicksTool.inputSchema as any;
412
+ expect(schema.properties).toHaveProperty('token0');
413
+ expect(schema.properties).toHaveProperty('token1');
414
+ expect(schema.properties).toHaveProperty('feeTier');
415
+ expect(schema.properties).toHaveProperty('tickLower');
416
+ expect(schema.properties).toHaveProperty('tickUpper');
417
+ expect(schema.properties).toHaveProperty('amount0Desired');
418
+ expect(schema.properties).toHaveProperty('amount1Desired');
419
+ });
420
+
421
+ it('should create liquidity position using precise tick boundaries', async () => {
422
+ const mockResult = {
423
+ transactionId: 'tx-789',
424
+ positionId: 'pos-131415',
425
+ token0: 'GALA',
426
+ token1: 'GUSDC',
427
+ };
428
+
429
+ mockSdk.addSwapLiquidityByTicks.mockResolvedValueOnce(mockResult);
430
+
431
+ const handler = addLiquidityByTicksTool.handler as any;
432
+ const result = await handler(mockSdk, {
433
+ token0: 'GALA',
434
+ token1: 'GUSDC',
435
+ feeTier: 3000,
436
+ tickLower: -276320,
437
+ tickUpper: -276000,
438
+ amount0Desired: '5000',
439
+ amount1Desired: '5000',
440
+ });
441
+
442
+ expect(result).toBeDefined();
443
+ expect(result.content[0].text).toContain('tx-789');
444
+ });
445
+ });
446
+
447
+ describe('removeLiquidityTool', () => {
448
+ it('should be properly configured tool', () => {
449
+ expect(removeLiquidityTool).toBeDefined();
450
+ expect(removeLiquidityTool.name).toBe('gala_launchpad_remove_liquidity');
451
+ expect(removeLiquidityTool.description).toMatch(/[Rr]emove/);
452
+ });
453
+
454
+ it('should have correct input schema with removal parameters', () => {
455
+ const schema = removeLiquidityTool.inputSchema as any;
456
+ expect(schema.properties).toHaveProperty('ownerAddress');
457
+ expect(schema.properties).toHaveProperty('positionId');
458
+ expect(schema.properties).toHaveProperty('liquidity');
459
+ expect(schema.properties).toHaveProperty('amount0Min');
460
+ expect(schema.properties).toHaveProperty('amount1Min');
461
+ expect(schema.properties).toHaveProperty('deadline');
462
+ });
463
+
464
+ it('should remove liquidity from position', async () => {
465
+ const mockResult = {
466
+ transactionId: 'tx-remove-1',
467
+ amount0: '5000',
468
+ amount1: '5000',
469
+ fee0: '50',
470
+ fee1: '50',
471
+ };
472
+
473
+ mockSdk.removeSwapLiquidity.mockResolvedValueOnce(mockResult);
474
+
475
+ const handler = removeLiquidityTool.handler as any;
476
+ const result = await handler(mockSdk, {
477
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
478
+ positionId: 'pos-789',
479
+ liquidity: '1000000000',
480
+ amount0Min: '0',
481
+ amount1Min: '0',
482
+ deadline: Math.floor(Date.now() / 1000) + 3600,
483
+ });
484
+
485
+ expect(result).toBeDefined();
486
+ expect(result.content[0].text).toContain('tx-remove-1');
487
+ });
488
+
489
+ it('should handle partial liquidity removal', async () => {
490
+ const mockResult = {
491
+ transactionId: 'tx-remove-2',
492
+ amount0: '2500',
493
+ amount1: '2500',
494
+ };
495
+
496
+ mockSdk.removeSwapLiquidity.mockResolvedValueOnce(mockResult);
497
+
498
+ const handler = removeLiquidityTool.handler as any;
499
+ const result = await handler(mockSdk, {
500
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
501
+ positionId: 'pos-789',
502
+ liquidity: '500000000', // Half
503
+ amount0Min: '0',
504
+ amount1Min: '0',
505
+ deadline: Math.floor(Date.now() / 1000) + 3600,
506
+ });
507
+
508
+ expect(result).toBeDefined();
509
+ expect(result.content[0].text).toContain('2500');
510
+ });
511
+
512
+ it('should handle removal errors', async () => {
513
+ mockSdk.removeSwapLiquidity.mockRejectedValueOnce(
514
+ new Error('Position not found')
515
+ );
516
+
517
+ const handler = removeLiquidityTool.handler as any;
518
+
519
+ try {
520
+ await handler(mockSdk, {
521
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
522
+ positionId: 'invalid',
523
+ liquidity: '1000000000',
524
+ amount0Min: '0',
525
+ amount1Min: '0',
526
+ deadline: Math.floor(Date.now() / 1000) + 3600,
527
+ });
528
+ throw new Error('Should have thrown error');
529
+ } catch (error) {
530
+ expect(error).toBeDefined();
531
+ }
532
+ });
533
+ });
534
+
535
+ describe('collectPositionFeesTool', () => {
536
+ it('should be properly configured tool', () => {
537
+ expect(collectPositionFeesTool).toBeDefined();
538
+ expect(collectPositionFeesTool.name).toBe('gala_launchpad_collect_position_fees');
539
+ expect(collectPositionFeesTool.description).toContain('fees');
540
+ });
541
+
542
+ it('should have correct input schema with position identification', () => {
543
+ const schema = collectPositionFeesTool.inputSchema as any;
544
+ expect(schema.properties).toHaveProperty('ownerAddress');
545
+ expect(schema.properties).toHaveProperty('positionId');
546
+ expect(schema.required).toEqual(['ownerAddress', 'positionId']);
547
+ });
548
+
549
+ it('should collect accumulated trading fees from position', async () => {
550
+ const mockResult = {
551
+ transactionId: 'tx-collect-1',
552
+ feeAmount0: '50',
553
+ feeAmount1: '50',
554
+ };
555
+
556
+ mockSdk.collectSwapPositionFees.mockResolvedValueOnce(mockResult);
557
+
558
+ const handler = collectPositionFeesTool.handler as any;
559
+ const result = await handler(mockSdk, {
560
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
561
+ positionId: 'pos-789',
562
+ });
563
+
564
+ expect(result).toBeDefined();
565
+ expect(result.content[0].text).toContain('tx-collect-1');
566
+ });
567
+
568
+ it('should handle fee collection when no fees accumulated', async () => {
569
+ const mockResult = {
570
+ transactionId: 'tx-collect-2',
571
+ feeAmount0: '0',
572
+ feeAmount1: '0',
573
+ };
574
+
575
+ mockSdk.collectSwapPositionFees.mockResolvedValueOnce(mockResult);
576
+
577
+ const handler = collectPositionFeesTool.handler as any;
578
+ const result = await handler(mockSdk, {
579
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
580
+ positionId: 'pos-no-fees',
581
+ });
582
+
583
+ expect(result).toBeDefined();
584
+ expect(result.content[0].text).toContain('0');
585
+ });
586
+
587
+ it('should handle fee collection errors', async () => {
588
+ mockSdk.collectSwapPositionFees.mockRejectedValueOnce(
589
+ new Error('Cannot collect from closed position')
590
+ );
591
+
592
+ const handler = collectPositionFeesTool.handler as any;
593
+
594
+ try {
595
+ await handler(mockSdk, {
596
+ ownerAddress: 'eth|0x1234567890abcdef1234567890abcdef12345678',
597
+ positionId: 'closed-position',
598
+ });
599
+ throw new Error('Should have thrown error');
600
+ } catch (error) {
601
+ expect(error).toBeDefined();
602
+ }
603
+ });
604
+ });
605
+
606
+ describe('Tool Integration', () => {
607
+ it('should export all 8 liquidity position tools', () => {
608
+ expect(getUserLiquidityPositionsTool).toBeDefined();
609
+ expect(getLiquidityPositionByIdTool).toBeDefined();
610
+ expect(getLiquidityPositionTool).toBeDefined();
611
+ expect(addLiquidityByPriceTool).toBeDefined();
612
+ expect(addLiquidityByTicksTool).toBeDefined();
613
+ expect(estimateRemoveLiquidityTool).toBeDefined();
614
+ expect(removeLiquidityTool).toBeDefined();
615
+ expect(collectPositionFeesTool).toBeDefined();
616
+ });
617
+
618
+ it('should have unique tool names', () => {
619
+ const tools = [
620
+ getUserLiquidityPositionsTool,
621
+ getLiquidityPositionByIdTool,
622
+ getLiquidityPositionTool,
623
+ addLiquidityByPriceTool,
624
+ addLiquidityByTicksTool,
625
+ estimateRemoveLiquidityTool,
626
+ removeLiquidityTool,
627
+ collectPositionFeesTool,
628
+ ];
629
+
630
+ const names = tools.map((t) => t.name);
631
+ const uniqueNames = new Set(names);
632
+ expect(uniqueNames.size).toBe(8);
633
+ });
634
+
635
+ it('should have descriptions for all tools', () => {
636
+ const tools = [
637
+ getUserLiquidityPositionsTool,
638
+ getLiquidityPositionByIdTool,
639
+ getLiquidityPositionTool,
640
+ addLiquidityByPriceTool,
641
+ addLiquidityByTicksTool,
642
+ estimateRemoveLiquidityTool,
643
+ removeLiquidityTool,
644
+ collectPositionFeesTool,
645
+ ];
646
+
647
+ tools.forEach((tool) => {
648
+ expect(tool.description).toBeDefined();
649
+ expect(tool.description.length).toBeGreaterThan(0);
650
+ });
651
+ });
652
+
653
+ it('should have input schemas for all tools', () => {
654
+ const tools = [
655
+ getUserLiquidityPositionsTool,
656
+ getLiquidityPositionByIdTool,
657
+ getLiquidityPositionTool,
658
+ addLiquidityByPriceTool,
659
+ addLiquidityByTicksTool,
660
+ estimateRemoveLiquidityTool,
661
+ removeLiquidityTool,
662
+ collectPositionFeesTool,
663
+ ];
664
+
665
+ tools.forEach((tool) => {
666
+ expect(tool.inputSchema).toBeDefined();
667
+ const schema = tool.inputSchema as any;
668
+ expect(schema.type).toBe('object');
669
+ expect(schema.properties).toBeDefined();
670
+ });
671
+ });
672
+ });
673
+ });