@michaleffffff/mcp-trading-server 2.3.6 → 2.4.1
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/dist/server.js +3 -3
- package/dist/services/marketService.js +11 -11
- package/dist/services/poolService.js +17 -19
- package/dist/services/tradeService.js +60 -110
- package/dist/tools/accountInfo.js +3 -3
- package/dist/tools/accountTransfer.js +7 -8
- package/dist/tools/adjustMargin.js +1 -1
- package/dist/tools/cancelAllOrders.js +4 -17
- package/dist/tools/cancelOrder.js +2 -11
- package/dist/tools/checkApproval.js +3 -4
- package/dist/tools/closeAllPositions.js +2 -2
- package/dist/tools/closePosition.js +12 -9
- package/dist/tools/executeTrade.js +20 -14
- package/dist/tools/getAccountVipInfo.js +1 -1
- package/dist/tools/getBaseDetail.js +4 -4
- package/dist/tools/getKline.js +3 -2
- package/dist/tools/getKlineLatestBar.js +2 -1
- package/dist/tools/getMarketList.js +1 -1
- package/dist/tools/getMarketPrice.js +4 -2
- package/dist/tools/getNetworkFee.js +1 -1
- package/dist/tools/getOraclePrice.js +4 -2
- package/dist/tools/getUserTradingFeeRate.js +3 -3
- package/dist/tools/manageLiquidity.js +14 -24
- package/dist/tools/marketInfo.js +11 -5
- package/dist/tools/orderQueries.js +3 -4
- package/dist/tools/poolConfig.js +4 -2
- package/dist/tools/positionHistory.js +3 -4
- package/dist/tools/searchMarket.js +1 -1
- package/dist/tools/setTpSl.js +11 -10
- package/dist/tools/updateOrderTpSl.js +9 -7
- package/package.json +1 -1
- package/dist/utils/schema.js +0 -18
package/dist/server.js
CHANGED
|
@@ -81,7 +81,7 @@ function zodSchemaToJsonSchema(zodSchema) {
|
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
83
|
// ─── MCP Server ───
|
|
84
|
-
const server = new Server({ name: "myx-mcp-trading-server", version: "2.
|
|
84
|
+
const server = new Server({ name: "myx-mcp-trading-server", version: "2.4.1" }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
|
|
85
85
|
// List tools
|
|
86
86
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
87
87
|
return {
|
|
@@ -105,7 +105,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
105
105
|
try {
|
|
106
106
|
let validatedArgs = args ?? {};
|
|
107
107
|
if (tool.schema) {
|
|
108
|
-
validatedArgs = z.object(tool.schema).parse(args ?? {});
|
|
108
|
+
validatedArgs = z.object(tool.schema).strict().parse(args ?? {});
|
|
109
109
|
}
|
|
110
110
|
logger.toolExecution(name, validatedArgs);
|
|
111
111
|
const result = await tool.handler(validatedArgs);
|
|
@@ -181,7 +181,7 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
|
181
181
|
async function main() {
|
|
182
182
|
const transport = new StdioServerTransport();
|
|
183
183
|
await server.connect(transport);
|
|
184
|
-
logger.info("🚀 MYX Trading MCP Server v2.
|
|
184
|
+
logger.info("🚀 MYX Trading MCP Server v2.4.1 running (stdio, pure on-chain, prod ready)");
|
|
185
185
|
}
|
|
186
186
|
main().catch((err) => {
|
|
187
187
|
logger.error("Fatal Server Startup Error", err);
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { getChainId } from "../auth/resolveClient.js";
|
|
2
2
|
import { getMarketStateDesc } from "../utils/mappings.js";
|
|
3
|
-
export async function getMarketPrice(client, poolId) {
|
|
4
|
-
const chainId = getChainId();
|
|
3
|
+
export async function getMarketPrice(client, poolId, chainIdOverride) {
|
|
4
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
5
5
|
const ticker = await client.markets.getTickerList({
|
|
6
6
|
chainId,
|
|
7
7
|
poolIds: [poolId],
|
|
8
8
|
});
|
|
9
9
|
return ticker?.data?.[0] ?? null;
|
|
10
10
|
}
|
|
11
|
-
export async function getOraclePrice(client, poolId) {
|
|
12
|
-
const chainId = getChainId();
|
|
11
|
+
export async function getOraclePrice(client, poolId, chainIdOverride) {
|
|
12
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
13
13
|
return client.utils.getOraclePrice(poolId, chainId);
|
|
14
14
|
}
|
|
15
15
|
export async function searchMarket(client, keyword, limit = 1000) {
|
|
16
16
|
const chainId = getChainId();
|
|
17
|
-
const searchRes = await client.markets.searchMarket({ chainId,
|
|
17
|
+
const searchRes = await client.markets.searchMarket({ chainId, keyword, limit });
|
|
18
18
|
const raw = searchRes;
|
|
19
19
|
let dataList = [];
|
|
20
20
|
if (raw && raw.contractInfo && Array.isArray(raw.contractInfo.list)) {
|
|
@@ -44,7 +44,7 @@ export async function searchMarket(client, keyword, limit = 1000) {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
return activeMarkets.map(m => {
|
|
47
|
-
const ticker = tickers.find(t => t.poolId.toLowerCase() === m.poolId.toLowerCase());
|
|
47
|
+
const ticker = tickers.find(t => String(t.poolId).toLowerCase() === String(m.poolId).toLowerCase());
|
|
48
48
|
return {
|
|
49
49
|
symbol: m.baseQuoteSymbol || `${m.baseSymbol}/${m.quoteSymbol}`,
|
|
50
50
|
name: m.symbolName || m.name,
|
|
@@ -57,8 +57,8 @@ export async function searchMarket(client, keyword, limit = 1000) {
|
|
|
57
57
|
};
|
|
58
58
|
});
|
|
59
59
|
}
|
|
60
|
-
export async function getMarketDetail(client, poolId) {
|
|
61
|
-
const chainId = getChainId();
|
|
60
|
+
export async function getMarketDetail(client, poolId, chainIdOverride) {
|
|
61
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
62
62
|
const res = await client.markets.getMarketDetail({ chainId, poolId });
|
|
63
63
|
// Ensure it's returned as { data: ... } for consistency with other services if needed,
|
|
64
64
|
// but looking at existing tools, they often stringify the whole result.
|
|
@@ -74,7 +74,7 @@ export async function getPoolList(client) {
|
|
|
74
74
|
/**
|
|
75
75
|
* 获取池子分级配置
|
|
76
76
|
*/
|
|
77
|
-
export async function getPoolLevelConfig(client, poolId) {
|
|
78
|
-
const chainId = getChainId();
|
|
79
|
-
return client.
|
|
77
|
+
export async function getPoolLevelConfig(client, poolId, chainIdOverride) {
|
|
78
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
79
|
+
return client.markets.getPoolLevelConfig(poolId, chainId);
|
|
80
80
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { pool, quote, base } from "@myx-trade/sdk";
|
|
2
2
|
import { getChainId, resolveClient } from "../auth/resolveClient.js";
|
|
3
|
-
import { ensureUnits } from "../utils/units.js";
|
|
4
3
|
/**
|
|
5
4
|
* 创建合约市场池子
|
|
6
5
|
*/
|
|
@@ -12,58 +11,57 @@ export async function createPool(baseToken, marketId) {
|
|
|
12
11
|
/**
|
|
13
12
|
* 获取池子信息
|
|
14
13
|
*/
|
|
15
|
-
export async function getPoolInfo(poolId) {
|
|
16
|
-
const chainId = getChainId();
|
|
14
|
+
export async function getPoolInfo(poolId, chainIdOverride) {
|
|
15
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
17
16
|
return pool.getPoolInfo(chainId, poolId);
|
|
18
17
|
}
|
|
19
18
|
/**
|
|
20
19
|
* 获取池子详情
|
|
21
20
|
*/
|
|
22
|
-
export async function getPoolDetail(poolId) {
|
|
23
|
-
const chainId = getChainId();
|
|
21
|
+
export async function getPoolDetail(poolId, chainIdOverride) {
|
|
22
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
24
23
|
return pool.getPoolDetail(chainId, poolId);
|
|
25
24
|
}
|
|
26
25
|
/**
|
|
27
26
|
* 获取流动性信息
|
|
28
27
|
*/
|
|
29
|
-
export async function getLiquidityInfo(client, poolId, marketPrice) {
|
|
30
|
-
const chainId = getChainId();
|
|
31
|
-
|
|
32
|
-
return client.utils.getLiquidityInfo({ chainId, poolId, marketPrice: price30 });
|
|
28
|
+
export async function getLiquidityInfo(client, poolId, marketPrice, chainIdOverride) {
|
|
29
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
30
|
+
return client.utils.getLiquidityInfo({ chainId, poolId, marketPrice });
|
|
33
31
|
}
|
|
34
32
|
/**
|
|
35
33
|
* Quote 池 deposit
|
|
36
34
|
*/
|
|
37
|
-
export async function quoteDeposit(poolId, amount, slippage) {
|
|
38
|
-
const chainId = getChainId();
|
|
35
|
+
export async function quoteDeposit(poolId, amount, slippage, chainIdOverride) {
|
|
36
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
39
37
|
return quote.deposit({ chainId, poolId, amount, slippage });
|
|
40
38
|
}
|
|
41
39
|
/**
|
|
42
40
|
* Quote 池 withdraw
|
|
43
41
|
*/
|
|
44
|
-
export async function quoteWithdraw(poolId, amount, slippage) {
|
|
45
|
-
const chainId = getChainId();
|
|
42
|
+
export async function quoteWithdraw(poolId, amount, slippage, chainIdOverride) {
|
|
43
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
46
44
|
return quote.withdraw({ chainId, poolId, amount, slippage });
|
|
47
45
|
}
|
|
48
46
|
/**
|
|
49
47
|
* Base 池 deposit
|
|
50
48
|
*/
|
|
51
|
-
export async function baseDeposit(poolId, amount, slippage) {
|
|
52
|
-
const chainId = getChainId();
|
|
49
|
+
export async function baseDeposit(poolId, amount, slippage, chainIdOverride) {
|
|
50
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
53
51
|
return base.deposit({ chainId, poolId, amount, slippage });
|
|
54
52
|
}
|
|
55
53
|
/**
|
|
56
54
|
* Base 池 withdraw
|
|
57
55
|
*/
|
|
58
|
-
export async function baseWithdraw(poolId, amount, slippage) {
|
|
59
|
-
const chainId = getChainId();
|
|
56
|
+
export async function baseWithdraw(poolId, amount, slippage, chainIdOverride) {
|
|
57
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
60
58
|
return base.withdraw({ chainId, poolId, amount, slippage });
|
|
61
59
|
}
|
|
62
60
|
/**
|
|
63
61
|
* 获取 LP 价格
|
|
64
62
|
*/
|
|
65
|
-
export async function getLpPrice(poolType, poolId) {
|
|
66
|
-
const chainId = getChainId();
|
|
63
|
+
export async function getLpPrice(poolType, poolId, chainIdOverride) {
|
|
64
|
+
const chainId = chainIdOverride ?? getChainId();
|
|
67
65
|
if (poolType === "BASE") {
|
|
68
66
|
return base.getLpPrice(chainId, poolId);
|
|
69
67
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Direction, OrderType, TriggerType } from "@myx-trade/sdk";
|
|
2
2
|
import { parseUnits } from "ethers";
|
|
3
|
-
import { getChainId, getQuoteToken
|
|
4
|
-
import { ensureUnits
|
|
3
|
+
import { getChainId, getQuoteToken } from "../auth/resolveClient.js";
|
|
4
|
+
import { ensureUnits } from "../utils/units.js";
|
|
5
5
|
import { normalizeAddress } from "../utils/address.js";
|
|
6
6
|
/**
|
|
7
7
|
* 将人类可读数值转为指定精度的整数字串
|
|
@@ -20,114 +20,61 @@ function resolveDirection(direction) {
|
|
|
20
20
|
* 开仓 / 加仓
|
|
21
21
|
*/
|
|
22
22
|
export async function openPosition(client, address, args) {
|
|
23
|
-
const maxTradeAmount = process.env.MAX_TRADE_AMOUNT;
|
|
24
|
-
if (maxTradeAmount && Number(args.collateralAmount) > Number(maxTradeAmount)) {
|
|
25
|
-
throw new Error(`Security Exception: collateralAmount (${args.collateralAmount}) exceeds MAX_TRADE_AMOUNT (${maxTradeAmount}). Update .env if you need to trade larger sizes.`);
|
|
26
|
-
}
|
|
27
23
|
const chainId = getChainId();
|
|
28
|
-
const quoteToken = normalizeAddress(args.quoteToken || getQuoteToken(), "quoteToken");
|
|
29
|
-
const quoteDecimals = args.quoteDecimals ?? getQuoteDecimals();
|
|
30
|
-
const rawLeverage = args.leverage ?? 10;
|
|
31
|
-
if (!Number.isFinite(rawLeverage) || rawLeverage <= 0) {
|
|
32
|
-
throw new Error("leverage must be a positive number.");
|
|
33
|
-
}
|
|
34
|
-
const leverage = Math.floor(rawLeverage);
|
|
35
|
-
let calcPrice30;
|
|
36
|
-
let orderPrice30;
|
|
37
|
-
if (args.price) {
|
|
38
|
-
const limitPrice30 = parseHumanUnits(args.price, 30, "price");
|
|
39
|
-
calcPrice30 = limitPrice30;
|
|
40
|
-
orderPrice30 = limitPrice30;
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
const oracleData = await client.utils.getOraclePrice(args.poolId, chainId);
|
|
44
|
-
calcPrice30 = ensureUnits(oracleData.price, 30, "oracle price");
|
|
45
|
-
orderPrice30 = calcPrice30;
|
|
46
|
-
console.error(`[Market Order] Fetched oracle price for size math: ${calcPrice30}`);
|
|
47
|
-
}
|
|
48
|
-
// 保证金转为 quote token 精度
|
|
49
|
-
const collateralWei = parseHumanUnits(args.collateralAmount, quoteDecimals, "collateralAmount");
|
|
50
|
-
// 仓位大小 (size): 在 MYX 这一版中,size 表示 Base Token(WETH)的数量,精度通常为 18
|
|
51
|
-
// 计算公式:size = (collateral * leverage) / price
|
|
52
|
-
// 为了防止浮点溢出,我们可以全部转为 BigInt 计算
|
|
53
|
-
const collateralBig = BigInt(collateralWei);
|
|
54
|
-
const leverageBig = BigInt(leverage);
|
|
55
|
-
const priceBig = BigInt(calcPrice30);
|
|
56
|
-
let size = "0";
|
|
57
|
-
if (priceBig > 0n) {
|
|
58
|
-
// collateral: 6位, price: 30位, 目标size: 18位
|
|
59
|
-
// (collateral * leverage * 10^(18 + 30 - 6)) / price
|
|
60
|
-
const exponent = BigInt(18 + 30 - quoteDecimals);
|
|
61
|
-
size = ((collateralBig * leverageBig * (10n ** exponent)) / priceBig).toString();
|
|
62
|
-
}
|
|
63
24
|
const dir = resolveDirection(args.direction);
|
|
64
|
-
|
|
65
|
-
const triggerType = args.price
|
|
66
|
-
? (args.direction === 0 ? TriggerType.LTE : TriggerType.GTE)
|
|
67
|
-
: TriggerType.NONE; // 没传价就是市价单
|
|
25
|
+
const executionFeeToken = normalizeAddress(args.executionFeeToken, "executionFeeToken");
|
|
68
26
|
const orderParams = {
|
|
69
27
|
chainId,
|
|
70
28
|
address,
|
|
71
29
|
poolId: args.poolId,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
triggerType: triggerType,
|
|
30
|
+
positionId: args.positionId,
|
|
31
|
+
orderType: args.orderType,
|
|
32
|
+
triggerType: args.triggerType,
|
|
76
33
|
direction: dir,
|
|
77
|
-
collateralAmount:
|
|
78
|
-
size,
|
|
79
|
-
price:
|
|
80
|
-
timeInForce:
|
|
81
|
-
postOnly:
|
|
82
|
-
slippagePct: args.slippagePct
|
|
83
|
-
executionFeeToken
|
|
84
|
-
leverage,
|
|
34
|
+
collateralAmount: args.collateralAmount,
|
|
35
|
+
size: args.size,
|
|
36
|
+
price: args.price,
|
|
37
|
+
timeInForce: args.timeInForce,
|
|
38
|
+
postOnly: args.postOnly,
|
|
39
|
+
slippagePct: args.slippagePct,
|
|
40
|
+
executionFeeToken,
|
|
41
|
+
leverage: args.leverage,
|
|
85
42
|
};
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
orderParams.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
orderParams.
|
|
94
|
-
|
|
95
|
-
// tradingFee: SDK 第二个参数
|
|
96
|
-
const tradingFeeStr = (args.tradingFee || "0").toString();
|
|
97
|
-
// 获取 marketId,SDK 0.1.267 要求 as 3rd parameter
|
|
98
|
-
const marketDetailRes = await client.markets.getMarketDetail({ chainId, poolId: args.poolId });
|
|
99
|
-
const marketId = marketDetailRes?.marketId || marketDetailRes?.data?.marketId;
|
|
100
|
-
if (!marketId) {
|
|
101
|
-
throw new Error(`Could not find marketId for poolId: ${args.poolId}`);
|
|
102
|
-
}
|
|
103
|
-
return client.order.createIncreaseOrder(orderParams, tradingFeeStr, marketId);
|
|
43
|
+
if (args.tpSize)
|
|
44
|
+
orderParams.tpSize = args.tpSize;
|
|
45
|
+
if (args.tpPrice)
|
|
46
|
+
orderParams.tpPrice = args.tpPrice;
|
|
47
|
+
if (args.slSize)
|
|
48
|
+
orderParams.slSize = args.slSize;
|
|
49
|
+
if (args.slPrice)
|
|
50
|
+
orderParams.slPrice = args.slPrice;
|
|
51
|
+
return client.order.createIncreaseOrder(orderParams, args.tradingFee, args.marketId);
|
|
104
52
|
}
|
|
105
53
|
/**
|
|
106
54
|
* 平仓 / 减仓
|
|
107
55
|
*/
|
|
108
56
|
export async function closePosition(client, address, args) {
|
|
109
57
|
const chainId = getChainId();
|
|
110
|
-
const
|
|
58
|
+
const executionFeeToken = normalizeAddress(args.executionFeeToken, "executionFeeToken");
|
|
111
59
|
if (args.direction === undefined || args.direction === null) {
|
|
112
60
|
throw new Error("direction is required (0=LONG, 1=SHORT), must match position direction.");
|
|
113
61
|
}
|
|
114
|
-
const price30 = parseHumanUnits(args.price, 30, "price");
|
|
115
|
-
const sizeWei = ensureUnits(args.size, 18, "size");
|
|
116
62
|
const dir = resolveDirection(args.direction);
|
|
117
63
|
return client.order.createDecreaseOrder({
|
|
118
64
|
chainId,
|
|
119
65
|
address,
|
|
120
66
|
poolId: args.poolId,
|
|
121
67
|
positionId: args.positionId,
|
|
122
|
-
orderType:
|
|
123
|
-
triggerType:
|
|
68
|
+
orderType: args.orderType,
|
|
69
|
+
triggerType: args.triggerType,
|
|
124
70
|
direction: dir,
|
|
125
|
-
collateralAmount:
|
|
126
|
-
size:
|
|
127
|
-
price:
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
71
|
+
collateralAmount: args.collateralAmount,
|
|
72
|
+
size: args.size,
|
|
73
|
+
price: args.price,
|
|
74
|
+
timeInForce: args.timeInForce,
|
|
75
|
+
postOnly: args.postOnly,
|
|
76
|
+
slippagePct: args.slippagePct,
|
|
77
|
+
executionFeeToken,
|
|
131
78
|
leverage: args.leverage,
|
|
132
79
|
});
|
|
133
80
|
}
|
|
@@ -136,7 +83,7 @@ export async function closePosition(client, address, args) {
|
|
|
136
83
|
*/
|
|
137
84
|
export async function setPositionTpSl(client, address, args) {
|
|
138
85
|
const chainId = getChainId();
|
|
139
|
-
const
|
|
86
|
+
const executionFeeToken = normalizeAddress(args.executionFeeToken, "executionFeeToken");
|
|
140
87
|
if (!args.tpPrice && !args.slPrice) {
|
|
141
88
|
throw new Error("At least one of tpPrice or slPrice must be provided.");
|
|
142
89
|
}
|
|
@@ -148,19 +95,19 @@ export async function setPositionTpSl(client, address, args) {
|
|
|
148
95
|
positionId: args.positionId,
|
|
149
96
|
direction: dir,
|
|
150
97
|
leverage: args.leverage,
|
|
151
|
-
executionFeeToken
|
|
152
|
-
tpTriggerType: args.
|
|
153
|
-
slTriggerType: args.
|
|
154
|
-
slippagePct:
|
|
98
|
+
executionFeeToken,
|
|
99
|
+
tpTriggerType: args.tpTriggerType,
|
|
100
|
+
slTriggerType: args.slTriggerType,
|
|
101
|
+
slippagePct: args.slippagePct,
|
|
155
102
|
};
|
|
156
|
-
if (args.tpPrice)
|
|
157
|
-
params.tpPrice =
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (args.slPrice)
|
|
161
|
-
params.slPrice =
|
|
162
|
-
|
|
163
|
-
|
|
103
|
+
if (args.tpPrice)
|
|
104
|
+
params.tpPrice = args.tpPrice;
|
|
105
|
+
if (args.tpSize)
|
|
106
|
+
params.tpSize = args.tpSize;
|
|
107
|
+
if (args.slPrice)
|
|
108
|
+
params.slPrice = args.slPrice;
|
|
109
|
+
if (args.slSize)
|
|
110
|
+
params.slSize = args.slSize;
|
|
164
111
|
return client.order.createPositionTpSlOrder(params);
|
|
165
112
|
}
|
|
166
113
|
/**
|
|
@@ -169,11 +116,14 @@ export async function setPositionTpSl(client, address, args) {
|
|
|
169
116
|
export async function adjustMargin(client, address, args) {
|
|
170
117
|
const chainId = getChainId();
|
|
171
118
|
const quoteToken = normalizeAddress(args.quoteToken || getQuoteToken(), "quoteToken");
|
|
172
|
-
const
|
|
119
|
+
const adjustAmount = String(args.adjustAmount ?? "").trim();
|
|
120
|
+
if (!/^-?\d+$/.test(adjustAmount)) {
|
|
121
|
+
throw new Error("adjustAmount must be an integer string in quote token raw units.");
|
|
122
|
+
}
|
|
173
123
|
return client.position.adjustCollateral({
|
|
174
124
|
poolId: args.poolId,
|
|
175
125
|
positionId: args.positionId,
|
|
176
|
-
adjustAmount
|
|
126
|
+
adjustAmount,
|
|
177
127
|
quoteToken,
|
|
178
128
|
chainId,
|
|
179
129
|
address,
|
|
@@ -231,17 +181,17 @@ export async function closeAllPositions(client, address) {
|
|
|
231
181
|
*/
|
|
232
182
|
export async function updateOrderTpSl(client, address, args) {
|
|
233
183
|
const chainId = getChainId();
|
|
234
|
-
const quoteToken = normalizeAddress(args.quoteToken
|
|
184
|
+
const quoteToken = normalizeAddress(args.quoteToken, "quoteToken");
|
|
235
185
|
const params = {
|
|
236
186
|
orderId: args.orderId,
|
|
237
|
-
tpSize: args.tpSize
|
|
238
|
-
tpPrice: args.tpPrice
|
|
239
|
-
slSize: args.slSize
|
|
240
|
-
slPrice: args.slPrice
|
|
241
|
-
useOrderCollateral: args.useOrderCollateral
|
|
187
|
+
tpSize: args.tpSize,
|
|
188
|
+
tpPrice: args.tpPrice,
|
|
189
|
+
slSize: args.slSize,
|
|
190
|
+
slPrice: args.slPrice,
|
|
191
|
+
useOrderCollateral: args.useOrderCollateral,
|
|
242
192
|
executionFeeToken: quoteToken,
|
|
243
|
-
size: args.size
|
|
244
|
-
price: args.price
|
|
193
|
+
size: args.size,
|
|
194
|
+
price: args.price,
|
|
245
195
|
};
|
|
246
|
-
return client.order.updateOrderTpSl(params, quoteToken, chainId, address, args.marketId, args.isTpSlOrder
|
|
196
|
+
return client.order.updateOrderTpSl(params, quoteToken, chainId, address, args.marketId, args.isTpSlOrder);
|
|
247
197
|
}
|
|
@@ -40,14 +40,14 @@ export const getTradeFlowTool = {
|
|
|
40
40
|
name: "get_trade_flow",
|
|
41
41
|
description: "Get account trade flow / transaction history.",
|
|
42
42
|
schema: {
|
|
43
|
-
|
|
44
|
-
limit: z.
|
|
43
|
+
poolId: z.string().optional().describe("Optional pool ID filter."),
|
|
44
|
+
limit: z.number().int().positive().optional().describe("Results per page (default 20)"),
|
|
45
45
|
},
|
|
46
46
|
handler: async (args) => {
|
|
47
47
|
try {
|
|
48
48
|
const { client, address } = await resolveClient();
|
|
49
49
|
const chainId = getChainId();
|
|
50
|
-
const query = { chainId,
|
|
50
|
+
const query = { chainId, poolId: args.poolId, limit: args.limit ?? 20 };
|
|
51
51
|
const result = await client.account.getTradeFlow(query, address);
|
|
52
52
|
const enhancedData = (result?.data || []).map((flow) => ({
|
|
53
53
|
...flow,
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { resolveClient, getChainId
|
|
2
|
+
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
3
|
import { normalizeAddress } from "../utils/address.js";
|
|
4
|
-
import { booleanLike } from "../utils/schema.js";
|
|
5
4
|
export const accountDepositTool = {
|
|
6
5
|
name: "account_deposit",
|
|
7
6
|
description: "Deposit funds from wallet into the MYX trading account.",
|
|
8
7
|
schema: {
|
|
9
|
-
amount: z.string().describe("Amount to deposit (
|
|
10
|
-
tokenAddress: z.string().
|
|
8
|
+
amount: z.string().regex(/^\d+$/).describe("Amount to deposit (token raw units)"),
|
|
9
|
+
tokenAddress: z.string().describe("Token address"),
|
|
11
10
|
},
|
|
12
11
|
handler: async (args) => {
|
|
13
12
|
try {
|
|
14
13
|
const { client } = await resolveClient();
|
|
15
14
|
const chainId = getChainId();
|
|
16
|
-
const tokenAddress = normalizeAddress(args.tokenAddress
|
|
15
|
+
const tokenAddress = normalizeAddress(args.tokenAddress, "tokenAddress");
|
|
17
16
|
const result = await client.account.deposit({
|
|
18
17
|
amount: args.amount,
|
|
19
18
|
tokenAddress,
|
|
@@ -31,8 +30,8 @@ export const accountWithdrawTool = {
|
|
|
31
30
|
description: "Withdraw funds from MYX trading account back to wallet.",
|
|
32
31
|
schema: {
|
|
33
32
|
poolId: z.string().describe("Pool ID to withdraw from"),
|
|
34
|
-
amount: z.string().describe("Amount to withdraw (
|
|
35
|
-
isQuoteToken:
|
|
33
|
+
amount: z.string().regex(/^\d+$/).describe("Amount to withdraw (token raw units)"),
|
|
34
|
+
isQuoteToken: z.boolean().describe("Whether to withdraw as quote token"),
|
|
36
35
|
},
|
|
37
36
|
handler: async (args) => {
|
|
38
37
|
try {
|
|
@@ -43,7 +42,7 @@ export const accountWithdrawTool = {
|
|
|
43
42
|
receiver: address,
|
|
44
43
|
amount: args.amount,
|
|
45
44
|
poolId: args.poolId,
|
|
46
|
-
isQuoteToken: args.isQuoteToken
|
|
45
|
+
isQuoteToken: args.isQuoteToken,
|
|
47
46
|
});
|
|
48
47
|
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
49
48
|
}
|
|
@@ -7,7 +7,7 @@ export const adjustMarginTool = {
|
|
|
7
7
|
schema: {
|
|
8
8
|
poolId: z.string().describe("Pool ID"),
|
|
9
9
|
positionId: z.string().describe("Position ID"),
|
|
10
|
-
adjustAmount: z.string().describe("
|
|
10
|
+
adjustAmount: z.string().regex(/^-?\d+$/).describe("Quote token raw units. Positive = add, negative = remove."),
|
|
11
11
|
quoteToken: z.string().optional().describe("Quote token address"),
|
|
12
12
|
},
|
|
13
13
|
handler: async (args) => {
|
|
@@ -2,28 +2,15 @@ import { z } from "zod";
|
|
|
2
2
|
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
3
|
export const cancelAllOrdersTool = {
|
|
4
4
|
name: "cancel_all_orders",
|
|
5
|
-
description: "Cancel
|
|
5
|
+
description: "Cancel multiple open orders by orderIds.",
|
|
6
6
|
schema: {
|
|
7
|
-
orderIds: z.array(z.string()).
|
|
7
|
+
orderIds: z.array(z.string()).min(1).describe("Order IDs to cancel."),
|
|
8
8
|
},
|
|
9
9
|
handler: async (args) => {
|
|
10
10
|
try {
|
|
11
|
-
const { client
|
|
11
|
+
const { client } = await resolveClient();
|
|
12
12
|
const chainId = getChainId();
|
|
13
|
-
|
|
14
|
-
if (orderIds.length === 0) {
|
|
15
|
-
const openOrders = await client.order.getOrders(address);
|
|
16
|
-
const rows = Array.isArray(openOrders?.data) ? openOrders.data : [];
|
|
17
|
-
orderIds = rows
|
|
18
|
-
.map((o) => o.orderId ?? o.id ?? o.order_id)
|
|
19
|
-
.filter((id) => id !== undefined && id !== null)
|
|
20
|
-
.map((id) => String(id));
|
|
21
|
-
}
|
|
22
|
-
if (orderIds.length === 0) {
|
|
23
|
-
return {
|
|
24
|
-
content: [{ type: "text", text: JSON.stringify({ status: "success", data: { message: "No open orders to cancel.", cancelled: 0 } }, (_, v) => typeof v === "bigint" ? v.toString() : v, 2) }],
|
|
25
|
-
};
|
|
26
|
-
}
|
|
13
|
+
const orderIds = args.orderIds;
|
|
27
14
|
const result = await client.order.cancelAllOrders(orderIds, chainId);
|
|
28
15
|
return {
|
|
29
16
|
content: [{ type: "text", text: JSON.stringify({ status: "success", data: { cancelled: orderIds.length, orderIds, result } }, (_, v) => typeof v === "bigint" ? v.toString() : v, 2) }],
|
|
@@ -4,22 +4,13 @@ export const cancelOrderTool = {
|
|
|
4
4
|
name: "cancel_order",
|
|
5
5
|
description: "Cancel an open order by its order ID.",
|
|
6
6
|
schema: {
|
|
7
|
-
|
|
7
|
+
orderId: z.string().describe("Order ID to cancel"),
|
|
8
8
|
},
|
|
9
9
|
handler: async (args) => {
|
|
10
10
|
try {
|
|
11
11
|
const { client } = await resolveClient();
|
|
12
12
|
const chainId = getChainId();
|
|
13
|
-
const
|
|
14
|
-
if (!ids || ids.length === 0)
|
|
15
|
-
throw new Error("orderIds array is required.");
|
|
16
|
-
let result;
|
|
17
|
-
if (ids.length === 1) {
|
|
18
|
-
result = await client.order.cancelOrder(ids[0], chainId);
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
result = await client.order.cancelOrders(ids, chainId);
|
|
22
|
-
}
|
|
13
|
+
const result = await client.order.cancelOrder(args.orderId, chainId);
|
|
23
14
|
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
24
15
|
}
|
|
25
16
|
catch (error) {
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { resolveClient, getChainId, getQuoteToken } from "../auth/resolveClient.js";
|
|
3
3
|
import { normalizeAddress } from "../utils/address.js";
|
|
4
|
-
import { booleanLike } from "../utils/schema.js";
|
|
5
4
|
const MAX_UINT256 = "115792089237316195423570985008687907853269984665640564039457584007913129639935";
|
|
6
5
|
export const checkApprovalTool = {
|
|
7
6
|
name: "check_approval",
|
|
8
7
|
description: "Check if token spending approval is needed. Supports auto-approve exact amount (default) or optional unlimited approval.",
|
|
9
8
|
schema: {
|
|
10
|
-
amount: z.string().describe("Amount to check approval for (
|
|
9
|
+
amount: z.string().regex(/^\d+$/).describe("Amount to check approval for (token raw units)"),
|
|
11
10
|
quoteToken: z.string().optional().describe("Token address to check. Uses default if omitted."),
|
|
12
|
-
autoApprove:
|
|
13
|
-
approveMax:
|
|
11
|
+
autoApprove: z.boolean().optional().describe("If true, automatically approve when needed."),
|
|
12
|
+
approveMax: z.boolean().optional().describe("If true with autoApprove, approve unlimited MaxUint256 (default false: approve exact amount only)."),
|
|
14
13
|
},
|
|
15
14
|
handler: async (args) => {
|
|
16
15
|
try {
|
|
@@ -7,7 +7,7 @@ export const closeAllPositionsTool = {
|
|
|
7
7
|
description: "Emergency: close ALL open positions in a pool at once. Use for risk management.",
|
|
8
8
|
schema: {
|
|
9
9
|
poolId: z.string().describe("Pool ID to close all positions in"),
|
|
10
|
-
slippagePct: z.string().optional().describe("Slippage in
|
|
10
|
+
slippagePct: z.string().regex(/^\d+$/).optional().describe("Slippage in 4-digit precision raw units (1 = 0.01%)"),
|
|
11
11
|
},
|
|
12
12
|
handler: async (args) => {
|
|
13
13
|
try {
|
|
@@ -60,7 +60,7 @@ export const closeAllPositionsTool = {
|
|
|
60
60
|
postOnly: false,
|
|
61
61
|
slippagePct,
|
|
62
62
|
executionFeeToken: pos.quoteToken || pos.quote_token || getQuoteToken(),
|
|
63
|
-
leverage: pos.leverage
|
|
63
|
+
leverage: pos.userLeverage ?? pos.leverage ?? 1,
|
|
64
64
|
};
|
|
65
65
|
});
|
|
66
66
|
const result = await client.order.closeAllPositions(chainId, closeParams);
|
|
@@ -3,18 +3,21 @@ import { resolveClient } from "../auth/resolveClient.js";
|
|
|
3
3
|
import { closePosition as closePos } from "../services/tradeService.js";
|
|
4
4
|
export const closePositionTool = {
|
|
5
5
|
name: "close_position",
|
|
6
|
-
description: "
|
|
6
|
+
description: "Create a decrease order using SDK-native parameters.",
|
|
7
7
|
schema: {
|
|
8
8
|
poolId: z.string().describe("Pool ID"),
|
|
9
9
|
positionId: z.string().describe("Position ID to close"),
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
size: z.string().describe("
|
|
15
|
-
price: z.string().describe("Price
|
|
16
|
-
|
|
17
|
-
|
|
10
|
+
orderType: z.number().int().min(0).max(3).describe("OrderType enum value"),
|
|
11
|
+
triggerType: z.number().int().min(0).max(2).describe("TriggerType enum value"),
|
|
12
|
+
direction: z.union([z.literal(0), z.literal(1)]).describe("0 = LONG, 1 = SHORT"),
|
|
13
|
+
collateralAmount: z.string().regex(/^\d+$/).describe("Collateral raw units"),
|
|
14
|
+
size: z.string().regex(/^\d+$/).describe("Position size raw units"),
|
|
15
|
+
price: z.string().regex(/^\d+$/).describe("Price raw units (30 decimals)"),
|
|
16
|
+
timeInForce: z.number().int().describe("TimeInForce enum value"),
|
|
17
|
+
postOnly: z.boolean().describe("Post-only flag"),
|
|
18
|
+
slippagePct: z.string().regex(/^\d+$/).describe("Slippage with 4-dec precision raw units"),
|
|
19
|
+
executionFeeToken: z.string().describe("Execution fee token address"),
|
|
20
|
+
leverage: z.number().describe("Leverage"),
|
|
18
21
|
},
|
|
19
22
|
handler: async (args) => {
|
|
20
23
|
try {
|
|
@@ -3,21 +3,27 @@ import { resolveClient } from "../auth/resolveClient.js";
|
|
|
3
3
|
import { openPosition } from "../services/tradeService.js";
|
|
4
4
|
export const executeTradeTool = {
|
|
5
5
|
name: "execute_trade",
|
|
6
|
-
description: "
|
|
6
|
+
description: "Create an increase order using SDK-native parameters.",
|
|
7
7
|
schema: {
|
|
8
|
-
poolId: z.string().describe("Pool ID
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
8
|
+
poolId: z.string().describe("Pool ID"),
|
|
9
|
+
positionId: z.string().describe("Position ID ('0' for new position)"),
|
|
10
|
+
orderType: z.number().int().min(0).max(3).describe("OrderType enum value"),
|
|
11
|
+
triggerType: z.number().int().min(0).max(2).describe("TriggerType enum value"),
|
|
12
|
+
direction: z.union([z.literal(0), z.literal(1)]).describe("0 = LONG, 1 = SHORT"),
|
|
13
|
+
collateralAmount: z.string().regex(/^\d+$/).describe("Quote token raw units"),
|
|
14
|
+
size: z.string().regex(/^\d+$/).describe("Position size raw units"),
|
|
15
|
+
price: z.string().regex(/^\d+$/).describe("Price raw units (30 decimals)"),
|
|
16
|
+
timeInForce: z.number().int().describe("TimeInForce enum value"),
|
|
17
|
+
postOnly: z.boolean().describe("Post-only flag"),
|
|
18
|
+
slippagePct: z.string().regex(/^\d+$/).describe("Slippage with 4-dec precision raw units"),
|
|
19
|
+
executionFeeToken: z.string().describe("Execution fee token address"),
|
|
20
|
+
leverage: z.number().describe("Leverage"),
|
|
21
|
+
tpSize: z.string().regex(/^\d+$/).optional().describe("TP size raw units"),
|
|
22
|
+
tpPrice: z.string().regex(/^\d+$/).optional().describe("TP price raw units (30 decimals)"),
|
|
23
|
+
slSize: z.string().regex(/^\d+$/).optional().describe("SL size raw units"),
|
|
24
|
+
slPrice: z.string().regex(/^\d+$/).optional().describe("SL price raw units (30 decimals)"),
|
|
25
|
+
tradingFee: z.string().regex(/^\d+$/).describe("Trading fee raw units"),
|
|
26
|
+
marketId: z.string().describe("Market ID"),
|
|
21
27
|
},
|
|
22
28
|
handler: async (args) => {
|
|
23
29
|
try {
|
|
@@ -4,7 +4,7 @@ export const getAccountVipInfoTool = {
|
|
|
4
4
|
name: "get_account_vip_info",
|
|
5
5
|
description: "Get account VIP/fee-tier information.",
|
|
6
6
|
schema: {
|
|
7
|
-
chainId: z.
|
|
7
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
8
8
|
},
|
|
9
9
|
handler: async (args) => {
|
|
10
10
|
try {
|
|
@@ -2,16 +2,16 @@ import { z } from "zod";
|
|
|
2
2
|
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
3
|
export const getBaseDetailTool = {
|
|
4
4
|
name: "get_base_detail",
|
|
5
|
-
description: "Get base
|
|
5
|
+
description: "Get base token details.",
|
|
6
6
|
schema: {
|
|
7
|
-
|
|
8
|
-
chainId: z.
|
|
7
|
+
baseAddress: z.string().describe("Base token address"),
|
|
8
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
9
9
|
},
|
|
10
10
|
handler: async (args) => {
|
|
11
11
|
try {
|
|
12
12
|
const { client } = await resolveClient();
|
|
13
13
|
const chainId = args.chainId ?? getChainId();
|
|
14
|
-
const result = await client.markets.getBaseDetail({ chainId,
|
|
14
|
+
const result = await client.markets.getBaseDetail({ chainId, baseAddress: args.baseAddress });
|
|
15
15
|
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === "bigint" ? v.toString() : v, 2) }] };
|
|
16
16
|
}
|
|
17
17
|
catch (error) {
|
package/dist/tools/getKline.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
|
+
const klineIntervalSchema = z.enum(["1m", "5m", "15m", "30m", "1h", "4h", "1d", "1w", "1M"]);
|
|
3
4
|
export const getKlineTool = {
|
|
4
5
|
name: "get_kline",
|
|
5
6
|
description: "Get K-line / candlestick data for a pool. Essential for price analysis.",
|
|
6
7
|
schema: {
|
|
7
8
|
poolId: z.string().describe("Pool ID"),
|
|
8
|
-
interval:
|
|
9
|
-
limit: z.
|
|
9
|
+
interval: klineIntervalSchema.describe("K-line interval"),
|
|
10
|
+
limit: z.number().int().positive().optional().describe("Number of bars (default 100)"),
|
|
10
11
|
},
|
|
11
12
|
handler: async (args) => {
|
|
12
13
|
try {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
|
+
const klineIntervalSchema = z.enum(["1m", "5m", "15m", "30m", "1h", "4h", "1d", "1w", "1M"]);
|
|
3
4
|
export const getKlineLatestBarTool = {
|
|
4
5
|
name: "get_kline_latest_bar",
|
|
5
6
|
description: "Get the latest single K-line/candlestick bar for a pool.",
|
|
6
7
|
schema: {
|
|
7
8
|
poolId: z.string().describe("Pool ID"),
|
|
8
|
-
interval:
|
|
9
|
+
interval: klineIntervalSchema.describe("K-line interval"),
|
|
9
10
|
},
|
|
10
11
|
handler: async (args) => {
|
|
11
12
|
try {
|
|
@@ -5,7 +5,7 @@ export const getMarketListTool = {
|
|
|
5
5
|
name: "get_market_list",
|
|
6
6
|
description: "Get tradable markets/pools (state=2 Active). Supports configurable result limit; backend may still enforce its own cap.",
|
|
7
7
|
schema: {
|
|
8
|
-
limit: z.
|
|
8
|
+
limit: z.number().int().positive().optional().describe("Max results to request (default 1000)."),
|
|
9
9
|
},
|
|
10
10
|
handler: async (args) => {
|
|
11
11
|
try {
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { resolveClient } from "../auth/resolveClient.js";
|
|
2
|
+
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
3
|
import { getMarketPrice } from "../services/marketService.js";
|
|
4
4
|
export const getMarketPriceTool = {
|
|
5
5
|
name: "get_market_price",
|
|
6
6
|
description: "Get the current market price for a specific pool.",
|
|
7
7
|
schema: {
|
|
8
8
|
poolId: z.string().describe("Pool ID to get price for"),
|
|
9
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
9
10
|
},
|
|
10
11
|
handler: async (args) => {
|
|
11
12
|
try {
|
|
12
13
|
const { client } = await resolveClient();
|
|
13
|
-
const
|
|
14
|
+
const chainId = args.chainId ?? getChainId();
|
|
15
|
+
const data = await getMarketPrice(client, args.poolId, chainId);
|
|
14
16
|
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (k, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
15
17
|
}
|
|
16
18
|
catch (error) {
|
|
@@ -5,7 +5,7 @@ export const getNetworkFeeTool = {
|
|
|
5
5
|
description: "Estimate network fee requirements for a market.",
|
|
6
6
|
schema: {
|
|
7
7
|
marketId: z.string().describe("Market ID"),
|
|
8
|
-
chainId: z.
|
|
8
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
9
9
|
},
|
|
10
10
|
handler: async (args) => {
|
|
11
11
|
try {
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { resolveClient } from "../auth/resolveClient.js";
|
|
2
|
+
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
3
|
import { getOraclePrice } from "../services/marketService.js";
|
|
4
4
|
export const getOraclePriceTool = {
|
|
5
5
|
name: "get_oracle_price",
|
|
6
6
|
description: "Get the current oracle price for a specific pool.",
|
|
7
7
|
schema: {
|
|
8
8
|
poolId: z.string().describe("Pool ID to get oracle price for"),
|
|
9
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
9
10
|
},
|
|
10
11
|
handler: async (args) => {
|
|
11
12
|
try {
|
|
12
13
|
const { client } = await resolveClient();
|
|
13
|
-
const
|
|
14
|
+
const chainId = args.chainId ?? getChainId();
|
|
15
|
+
const data = await getOraclePrice(client, args.poolId, chainId);
|
|
14
16
|
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (k, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
15
17
|
}
|
|
16
18
|
catch (error) {
|
|
@@ -4,9 +4,9 @@ export const getUserTradingFeeRateTool = {
|
|
|
4
4
|
name: "get_user_trading_fee_rate",
|
|
5
5
|
description: "Get maker/taker fee rates for a given assetClass and riskTier.",
|
|
6
6
|
schema: {
|
|
7
|
-
assetClass: z.
|
|
8
|
-
riskTier: z.
|
|
9
|
-
chainId: z.
|
|
7
|
+
assetClass: z.number().int().nonnegative().describe("Asset class ID"),
|
|
8
|
+
riskTier: z.number().int().nonnegative().describe("Risk tier"),
|
|
9
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
10
10
|
},
|
|
11
11
|
handler: async (args) => {
|
|
12
12
|
try {
|
|
@@ -1,39 +1,30 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { quoteDeposit, quoteWithdraw, baseDeposit, baseWithdraw, getLpPrice, } from "../services/poolService.js";
|
|
3
|
-
import { parseSafeNumber } from "../utils/units.js";
|
|
4
3
|
export const manageLiquidityTool = {
|
|
5
4
|
name: "manage_liquidity",
|
|
6
|
-
description: "Add or withdraw liquidity from a BASE or QUOTE pool.
|
|
5
|
+
description: "Add or withdraw liquidity from a BASE or QUOTE pool.",
|
|
7
6
|
schema: {
|
|
8
|
-
action: z.
|
|
9
|
-
|
|
10
|
-
}).describe("'deposit' or 'withdraw'"),
|
|
11
|
-
poolType: z.string().trim().toUpperCase().refine((value) => value === "BASE" || value === "QUOTE", {
|
|
12
|
-
message: "poolType must be 'BASE' or 'QUOTE'.",
|
|
13
|
-
}).describe("'BASE' or 'QUOTE'"),
|
|
7
|
+
action: z.enum(["deposit", "withdraw"]).describe("'deposit' or 'withdraw'"),
|
|
8
|
+
poolType: z.enum(["BASE", "QUOTE"]).describe("'BASE' or 'QUOTE'"),
|
|
14
9
|
poolId: z.string().describe("Pool ID"),
|
|
15
|
-
amount: z.
|
|
16
|
-
slippage: z.
|
|
10
|
+
amount: z.number().positive().describe("Amount in human-readable units"),
|
|
11
|
+
slippage: z.number().min(0).describe("LP slippage ratio (e.g. 0.01 = 1%)"),
|
|
12
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
17
13
|
},
|
|
18
14
|
handler: async (args) => {
|
|
19
15
|
try {
|
|
20
16
|
const { action, poolType, poolId } = args;
|
|
21
|
-
const amount =
|
|
22
|
-
const slippage = parseSafeNumber(args.slippage, "slippage");
|
|
23
|
-
if (amount <= 0)
|
|
24
|
-
throw new Error("amount must be a positive number.");
|
|
25
|
-
if (slippage < 0)
|
|
26
|
-
throw new Error("slippage must be a non-negative number.");
|
|
17
|
+
const { amount, slippage } = args;
|
|
27
18
|
let result;
|
|
28
19
|
if (poolType === "QUOTE") {
|
|
29
20
|
result = action === "deposit"
|
|
30
|
-
? await quoteDeposit(poolId, amount, slippage)
|
|
31
|
-
: await quoteWithdraw(poolId, amount, slippage);
|
|
21
|
+
? await quoteDeposit(poolId, amount, slippage, args.chainId)
|
|
22
|
+
: await quoteWithdraw(poolId, amount, slippage, args.chainId);
|
|
32
23
|
}
|
|
33
24
|
else {
|
|
34
25
|
result = action === "deposit"
|
|
35
|
-
? await baseDeposit(poolId, amount, slippage)
|
|
36
|
-
: await baseWithdraw(poolId, amount, slippage);
|
|
26
|
+
? await baseDeposit(poolId, amount, slippage, args.chainId)
|
|
27
|
+
: await baseWithdraw(poolId, amount, slippage, args.chainId);
|
|
37
28
|
}
|
|
38
29
|
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
39
30
|
}
|
|
@@ -46,14 +37,13 @@ export const getLpPriceTool = {
|
|
|
46
37
|
name: "get_lp_price",
|
|
47
38
|
description: "Get the current internal net asset value (NAV) price of an LP token for a BASE or QUOTE pool. Note: This is NOT the underlying token's external Oracle market price (e.g. WETH's price), but rather the internal exchange rate / net worth of the LP token itself which fluctuates based on pool PnL and fees.",
|
|
48
39
|
schema: {
|
|
49
|
-
poolType: z.
|
|
50
|
-
message: "poolType must be 'BASE' or 'QUOTE'.",
|
|
51
|
-
}).describe("'BASE' or 'QUOTE'"),
|
|
40
|
+
poolType: z.enum(["BASE", "QUOTE"]).describe("'BASE' or 'QUOTE'"),
|
|
52
41
|
poolId: z.string().describe("Pool ID"),
|
|
42
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
53
43
|
},
|
|
54
44
|
handler: async (args) => {
|
|
55
45
|
try {
|
|
56
|
-
const data = await getLpPrice(args.poolType, args.poolId);
|
|
46
|
+
const data = await getLpPrice(args.poolType, args.poolId, args.chainId);
|
|
57
47
|
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (k, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
58
48
|
}
|
|
59
49
|
catch (error) {
|
package/dist/tools/marketInfo.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { resolveClient } from "../auth/resolveClient.js";
|
|
2
|
+
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
3
|
import { getMarketDetail } from "../services/marketService.js";
|
|
4
4
|
import { getPoolInfo, getLiquidityInfo } from "../services/poolService.js";
|
|
5
5
|
export const getMarketDetailTool = {
|
|
@@ -7,11 +7,13 @@ export const getMarketDetailTool = {
|
|
|
7
7
|
description: "Get detailed information for a specific trading pool (fee rates, open interest, etc.).",
|
|
8
8
|
schema: {
|
|
9
9
|
poolId: z.string().describe("Pool ID"),
|
|
10
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
10
11
|
},
|
|
11
12
|
handler: async (args) => {
|
|
12
13
|
try {
|
|
13
14
|
const { client } = await resolveClient();
|
|
14
|
-
const
|
|
15
|
+
const chainId = args.chainId ?? getChainId();
|
|
16
|
+
const data = await getMarketDetail(client, args.poolId, chainId);
|
|
15
17
|
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
16
18
|
}
|
|
17
19
|
catch (error) {
|
|
@@ -24,10 +26,12 @@ export const getPoolInfoTool = {
|
|
|
24
26
|
description: "Get pool on-chain information (reserves, utilization, etc.).",
|
|
25
27
|
schema: {
|
|
26
28
|
poolId: z.string().describe("Pool ID"),
|
|
29
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
27
30
|
},
|
|
28
31
|
handler: async (args) => {
|
|
29
32
|
try {
|
|
30
|
-
const
|
|
33
|
+
const chainId = args.chainId ?? getChainId();
|
|
34
|
+
const data = await getPoolInfo(args.poolId, chainId);
|
|
31
35
|
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
32
36
|
}
|
|
33
37
|
catch (error) {
|
|
@@ -40,12 +44,14 @@ export const getLiquidityInfoTool = {
|
|
|
40
44
|
description: "Get pool liquidity utilization and depth information.",
|
|
41
45
|
schema: {
|
|
42
46
|
poolId: z.string().describe("Pool ID"),
|
|
43
|
-
marketPrice: z.string().describe("Current market price
|
|
47
|
+
marketPrice: z.string().regex(/^\d+$/).describe("Current market price in 30-decimal raw units"),
|
|
48
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
44
49
|
},
|
|
45
50
|
handler: async (args) => {
|
|
46
51
|
try {
|
|
47
52
|
const { client } = await resolveClient();
|
|
48
|
-
const
|
|
53
|
+
const chainId = args.chainId ?? getChainId();
|
|
54
|
+
const data = await getLiquidityInfo(client, args.poolId, args.marketPrice, chainId);
|
|
49
55
|
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
50
56
|
}
|
|
51
57
|
catch (error) {
|
|
@@ -24,17 +24,16 @@ export const getOpenOrdersTool = {
|
|
|
24
24
|
};
|
|
25
25
|
export const getOrderHistoryTool = {
|
|
26
26
|
name: "get_order_history",
|
|
27
|
-
description: "Get historical orders with optional pool filter
|
|
27
|
+
description: "Get historical orders with optional pool filter.",
|
|
28
28
|
schema: {
|
|
29
29
|
poolId: z.string().optional().describe("Filter by pool ID"),
|
|
30
|
-
|
|
31
|
-
limit: z.coerce.number().optional().describe("Results per page (default 20)"),
|
|
30
|
+
limit: z.number().int().positive().optional().describe("Results per page (default 20)"),
|
|
32
31
|
},
|
|
33
32
|
handler: async (args) => {
|
|
34
33
|
try {
|
|
35
34
|
const { client, address } = await resolveClient();
|
|
36
35
|
const chainId = getChainId();
|
|
37
|
-
const query = { chainId, poolId: args.poolId,
|
|
36
|
+
const query = { chainId, poolId: args.poolId, limit: args.limit ?? 20 };
|
|
38
37
|
const result = await client.order.getOrderHistory(query, address);
|
|
39
38
|
const enhancedData = (result?.data || []).map((order) => ({
|
|
40
39
|
...order,
|
package/dist/tools/poolConfig.js
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { resolveClient } from "../auth/resolveClient.js";
|
|
2
|
+
import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
3
3
|
import { getPoolLevelConfig } from "../services/marketService.js";
|
|
4
4
|
export const getPoolLevelConfigTool = {
|
|
5
5
|
name: "get_pool_level_config",
|
|
6
6
|
description: "Get the level configuration and trading limits for a specific pool.",
|
|
7
7
|
schema: {
|
|
8
8
|
poolId: z.string().describe("Pool ID"),
|
|
9
|
+
chainId: z.number().int().positive().optional().describe("Optional chainId override"),
|
|
9
10
|
},
|
|
10
11
|
handler: async (args) => {
|
|
11
12
|
try {
|
|
12
13
|
const { client } = await resolveClient();
|
|
13
|
-
const
|
|
14
|
+
const chainId = args.chainId ?? getChainId();
|
|
15
|
+
const result = await getPoolLevelConfig(client, args.poolId, chainId);
|
|
14
16
|
return { content: [{ type: "text", text: JSON.stringify({ status: "success", data: result }, (_, v) => typeof v === 'bigint' ? v.toString() : v, 2) }] };
|
|
15
17
|
}
|
|
16
18
|
catch (error) {
|
|
@@ -3,17 +3,16 @@ import { resolveClient, getChainId } from "../auth/resolveClient.js";
|
|
|
3
3
|
import { getDirectionDesc, getCloseTypeDesc } from "../utils/mappings.js";
|
|
4
4
|
export const getPositionHistoryTool = {
|
|
5
5
|
name: "get_position_history",
|
|
6
|
-
description: "Get historical closed positions with optional pool filter
|
|
6
|
+
description: "Get historical closed positions with optional pool filter.",
|
|
7
7
|
schema: {
|
|
8
8
|
poolId: z.string().optional().describe("Filter by pool ID"),
|
|
9
|
-
|
|
10
|
-
limit: z.coerce.number().optional().describe("Results per page (default 20)"),
|
|
9
|
+
limit: z.number().int().positive().optional().describe("Results per page (default 20)"),
|
|
11
10
|
},
|
|
12
11
|
handler: async (args) => {
|
|
13
12
|
try {
|
|
14
13
|
const { client, address } = await resolveClient();
|
|
15
14
|
const chainId = getChainId();
|
|
16
|
-
const query = { chainId, poolId: args.poolId,
|
|
15
|
+
const query = { chainId, poolId: args.poolId, limit: args.limit ?? 20 };
|
|
17
16
|
const result = await client.position.getPositionHistory(query, address);
|
|
18
17
|
const enhancedData = (result?.data || []).map((pos) => ({
|
|
19
18
|
...pos,
|
|
@@ -6,7 +6,7 @@ export const searchMarketTool = {
|
|
|
6
6
|
description: "Search for an active market by keyword.",
|
|
7
7
|
schema: {
|
|
8
8
|
keyword: z.string().describe('Search keyword, e.g. "BTC", "ETH"'),
|
|
9
|
-
limit: z.
|
|
9
|
+
limit: z.number().int().positive().optional().describe("Max results (default 100)"),
|
|
10
10
|
},
|
|
11
11
|
handler: async (args) => {
|
|
12
12
|
try {
|
package/dist/tools/setTpSl.js
CHANGED
|
@@ -3,19 +3,20 @@ import { resolveClient } from "../auth/resolveClient.js";
|
|
|
3
3
|
import { setPositionTpSl } from "../services/tradeService.js";
|
|
4
4
|
export const setTpSlTool = {
|
|
5
5
|
name: "set_tp_sl",
|
|
6
|
-
description: "
|
|
6
|
+
description: "Create TP/SL order using SDK-native parameters.",
|
|
7
7
|
schema: {
|
|
8
8
|
poolId: z.string().describe("Pool ID"),
|
|
9
9
|
positionId: z.string().describe("Position ID"),
|
|
10
|
-
direction: z.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
direction: z.union([z.literal(0), z.literal(1)]).describe("0 = LONG, 1 = SHORT"),
|
|
11
|
+
leverage: z.number().describe("Leverage"),
|
|
12
|
+
executionFeeToken: z.string().describe("Execution fee token address"),
|
|
13
|
+
tpTriggerType: z.number().int().min(0).max(2).describe("TP trigger type"),
|
|
14
|
+
slTriggerType: z.number().int().min(0).max(2).describe("SL trigger type"),
|
|
15
|
+
slippagePct: z.string().regex(/^\d+$/).describe("Slippage with 4-dec precision raw units"),
|
|
16
|
+
tpPrice: z.string().regex(/^\d+$/).optional().describe("TP price raw units (30 decimals)"),
|
|
17
|
+
tpSize: z.string().regex(/^\d+$/).optional().describe("TP size raw units"),
|
|
18
|
+
slPrice: z.string().regex(/^\d+$/).optional().describe("SL price raw units (30 decimals)"),
|
|
19
|
+
slSize: z.string().regex(/^\d+$/).optional().describe("SL size raw units"),
|
|
19
20
|
},
|
|
20
21
|
handler: async (args) => {
|
|
21
22
|
try {
|
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { resolveClient } from "../auth/resolveClient.js";
|
|
3
3
|
import { updateOrderTpSl } from "../services/tradeService.js";
|
|
4
|
-
import { booleanLike } from "../utils/schema.js";
|
|
5
4
|
export const updateOrderTpSlTool = {
|
|
6
5
|
name: "update_order_tp_sl",
|
|
7
6
|
description: "Update an existing take profit or stop loss order.",
|
|
8
7
|
schema: {
|
|
9
8
|
orderId: z.string().describe("The ID of the order to update"),
|
|
10
9
|
marketId: z.string().describe("The market ID (config hash) for the order"),
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
10
|
+
size: z.string().regex(/^\d+$/).describe("Order size raw units"),
|
|
11
|
+
price: z.string().regex(/^\d+$/).describe("Order price raw units (30 decimals)"),
|
|
12
|
+
tpPrice: z.string().regex(/^\d+$/).describe("TP price raw units (30 decimals)"),
|
|
13
|
+
tpSize: z.string().regex(/^\d+$/).describe("TP size raw units"),
|
|
14
|
+
slPrice: z.string().regex(/^\d+$/).describe("SL price raw units (30 decimals)"),
|
|
15
|
+
slSize: z.string().regex(/^\d+$/).describe("SL size raw units"),
|
|
16
|
+
useOrderCollateral: z.boolean().describe("Whether to use order collateral"),
|
|
17
|
+
isTpSlOrder: z.boolean().optional().describe("Whether this is a TP/SL order"),
|
|
18
|
+
quoteToken: z.string().describe("Quote token address"),
|
|
17
19
|
},
|
|
18
20
|
handler: async (args) => {
|
|
19
21
|
try {
|
package/package.json
CHANGED
package/dist/utils/schema.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
const trueValues = new Set(["true", "1", "yes", "y", "on"]);
|
|
3
|
-
const falseValues = new Set(["false", "0", "no", "n", "off"]);
|
|
4
|
-
/**
|
|
5
|
-
* Safe boolean coercion for MCP inputs:
|
|
6
|
-
* - boolean: true/false
|
|
7
|
-
* - number: 1/0
|
|
8
|
-
* - string: true/false/1/0/yes/no/on/off (case-insensitive)
|
|
9
|
-
*/
|
|
10
|
-
export const booleanLike = z.union([
|
|
11
|
-
z.boolean(),
|
|
12
|
-
z.number().refine((value) => value === 0 || value === 1, {
|
|
13
|
-
message: "Expected 0 or 1 for boolean value.",
|
|
14
|
-
}).transform((value) => value === 1),
|
|
15
|
-
z.string().trim().toLowerCase().refine((value) => trueValues.has(value) || falseValues.has(value), {
|
|
16
|
-
message: "Expected boolean-like value: true/false/1/0/yes/no/on/off.",
|
|
17
|
-
}).transform((value) => trueValues.has(value)),
|
|
18
|
-
]);
|