hchain-mcp 1.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/.env.example +5 -0
- package/AGENT-MCP-RULES.md +248 -0
- package/OnchainOS-API/345/257/271/346/216/245/350/247/204/350/214/203.md +329 -0
- package/README.md +106 -0
- package/dist/adapters/onchainos-ws.d.ts +31 -0
- package/dist/adapters/onchainos-ws.js +103 -0
- package/dist/adapters/onchainos.d.ts +343 -0
- package/dist/adapters/onchainos.js +275 -0
- package/dist/adapters/shared.d.ts +23 -0
- package/dist/adapters/shared.js +107 -0
- package/dist/http.d.ts +9 -0
- package/dist/http.js +124 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +54 -0
- package/dist/tools/balance.d.ts +4 -0
- package/dist/tools/balance.js +69 -0
- package/dist/tools/defi.d.ts +4 -0
- package/dist/tools/defi.js +268 -0
- package/dist/tools/gateway.d.ts +4 -0
- package/dist/tools/gateway.js +107 -0
- package/dist/tools/intent.d.ts +4 -0
- package/dist/tools/intent.js +111 -0
- package/dist/tools/market.d.ts +4 -0
- package/dist/tools/market.js +612 -0
- package/dist/tools/payments.d.ts +4 -0
- package/dist/tools/payments.js +100 -0
- package/dist/tools/skills.d.ts +4 -0
- package/dist/tools/skills.js +464 -0
- package/dist/tools/trade.d.ts +4 -0
- package/dist/tools/trade.js +195 -0
- package/dist/tools/txhistory.d.ts +4 -0
- package/dist/tools/txhistory.js +49 -0
- package/dist/tools/ws.d.ts +4 -0
- package/dist/tools/ws.js +64 -0
- package/docs/DEFI.md +65 -0
- package/docs/GATEWAY.md +45 -0
- package/docs/MARKET.md +109 -0
- package/docs/PAYMENTS.md +83 -0
- package/docs/TRADE.md +103 -0
- package/package.json +25 -0
- package/src/adapters/onchainos-ws.ts +126 -0
- package/src/adapters/onchainos.ts +488 -0
- package/src/adapters/shared.ts +100 -0
- package/src/http.ts +132 -0
- package/src/index.ts +57 -0
- package/src/tools/balance.ts +67 -0
- package/src/tools/defi.ts +224 -0
- package/src/tools/gateway.ts +115 -0
- package/src/tools/intent.ts +106 -0
- package/src/tools/market.ts +543 -0
- package/src/tools/payments.ts +105 -0
- package/src/tools/skills.ts +489 -0
- package/src/tools/trade.ts +197 -0
- package/src/tools/txhistory.ts +51 -0
- package/src/tools/ws.ts +72 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Onchain OS REST API 适配层
|
|
3
|
+
* Base: https://web3.okx.com
|
|
4
|
+
* 按官方文档逐端点对接,杜绝幻觉
|
|
5
|
+
*/
|
|
6
|
+
import crypto from "node:crypto";
|
|
7
|
+
import type { Auth } from "./shared.js";
|
|
8
|
+
|
|
9
|
+
const BASE = "https://web3.okx.com";
|
|
10
|
+
|
|
11
|
+
function ts(): string { return new Date().toISOString().replace(/(\.\d{3})\d*Z/, "$1Z"); }
|
|
12
|
+
|
|
13
|
+
function buildQuery(p: Record<string, string | number | boolean | undefined>): string {
|
|
14
|
+
const s = new URLSearchParams();
|
|
15
|
+
for (const [k, v] of Object.entries(p)) if (v !== undefined && v !== "") s.append(k, String(v));
|
|
16
|
+
return s.size ? "?" + s.toString() : "";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
async function request<T>(
|
|
20
|
+
method: "GET" | "POST", path: string,
|
|
21
|
+
opts: { params?: Record<string, string | number | boolean | undefined>; body?: unknown; auth?: Auth } = {},
|
|
22
|
+
): Promise<T> {
|
|
23
|
+
const query = opts.params ? buildQuery(opts.params) : "";
|
|
24
|
+
const fullPath = path + query;
|
|
25
|
+
const bodyStr = opts.body ? JSON.stringify(opts.body) : "";
|
|
26
|
+
const headers: Record<string, string> = { "Content-Type": "application/json", "Accept": "application/json" };
|
|
27
|
+
|
|
28
|
+
if (opts.auth) {
|
|
29
|
+
const t = ts();
|
|
30
|
+
const sign = crypto.createHmac("sha256", opts.auth.secret).update(t + method + fullPath + bodyStr).digest("base64");
|
|
31
|
+
headers["OK-ACCESS-KEY"] = opts.auth.apiKey;
|
|
32
|
+
headers["OK-ACCESS-SIGN"] = sign;
|
|
33
|
+
headers["OK-ACCESS-TIMESTAMP"] = t;
|
|
34
|
+
headers["OK-ACCESS-PASSPHRASE"] = opts.auth.passphrase;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const res = await fetch(BASE + fullPath, { method, headers, ...(bodyStr ? { body: bodyStr } : {}) });
|
|
38
|
+
if (!res.ok) { const t = await res.text().catch(() => ""); throw new Error(`HTTP ${res.status}: ${t}`); }
|
|
39
|
+
const json = await res.json() as { code: string; msg?: string; data?: T };
|
|
40
|
+
if (json.code && json.code !== "0") throw new Error(`OKX ${json.code}: ${json.msg ?? ""}`);
|
|
41
|
+
return (json.data ?? json) as T;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ═══════════════════════════════════════════════════════════════
|
|
45
|
+
// 按官方文档逐模块添加
|
|
46
|
+
// ═══════════════════════════════════════════════════════════════
|
|
47
|
+
|
|
48
|
+
// ── Balance API v6 ─────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
export const balanceApi = {
|
|
51
|
+
/** GET /api/v6/dex/balance/supported/chain — 返回 name/logoUrl/shortName/chainIndex */
|
|
52
|
+
supportedChain: (auth: Auth) =>
|
|
53
|
+
request("GET", "/api/v6/dex/balance/supported/chain", { auth }),
|
|
54
|
+
|
|
55
|
+
/** GET /api/v6/dex/balance/total-value-by-address?address=&chains=&assetType=&excludeRiskToken= */
|
|
56
|
+
totalValue: (auth: Auth, address: string, chains: string, assetType?: string, excludeRiskToken?: boolean) =>
|
|
57
|
+
request("GET", "/api/v6/dex/balance/total-value-by-address", {
|
|
58
|
+
params: { address, chains, assetType, excludeRiskToken },
|
|
59
|
+
auth,
|
|
60
|
+
}),
|
|
61
|
+
|
|
62
|
+
/** GET /api/v6/dex/balance/all-token-balances-by-address?address=&chains=&excludeRiskToken= */
|
|
63
|
+
allTokenBalances: (auth: Auth, address: string, chains: string, excludeRiskToken?: string) =>
|
|
64
|
+
request("GET", "/api/v6/dex/balance/all-token-balances-by-address", {
|
|
65
|
+
params: { address, chains, excludeRiskToken },
|
|
66
|
+
auth,
|
|
67
|
+
}),
|
|
68
|
+
|
|
69
|
+
/** POST /api/v6/dex/balance/token-balances-by-address — body: { address, tokenContractAddresses: [{chainIndex, tokenContractAddress}], excludeRiskToken? } */
|
|
70
|
+
specificTokenBalance: (
|
|
71
|
+
auth: Auth,
|
|
72
|
+
address: string,
|
|
73
|
+
tokenContractAddresses: Array<{ chainIndex: string; tokenContractAddress: string }>,
|
|
74
|
+
excludeRiskToken?: string,
|
|
75
|
+
) =>
|
|
76
|
+
request("POST", "/api/v6/dex/balance/token-balances-by-address", {
|
|
77
|
+
body: { address, tokenContractAddresses, ...(excludeRiskToken !== undefined ? { excludeRiskToken } : {}) },
|
|
78
|
+
auth,
|
|
79
|
+
}),
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// ── Gateway API v6 (交易上链) ──────────────────────────────────
|
|
83
|
+
|
|
84
|
+
export const gatewayApi = {
|
|
85
|
+
/** GET /api/v6/dex/pre-transaction/supported/chain */
|
|
86
|
+
supportedChain: (auth: Auth) =>
|
|
87
|
+
request("GET", "/api/v6/dex/pre-transaction/supported/chain", { auth }),
|
|
88
|
+
|
|
89
|
+
/** GET /api/v6/dex/pre-transaction/gas-price?chainIndex= */
|
|
90
|
+
gasPrice: (auth: Auth, chainIndex: string) =>
|
|
91
|
+
request("GET", "/api/v6/dex/pre-transaction/gas-price", { params: { chainIndex }, auth }),
|
|
92
|
+
|
|
93
|
+
/** POST /api/v6/dex/pre-transaction/gas-limit */
|
|
94
|
+
gasLimit: (auth: Auth, body: { chainIndex: string; fromAddress: string; toAddress: string; txAmount?: string; extJson?: { inputData?: string } }) =>
|
|
95
|
+
request("POST", "/api/v6/dex/pre-transaction/gas-limit", { body, auth }),
|
|
96
|
+
|
|
97
|
+
/** POST /api/v6/dex/pre-transaction/simulate — 模拟执行, 返回 intention/assetChange/gasUsed/failReason/risks */
|
|
98
|
+
simulate: (auth: Auth, body: { fromAddress: string; toAddress: string; chainIndex: string; txAmount?: string; extJson: { inputData: string }; priorityFee?: string; gasPrice?: string }) =>
|
|
99
|
+
request("POST", "/api/v6/dex/pre-transaction/simulate", { body, auth }),
|
|
100
|
+
|
|
101
|
+
/** POST /api/v6/dex/pre-transaction/broadcast-transaction — 返回 orderId/txHash */
|
|
102
|
+
broadcast: (auth: Auth, body: { signedTx: string; chainIndex: string; address: string; extraData?: string }) =>
|
|
103
|
+
request("POST", "/api/v6/dex/pre-transaction/broadcast-transaction", { body, auth }),
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// ── Post-transaction API v6 ───────────────────────────────────
|
|
107
|
+
|
|
108
|
+
export const postTxApi = {
|
|
109
|
+
/** GET /api/v6/dex/post-transaction/orders — 广播订单列表 */
|
|
110
|
+
orders: (auth: Auth, address: string, chainIndex: string, txStatus?: string, orderId?: string, cursor?: string, limit?: string) =>
|
|
111
|
+
request("GET", "/api/v6/dex/post-transaction/orders", {
|
|
112
|
+
params: { address, chainIndex, txStatus, orderId, cursor, limit },
|
|
113
|
+
auth,
|
|
114
|
+
}),
|
|
115
|
+
|
|
116
|
+
/** GET /api/v6/dex/post-transaction/supported/chain — 交易历史支持的链 */
|
|
117
|
+
supportedChain: (auth: Auth) =>
|
|
118
|
+
request("GET", "/api/v6/dex/post-transaction/supported/chain", { auth }),
|
|
119
|
+
|
|
120
|
+
/** GET /api/v6/dex/post-transaction/transactions-by-address?address=&chains=&tokenContractAddress=&begin=&end=&cursor=&limit= */
|
|
121
|
+
transactions: (auth: Auth, address: string, chains: string, tokenContractAddress?: string, begin?: string, end?: string, cursor?: string, limit?: string) =>
|
|
122
|
+
request("GET", "/api/v6/dex/post-transaction/transactions-by-address", {
|
|
123
|
+
params: { address, chains, tokenContractAddress, begin, end, cursor, limit },
|
|
124
|
+
auth,
|
|
125
|
+
}),
|
|
126
|
+
|
|
127
|
+
/** GET /api/v6/dex/post-transaction/transaction-detail-by-txhash?chainIndex=&txHash=&itype= */
|
|
128
|
+
transactionDetail: (auth: Auth, chainIndex: string, txHash: string, itype?: string) =>
|
|
129
|
+
request("GET", "/api/v6/dex/post-transaction/transaction-detail-by-txhash", {
|
|
130
|
+
params: { chainIndex, txHash, itype },
|
|
131
|
+
auth,
|
|
132
|
+
}),
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// ── DeFi API v6 ──────────────────────────────────────────────
|
|
136
|
+
|
|
137
|
+
export const defiApi = {
|
|
138
|
+
/** GET /api/v6/defi/product/supported-chains — 返回 chainIndex(String)+network */
|
|
139
|
+
supportedChains: (auth: Auth) =>
|
|
140
|
+
request("GET", "/api/v6/defi/product/supported-chains", { auth }),
|
|
141
|
+
|
|
142
|
+
/** GET /api/v6/defi/product/supported-platforms — 返回 analysisPlatformId+platformName+investmentCount */
|
|
143
|
+
supportedPlatforms: (auth: Auth) =>
|
|
144
|
+
request("GET", "/api/v6/defi/product/supported-platforms", { auth }),
|
|
145
|
+
|
|
146
|
+
/** POST /api/v6/defi/product/search — body: { tokenKeywordList, platformKeywordList?, pageNum?, chainIndex?, productGroup? } */
|
|
147
|
+
searchProducts: (auth: Auth, body: { tokenKeywordList: string[]; platformKeywordList?: string[]; pageNum?: number; chainIndex?: string; productGroup?: string }) =>
|
|
148
|
+
request("POST", "/api/v6/defi/product/search", { body, auth }),
|
|
149
|
+
|
|
150
|
+
/** GET /api/v6/defi/product/detail?investmentId= */
|
|
151
|
+
productDetail: (auth: Auth, investmentId: string) =>
|
|
152
|
+
request("GET", "/api/v6/defi/product/detail", { params: { investmentId }, auth }),
|
|
153
|
+
|
|
154
|
+
/** GET /api/v6/defi/product/rate/chart?investmentId=&timeRange= — APY 折线图 */
|
|
155
|
+
rateChart: (auth: Auth, investmentId: string, timeRange?: string) =>
|
|
156
|
+
request("GET", "/api/v6/defi/product/rate/chart", { params: { investmentId, timeRange }, auth }),
|
|
157
|
+
|
|
158
|
+
/** GET /api/v6/defi/product/tvl/chart?investmentId=&timeRange= — TVL 折线图 */
|
|
159
|
+
tvlChart: (auth: Auth, investmentId: string, timeRange?: string) =>
|
|
160
|
+
request("GET", "/api/v6/defi/product/tvl/chart", { params: { investmentId, timeRange }, auth }),
|
|
161
|
+
|
|
162
|
+
/** GET /api/v6/defi/product/depth-price/chart?investmentId=&chartType=&timeRange= — V3 深度/价格图 */
|
|
163
|
+
depthPriceChart: (auth: Auth, investmentId: string, chartType?: string, timeRange?: string) =>
|
|
164
|
+
request("GET", "/api/v6/defi/product/depth-price/chart", { params: { investmentId, chartType, timeRange }, auth }),
|
|
165
|
+
|
|
166
|
+
/** POST /api/v6/defi/product/detail/prepare — 交易前准备, 返回 investWithTokenList/receiveTokenInfo */
|
|
167
|
+
prepareTransaction: (auth: Auth, investmentId: string) =>
|
|
168
|
+
request("POST", "/api/v6/defi/product/detail/prepare", { body: { investmentId }, auth }),
|
|
169
|
+
|
|
170
|
+
/** POST /api/v6/defi/calculator/enter/info — V3 Pool 双币分配计算 */
|
|
171
|
+
calcEnterInfo: (auth: Auth, body: { inputAmount: string; inputTokenAddress: string; tokenDecimal: string; investmentId: string; address: string; tickLower: string; tickUpper: string }) =>
|
|
172
|
+
request("POST", "/api/v6/defi/calculator/enter/info", { body, auth }),
|
|
173
|
+
|
|
174
|
+
/** POST /api/v6/defi/transaction/enter — 申购/存款/借款, 返回 dataList(APPROVE→DEPOSIT) */
|
|
175
|
+
enter: (auth: Auth, body: Record<string, unknown>) =>
|
|
176
|
+
request("POST", "/api/v6/defi/transaction/enter", { body, auth }),
|
|
177
|
+
|
|
178
|
+
/** POST /api/v6/defi/transaction/exit — 赎回/还款, 返回 dataList */
|
|
179
|
+
exit: (auth: Auth, body: Record<string, unknown>) =>
|
|
180
|
+
request("POST", "/api/v6/defi/transaction/exit", { body, auth }),
|
|
181
|
+
|
|
182
|
+
/** POST /api/v6/defi/transaction/claim — 领取奖励, 返回 dataList */
|
|
183
|
+
claim: (auth: Auth, body: Record<string, unknown>) =>
|
|
184
|
+
request("POST", "/api/v6/defi/transaction/claim", { body, auth }),
|
|
185
|
+
|
|
186
|
+
/** POST /api/v6/defi/user/asset/platform/list — 用户持仓概览(协议维度) */
|
|
187
|
+
userPlatformList: (auth: Auth, body: { walletAddressList: Array<{ chainIndex: string; walletAddress: string; pubKey?: string }>; tag?: string }) =>
|
|
188
|
+
request("POST", "/api/v6/defi/user/asset/platform/list", { body, auth }),
|
|
189
|
+
|
|
190
|
+
/** POST /api/v6/defi/user/asset/platform/detail — 用户持仓明细(投资品维度) */
|
|
191
|
+
userPlatformDetail: (auth: Auth, body: Record<string, unknown>) =>
|
|
192
|
+
request("POST", "/api/v6/defi/user/asset/platform/detail", { body, auth }),
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// ── Payments API (Agent Payments Protocol) ──────────────────
|
|
196
|
+
// 路径来源: API 参考 (HTTP端 + Agent端)
|
|
197
|
+
|
|
198
|
+
export const paymentsApi = {
|
|
199
|
+
// ── Agent 端 A2A (单次支付) ────────────────────────────
|
|
200
|
+
|
|
201
|
+
/** POST /api/v6/pay/a2a/payment/create — Seller 创建付款, 返回 paymentId+challenge+付款链接 */
|
|
202
|
+
create: (auth: Auth, body: { type: string; amount: string; symbol: string; recipient: string; description?: string; externalId?: string; expiresIn?: number; realm?: string; deliveries?: Record<string, unknown> }) =>
|
|
203
|
+
request("POST", "/api/v6/pay/a2a/payment/create", { body, auth }),
|
|
204
|
+
|
|
205
|
+
/** GET /api/v6/pay/a2a/p/{paymentId} — Buyer 拉取付款详情, PUBLIC */
|
|
206
|
+
detail: (paymentId: string) =>
|
|
207
|
+
request("GET", `/api/v6/pay/a2a/p/${paymentId}`),
|
|
208
|
+
|
|
209
|
+
/** POST /api/v6/pay/a2a/p/{paymentId}/credential — Buyer 提交 EIP-3009 签名凭证, PUBLIC */
|
|
210
|
+
submit: (paymentId: string, body: Record<string, unknown>) =>
|
|
211
|
+
request("POST", `/api/v6/pay/a2a/p/${paymentId}/credential`, { body }),
|
|
212
|
+
|
|
213
|
+
/** GET /api/v6/pay/a2a/p/{paymentId}/status — 查询支付状态, PUBLIC */
|
|
214
|
+
status: (paymentId: string) =>
|
|
215
|
+
request("GET", `/api/v6/pay/a2a/p/${paymentId}/status`),
|
|
216
|
+
|
|
217
|
+
// ── HTTP 端 x402 (单次/批量) ──────────────────────────
|
|
218
|
+
|
|
219
|
+
/** GET /api/v6/pay/x402/supported — 支持的网络/代币/scheme */
|
|
220
|
+
supported: (auth: Auth) =>
|
|
221
|
+
request("GET", "/api/v6/pay/x402/supported", { auth }),
|
|
222
|
+
|
|
223
|
+
/** POST /api/v6/pay/x402/verify — 验签 */
|
|
224
|
+
verify: (auth: Auth, body: Record<string, unknown>) =>
|
|
225
|
+
request("POST", "/api/v6/pay/x402/verify", { body, auth }),
|
|
226
|
+
|
|
227
|
+
/** POST /api/v6/pay/x402/settle — 上链结算 */
|
|
228
|
+
settle: (auth: Auth, body: Record<string, unknown>) =>
|
|
229
|
+
request("POST", "/api/v6/pay/x402/settle", { body, auth }),
|
|
230
|
+
|
|
231
|
+
/** GET /api/v6/pay/x402/settle/status?txHash= — 轮询结算状态 */
|
|
232
|
+
settleStatus: (auth: Auth, txHash: string) =>
|
|
233
|
+
request("GET", "/api/v6/pay/x402/settle/status", { params: { txHash }, auth }),
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
// ── Trade / DEX API v6 (经典兑换) ────────────────────────────
|
|
237
|
+
// 来源: Solana/EVM/Sui/Ton 搭建指南 + API 参考
|
|
238
|
+
|
|
239
|
+
export const tradeApi = {
|
|
240
|
+
/** GET /api/v6/dex/aggregator/supported/chain?chainIndex= — 返回 chainIndex/chainName/dexTokenApproveAddress */
|
|
241
|
+
supportedChain: (auth: Auth, chainIndex?: string) =>
|
|
242
|
+
request("GET", "/api/v6/dex/aggregator/supported/chain", { params: { chainIndex }, auth }),
|
|
243
|
+
|
|
244
|
+
allTokens: (auth: Auth, chainIndex: string) =>
|
|
245
|
+
request("GET", "/api/v6/dex/aggregator/all-tokens", { params: { chainIndex }, auth }),
|
|
246
|
+
|
|
247
|
+
liquidity: (auth: Auth, chainIndex: string) =>
|
|
248
|
+
request("GET", "/api/v6/dex/aggregator/get-liquidity", { params: { chainIndex }, auth }),
|
|
249
|
+
|
|
250
|
+
approveTransaction: (auth: Auth, chainIndex: string, tokenContractAddress: string, approveAmount: string) =>
|
|
251
|
+
request("GET", "/api/v6/dex/aggregator/approve-transaction", { params: { chainIndex, tokenContractAddress, approveAmount }, auth }),
|
|
252
|
+
|
|
253
|
+
quote: (auth: Auth, params: Record<string, string>) =>
|
|
254
|
+
request("GET", "/api/v6/dex/aggregator/quote", { params, auth }),
|
|
255
|
+
|
|
256
|
+
swap: (auth: Auth, params: Record<string, string>) =>
|
|
257
|
+
request("GET", "/api/v6/dex/aggregator/swap", { params, auth }),
|
|
258
|
+
|
|
259
|
+
swapInstruction: (auth: Auth, params: Record<string, string>) =>
|
|
260
|
+
request("GET", "/api/v6/dex/aggregator/swap-instruction", { params, auth }),
|
|
261
|
+
|
|
262
|
+
swapHistory: (auth: Auth, chainIndex: string, txHash: string, isFromMyProject?: boolean) =>
|
|
263
|
+
request("GET", "/api/v6/dex/aggregator/history", { params: { chainIndex, txHash, isFromMyProject }, auth }),
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// ── Intent Swap API v6 ──────────────────────────────────────
|
|
267
|
+
|
|
268
|
+
export const intentApi = {
|
|
269
|
+
/** POST /api/v6/dex/aggregator/intent/create-order — 创建意图订单, 返回 orderUid */
|
|
270
|
+
createOrder: (auth: Auth, body: Record<string, unknown>) =>
|
|
271
|
+
request("POST", "/api/v6/dex/aggregator/intent/create-order", { body, auth }),
|
|
272
|
+
|
|
273
|
+
/** GET /api/v6/dex/aggregator/intent/order-list?userWalletAddress=&orderUid=&cursor=&limit= — 订单列表 */
|
|
274
|
+
orderList: (auth: Auth, params: { userWalletAddress?: string; orderUid?: string; cursor?: string; limit?: number }) =>
|
|
275
|
+
request("GET", "/api/v6/dex/aggregator/intent/order-list", { params, auth }),
|
|
276
|
+
|
|
277
|
+
/** GET /api/v6/dex/aggregator/intent/order-status?orderUid= — 查订单状态 */
|
|
278
|
+
orderStatus: (auth: Auth, orderUid: string) =>
|
|
279
|
+
request("GET", "/api/v6/dex/aggregator/intent/order-status", { params: { orderUid }, auth }),
|
|
280
|
+
|
|
281
|
+
/** POST /api/v6/dex/aggregator/intent/cancel-signdata — 获取取消签名数据 */
|
|
282
|
+
cancelSignData: (auth: Auth, userWalletAddress: string, orderUid: string) =>
|
|
283
|
+
request("POST", "/api/v6/dex/aggregator/intent/cancel-signdata", { body: { userWalletAddress, orderUid }, auth }),
|
|
284
|
+
|
|
285
|
+
/** POST /api/v6/dex/aggregator/intent/cancel-order — 取消订单 */
|
|
286
|
+
cancelOrder: (auth: Auth, userWalletAddress: string, orderUid: string, signature: string) =>
|
|
287
|
+
request("POST", "/api/v6/dex/aggregator/intent/cancel-order", { body: { userWalletAddress, orderUid, signature }, auth }),
|
|
288
|
+
|
|
289
|
+
/** GET /api/v6/dex/aggregator/intent/auction-info?auctionId=&txHash= — 查拍卖结果 */
|
|
290
|
+
auctionInfo: (auth: Auth, params: { auctionId?: string; txHash?: string }) =>
|
|
291
|
+
request("GET", "/api/v6/dex/aggregator/intent/auction-info", { params, auth }),
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
// ── Market API v6 (行情 — x402 付费) ──────────────────────
|
|
295
|
+
|
|
296
|
+
export const marketApi = {
|
|
297
|
+
/** GET /api/v6/dex/market/supported/chain?chainIndex= */
|
|
298
|
+
supportedChain: (auth: Auth, chainIndex?: string) =>
|
|
299
|
+
request("GET", "/api/v6/dex/market/supported/chain", { params: { chainIndex }, auth }),
|
|
300
|
+
|
|
301
|
+
/** POST /api/v6/dex/market/price — body: [{chainIndex, tokenContractAddress}] */
|
|
302
|
+
price: (auth: Auth, body: Array<{ chainIndex: string; tokenContractAddress: string }>) =>
|
|
303
|
+
request("POST", "/api/v6/dex/market/price", { body, auth }),
|
|
304
|
+
|
|
305
|
+
/** GET /api/v6/dex/market/candles?chainIndex=&tokenContractAddress=&bar=&after=&before=&limit= */
|
|
306
|
+
candles: (auth: Auth, params: { chainIndex: string; tokenContractAddress: string; bar?: string; after?: string; before?: string; limit?: string }) =>
|
|
307
|
+
request("GET", "/api/v6/dex/market/candles", { params, auth }),
|
|
308
|
+
|
|
309
|
+
/** GET /api/v6/dex/market/historical-candles?chainIndex=&tokenContractAddress=&bar=&after=&before=&limit= */
|
|
310
|
+
historicalCandles: (auth: Auth, params: { chainIndex: string; tokenContractAddress: string; bar?: string; after?: string; before?: string; limit?: string }) =>
|
|
311
|
+
request("GET", "/api/v6/dex/market/historical-candles", { params, auth }),
|
|
312
|
+
|
|
313
|
+
// ── 综合币价 ──────────────────────────────────────
|
|
314
|
+
|
|
315
|
+
/** POST /api/v6/dex/index/current-price — body: [{chainIndex, tokenContractAddress}] */
|
|
316
|
+
indexCurrentPrice: (auth: Auth, body: Array<{ chainIndex: string; tokenContractAddress: string }>) =>
|
|
317
|
+
request("POST", "/api/v6/dex/index/current-price", { body, auth }),
|
|
318
|
+
|
|
319
|
+
/** GET /api/v6/dex/index/historical-price?chainIndex=&tokenContractAddress=&limit=&cursor=&begin=&end=&period= */
|
|
320
|
+
indexHistoricalPrice: (auth: Auth, params: { chainIndex: string; tokenContractAddress?: string; limit?: string; cursor?: string; begin?: string; end?: string; period?: string }) =>
|
|
321
|
+
request("GET", "/api/v6/dex/index/historical-price", { params, auth }),
|
|
322
|
+
|
|
323
|
+
// ── 代币 API ──────────────────────────────────────
|
|
324
|
+
|
|
325
|
+
/** GET /api/v6/dex/market/token/search?chains=&search=&cursor=&limit= — 搜索代币 */
|
|
326
|
+
searchToken: (auth: Auth, chains: string, search: string, cursor?: string, limit?: string) =>
|
|
327
|
+
request("GET", "/api/v6/dex/market/token/search", { params: { chains, search, cursor, limit }, auth }),
|
|
328
|
+
|
|
329
|
+
/** POST /api/v6/dex/market/token/basic-info — body: [{chainIndex, tokenContractAddress}] */
|
|
330
|
+
tokenBasicInfo: (auth: Auth, body: Array<{ chainIndex: string; tokenContractAddress: string }>) =>
|
|
331
|
+
request("POST", "/api/v6/dex/market/token/basic-info", { body, auth }),
|
|
332
|
+
|
|
333
|
+
/** GET /api/v6/dex/market/token/top-liquidity?chainIndex=&tokenContractAddress= — 流动性池 */
|
|
334
|
+
tokenTopLiquidity: (auth: Auth, chainIndex: string, tokenContractAddress: string) =>
|
|
335
|
+
request("GET", "/api/v6/dex/market/token/top-liquidity", { params: { chainIndex, tokenContractAddress }, auth }),
|
|
336
|
+
|
|
337
|
+
/** POST /api/v6/dex/market/price-info — 批量交易信息, body: [{chainIndex, tokenContractAddress}], max 100 */
|
|
338
|
+
priceInfo: (auth: Auth, body: Array<{ chainIndex: string; tokenContractAddress: string }>) =>
|
|
339
|
+
request("POST", "/api/v6/dex/market/price-info", { body, auth }),
|
|
340
|
+
|
|
341
|
+
/** GET /api/v6/dex/market/token/advanced-info?chainIndex=&tokenContractAddress= — 代币安全分析(貔貅/开发者/狙击手) */
|
|
342
|
+
tokenAdvancedInfo: (auth: Auth, chainIndex: string, tokenContractAddress: string) =>
|
|
343
|
+
request("GET", "/api/v6/dex/market/token/advanced-info", { params: { chainIndex, tokenContractAddress }, auth }),
|
|
344
|
+
|
|
345
|
+
/** GET /api/v6/dex/market/token/hot-token?rankingType=&chainIndex=&rankBy=... — 热门代币(最多100) */
|
|
346
|
+
tokenHot: (auth: Auth, params: Record<string, string | number | boolean | undefined>) =>
|
|
347
|
+
request("GET", "/api/v6/dex/market/token/hot-token", { params, auth }),
|
|
348
|
+
|
|
349
|
+
/** GET /api/v6/dex/market/token/holder?chainIndex=&tokenContractAddress=&tagFilter=&cursor=&limit= — 前100持有人 */
|
|
350
|
+
tokenHolder: (auth: Auth, params: { chainIndex: string; tokenContractAddress: string; tagFilter?: string; cursor?: string; limit?: string }) =>
|
|
351
|
+
request("GET", "/api/v6/dex/market/token/holder", { params, auth }),
|
|
352
|
+
|
|
353
|
+
/** GET /api/v6/dex/market/token/cluster/supported/chain — 聚类支持链 */
|
|
354
|
+
tokenClusterSupportedChain: (auth: Auth) =>
|
|
355
|
+
request("GET", "/api/v6/dex/market/token/cluster/supported/chain", { auth }),
|
|
356
|
+
|
|
357
|
+
/** GET /api/v6/dex/market/token/cluster/overview?chainIndex=&tokenContractAddress= — 持仓集中度 */
|
|
358
|
+
tokenClusterOverview: (auth: Auth, chainIndex: string, tokenContractAddress: string) =>
|
|
359
|
+
request("GET", "/api/v6/dex/market/token/cluster/overview", { params: { chainIndex, tokenContractAddress }, auth }),
|
|
360
|
+
|
|
361
|
+
/** GET /api/v6/dex/market/token/cluster/list?chainIndex=&tokenContractAddress= — 聚类列表(top100集群) */
|
|
362
|
+
tokenClusterList: (auth: Auth, chainIndex: string, tokenContractAddress: string) =>
|
|
363
|
+
request("GET", "/api/v6/dex/market/token/cluster/list", { params: { chainIndex, tokenContractAddress }, auth }),
|
|
364
|
+
|
|
365
|
+
/** GET /api/v6/dex/market/token/cluster/top-holders?chainIndex=&tokenContractAddress=&rangeFilter= — 前10/50/100持仓 */
|
|
366
|
+
tokenClusterTopHolders: (auth: Auth, chainIndex: string, tokenContractAddress: string, rangeFilter: string) =>
|
|
367
|
+
request("GET", "/api/v6/dex/market/token/cluster/top-holders", { params: { chainIndex, tokenContractAddress, rangeFilter }, auth }),
|
|
368
|
+
|
|
369
|
+
/** GET /api/v6/dex/market/token/top-trader?chainIndex=&tokenContractAddress=&tagFilter=&cursor=&limit= — 前100盈利地址 */
|
|
370
|
+
tokenTopTrader: (auth: Auth, params: { chainIndex: string; tokenContractAddress: string; tagFilter?: string; cursor?: string; limit?: string }) =>
|
|
371
|
+
request("GET", "/api/v6/dex/market/token/top-trader", { params, auth }),
|
|
372
|
+
|
|
373
|
+
// ── 信号 API ──────────────────────────────────────
|
|
374
|
+
|
|
375
|
+
/** GET /api/v6/dex/market/signal/supported/chain — 信号支持链 */
|
|
376
|
+
signalSupportedChain: (auth: Auth) =>
|
|
377
|
+
request("GET", "/api/v6/dex/market/signal/supported/chain", { auth }),
|
|
378
|
+
|
|
379
|
+
/** POST /api/v6/dex/market/signal/list — 获取信号 */
|
|
380
|
+
signalList: (auth: Auth, body: Record<string, unknown>) =>
|
|
381
|
+
request("POST", "/api/v6/dex/market/signal/list", { body, auth }),
|
|
382
|
+
|
|
383
|
+
/** GET /api/v6/dex/market/leaderboard/supported/chain — 聪明钱榜单支持链 */
|
|
384
|
+
leaderboardSupportedChain: (auth: Auth) =>
|
|
385
|
+
request("GET", "/api/v6/dex/market/leaderboard/supported/chain", { auth }),
|
|
386
|
+
|
|
387
|
+
/** GET /api/v6/dex/market/leaderboard/list?chainIndex=&timeFrame=&sortBy=&walletType=... — 聪明钱榜单 */
|
|
388
|
+
leaderboardList: (auth: Auth, params: Record<string, string>) =>
|
|
389
|
+
request("GET", "/api/v6/dex/market/leaderboard/list", { params, auth }),
|
|
390
|
+
|
|
391
|
+
// ── Memepump / 扫链 ──────────────────────────────────
|
|
392
|
+
|
|
393
|
+
/** GET /api/v6/dex/market/memepump/supported/chainsProtocol — 支持的链+协议 */
|
|
394
|
+
memepumpSupported: (auth: Auth) =>
|
|
395
|
+
request("GET", "/api/v6/dex/market/memepump/supported/chainsProtocol", { auth }),
|
|
396
|
+
|
|
397
|
+
/** GET /api/v6/dex/market/memepump/tokenList?chainIndex=&stage=&... — 代币列表(最多30) */
|
|
398
|
+
memepumpTokenList: (auth: Auth, params: Record<string, string | boolean | undefined>) =>
|
|
399
|
+
request("GET", "/api/v6/dex/market/memepump/tokenList", { params, auth }),
|
|
400
|
+
|
|
401
|
+
/** GET /api/v6/dex/market/memepump/tokenDetails?chainIndex=&tokenContractAddress=&walletAddress= */
|
|
402
|
+
memepumpTokenDetails: (auth: Auth, chainIndex: string, tokenContractAddress: string, walletAddress?: string) =>
|
|
403
|
+
request("GET", "/api/v6/dex/market/memepump/tokenDetails", { params: { chainIndex, tokenContractAddress, walletAddress }, auth }),
|
|
404
|
+
|
|
405
|
+
/** GET /api/v6/dex/market/memepump/tokenDevInfo?chainIndex=&tokenContractAddress= */
|
|
406
|
+
memepumpTokenDevInfo: (auth: Auth, chainIndex: string, tokenContractAddress: string) =>
|
|
407
|
+
request("GET", "/api/v6/dex/market/memepump/tokenDevInfo", { params: { chainIndex, tokenContractAddress }, auth }),
|
|
408
|
+
|
|
409
|
+
/** GET /api/v6/dex/market/memepump/similarToken?chainIndex=&tokenContractAddress= */
|
|
410
|
+
memepumpSimilarToken: (auth: Auth, chainIndex: string, tokenContractAddress: string) =>
|
|
411
|
+
request("GET", "/api/v6/dex/market/memepump/similarToken", { params: { chainIndex, tokenContractAddress }, auth }),
|
|
412
|
+
|
|
413
|
+
/** GET /api/v6/dex/market/memepump/tokenBundleInfo?chainIndex=&tokenContractAddress= */
|
|
414
|
+
memepumpBundleInfo: (auth: Auth, chainIndex: string, tokenContractAddress: string) =>
|
|
415
|
+
request("GET", "/api/v6/dex/market/memepump/tokenBundleInfo", { params: { chainIndex, tokenContractAddress }, auth }),
|
|
416
|
+
|
|
417
|
+
/** GET /api/v6/dex/market/memepump/apedWallet?chainIndex=&tokenContractAddress=&walletAddress= */
|
|
418
|
+
memepumpApedWallet: (auth: Auth, chainIndex: string, tokenContractAddress: string, walletAddress?: string) =>
|
|
419
|
+
request("GET", "/api/v6/dex/market/memepump/apedWallet", { params: { chainIndex, tokenContractAddress, walletAddress }, auth }),
|
|
420
|
+
|
|
421
|
+
// ── Portfolio / 地址分析 ─────────────────────────────
|
|
422
|
+
|
|
423
|
+
/** GET /api/v6/dex/market/portfolio/supported/chain */
|
|
424
|
+
portfolioSupportedChain: (auth: Auth) =>
|
|
425
|
+
request("GET", "/api/v6/dex/market/portfolio/supported/chain", { auth }),
|
|
426
|
+
|
|
427
|
+
/** GET /api/v6/dex/market/portfolio/overview?chainIndex=&walletAddress=&timeFrame= */
|
|
428
|
+
portfolioOverview: (auth: Auth, chainIndex: string, walletAddress: string, timeFrame: string) =>
|
|
429
|
+
request("GET", "/api/v6/dex/market/portfolio/overview", { params: { chainIndex, walletAddress, timeFrame }, auth }),
|
|
430
|
+
|
|
431
|
+
/** GET /api/v6/dex/market/portfolio/recent-pnl?chainIndex=&walletAddress=&cursor=&limit= */
|
|
432
|
+
portfolioRecentPnl: (auth: Auth, params: { chainIndex: string; walletAddress: string; cursor?: string; limit?: string }) =>
|
|
433
|
+
request("GET", "/api/v6/dex/market/portfolio/recent-pnl", { params, auth }),
|
|
434
|
+
|
|
435
|
+
/** GET /api/v6/dex/market/portfolio/token/latest-pnl?chainIndex=&walletAddress=&tokenContractAddress= */
|
|
436
|
+
portfolioTokenLatestPnl: (auth: Auth, chainIndex: string, walletAddress: string, tokenContractAddress: string) =>
|
|
437
|
+
request("GET", "/api/v6/dex/market/portfolio/token/latest-pnl", { params: { chainIndex, walletAddress, tokenContractAddress }, auth }),
|
|
438
|
+
|
|
439
|
+
/** GET /api/v6/dex/market/portfolio/dex-history?chainIndex=&walletAddress=&begin=&end=&... */
|
|
440
|
+
portfolioDexHistory: (auth: Auth, params: { chainIndex: string; walletAddress: string; begin: string; end: string; tokenContractAddress?: string; type?: string; cursor?: string; limit?: string }) =>
|
|
441
|
+
request("GET", "/api/v6/dex/market/portfolio/dex-history", { params, auth }),
|
|
442
|
+
|
|
443
|
+
/** GET /api/v6/dex/market/address-tracker/trades?trackerType=&walletAddress=&tradeType=... */
|
|
444
|
+
addressTrackerTrades: (auth: Auth, params: { trackerType: string; walletAddress?: string; tradeType?: string; chainIndex?: string; minVolume?: string; maxVolume?: string; minHolders?: string; minMarketCap?: string; maxMarketCap?: string; minLiquidity?: string; maxLiquidity?: string }) =>
|
|
445
|
+
request("GET", "/api/v6/dex/market/address-tracker/trades", { params, auth }),
|
|
446
|
+
|
|
447
|
+
// ── Social / 社媒 ──────────────────────────────────
|
|
448
|
+
|
|
449
|
+
/** GET /api/v6/dex/market/social/news/latest */
|
|
450
|
+
socialNewsLatest: (auth: Auth, params: Record<string, string>) =>
|
|
451
|
+
request("GET", "/api/v6/dex/market/social/news/latest", { params, auth }),
|
|
452
|
+
|
|
453
|
+
/** GET /api/v6/dex/market/social/news/by-symbol */
|
|
454
|
+
socialNewsBySymbol: (auth: Auth, params: Record<string, string>) =>
|
|
455
|
+
request("GET", "/api/v6/dex/market/social/news/by-symbol", { params, auth }),
|
|
456
|
+
|
|
457
|
+
/** GET /api/v6/dex/market/social/news/search */
|
|
458
|
+
socialNewsSearch: (auth: Auth, params: Record<string, string>) =>
|
|
459
|
+
request("GET", "/api/v6/dex/market/social/news/search", { params, auth }),
|
|
460
|
+
|
|
461
|
+
/** GET /api/v6/dex/market/social/news/detail?articleId= */
|
|
462
|
+
socialNewsDetail: (auth: Auth, articleId: string, language?: string) =>
|
|
463
|
+
request("GET", "/api/v6/dex/market/social/news/detail", { params: { articleId, language }, auth }),
|
|
464
|
+
|
|
465
|
+
/** GET /api/v6/dex/market/social/news/platforms */
|
|
466
|
+
socialNewsPlatforms: (auth: Auth) =>
|
|
467
|
+
request("GET", "/api/v6/dex/market/social/news/platforms", { auth }),
|
|
468
|
+
|
|
469
|
+
/** GET /api/v6/dex/market/social/sentiment/symbol?tokenSymbols=&timeFrame=&trendPoints= */
|
|
470
|
+
socialSentimentSymbol: (auth: Auth, params: Record<string, string>) =>
|
|
471
|
+
request("GET", "/api/v6/dex/market/social/sentiment/symbol", { params, auth }),
|
|
472
|
+
|
|
473
|
+
/** GET /api/v6/dex/market/social/sentiment/ranking?timeFrame=&sortBy=&limit= */
|
|
474
|
+
socialSentimentRanking: (auth: Auth, params: Record<string, string>) =>
|
|
475
|
+
request("GET", "/api/v6/dex/market/social/sentiment/ranking", { params, auth }),
|
|
476
|
+
|
|
477
|
+
/** GET /api/v6/dex/market/social/vibe/timeline?chainIndex=&tokenAddress=&timeFrame= */
|
|
478
|
+
socialVibeTimeline: (auth: Auth, params: Record<string, string>) =>
|
|
479
|
+
request("GET", "/api/v6/dex/market/social/vibe/timeline", { params, auth }),
|
|
480
|
+
|
|
481
|
+
/** GET /api/v6/dex/market/social/vibe/top-kols?chainIndex=&tokenAddress=&sortBy=&timeFrame=&limit= */
|
|
482
|
+
socialVibeTopKols: (auth: Auth, params: Record<string, string>) =>
|
|
483
|
+
request("GET", "/api/v6/dex/market/social/vibe/top-kols", { params, auth }),
|
|
484
|
+
|
|
485
|
+
/** GET /api/v6/dex/market/trades?chainIndex=&tokenContractAddress=&after=&limit=&tagFilter=&walletAddressFilter= */
|
|
486
|
+
trades: (auth: Auth, params: { chainIndex: string; tokenContractAddress: string; after?: string; limit?: string; tagFilter?: string; walletAddressFilter?: string }) =>
|
|
487
|
+
request("GET", "/api/v6/dex/market/trades", { params, auth }),
|
|
488
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* h-mcp — 共享工具层
|
|
3
|
+
* 规范: OnchainOS-API对接规范.md §四/§六 + AGENT-MCP-RULES.md §4/§8
|
|
4
|
+
*/
|
|
5
|
+
import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
|
|
7
|
+
// ── 类型 ────────────────────────────────────────────────────
|
|
8
|
+
export interface Auth { apiKey: string; secret: string; passphrase: string; }
|
|
9
|
+
|
|
10
|
+
export interface NextStep {
|
|
11
|
+
action: string;
|
|
12
|
+
tool: string;
|
|
13
|
+
params?: Record<string, unknown>;
|
|
14
|
+
condition?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// ── toResult ────────────────────────────────────────────────
|
|
18
|
+
export function toResult<T>(data: T, opts?: { warnings?: string[]; nextSteps?: NextStep[] }): CallToolResult {
|
|
19
|
+
const body: Record<string, unknown> = { success: true, data, tsIso: new Date().toISOString() };
|
|
20
|
+
if (opts?.warnings?.length) body.warnings = opts.warnings;
|
|
21
|
+
if (opts?.nextSteps?.length) body.nextSteps = opts.nextSteps;
|
|
22
|
+
return { content: [{ type: "text", text: JSON.stringify(body) }] };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// ── toError ─────────────────────────────────────────────────
|
|
26
|
+
export function toError(e: unknown): CallToolResult {
|
|
27
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
28
|
+
let error: { code: string; message: string; fix: string; retryAfter?: number };
|
|
29
|
+
|
|
30
|
+
// OKX 业务错误码 (HTTP 200, code != "0")
|
|
31
|
+
if (msg.includes("OKX 50001")) {
|
|
32
|
+
error = { code: "SERVICE_UNAVAILABLE", message: msg, fix: "服务暂不可用, 等待几秒后重试", retryAfter: 3000 };
|
|
33
|
+
} else if (msg.includes("OKX 50011")) {
|
|
34
|
+
error = { code: "RATE_LIMITED", message: msg, fix: "超出频率限制, 请降低请求频率", retryAfter: 5000 };
|
|
35
|
+
} else if (msg.includes("OKX 50103") || msg.includes("OKX 50104") || msg.includes("OKX 50105") || msg.includes("OKX 50106") || msg.includes("OKX 50107") || msg.includes("OKX 50111") || msg.includes("OKX 50112") || msg.includes("OKX 50113")) {
|
|
36
|
+
error = { code: "AUTH_ERROR", message: msg, fix: "API Key 签名错误, 请检查 OKX_API_KEY/OKX_SECRET_KEY/OKX_PASSPHRASE" };
|
|
37
|
+
} else if (msg.includes("OKX 81001")) {
|
|
38
|
+
error = { code: "BAD_PARAMETER", message: msg, fix: "参数不正确, 请检查参数名/类型/必填项" };
|
|
39
|
+
} else if (msg.includes("OKX 81108")) {
|
|
40
|
+
error = { code: "WALLET_TYPE_MISMATCH", message: msg, fix: "钱包类型不匹配, 请确认链和地址格式一致" };
|
|
41
|
+
} else if (msg.includes("OKX 81104")) {
|
|
42
|
+
error = { code: "CHAIN_NOT_SUPPORT", message: msg, fix: "该链不支持此操作, 请调用 supported_chain 确认可用链" };
|
|
43
|
+
} else if (msg.includes("OKX 81152")) {
|
|
44
|
+
error = { code: "COIN_NOT_EXIST", message: msg, fix: "代币不存在, 请用 onchainos_token_search 搜索正确地址" };
|
|
45
|
+
} else if (msg.includes("OKX 81451")) {
|
|
46
|
+
error = { code: "NODE_FAILED", message: msg, fix: "节点返回失败, 请稍后重试", retryAfter: 2000 };
|
|
47
|
+
} else if (msg.includes("OKX 84001") || msg.includes("OKX 84003")) {
|
|
48
|
+
error = { code: "PROTOCOL_NOT_SUPPORT", message: msg, fix: "协议不支持, 请用 onchainos_defi_supported_platforms 确认支持列表" };
|
|
49
|
+
} else if (msg.includes("OKX 84007") || msg.includes("OKX 84024")) {
|
|
50
|
+
error = { code: "PRODUCT_NOT_SUPPORT", message: msg, fix: "投资品不支持或不存在, 请用 onchainos_defi_search_products 重新搜索" };
|
|
51
|
+
} else if (msg.includes("OKX 84010")) {
|
|
52
|
+
error = { code: "TOKEN_NOT_SUPPORT", message: msg, fix: "代币不支持, 请确认 tokenAddress 正确" };
|
|
53
|
+
} else if (msg.includes("OKX 84014")) {
|
|
54
|
+
error = { code: "BALANCE_FAILED", message: msg, fix: "余额验证失败, 请确认钱包余额充足" };
|
|
55
|
+
} else if (msg.includes("OKX 84016")) {
|
|
56
|
+
error = { code: "CONTRACT_FAILED", message: msg, fix: "智能合约执行失败, 请检查参数和链上状态" };
|
|
57
|
+
} else if (msg.includes("OKX 84019")) {
|
|
58
|
+
error = { code: "ADDRESS_MISMATCH", message: msg, fix: "地址格式不匹配, 请用 onchainos_wallet_validate_address 校验" };
|
|
59
|
+
} else if (msg.includes("OKX 84021")) {
|
|
60
|
+
error = { code: "SYNCING", message: msg, fix: "资产正在同步中, 请等待片刻后重试", retryAfter: 3000 };
|
|
61
|
+
} else if (msg.includes("OKX 84025")) {
|
|
62
|
+
error = { code: "NO_REWARD", message: msg, fix: "当前无可领取的奖励" };
|
|
63
|
+
} else if (msg.includes("OKX 84029")) {
|
|
64
|
+
error = { code: "LOCKED", message: msg, fix: "本金仍在锁定期, 无法领取" };
|
|
65
|
+
} else if (msg.includes("OKX 84030")) {
|
|
66
|
+
error = { code: "EXPIRED", message: msg, fix: "本金领取已过期" };
|
|
67
|
+
} else if (msg.includes("OKX 84032")) {
|
|
68
|
+
error = { code: "V3_ONLY", message: msg, fix: "此接口仅适用于 V3 DEX Pool 投资品" };
|
|
69
|
+
}
|
|
70
|
+
// HTTP 传输层错误
|
|
71
|
+
else if (msg.includes("429") || msg.includes("RATE")) {
|
|
72
|
+
error = { code: "RATE_LIMITED", message: msg, fix: "请等待 1-2 秒后重试", retryAfter: 1000 };
|
|
73
|
+
} else if (msg.includes("503")) {
|
|
74
|
+
error = { code: "UNAVAILABLE", message: msg, fix: "服务暂时不可用,请等待 5 秒后重试", retryAfter: 5000 };
|
|
75
|
+
} else if (msg.includes("400")) {
|
|
76
|
+
error = { code: "BAD_REQUEST", message: msg, fix: "请检查参数格式和必填字段" };
|
|
77
|
+
} else if (msg.includes("422")) {
|
|
78
|
+
error = { code: "BUSINESS_REJECT", message: msg, fix: "参数合法但业务不可行,请检查余额/授权等条件" };
|
|
79
|
+
} else if (msg.includes("500")) {
|
|
80
|
+
error = { code: "SYSTEM_ERROR", message: msg, fix: "系统错误,不建议重试" };
|
|
81
|
+
} else {
|
|
82
|
+
error = { code: "ERROR", message: msg, fix: "请检查网络和 API 配置" };
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error, tsIso: new Date().toISOString() }) }],
|
|
86
|
+
isError: true,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// ── AUTH_REQUIRED ───────────────────────────────────────────
|
|
91
|
+
export function AUTH_REQUIRED(scope: "READ" | "TRADE" = "READ"): CallToolResult {
|
|
92
|
+
return {
|
|
93
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
94
|
+
success: false,
|
|
95
|
+
error: { code: "AUTH_REQUIRED", message: `需要 OKX API Key(${scope} 权限)`, fix: "请设置环境变量 OKX_API_KEY / OKX_SECRET_KEY / OKX_PASSPHRASE" },
|
|
96
|
+
tsIso: new Date().toISOString(),
|
|
97
|
+
}) }],
|
|
98
|
+
isError: true,
|
|
99
|
+
};
|
|
100
|
+
}
|