hak-saucerswap-plugin 1.0.0 → 2.0.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.
- package/LICENSE +1 -1
- package/README.md +17 -93
- package/dist/index.cjs +404 -313
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js +404 -314
- package/dist/index.js.map +1 -1
- package/package.json +6 -17
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { BaseTool, handleTransaction } from '@hashgraph/hedera-agent-kit';
|
|
1
2
|
import { z } from 'zod';
|
|
2
|
-
import { ContractFunctionParameters, ContractExecuteTransaction, AccountId, TokenId, ContractId } from '@hashgraph/sdk';
|
|
3
3
|
import axios from 'axios';
|
|
4
|
-
import {
|
|
4
|
+
import { ContractFunctionParameters, ContractExecuteTransaction, AccountId, TokenId, ContractId } from '@hiero-ledger/sdk';
|
|
5
5
|
|
|
6
|
-
// src/tools/
|
|
6
|
+
// src/tools/farms.ts
|
|
7
7
|
|
|
8
8
|
// src/api/endpoints.ts
|
|
9
9
|
var SAUCER_ENDPOINTS = {
|
|
@@ -34,7 +34,8 @@ var SaucerSwapClient = class {
|
|
|
34
34
|
this.retries = options.retries ?? 2;
|
|
35
35
|
this.http = options.http ?? axios.create({
|
|
36
36
|
baseURL: options.baseUrl ?? "https://api.saucerswap.finance",
|
|
37
|
-
timeout: options.timeoutMs ?? 1e4
|
|
37
|
+
timeout: options.timeoutMs ?? 1e4,
|
|
38
|
+
headers: options.apiKey ? { "x-api-key": options.apiKey } : void 0
|
|
38
39
|
});
|
|
39
40
|
}
|
|
40
41
|
async request(path, params) {
|
|
@@ -176,6 +177,7 @@ var resolveSaucerSwapConfig = (context) => {
|
|
|
176
177
|
baseUrl: ctxConfig.baseUrl ?? process.env.SAUCERSWAP_BASE_URL ?? DEFAULT_CONFIG.baseUrl,
|
|
177
178
|
timeoutMs: ctxConfig.timeoutMs ?? toNumber(process.env.SAUCERSWAP_TIMEOUT_MS, DEFAULT_CONFIG.timeoutMs),
|
|
178
179
|
retries: ctxConfig.retries ?? toNumber(process.env.SAUCERSWAP_RETRIES, DEFAULT_CONFIG.retries),
|
|
180
|
+
apiKey: ctxConfig.apiKey ?? process.env.SAUCERSWAP_API_KEY,
|
|
179
181
|
routerContractId: ctxConfig.routerContractId ?? process.env.SAUCERSWAP_ROUTER_CONTRACT_ID,
|
|
180
182
|
routerV2ContractId: ctxConfig.routerV2ContractId ?? process.env.SAUCERSWAP_ROUTER_V2_CONTRACT_ID,
|
|
181
183
|
wrappedHbarTokenId: ctxConfig.wrappedHbarTokenId ?? process.env.SAUCERSWAP_WRAPPED_HBAR_TOKEN_ID,
|
|
@@ -189,6 +191,47 @@ var resolveSaucerSwapConfig = (context) => {
|
|
|
189
191
|
};
|
|
190
192
|
};
|
|
191
193
|
|
|
194
|
+
// src/tools/farms.ts
|
|
195
|
+
var farmsInputSchema = z.object({
|
|
196
|
+
poolId: z.number().int().positive().optional().describe("Optional pool ID to filter farms")
|
|
197
|
+
});
|
|
198
|
+
var FarmsTool = class extends BaseTool {
|
|
199
|
+
constructor() {
|
|
200
|
+
super(...arguments);
|
|
201
|
+
this.method = "saucerswap_get_farms";
|
|
202
|
+
this.name = "SaucerSwap Get Farms";
|
|
203
|
+
this.description = "Get active farming opportunities on SaucerSwap.";
|
|
204
|
+
this.parameters = farmsInputSchema;
|
|
205
|
+
}
|
|
206
|
+
async normalizeParams(params, _context, _client) {
|
|
207
|
+
return farmsInputSchema.parse(params);
|
|
208
|
+
}
|
|
209
|
+
async coreAction(args, context, _client) {
|
|
210
|
+
const config = resolveSaucerSwapConfig(context);
|
|
211
|
+
const api = context.saucerswapClient ?? createSaucerSwapClient(config);
|
|
212
|
+
try {
|
|
213
|
+
const farms = await api.getFarms();
|
|
214
|
+
const filtered = args.poolId ? farms.filter((farm) => farm.poolId === args.poolId) : farms;
|
|
215
|
+
return {
|
|
216
|
+
success: true,
|
|
217
|
+
farms: filtered
|
|
218
|
+
};
|
|
219
|
+
} catch (error) {
|
|
220
|
+
return {
|
|
221
|
+
success: false,
|
|
222
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
async shouldSecondaryAction(_coreActionResult, _context) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
async secondaryAction(_request, _client, _context) {
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
var farmsTool = new FarmsTool();
|
|
234
|
+
|
|
192
235
|
// src/utils/amm.ts
|
|
193
236
|
var calculatePriceImpact = (inputAmount, outputAmount, poolReserveIn, poolReserveOut) => {
|
|
194
237
|
const inAmount = Number(inputAmount);
|
|
@@ -210,53 +253,6 @@ var applySlippageToAmount = (amount, slippageTolerance) => {
|
|
|
210
253
|
const numerator = BigInt(1e4 - bps);
|
|
211
254
|
return (amountBig * numerator / 10000n).toString();
|
|
212
255
|
};
|
|
213
|
-
|
|
214
|
-
// src/utils/quote.ts
|
|
215
|
-
var readAmount = (value) => {
|
|
216
|
-
if (typeof value === "string") {
|
|
217
|
-
return value;
|
|
218
|
-
}
|
|
219
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
220
|
-
return value.toString();
|
|
221
|
-
}
|
|
222
|
-
return null;
|
|
223
|
-
};
|
|
224
|
-
var normalizeSwapQuote = (quote, fallbackAmountIn) => {
|
|
225
|
-
const amountIn = readAmount(quote.amountIn) ?? fallbackAmountIn;
|
|
226
|
-
const expectedOutput = readAmount(quote.expectedOutput) ?? readAmount(quote.amountOut) ?? readAmount(quote.amountOutMin) ?? "";
|
|
227
|
-
if (!expectedOutput) {
|
|
228
|
-
throw new Error("SaucerSwap quote did not include an output amount.");
|
|
229
|
-
}
|
|
230
|
-
return {
|
|
231
|
-
amountIn,
|
|
232
|
-
expectedOutput,
|
|
233
|
-
priceImpact: typeof quote.priceImpact === "number" ? quote.priceImpact : null,
|
|
234
|
-
route: Array.isArray(quote.route) ? quote.route : [],
|
|
235
|
-
raw: quote
|
|
236
|
-
};
|
|
237
|
-
};
|
|
238
|
-
|
|
239
|
-
// src/utils/units.ts
|
|
240
|
-
var parseUnits = (amount, decimals) => {
|
|
241
|
-
if (!amount || typeof amount !== "string") {
|
|
242
|
-
throw new Error("Amount must be a non-empty string.");
|
|
243
|
-
}
|
|
244
|
-
if (decimals < 0) {
|
|
245
|
-
throw new Error("Decimals must be non-negative.");
|
|
246
|
-
}
|
|
247
|
-
const trimmed = amount.trim();
|
|
248
|
-
if (!/^\d+(\.\d+)?$/.test(trimmed)) {
|
|
249
|
-
throw new Error(`Invalid amount format: ${amount}`);
|
|
250
|
-
}
|
|
251
|
-
const [whole, fraction = ""] = trimmed.split(".");
|
|
252
|
-
if (fraction.length > decimals) {
|
|
253
|
-
throw new Error(`Amount has more than ${decimals} decimal places.`);
|
|
254
|
-
}
|
|
255
|
-
const paddedFraction = fraction.padEnd(decimals, "0");
|
|
256
|
-
const combined = `${whole}${paddedFraction}`;
|
|
257
|
-
const normalized = combined.replace(/^0+/, "");
|
|
258
|
-
return normalized === "" ? "0" : normalized;
|
|
259
|
-
};
|
|
260
256
|
var normalizeTokenAlias = (token, config) => {
|
|
261
257
|
const tokenLower = token.toLowerCase();
|
|
262
258
|
for (const [alias, value] of Object.entries(config.tokenAliases)) {
|
|
@@ -284,115 +280,106 @@ var accountIdToSolidityAddress = (accountId) => {
|
|
|
284
280
|
var contractIdFromString = (contractId) => {
|
|
285
281
|
return ContractId.fromString(contractId);
|
|
286
282
|
};
|
|
287
|
-
var finalizeTransaction = async (transaction, client, context, extra) => {
|
|
288
|
-
const mode = context.mode;
|
|
289
|
-
if (mode === AgentMode.RETURN_BYTES || mode === "returnBytes" || mode === "RETURN_BYTES") {
|
|
290
|
-
const txBytes = await transaction.toBytes();
|
|
291
|
-
return {
|
|
292
|
-
success: true,
|
|
293
|
-
transactionBytes: Buffer.from(txBytes).toString("base64"),
|
|
294
|
-
...extra
|
|
295
|
-
};
|
|
296
|
-
}
|
|
297
|
-
const response = await transaction.execute(client);
|
|
298
|
-
const receipt = await response.getReceipt(client);
|
|
299
|
-
return {
|
|
300
|
-
success: true,
|
|
301
|
-
transactionId: response.transactionId?.toString(),
|
|
302
|
-
status: receipt.status.toString(),
|
|
303
|
-
...extra
|
|
304
|
-
};
|
|
305
|
-
};
|
|
306
283
|
|
|
307
|
-
// src/
|
|
308
|
-
var
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
amount: z.string().describe("Amount to swap (decimal format)"),
|
|
312
|
-
slippageTolerance: z.number().optional().default(0.5).describe("Maximum slippage tolerance percentage"),
|
|
313
|
-
deadline: z.number().optional().describe("Transaction deadline in minutes from now or a unix timestamp")
|
|
314
|
-
});
|
|
315
|
-
var resolveDeadline = (deadlineInput, defaultMinutes) => {
|
|
316
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
317
|
-
if (!deadlineInput) {
|
|
318
|
-
return now + defaultMinutes * 60;
|
|
284
|
+
// src/utils/units.ts
|
|
285
|
+
var parseUnits = (amount, decimals) => {
|
|
286
|
+
if (!amount || typeof amount !== "string") {
|
|
287
|
+
throw new Error("Amount must be a non-empty string.");
|
|
319
288
|
}
|
|
320
|
-
if (
|
|
321
|
-
|
|
289
|
+
if (decimals < 0) {
|
|
290
|
+
throw new Error("Decimals must be non-negative.");
|
|
322
291
|
}
|
|
323
|
-
|
|
292
|
+
const trimmed = amount.trim();
|
|
293
|
+
if (!/^\d+(\.\d+)?$/.test(trimmed)) {
|
|
294
|
+
throw new Error(`Invalid amount format: ${amount}`);
|
|
295
|
+
}
|
|
296
|
+
const [whole, fraction = ""] = trimmed.split(".");
|
|
297
|
+
if (fraction.length > decimals) {
|
|
298
|
+
throw new Error(`Amount has more than ${decimals} decimal places.`);
|
|
299
|
+
}
|
|
300
|
+
const paddedFraction = fraction.padEnd(decimals, "0");
|
|
301
|
+
const combined = `${whole}${paddedFraction}`;
|
|
302
|
+
const normalized = combined.replace(/^0+/, "");
|
|
303
|
+
return normalized === "" ? "0" : normalized;
|
|
324
304
|
};
|
|
325
|
-
|
|
326
|
-
|
|
305
|
+
|
|
306
|
+
// src/tools/liquidity.ts
|
|
307
|
+
var addLiquidityInputSchema = z.object({
|
|
308
|
+
tokenA: z.string().describe("First token ID"),
|
|
309
|
+
tokenB: z.string().describe("Second token ID"),
|
|
310
|
+
amountA: z.string().describe("Amount of tokenA to add"),
|
|
311
|
+
amountB: z.string().describe("Amount of tokenB to add"),
|
|
312
|
+
slippageTolerance: z.number().optional().default(0.5).describe("Maximum slippage tolerance percentage")
|
|
313
|
+
});
|
|
314
|
+
var removeLiquidityInputSchema = z.object({
|
|
315
|
+
tokenA: z.string().describe("First token ID"),
|
|
316
|
+
tokenB: z.string().describe("Second token ID"),
|
|
317
|
+
lpTokenAmount: z.string().describe("Amount of LP tokens to burn"),
|
|
318
|
+
minAmountA: z.string().describe("Minimum amount of tokenA to receive"),
|
|
319
|
+
minAmountB: z.string().describe("Minimum amount of tokenB to receive")
|
|
320
|
+
});
|
|
321
|
+
var isLiquidityCorePayload = (value) => typeof value === "object" && value !== null && "transaction" in value;
|
|
322
|
+
var addLiquidityPostProcess = (response) => `SaucerSwap add liquidity submitted. Status: ${response.status}. Transaction ID: ${response.transactionId}`;
|
|
323
|
+
var removeLiquidityPostProcess = (response) => `SaucerSwap remove liquidity submitted. Status: ${response.status}. Transaction ID: ${response.transactionId}`;
|
|
324
|
+
var resolveDeadline = (defaultMinutes) => {
|
|
325
|
+
return Math.floor(Date.now() / 1e3) + defaultMinutes * 60;
|
|
327
326
|
};
|
|
328
|
-
var
|
|
329
|
-
|
|
327
|
+
var resolveRouterContract = (config) => {
|
|
328
|
+
const routerContractId = config.defaultPoolVersion === "v2" ? config.routerV2ContractId ?? config.routerContractId : config.routerContractId ?? config.routerV2ContractId;
|
|
329
|
+
if (!routerContractId) {
|
|
330
|
+
throw new Error("Missing SaucerSwap router contract ID configuration.");
|
|
331
|
+
}
|
|
332
|
+
return routerContractId;
|
|
330
333
|
};
|
|
331
|
-
var
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
334
|
+
var AddLiquidityTool = class extends BaseTool {
|
|
335
|
+
constructor() {
|
|
336
|
+
super(...arguments);
|
|
337
|
+
this.method = "saucerswap_add_liquidity";
|
|
338
|
+
this.name = "SaucerSwap Add Liquidity";
|
|
339
|
+
this.description = "Add liquidity to a SaucerSwap pool.";
|
|
340
|
+
this.parameters = addLiquidityInputSchema;
|
|
341
|
+
}
|
|
342
|
+
async normalizeParams(params, _context, _client) {
|
|
343
|
+
return addLiquidityInputSchema.parse(params);
|
|
344
|
+
}
|
|
345
|
+
async coreAction(args, context, client) {
|
|
338
346
|
const config = resolveSaucerSwapConfig(context);
|
|
339
347
|
const operatorAccountId = client?.operatorAccountId?.toString();
|
|
340
348
|
const slippageTolerance = args.slippageTolerance ?? 0.5;
|
|
341
349
|
if (!operatorAccountId) {
|
|
342
350
|
return {
|
|
343
351
|
success: false,
|
|
344
|
-
error: "Hedera client with an operator account is required for
|
|
352
|
+
error: "Hedera client with an operator account is required for liquidity actions."
|
|
345
353
|
};
|
|
346
354
|
}
|
|
347
355
|
try {
|
|
348
356
|
const api = context.saucerswapClient ?? createSaucerSwapClient(config);
|
|
349
|
-
const
|
|
350
|
-
const
|
|
351
|
-
const
|
|
352
|
-
const
|
|
353
|
-
const
|
|
354
|
-
const
|
|
355
|
-
if (!
|
|
357
|
+
const tokenAInput = normalizeTokenAlias(args.tokenA, config);
|
|
358
|
+
const tokenBInput = normalizeTokenAlias(args.tokenB, config);
|
|
359
|
+
const tokenAId = await api.resolveTokenId(tokenAInput);
|
|
360
|
+
const tokenBId = await api.resolveTokenId(tokenBInput);
|
|
361
|
+
const tokenA = await api.getTokenByIdOrSymbol(tokenAId);
|
|
362
|
+
const tokenB = await api.getTokenByIdOrSymbol(tokenBId);
|
|
363
|
+
if (!tokenA || !tokenB) {
|
|
356
364
|
return {
|
|
357
365
|
success: false,
|
|
358
366
|
error: "Unable to resolve token metadata from SaucerSwap API."
|
|
359
367
|
};
|
|
360
368
|
}
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
args.amount
|
|
368
|
-
);
|
|
369
|
-
const amountInSmallest = amountToSmallest(args.amount, fromTokenMeta.decimals);
|
|
370
|
-
const expectedOutSmallest = expectedToSmallest(
|
|
371
|
-
quote.expectedOutput,
|
|
372
|
-
toTokenMeta.decimals
|
|
373
|
-
);
|
|
374
|
-
const minOutSmallest = applySlippageToAmount(expectedOutSmallest, slippageTolerance);
|
|
375
|
-
const routerContractId = config.defaultPoolVersion === "v2" ? config.routerV2ContractId ?? config.routerContractId : config.routerContractId ?? config.routerV2ContractId;
|
|
376
|
-
if (!routerContractId) {
|
|
377
|
-
return {
|
|
378
|
-
success: false,
|
|
379
|
-
error: "Missing SaucerSwap router contract ID configuration."
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
const deadline = resolveDeadline(args.deadline, config.deadlineMinutes);
|
|
369
|
+
const amountADesired = parseUnits(args.amountA, tokenA.decimals);
|
|
370
|
+
const amountBDesired = parseUnits(args.amountB, tokenB.decimals);
|
|
371
|
+
const amountAMin = applySlippageToAmount(amountADesired, slippageTolerance);
|
|
372
|
+
const amountBMin = applySlippageToAmount(amountBDesired, slippageTolerance);
|
|
373
|
+
const routerContractId = resolveRouterContract(config);
|
|
374
|
+
const deadline = resolveDeadline(config.deadlineMinutes);
|
|
383
375
|
const toAddress = accountIdToSolidityAddress(operatorAccountId);
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
return
|
|
391
|
-
estimatedOutput: quote.expectedOutput,
|
|
392
|
-
minOutput: minOutSmallest,
|
|
393
|
-
priceImpact: quote.priceImpact,
|
|
394
|
-
route: quote.route
|
|
395
|
-
});
|
|
376
|
+
const params = new ContractFunctionParameters().addAddress(tokenIdToSolidityAddress(requireTokenId(tokenAId))).addAddress(tokenIdToSolidityAddress(requireTokenId(tokenBId))).addUint256(amountADesired).addUint256(amountBDesired).addUint256(amountAMin).addUint256(amountBMin).addAddress(toAddress).addUint256(deadline);
|
|
377
|
+
const transaction = new ContractExecuteTransaction().setContractId(contractIdFromString(routerContractId)).setGas(config.gasLimit).setFunction("addLiquidity", params);
|
|
378
|
+
const payload = {
|
|
379
|
+
transaction,
|
|
380
|
+
extras: { amountADesired, amountBDesired, amountAMin, amountBMin }
|
|
381
|
+
};
|
|
382
|
+
return payload;
|
|
396
383
|
} catch (error) {
|
|
397
384
|
return {
|
|
398
385
|
success: false,
|
|
@@ -400,61 +387,73 @@ var swapTool = {
|
|
|
400
387
|
};
|
|
401
388
|
}
|
|
402
389
|
}
|
|
390
|
+
async shouldSecondaryAction(coreActionResult, _context) {
|
|
391
|
+
return isLiquidityCorePayload(coreActionResult);
|
|
392
|
+
}
|
|
393
|
+
async secondaryAction(payload, client, context) {
|
|
394
|
+
const result = await handleTransaction(
|
|
395
|
+
payload.transaction,
|
|
396
|
+
client,
|
|
397
|
+
context,
|
|
398
|
+
addLiquidityPostProcess
|
|
399
|
+
);
|
|
400
|
+
return { ...result, ...payload.extras };
|
|
401
|
+
}
|
|
403
402
|
};
|
|
404
|
-
var
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const args = quoteInputSchema.parse(params);
|
|
403
|
+
var RemoveLiquidityTool = class extends BaseTool {
|
|
404
|
+
constructor() {
|
|
405
|
+
super(...arguments);
|
|
406
|
+
this.method = "saucerswap_remove_liquidity";
|
|
407
|
+
this.name = "SaucerSwap Remove Liquidity";
|
|
408
|
+
this.description = "Remove liquidity from a SaucerSwap pool.";
|
|
409
|
+
this.parameters = removeLiquidityInputSchema;
|
|
410
|
+
}
|
|
411
|
+
async normalizeParams(params, _context, _client) {
|
|
412
|
+
return removeLiquidityInputSchema.parse(params);
|
|
413
|
+
}
|
|
414
|
+
async coreAction(args, context, client) {
|
|
417
415
|
const config = resolveSaucerSwapConfig(context);
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
416
|
+
const operatorAccountId = client?.operatorAccountId?.toString();
|
|
417
|
+
if (!operatorAccountId) {
|
|
418
|
+
return {
|
|
419
|
+
success: false,
|
|
420
|
+
error: "Hedera client with an operator account is required for liquidity actions."
|
|
421
|
+
};
|
|
422
|
+
}
|
|
421
423
|
try {
|
|
422
|
-
const
|
|
423
|
-
const
|
|
424
|
-
const
|
|
425
|
-
const
|
|
426
|
-
const
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
const pool = await api.getPoolByTokens(fromTokenId, toTokenId, config.defaultPoolVersion);
|
|
434
|
-
if (pool && rawQuote.amountIn && rawQuote.amountOut) {
|
|
435
|
-
const isAToB = pool.tokenA.id === fromTokenId;
|
|
436
|
-
const reserveIn = isAToB ? pool.tokenReserveA : pool.tokenReserveB;
|
|
437
|
-
const reserveOut = isAToB ? pool.tokenReserveB : pool.tokenReserveA;
|
|
438
|
-
normalized.priceImpact = calculatePriceImpact(
|
|
439
|
-
rawQuote.amountIn,
|
|
440
|
-
rawQuote.amountOut,
|
|
441
|
-
reserveIn,
|
|
442
|
-
reserveOut
|
|
443
|
-
);
|
|
444
|
-
}
|
|
424
|
+
const api = context.saucerswapClient ?? createSaucerSwapClient(config);
|
|
425
|
+
const tokenAInput = normalizeTokenAlias(args.tokenA, config);
|
|
426
|
+
const tokenBInput = normalizeTokenAlias(args.tokenB, config);
|
|
427
|
+
const tokenAId = await api.resolveTokenId(tokenAInput);
|
|
428
|
+
const tokenBId = await api.resolveTokenId(tokenBInput);
|
|
429
|
+
const pool = await api.getPoolByTokens(tokenAId, tokenBId, config.defaultPoolVersion);
|
|
430
|
+
if (!pool) {
|
|
431
|
+
return {
|
|
432
|
+
success: false,
|
|
433
|
+
error: "Unable to locate pool for the provided token pair."
|
|
434
|
+
};
|
|
445
435
|
}
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
436
|
+
const tokenA = await api.getTokenByIdOrSymbol(tokenAId);
|
|
437
|
+
const tokenB = await api.getTokenByIdOrSymbol(tokenBId);
|
|
438
|
+
if (!tokenA || !tokenB) {
|
|
439
|
+
return {
|
|
440
|
+
success: false,
|
|
441
|
+
error: "Unable to resolve token metadata from SaucerSwap API."
|
|
442
|
+
};
|
|
452
443
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
444
|
+
const lpAmount = parseUnits(args.lpTokenAmount, pool.lpToken.decimals);
|
|
445
|
+
const minAmountA = parseUnits(args.minAmountA, tokenA.decimals);
|
|
446
|
+
const minAmountB = parseUnits(args.minAmountB, tokenB.decimals);
|
|
447
|
+
const routerContractId = resolveRouterContract(config);
|
|
448
|
+
const deadline = resolveDeadline(config.deadlineMinutes);
|
|
449
|
+
const toAddress = accountIdToSolidityAddress(operatorAccountId);
|
|
450
|
+
const params = new ContractFunctionParameters().addAddress(tokenIdToSolidityAddress(requireTokenId(tokenAId))).addAddress(tokenIdToSolidityAddress(requireTokenId(tokenBId))).addUint256(lpAmount).addUint256(minAmountA).addUint256(minAmountB).addAddress(toAddress).addUint256(deadline);
|
|
451
|
+
const transaction = new ContractExecuteTransaction().setContractId(contractIdFromString(routerContractId)).setGas(config.gasLimit).setFunction("removeLiquidity", params);
|
|
452
|
+
const payload = {
|
|
453
|
+
transaction,
|
|
454
|
+
extras: { lpAmount, minAmountA, minAmountB }
|
|
457
455
|
};
|
|
456
|
+
return payload;
|
|
458
457
|
} catch (error) {
|
|
459
458
|
return {
|
|
460
459
|
success: false,
|
|
@@ -462,20 +461,39 @@ var quoteTool = {
|
|
|
462
461
|
};
|
|
463
462
|
}
|
|
464
463
|
}
|
|
464
|
+
async shouldSecondaryAction(coreActionResult, _context) {
|
|
465
|
+
return isLiquidityCorePayload(coreActionResult);
|
|
466
|
+
}
|
|
467
|
+
async secondaryAction(payload, client, context) {
|
|
468
|
+
const result = await handleTransaction(
|
|
469
|
+
payload.transaction,
|
|
470
|
+
client,
|
|
471
|
+
context,
|
|
472
|
+
removeLiquidityPostProcess
|
|
473
|
+
);
|
|
474
|
+
return { ...result, ...payload.extras };
|
|
475
|
+
}
|
|
465
476
|
};
|
|
477
|
+
var addLiquidityTool = new AddLiquidityTool();
|
|
478
|
+
var removeLiquidityTool = new RemoveLiquidityTool();
|
|
466
479
|
var poolsInputSchema = z.object({
|
|
467
480
|
tokenA: z.string().optional().describe("First token ID or symbol"),
|
|
468
481
|
tokenB: z.string().optional().describe("Second token ID or symbol"),
|
|
469
482
|
version: z.enum(["v1", "v2"]).optional().describe("Pool version"),
|
|
470
483
|
limit: z.number().int().positive().optional().describe("Maximum number of pools to return")
|
|
471
484
|
});
|
|
472
|
-
var
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
485
|
+
var PoolsTool = class extends BaseTool {
|
|
486
|
+
constructor() {
|
|
487
|
+
super(...arguments);
|
|
488
|
+
this.method = "saucerswap_get_pools";
|
|
489
|
+
this.name = "SaucerSwap Get Pools";
|
|
490
|
+
this.description = "Query SaucerSwap liquidity pools and reserves.";
|
|
491
|
+
this.parameters = poolsInputSchema;
|
|
492
|
+
}
|
|
493
|
+
async normalizeParams(params, _context, _client) {
|
|
494
|
+
return poolsInputSchema.parse(params);
|
|
495
|
+
}
|
|
496
|
+
async coreAction(args, context, _client) {
|
|
479
497
|
const config = resolveSaucerSwapConfig(context);
|
|
480
498
|
const api = context.saucerswapClient ?? createSaucerSwapClient(config);
|
|
481
499
|
try {
|
|
@@ -508,76 +526,100 @@ var poolsTool = {
|
|
|
508
526
|
};
|
|
509
527
|
}
|
|
510
528
|
}
|
|
529
|
+
async shouldSecondaryAction(_coreActionResult, _context) {
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
532
|
+
async secondaryAction(_request, _client, _context) {
|
|
533
|
+
return null;
|
|
534
|
+
}
|
|
511
535
|
};
|
|
512
|
-
var
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
minAmountA: z.string().describe("Minimum amount of tokenA to receive"),
|
|
524
|
-
minAmountB: z.string().describe("Minimum amount of tokenB to receive")
|
|
525
|
-
});
|
|
526
|
-
var resolveDeadline2 = (defaultMinutes) => {
|
|
527
|
-
return Math.floor(Date.now() / 1e3) + defaultMinutes * 60;
|
|
536
|
+
var poolsTool = new PoolsTool();
|
|
537
|
+
|
|
538
|
+
// src/utils/quote.ts
|
|
539
|
+
var readAmount = (value) => {
|
|
540
|
+
if (typeof value === "string") {
|
|
541
|
+
return value;
|
|
542
|
+
}
|
|
543
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
544
|
+
return value.toString();
|
|
545
|
+
}
|
|
546
|
+
return null;
|
|
528
547
|
};
|
|
529
|
-
var
|
|
530
|
-
const
|
|
531
|
-
|
|
532
|
-
|
|
548
|
+
var normalizeSwapQuote = (quote, fallbackAmountIn) => {
|
|
549
|
+
const amountIn = readAmount(quote.amountIn) ?? fallbackAmountIn;
|
|
550
|
+
const expectedOutput = readAmount(quote.expectedOutput) ?? readAmount(quote.amountOut) ?? readAmount(quote.amountOutMin) ?? "";
|
|
551
|
+
if (!expectedOutput) {
|
|
552
|
+
throw new Error("SaucerSwap quote did not include an output amount.");
|
|
533
553
|
}
|
|
534
|
-
return
|
|
554
|
+
return {
|
|
555
|
+
amountIn,
|
|
556
|
+
expectedOutput,
|
|
557
|
+
priceImpact: typeof quote.priceImpact === "number" ? quote.priceImpact : null,
|
|
558
|
+
route: Array.isArray(quote.route) ? quote.route : [],
|
|
559
|
+
raw: quote
|
|
560
|
+
};
|
|
535
561
|
};
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
562
|
+
|
|
563
|
+
// src/tools/quote.ts
|
|
564
|
+
var quoteInputSchema = z.object({
|
|
565
|
+
fromToken: z.string().describe("Token ID to swap from (e.g., 'HBAR' or '0.0.123456')"),
|
|
566
|
+
toToken: z.string().describe("Token ID to swap to"),
|
|
567
|
+
amount: z.string().describe("Amount to swap (decimal format)"),
|
|
568
|
+
slippageTolerance: z.number().optional().default(0.5).describe("Maximum slippage tolerance percentage")
|
|
569
|
+
});
|
|
570
|
+
var QuoteTool = class extends BaseTool {
|
|
571
|
+
constructor() {
|
|
572
|
+
super(...arguments);
|
|
573
|
+
this.method = "saucerswap_get_swap_quote";
|
|
574
|
+
this.name = "SaucerSwap Get Swap Quote";
|
|
575
|
+
this.description = "Get a price quote for swapping tokens on SaucerSwap.";
|
|
576
|
+
this.parameters = quoteInputSchema;
|
|
577
|
+
}
|
|
578
|
+
async normalizeParams(params, _context, _client) {
|
|
579
|
+
return quoteInputSchema.parse(params);
|
|
580
|
+
}
|
|
581
|
+
async coreAction(args, context, _client) {
|
|
543
582
|
const config = resolveSaucerSwapConfig(context);
|
|
544
|
-
const
|
|
583
|
+
const cachedApi = context.saucerswapClient;
|
|
584
|
+
const api = cachedApi ?? createSaucerSwapClient(config);
|
|
545
585
|
const slippageTolerance = args.slippageTolerance ?? 0.5;
|
|
546
|
-
if (!operatorAccountId) {
|
|
547
|
-
return {
|
|
548
|
-
success: false,
|
|
549
|
-
error: "Hedera client with an operator account is required for liquidity actions."
|
|
550
|
-
};
|
|
551
|
-
}
|
|
552
586
|
try {
|
|
553
|
-
const
|
|
554
|
-
const
|
|
555
|
-
const
|
|
556
|
-
const
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
return {
|
|
562
|
-
success: false,
|
|
563
|
-
error: "Unable to resolve token metadata from SaucerSwap API."
|
|
564
|
-
};
|
|
565
|
-
}
|
|
566
|
-
const amountADesired = parseUnits(args.amountA, tokenA.decimals);
|
|
567
|
-
const amountBDesired = parseUnits(args.amountB, tokenB.decimals);
|
|
568
|
-
const amountAMin = applySlippageToAmount(amountADesired, slippageTolerance);
|
|
569
|
-
const amountBMin = applySlippageToAmount(amountBDesired, slippageTolerance);
|
|
570
|
-
const routerContractId = resolveRouterContract(config);
|
|
571
|
-
const deadline = resolveDeadline2(config.deadlineMinutes);
|
|
572
|
-
const toAddress = accountIdToSolidityAddress(operatorAccountId);
|
|
573
|
-
const params2 = new ContractFunctionParameters().addAddress(tokenIdToSolidityAddress(requireTokenId(tokenAId))).addAddress(tokenIdToSolidityAddress(requireTokenId(tokenBId))).addUint256(amountADesired).addUint256(amountBDesired).addUint256(amountAMin).addUint256(amountBMin).addAddress(toAddress).addUint256(deadline);
|
|
574
|
-
const transaction = new ContractExecuteTransaction().setContractId(contractIdFromString(routerContractId)).setGas(config.gasLimit).setFunction("addLiquidity", params2);
|
|
575
|
-
return await finalizeTransaction(transaction, client, context, {
|
|
576
|
-
amountADesired,
|
|
577
|
-
amountBDesired,
|
|
578
|
-
amountAMin,
|
|
579
|
-
amountBMin
|
|
587
|
+
const fromToken = normalizeTokenAlias(args.fromToken, config);
|
|
588
|
+
const toToken = normalizeTokenAlias(args.toToken, config);
|
|
589
|
+
const fromTokenId = await api.resolveTokenId(fromToken);
|
|
590
|
+
const toTokenId = await api.resolveTokenId(toToken);
|
|
591
|
+
const rawQuote = await api.getSwapQuote({
|
|
592
|
+
fromToken: fromTokenId,
|
|
593
|
+
toToken: toTokenId,
|
|
594
|
+
amount: args.amount
|
|
580
595
|
});
|
|
596
|
+
const normalized = normalizeSwapQuote(rawQuote, args.amount);
|
|
597
|
+
if (normalized.priceImpact === null) {
|
|
598
|
+
const pool = await api.getPoolByTokens(fromTokenId, toTokenId, config.defaultPoolVersion);
|
|
599
|
+
if (pool && rawQuote.amountIn && rawQuote.amountOut) {
|
|
600
|
+
const isAToB = pool.tokenA.id === fromTokenId;
|
|
601
|
+
const reserveIn = isAToB ? pool.tokenReserveA : pool.tokenReserveB;
|
|
602
|
+
const reserveOut = isAToB ? pool.tokenReserveB : pool.tokenReserveA;
|
|
603
|
+
normalized.priceImpact = calculatePriceImpact(
|
|
604
|
+
rawQuote.amountIn,
|
|
605
|
+
rawQuote.amountOut,
|
|
606
|
+
reserveIn,
|
|
607
|
+
reserveOut
|
|
608
|
+
);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
let minOutput = null;
|
|
612
|
+
if (normalized.expectedOutput.includes(".")) {
|
|
613
|
+
const expectedNumber = Number(normalized.expectedOutput);
|
|
614
|
+
minOutput = Number.isFinite(expectedNumber) ? (expectedNumber * (1 - slippageTolerance / 100)).toString() : null;
|
|
615
|
+
} else {
|
|
616
|
+
minOutput = applySlippageToAmount(normalized.expectedOutput, slippageTolerance);
|
|
617
|
+
}
|
|
618
|
+
return {
|
|
619
|
+
success: true,
|
|
620
|
+
quote: normalized,
|
|
621
|
+
minOutput
|
|
622
|
+
};
|
|
581
623
|
} catch (error) {
|
|
582
624
|
return {
|
|
583
625
|
success: false,
|
|
@@ -585,83 +627,110 @@ var addLiquidityTool = {
|
|
|
585
627
|
};
|
|
586
628
|
}
|
|
587
629
|
}
|
|
630
|
+
async shouldSecondaryAction(_coreActionResult, _context) {
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
async secondaryAction(_request, _client, _context) {
|
|
634
|
+
return null;
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
var quoteTool = new QuoteTool();
|
|
638
|
+
var swapInputSchema = z.object({
|
|
639
|
+
fromToken: z.string().describe("Token ID to swap from (e.g., 'HBAR' or '0.0.123456')"),
|
|
640
|
+
toToken: z.string().describe("Token ID to swap to"),
|
|
641
|
+
amount: z.string().describe("Amount to swap (decimal format)"),
|
|
642
|
+
slippageTolerance: z.number().optional().default(0.5).describe("Maximum slippage tolerance percentage"),
|
|
643
|
+
deadline: z.number().optional().describe("Transaction deadline in minutes from now or a unix timestamp")
|
|
644
|
+
});
|
|
645
|
+
var isSwapCorePayload = (value) => typeof value === "object" && value !== null && "transaction" in value;
|
|
646
|
+
var swapPostProcess = (response) => `SaucerSwap swap submitted. Status: ${response.status}. Transaction ID: ${response.transactionId}`;
|
|
647
|
+
var resolveDeadline2 = (deadlineInput, defaultMinutes) => {
|
|
648
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
649
|
+
if (!deadlineInput) {
|
|
650
|
+
return now + defaultMinutes * 60;
|
|
651
|
+
}
|
|
652
|
+
if (deadlineInput > now + 60) {
|
|
653
|
+
return Math.floor(deadlineInput);
|
|
654
|
+
}
|
|
655
|
+
return now + Math.round(deadlineInput) * 60;
|
|
588
656
|
};
|
|
589
|
-
var
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
657
|
+
var amountToSmallest = (amount, decimals) => {
|
|
658
|
+
return parseUnits(amount, decimals);
|
|
659
|
+
};
|
|
660
|
+
var expectedToSmallest = (amount, decimals) => {
|
|
661
|
+
return amount.includes(".") ? parseUnits(amount, decimals) : amount;
|
|
662
|
+
};
|
|
663
|
+
var SwapTool = class extends BaseTool {
|
|
664
|
+
constructor() {
|
|
665
|
+
super(...arguments);
|
|
666
|
+
this.method = "saucerswap_swap_tokens";
|
|
667
|
+
this.name = "SaucerSwap Swap Tokens";
|
|
668
|
+
this.description = "Execute a token swap on SaucerSwap DEX.";
|
|
669
|
+
this.parameters = swapInputSchema;
|
|
670
|
+
}
|
|
671
|
+
async normalizeParams(params, _context, _client) {
|
|
672
|
+
return swapInputSchema.parse(params);
|
|
673
|
+
}
|
|
674
|
+
async coreAction(args, context, client) {
|
|
596
675
|
const config = resolveSaucerSwapConfig(context);
|
|
597
676
|
const operatorAccountId = client?.operatorAccountId?.toString();
|
|
677
|
+
const slippageTolerance = args.slippageTolerance ?? 0.5;
|
|
598
678
|
if (!operatorAccountId) {
|
|
599
679
|
return {
|
|
600
680
|
success: false,
|
|
601
|
-
error: "Hedera client with an operator account is required for
|
|
681
|
+
error: "Hedera client with an operator account is required for swaps."
|
|
602
682
|
};
|
|
603
683
|
}
|
|
604
684
|
try {
|
|
605
685
|
const api = context.saucerswapClient ?? createSaucerSwapClient(config);
|
|
606
|
-
const
|
|
607
|
-
const
|
|
608
|
-
const
|
|
609
|
-
const
|
|
610
|
-
const
|
|
611
|
-
|
|
686
|
+
const fromTokenAlias = normalizeTokenAlias(args.fromToken, config);
|
|
687
|
+
const toTokenAlias = normalizeTokenAlias(args.toToken, config);
|
|
688
|
+
const fromTokenId = await api.resolveTokenId(fromTokenAlias);
|
|
689
|
+
const toTokenId = await api.resolveTokenId(toTokenAlias);
|
|
690
|
+
const fromTokenMeta = await api.getTokenByIdOrSymbol(fromTokenId);
|
|
691
|
+
const toTokenMeta = await api.getTokenByIdOrSymbol(toTokenId);
|
|
692
|
+
if (!fromTokenMeta || !toTokenMeta) {
|
|
612
693
|
return {
|
|
613
694
|
success: false,
|
|
614
|
-
error: "Unable to
|
|
695
|
+
error: "Unable to resolve token metadata from SaucerSwap API."
|
|
615
696
|
};
|
|
616
697
|
}
|
|
617
|
-
const
|
|
618
|
-
|
|
619
|
-
|
|
698
|
+
const quote = normalizeSwapQuote(
|
|
699
|
+
await api.getSwapQuote({
|
|
700
|
+
fromToken: fromTokenId,
|
|
701
|
+
toToken: toTokenId,
|
|
702
|
+
amount: args.amount
|
|
703
|
+
}),
|
|
704
|
+
args.amount
|
|
705
|
+
);
|
|
706
|
+
const amountInSmallest = amountToSmallest(args.amount, fromTokenMeta.decimals);
|
|
707
|
+
const expectedOutSmallest = expectedToSmallest(quote.expectedOutput, toTokenMeta.decimals);
|
|
708
|
+
const minOutSmallest = applySlippageToAmount(expectedOutSmallest, slippageTolerance);
|
|
709
|
+
const routerContractId = config.defaultPoolVersion === "v2" ? config.routerV2ContractId ?? config.routerContractId : config.routerContractId ?? config.routerV2ContractId;
|
|
710
|
+
if (!routerContractId) {
|
|
620
711
|
return {
|
|
621
712
|
success: false,
|
|
622
|
-
error: "
|
|
713
|
+
error: "Missing SaucerSwap router contract ID configuration."
|
|
623
714
|
};
|
|
624
715
|
}
|
|
625
|
-
const
|
|
626
|
-
const minAmountA = parseUnits(args.minAmountA, tokenA.decimals);
|
|
627
|
-
const minAmountB = parseUnits(args.minAmountB, tokenB.decimals);
|
|
628
|
-
const routerContractId = resolveRouterContract(config);
|
|
629
|
-
const deadline = resolveDeadline2(config.deadlineMinutes);
|
|
716
|
+
const deadline = resolveDeadline2(args.deadline, config.deadlineMinutes);
|
|
630
717
|
const toAddress = accountIdToSolidityAddress(operatorAccountId);
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
};
|
|
646
|
-
var farmsInputSchema = z.object({
|
|
647
|
-
poolId: z.number().int().positive().optional().describe("Optional pool ID to filter farms")
|
|
648
|
-
});
|
|
649
|
-
var farmsTool = {
|
|
650
|
-
method: "saucerswap_get_farms",
|
|
651
|
-
name: "SaucerSwap Get Farms",
|
|
652
|
-
description: "Get active farming opportunities on SaucerSwap.",
|
|
653
|
-
parameters: farmsInputSchema,
|
|
654
|
-
execute: async (_client, context, params) => {
|
|
655
|
-
const args = farmsInputSchema.parse(params);
|
|
656
|
-
const config = resolveSaucerSwapConfig(context);
|
|
657
|
-
const api = context.saucerswapClient ?? createSaucerSwapClient(config);
|
|
658
|
-
try {
|
|
659
|
-
const farms = await api.getFarms();
|
|
660
|
-
const filtered = args.poolId ? farms.filter((farm) => farm.poolId === args.poolId) : farms;
|
|
661
|
-
return {
|
|
662
|
-
success: true,
|
|
663
|
-
farms: filtered
|
|
718
|
+
const path = [
|
|
719
|
+
tokenIdToSolidityAddress(requireTokenId(fromTokenId)),
|
|
720
|
+
tokenIdToSolidityAddress(requireTokenId(toTokenId))
|
|
721
|
+
];
|
|
722
|
+
const params = new ContractFunctionParameters().addUint256(amountInSmallest).addUint256(minOutSmallest).addAddressArray(path).addAddress(toAddress).addUint256(deadline);
|
|
723
|
+
const transaction = new ContractExecuteTransaction().setContractId(contractIdFromString(routerContractId)).setGas(config.gasLimit).setFunction("swapExactTokensForTokens", params);
|
|
724
|
+
const payload = {
|
|
725
|
+
transaction,
|
|
726
|
+
extras: {
|
|
727
|
+
estimatedOutput: quote.expectedOutput,
|
|
728
|
+
minOutput: minOutSmallest,
|
|
729
|
+
priceImpact: quote.priceImpact,
|
|
730
|
+
route: quote.route
|
|
731
|
+
}
|
|
664
732
|
};
|
|
733
|
+
return payload;
|
|
665
734
|
} catch (error) {
|
|
666
735
|
return {
|
|
667
736
|
success: false,
|
|
@@ -669,15 +738,36 @@ var farmsTool = {
|
|
|
669
738
|
};
|
|
670
739
|
}
|
|
671
740
|
}
|
|
741
|
+
async shouldSecondaryAction(coreActionResult, _context) {
|
|
742
|
+
return isSwapCorePayload(coreActionResult);
|
|
743
|
+
}
|
|
744
|
+
async secondaryAction(payload, client, context) {
|
|
745
|
+
const result = await handleTransaction(
|
|
746
|
+
payload.transaction,
|
|
747
|
+
client,
|
|
748
|
+
context,
|
|
749
|
+
swapPostProcess
|
|
750
|
+
);
|
|
751
|
+
return { ...result, ...payload.extras };
|
|
752
|
+
}
|
|
672
753
|
};
|
|
754
|
+
var swapTool = new SwapTool();
|
|
673
755
|
|
|
674
756
|
// src/index.ts
|
|
757
|
+
var saucerswapPluginToolNames = {
|
|
758
|
+
SAUCERSWAP_GET_SWAP_QUOTE_TOOL: "saucerswap_get_swap_quote",
|
|
759
|
+
SAUCERSWAP_SWAP_TOKENS_TOOL: "saucerswap_swap_tokens",
|
|
760
|
+
SAUCERSWAP_GET_POOLS_TOOL: "saucerswap_get_pools",
|
|
761
|
+
SAUCERSWAP_ADD_LIQUIDITY_TOOL: "saucerswap_add_liquidity",
|
|
762
|
+
SAUCERSWAP_REMOVE_LIQUIDITY_TOOL: "saucerswap_remove_liquidity",
|
|
763
|
+
SAUCERSWAP_GET_FARMS_TOOL: "saucerswap_get_farms"
|
|
764
|
+
};
|
|
675
765
|
var saucerswapPlugin = {
|
|
676
766
|
name: "saucerswap",
|
|
677
767
|
description: "Integration with SaucerSwap DEX for token swaps, liquidity provision, and yield farming",
|
|
678
768
|
tools: () => [swapTool, quoteTool, poolsTool, addLiquidityTool, removeLiquidityTool, farmsTool]
|
|
679
769
|
};
|
|
680
770
|
|
|
681
|
-
export { saucerswapPlugin as default, saucerswapPlugin };
|
|
771
|
+
export { saucerswapPlugin as default, saucerswapPlugin, saucerswapPluginToolNames };
|
|
682
772
|
//# sourceMappingURL=index.js.map
|
|
683
773
|
//# sourceMappingURL=index.js.map
|