@oobe-protocol-labs/sap-mcp-server 0.9.37 → 0.9.38
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 +14 -0
- package/CHANGELOG.md +85 -0
- package/README.md +3 -3
- package/USER_DOCS/01_HOSTED_REMOTE_MCP.md +1 -1
- package/USER_DOCS/04_CLIENT_CONFIGS.md +3 -3
- package/USER_DOCS/06_DESKTOP_GUI_WIZARD.md +5 -5
- package/dist/config/env.d.ts +32 -0
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +24 -1
- package/dist/config/env.js.map +1 -1
- package/dist/core/constants.d.ts +1 -1
- package/dist/core/constants.js +1 -1
- package/dist/core/logger.js +1 -1
- package/dist/payments/pricing.d.ts.map +1 -1
- package/dist/payments/pricing.js +39 -1
- package/dist/payments/pricing.js.map +1 -1
- package/dist/perps/adrena/adrena-builder.d.ts +301 -0
- package/dist/perps/adrena/adrena-builder.d.ts.map +1 -0
- package/dist/perps/adrena/adrena-builder.js +1148 -0
- package/dist/perps/adrena/adrena-builder.js.map +1 -0
- package/dist/perps/adrena/adrena-constants.d.ts +135 -0
- package/dist/perps/adrena/adrena-constants.d.ts.map +1 -0
- package/dist/perps/adrena/adrena-constants.js +100 -0
- package/dist/perps/adrena/adrena-constants.js.map +1 -0
- package/dist/perps/adrena/adrena-data-api.d.ts +180 -0
- package/dist/perps/adrena/adrena-data-api.d.ts.map +1 -0
- package/dist/perps/adrena/adrena-data-api.js +169 -0
- package/dist/perps/adrena/adrena-data-api.js.map +1 -0
- package/dist/perps/adrena/adrena-pda.d.ts +146 -0
- package/dist/perps/adrena/adrena-pda.d.ts.map +1 -0
- package/dist/perps/adrena/adrena-pda.js +215 -0
- package/dist/perps/adrena/adrena-pda.js.map +1 -0
- package/dist/perps/adrena/index.d.ts +11 -0
- package/dist/perps/adrena/index.d.ts.map +1 -0
- package/dist/perps/adrena/index.js +11 -0
- package/dist/perps/adrena/index.js.map +1 -0
- package/dist/server/server-metadata.d.ts +2 -0
- package/dist/server/server-metadata.d.ts.map +1 -1
- package/dist/server/server-metadata.js +3 -1
- package/dist/server/server-metadata.js.map +1 -1
- package/dist/tools/adrena-tools.d.ts +67 -0
- package/dist/tools/adrena-tools.d.ts.map +1 -0
- package/dist/tools/adrena-tools.js +1062 -0
- package/dist/tools/adrena-tools.js.map +1 -0
- package/dist/tools/client-sdk-tools.d.ts +8 -0
- package/dist/tools/client-sdk-tools.d.ts.map +1 -1
- package/dist/tools/client-sdk-tools.js +31 -6
- package/dist/tools/client-sdk-tools.js.map +1 -1
- package/dist/tools/perp-tools.d.ts +150 -7
- package/dist/tools/perp-tools.d.ts.map +1 -1
- package/dist/tools/perp-tools.js +787 -212
- package/dist/tools/perp-tools.js.map +1 -1
- package/dist/tools/quick-context-tool.js +1 -0
- package/dist/tools/quick-context-tool.js.map +1 -1
- package/dist/tools/register-tools.d.ts.map +1 -1
- package/dist/tools/register-tools.js +4 -0
- package/dist/tools/register-tools.js.map +1 -1
- package/docs/07_ENDPOINTS_AND_CLIENTS.md +1 -1
- package/docs/10_OPERATIONS_RELEASE_AND_PM2.md +54 -6
- package/docs/14_DESKTOP_WIZARD_RELEASE.md +3 -3
- package/docs/BRANCH_AND_CI.md +2 -2
- package/package.json +3 -3
- package/server.json +3 -3
- package/skills/sap-defi/SKILL.md +93 -22
- package/skills/sap-mcp/TOOL_REFERENCE.md +39 -4
|
@@ -0,0 +1,1062 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @name tools/adrena-tools
|
|
3
|
+
* @description MCP tool registrations for the Adrena perps protocol integration.
|
|
4
|
+
*
|
|
5
|
+
* Registers local unsigned transaction builders for all Adrena operations:
|
|
6
|
+
*
|
|
7
|
+
* Trading builders (10):
|
|
8
|
+
* - sap_adrena_build_open_long — Open/increase a long perp position.
|
|
9
|
+
* - sap_adrena_build_open_short — Open/increase a short perp position.
|
|
10
|
+
* - sap_adrena_build_close_long — Close a long perp position.
|
|
11
|
+
* - sap_adrena_build_close_short — Close a short perp position.
|
|
12
|
+
* - sap_adrena_build_set_stop_loss — Set stop loss on a position.
|
|
13
|
+
* - sap_adrena_build_set_take_profit — Set take profit on a position.
|
|
14
|
+
* - sap_adrena_build_cancel_stop_loss — Cancel stop loss.
|
|
15
|
+
* - sap_adrena_build_cancel_take_profit— Cancel take profit.
|
|
16
|
+
* - sap_adrena_build_add_limit_order — Place a limit order.
|
|
17
|
+
* - sap_adrena_build_cancel_limit_order— Cancel a limit order.
|
|
18
|
+
*
|
|
19
|
+
* Commodity builders (4):
|
|
20
|
+
* - sap_adrena_build_open_commodity_long — Open a commodity long (XAU/XAG/WTI).
|
|
21
|
+
* - sap_adrena_build_open_commodity_short — Open a commodity short.
|
|
22
|
+
* - sap_adrena_build_close_commodity_long — Close a commodity long.
|
|
23
|
+
* - sap_adrena_build_close_commodity_short— Close a commodity short.
|
|
24
|
+
*
|
|
25
|
+
* Liquidity & Swap builders (3):
|
|
26
|
+
* - sap_adrena_build_add_liquidity — Add liquidity to a pool.
|
|
27
|
+
* - sap_adrena_build_remove_liquidity — Remove liquidity from a pool.
|
|
28
|
+
* - sap_adrena_build_swap — Swap tokens through a pool.
|
|
29
|
+
*
|
|
30
|
+
* Staking builders (5):
|
|
31
|
+
* - sap_adrena_build_init_user_staking — Initialize user staking account.
|
|
32
|
+
* - sap_adrena_build_add_liquid_stake — Add liquid stake.
|
|
33
|
+
* - sap_adrena_build_remove_liquid_stake— Remove liquid stake.
|
|
34
|
+
* - sap_adrena_build_add_locked_stake — Add locked stake.
|
|
35
|
+
* - sap_adrena_build_claim_stakes — Claim staking rewards.
|
|
36
|
+
*
|
|
37
|
+
* Data API tools (10):
|
|
38
|
+
* - sap_adrena_get_positions — Position history for a wallet.
|
|
39
|
+
* - sap_adrena_get_pool_info — Latest pool statistics.
|
|
40
|
+
* - sap_adrena_get_custody_info — Per-asset custody statistics.
|
|
41
|
+
* - sap_adrena_get_trader_info — Trader performance metrics.
|
|
42
|
+
* - sap_adrena_get_trader_leaderboard — Trader leaderboard.
|
|
43
|
+
* - sap_adrena_get_mutagen — Mutagen points for a wallet.
|
|
44
|
+
* - sap_adrena_get_mutagen_leaderboard — Mutagen leaderboard.
|
|
45
|
+
* - sap_adrena_get_prices — ADX and ALP token prices.
|
|
46
|
+
* - sap_adrena_get_trading_prices — Latest oracle prices for all assets.
|
|
47
|
+
* - sap_adrena_get_position_status — Live position P&L from Data API.
|
|
48
|
+
*
|
|
49
|
+
* All builder tools return an unsigned base64 transaction for local signing
|
|
50
|
+
* via `sap_payments_finalize_transaction`. SAP MCP never signs user-owned
|
|
51
|
+
* Adrena transactions.
|
|
52
|
+
*
|
|
53
|
+
* @module tools/adrena-tools
|
|
54
|
+
*/
|
|
55
|
+
import { PublicKey } from '@solana/web3.js';
|
|
56
|
+
import { createTextResponse } from '../adapters/mcp/tool-response.js';
|
|
57
|
+
import { registerTool } from '../adapters/mcp/sdk-compat.js';
|
|
58
|
+
import { logger } from '../core/logger.js';
|
|
59
|
+
import { buildOpenPositionLong, buildOpenPositionShort, buildClosePositionLong, buildClosePositionShort, buildSetStopLoss, buildSetTakeProfit, buildCancelStopLoss, buildCancelTakeProfit, buildAddLimitOrder, buildCancelLimitOrder, buildAddLiquidity, buildRemoveLiquidity, buildSwap, buildInitUserStaking, buildAddLiquidStake, buildRemoveLiquidStake, buildAddLockedStake, buildClaimStakes, buildOpenCommodityLong, buildOpenCommodityShort, buildCloseCommodityLong, buildCloseCommodityShort, adrenaDataApi, } from '../perps/adrena/index.js';
|
|
60
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
61
|
+
* Helpers
|
|
62
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
63
|
+
/** Supported principal tokens for the main pool. */
|
|
64
|
+
const MAIN_POOL_TOKENS = ['JITOSOL', 'WBTC', 'BONK'];
|
|
65
|
+
/** Supported commodity tokens. */
|
|
66
|
+
const COMMODITY_TOKENS = ['XAU', 'XAG', 'WTI'];
|
|
67
|
+
/** Supported collateral tokens. */
|
|
68
|
+
const COLLATERAL_TOKENS = ['USDC', 'JITOSOL', 'WBTC', 'BONK'];
|
|
69
|
+
/**
|
|
70
|
+
* Convert a human-readable price to Adrena raw price (10^10 scaling).
|
|
71
|
+
* @param priceUsd — Price in USD.
|
|
72
|
+
* @returns Raw price as bigint.
|
|
73
|
+
*/
|
|
74
|
+
function priceToRaw(priceUsd) {
|
|
75
|
+
return BigInt(Math.floor(priceUsd * Math.pow(10, 10)));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get the connection from context.
|
|
79
|
+
* @param context — SAP MCP context.
|
|
80
|
+
* @returns Solana connection.
|
|
81
|
+
*/
|
|
82
|
+
function getConnection(context) {
|
|
83
|
+
return context.connection;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Parse and validate a public key.
|
|
87
|
+
* @param value — Base58 public key string.
|
|
88
|
+
* @returns PublicKey or throws.
|
|
89
|
+
*/
|
|
90
|
+
function parsePublicKey(value) {
|
|
91
|
+
return new PublicKey(value);
|
|
92
|
+
}
|
|
93
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
94
|
+
* Trading Builders
|
|
95
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
96
|
+
/**
|
|
97
|
+
* @name registerAdrenaOpenLongTool
|
|
98
|
+
* @description Register sap_adrena_build_open_long.
|
|
99
|
+
* @internal
|
|
100
|
+
*/
|
|
101
|
+
function registerAdrenaOpenLongTool(server, context) {
|
|
102
|
+
const schema = {
|
|
103
|
+
type: 'object',
|
|
104
|
+
properties: {
|
|
105
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58). This is the fee payer and signer.' },
|
|
106
|
+
principalToken: { type: 'string', description: 'Asset to trade (long). Supported: JITOSOL, WBTC, BONK.', enum: MAIN_POOL_TOKENS },
|
|
107
|
+
collateralToken: { type: 'string', description: 'Collateral token. Must match principal for longs. Supported: JITOSOL, WBTC, BONK.', enum: COLLATERAL_TOKENS },
|
|
108
|
+
collateralAmount: { type: 'number', description: 'Collateral amount in human-readable units (e.g. 10 = 10 JITOSOL).', minimum: 0 },
|
|
109
|
+
leverage: { type: 'number', description: 'Leverage multiplier (e.g. 3 = 3x).', minimum: 1, maximum: 100 },
|
|
110
|
+
priceUsd: { type: 'number', description: 'Optional limit price in USD. Omit for market order.', minimum: 0 },
|
|
111
|
+
},
|
|
112
|
+
required: ['owner', 'principalToken', 'collateralToken', 'collateralAmount', 'leverage'],
|
|
113
|
+
additionalProperties: false,
|
|
114
|
+
};
|
|
115
|
+
registerTool(server, 'sap_adrena_build_open_long', {
|
|
116
|
+
description: 'Build an unsigned transaction to open or increase a long perp position on Adrena. Returns transactionBase64 for local signing via sap_payments_finalize_transaction. The agent must sign locally — SAP MCP never signs user-owned perp transactions.',
|
|
117
|
+
inputSchema: schema,
|
|
118
|
+
}, async (args) => {
|
|
119
|
+
try {
|
|
120
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
121
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
122
|
+
const collateralToken = String(args['collateralToken']).toUpperCase();
|
|
123
|
+
const collateralAmount = Number(args['collateralAmount']);
|
|
124
|
+
const leverage = Number(args['leverage']);
|
|
125
|
+
const priceUsd = args['priceUsd'] !== undefined ? Number(args['priceUsd']) : null;
|
|
126
|
+
const price = priceUsd !== null ? priceToRaw(priceUsd) : null;
|
|
127
|
+
const result = await buildOpenPositionLong(getConnection(context), owner, principalToken, collateralToken, collateralAmount, leverage, price);
|
|
128
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build open long transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* @name registerAdrenaOpenShortTool
|
|
137
|
+
* @description Register sap_adrena_build_open_short.
|
|
138
|
+
* @internal
|
|
139
|
+
*/
|
|
140
|
+
function registerAdrenaOpenShortTool(server, context) {
|
|
141
|
+
const schema = {
|
|
142
|
+
type: 'object',
|
|
143
|
+
properties: {
|
|
144
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58).' },
|
|
145
|
+
principalToken: { type: 'string', description: 'Asset to short. Supported: JITOSOL, WBTC, BONK.', enum: MAIN_POOL_TOKENS },
|
|
146
|
+
collateralToken: { type: 'string', description: 'Collateral token. Must be USDC for shorts.', enum: ['USDC'] },
|
|
147
|
+
collateralAmount: { type: 'number', description: 'Collateral (USDC) amount in human-readable units.', minimum: 0 },
|
|
148
|
+
leverage: { type: 'number', description: 'Leverage multiplier.', minimum: 1, maximum: 100 },
|
|
149
|
+
priceUsd: { type: 'number', description: 'Optional limit price in USD. Omit for market order.', minimum: 0 },
|
|
150
|
+
},
|
|
151
|
+
required: ['owner', 'principalToken', 'collateralToken', 'collateralAmount', 'leverage'],
|
|
152
|
+
additionalProperties: false,
|
|
153
|
+
};
|
|
154
|
+
registerTool(server, 'sap_adrena_build_open_short', {
|
|
155
|
+
description: 'Build an unsigned transaction to open or increase a short perp position on Adrena. Collateral must be USDC for shorts. Returns transactionBase64 for local signing.',
|
|
156
|
+
inputSchema: schema,
|
|
157
|
+
}, async (args) => {
|
|
158
|
+
try {
|
|
159
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
160
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
161
|
+
const collateralToken = String(args['collateralToken']).toUpperCase();
|
|
162
|
+
const collateralAmount = Number(args['collateralAmount']);
|
|
163
|
+
const leverage = Number(args['leverage']);
|
|
164
|
+
const priceUsd = args['priceUsd'] !== undefined ? Number(args['priceUsd']) : null;
|
|
165
|
+
const price = priceUsd !== null ? priceToRaw(priceUsd) : null;
|
|
166
|
+
const result = await buildOpenPositionShort(getConnection(context), owner, principalToken, collateralToken, collateralAmount, leverage, price);
|
|
167
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build open short transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* @name registerAdrenaCloseLongTool
|
|
176
|
+
* @description Register sap_adrena_build_close_long.
|
|
177
|
+
* @internal
|
|
178
|
+
*/
|
|
179
|
+
function registerAdrenaCloseLongTool(server, context) {
|
|
180
|
+
const schema = {
|
|
181
|
+
type: 'object',
|
|
182
|
+
properties: {
|
|
183
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58).' },
|
|
184
|
+
principalToken: { type: 'string', description: 'Asset of the position. Supported: JITOSOL, WBTC, BONK.', enum: MAIN_POOL_TOKENS },
|
|
185
|
+
priceUsd: { type: 'number', description: 'Optional close price in USD. Omit for market close.', minimum: 0 },
|
|
186
|
+
percentage: { type: 'number', description: 'Percentage to close (0-1000000, where 1000000 = 100%). Default 1000000.', minimum: 0, maximum: 1000000 },
|
|
187
|
+
},
|
|
188
|
+
required: ['owner', 'principalToken'],
|
|
189
|
+
additionalProperties: false,
|
|
190
|
+
};
|
|
191
|
+
registerTool(server, 'sap_adrena_build_close_long', {
|
|
192
|
+
description: 'Build an unsigned transaction to close a long perp position on Adrena. Default closes 100% at market price. Returns transactionBase64 for local signing.',
|
|
193
|
+
inputSchema: schema,
|
|
194
|
+
}, async (args) => {
|
|
195
|
+
try {
|
|
196
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
197
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
198
|
+
const priceUsd = args['priceUsd'] !== undefined ? Number(args['priceUsd']) : null;
|
|
199
|
+
const price = priceUsd !== null ? priceToRaw(priceUsd) : null;
|
|
200
|
+
const percentage = args['percentage'] !== undefined ? BigInt(Math.floor(Number(args['percentage']))) : 1000000n;
|
|
201
|
+
const result = await buildClosePositionLong(getConnection(context), owner, principalToken, price, percentage);
|
|
202
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build close long transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* @name registerAdrenaCloseShortTool
|
|
211
|
+
* @description Register sap_adrena_build_close_short.
|
|
212
|
+
* @internal
|
|
213
|
+
*/
|
|
214
|
+
function registerAdrenaCloseShortTool(server, context) {
|
|
215
|
+
const schema = {
|
|
216
|
+
type: 'object',
|
|
217
|
+
properties: {
|
|
218
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58).' },
|
|
219
|
+
principalToken: { type: 'string', description: 'Asset of the position.', enum: MAIN_POOL_TOKENS },
|
|
220
|
+
collateralToken: { type: 'string', description: 'Collateral token. USDC for shorts.', enum: ['USDC'] },
|
|
221
|
+
priceUsd: { type: 'number', description: 'Optional close price in USD.', minimum: 0 },
|
|
222
|
+
percentage: { type: 'number', description: 'Percentage to close (0-1000000). Default 1000000.', minimum: 0, maximum: 1000000 },
|
|
223
|
+
},
|
|
224
|
+
required: ['owner', 'principalToken', 'collateralToken'],
|
|
225
|
+
additionalProperties: false,
|
|
226
|
+
};
|
|
227
|
+
registerTool(server, 'sap_adrena_build_close_short', {
|
|
228
|
+
description: 'Build an unsigned transaction to close a short perp position on Adrena. Returns transactionBase64 for local signing.',
|
|
229
|
+
inputSchema: schema,
|
|
230
|
+
}, async (args) => {
|
|
231
|
+
try {
|
|
232
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
233
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
234
|
+
const collateralToken = String(args['collateralToken']).toUpperCase();
|
|
235
|
+
const priceUsd = args['priceUsd'] !== undefined ? Number(args['priceUsd']) : null;
|
|
236
|
+
const price = priceUsd !== null ? priceToRaw(priceUsd) : null;
|
|
237
|
+
const percentage = args['percentage'] !== undefined ? BigInt(Math.floor(Number(args['percentage']))) : 1000000n;
|
|
238
|
+
const result = await buildClosePositionShort(getConnection(context), owner, principalToken, collateralToken, price, percentage);
|
|
239
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build close short transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
247
|
+
* SL / TP Builders
|
|
248
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
249
|
+
/**
|
|
250
|
+
* @name registerAdrenaSetStopLossTool
|
|
251
|
+
* @description Register sap_adrena_build_set_stop_loss.
|
|
252
|
+
* @internal
|
|
253
|
+
*/
|
|
254
|
+
function registerAdrenaSetStopLossTool(server, context) {
|
|
255
|
+
const schema = {
|
|
256
|
+
type: 'object',
|
|
257
|
+
properties: {
|
|
258
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58).' },
|
|
259
|
+
principalToken: { type: 'string', description: 'Asset of the position.', enum: [...MAIN_POOL_TOKENS, ...COMMODITY_TOKENS] },
|
|
260
|
+
side: { type: 'string', description: 'Position side.', enum: ['long', 'short'] },
|
|
261
|
+
stopLossPriceUsd: { type: 'number', description: 'Stop loss trigger price in USD.', minimum: 0 },
|
|
262
|
+
closePositionPriceUsd: { type: 'number', description: 'Optional close position price in USD. If set, the position closes at this price when triggered.', minimum: 0 },
|
|
263
|
+
},
|
|
264
|
+
required: ['owner', 'principalToken', 'side', 'stopLossPriceUsd'],
|
|
265
|
+
additionalProperties: false,
|
|
266
|
+
};
|
|
267
|
+
registerTool(server, 'sap_adrena_build_set_stop_loss', {
|
|
268
|
+
description: 'Build an unsigned transaction to set stop loss on an Adrena position. Returns transactionBase64 for local signing.',
|
|
269
|
+
inputSchema: schema,
|
|
270
|
+
}, async (args) => {
|
|
271
|
+
try {
|
|
272
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
273
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
274
|
+
const side = args['side'] === 'short' ? 'short' : 'long';
|
|
275
|
+
const stopLossPriceUsd = Number(args['stopLossPriceUsd']);
|
|
276
|
+
const closePositionPriceUsd = args['closePositionPriceUsd'] !== undefined ? Number(args['closePositionPriceUsd']) : null;
|
|
277
|
+
const stopLossLimitPrice = priceToRaw(stopLossPriceUsd);
|
|
278
|
+
const closePositionPrice = closePositionPriceUsd !== null ? priceToRaw(closePositionPriceUsd) : null;
|
|
279
|
+
const result = await buildSetStopLoss(getConnection(context), owner, principalToken, side, stopLossLimitPrice, closePositionPrice);
|
|
280
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build set stop loss transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* @name registerAdrenaSetTakeProfitTool
|
|
289
|
+
* @description Register sap_adrena_build_set_take_profit.
|
|
290
|
+
* @internal
|
|
291
|
+
*/
|
|
292
|
+
function registerAdrenaSetTakeProfitTool(server, context) {
|
|
293
|
+
const schema = {
|
|
294
|
+
type: 'object',
|
|
295
|
+
properties: {
|
|
296
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58).' },
|
|
297
|
+
principalToken: { type: 'string', description: 'Asset of the position.', enum: [...MAIN_POOL_TOKENS, ...COMMODITY_TOKENS] },
|
|
298
|
+
side: { type: 'string', description: 'Position side.', enum: ['long', 'short'] },
|
|
299
|
+
takeProfitPriceUsd: { type: 'number', description: 'Take profit trigger price in USD.', minimum: 0 },
|
|
300
|
+
},
|
|
301
|
+
required: ['owner', 'principalToken', 'side', 'takeProfitPriceUsd'],
|
|
302
|
+
additionalProperties: false,
|
|
303
|
+
};
|
|
304
|
+
registerTool(server, 'sap_adrena_build_set_take_profit', {
|
|
305
|
+
description: 'Build an unsigned transaction to set take profit on an Adrena position. Returns transactionBase64 for local signing.',
|
|
306
|
+
inputSchema: schema,
|
|
307
|
+
}, async (args) => {
|
|
308
|
+
try {
|
|
309
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
310
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
311
|
+
const side = args['side'] === 'short' ? 'short' : 'long';
|
|
312
|
+
const takeProfitPriceUsd = Number(args['takeProfitPriceUsd']);
|
|
313
|
+
const takeProfitLimitPrice = priceToRaw(takeProfitPriceUsd);
|
|
314
|
+
const result = await buildSetTakeProfit(getConnection(context), owner, principalToken, side, takeProfitLimitPrice);
|
|
315
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
316
|
+
}
|
|
317
|
+
catch (err) {
|
|
318
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build set take profit transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* @name registerAdrenaCancelStopLossTool
|
|
324
|
+
* @description Register sap_adrena_build_cancel_stop_loss.
|
|
325
|
+
* @internal
|
|
326
|
+
*/
|
|
327
|
+
function registerAdrenaCancelStopLossTool(server, context) {
|
|
328
|
+
const schema = {
|
|
329
|
+
type: 'object',
|
|
330
|
+
properties: {
|
|
331
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58).' },
|
|
332
|
+
principalToken: { type: 'string', description: 'Asset of the position.', enum: [...MAIN_POOL_TOKENS, ...COMMODITY_TOKENS] },
|
|
333
|
+
side: { type: 'string', description: 'Position side.', enum: ['long', 'short'] },
|
|
334
|
+
},
|
|
335
|
+
required: ['owner', 'principalToken', 'side'],
|
|
336
|
+
additionalProperties: false,
|
|
337
|
+
};
|
|
338
|
+
registerTool(server, 'sap_adrena_build_cancel_stop_loss', {
|
|
339
|
+
description: 'Build an unsigned transaction to cancel stop loss on an Adrena position. Returns transactionBase64 for local signing.',
|
|
340
|
+
inputSchema: schema,
|
|
341
|
+
}, async (args) => {
|
|
342
|
+
try {
|
|
343
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
344
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
345
|
+
const side = args['side'] === 'short' ? 'short' : 'long';
|
|
346
|
+
const result = await buildCancelStopLoss(getConnection(context), owner, principalToken, side);
|
|
347
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
348
|
+
}
|
|
349
|
+
catch (err) {
|
|
350
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build cancel stop loss transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* @name registerAdrenaCancelTakeProfitTool
|
|
356
|
+
* @description Register sap_adrena_build_cancel_take_profit.
|
|
357
|
+
* @internal
|
|
358
|
+
*/
|
|
359
|
+
function registerAdrenaCancelTakeProfitTool(server, context) {
|
|
360
|
+
const schema = {
|
|
361
|
+
type: 'object',
|
|
362
|
+
properties: {
|
|
363
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58).' },
|
|
364
|
+
principalToken: { type: 'string', description: 'Asset of the position.', enum: [...MAIN_POOL_TOKENS, ...COMMODITY_TOKENS] },
|
|
365
|
+
side: { type: 'string', description: 'Position side.', enum: ['long', 'short'] },
|
|
366
|
+
},
|
|
367
|
+
required: ['owner', 'principalToken', 'side'],
|
|
368
|
+
additionalProperties: false,
|
|
369
|
+
};
|
|
370
|
+
registerTool(server, 'sap_adrena_build_cancel_take_profit', {
|
|
371
|
+
description: 'Build an unsigned transaction to cancel take profit on an Adrena position. Returns transactionBase64 for local signing.',
|
|
372
|
+
inputSchema: schema,
|
|
373
|
+
}, async (args) => {
|
|
374
|
+
try {
|
|
375
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
376
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
377
|
+
const side = args['side'] === 'short' ? 'short' : 'long';
|
|
378
|
+
const result = await buildCancelTakeProfit(getConnection(context), owner, principalToken, side);
|
|
379
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
380
|
+
}
|
|
381
|
+
catch (err) {
|
|
382
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build cancel take profit transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
387
|
+
* Limit Order Builders
|
|
388
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
389
|
+
/**
|
|
390
|
+
* @name registerAdrenaAddLimitOrderTool
|
|
391
|
+
* @description Register sap_adrena_build_add_limit_order.
|
|
392
|
+
* @internal
|
|
393
|
+
*/
|
|
394
|
+
function registerAdrenaAddLimitOrderTool(server, context) {
|
|
395
|
+
const schema = {
|
|
396
|
+
type: 'object',
|
|
397
|
+
properties: {
|
|
398
|
+
owner: { type: 'string', description: 'Order owner wallet public key (base58).' },
|
|
399
|
+
principalToken: { type: 'string', description: 'Asset to trade.', enum: MAIN_POOL_TOKENS },
|
|
400
|
+
collateralToken: { type: 'string', description: 'Collateral token.', enum: COLLATERAL_TOKENS },
|
|
401
|
+
collateralAmount: { type: 'number', description: 'Collateral amount in human-readable units.', minimum: 0 },
|
|
402
|
+
leverage: { type: 'number', description: 'Leverage multiplier.', minimum: 1, maximum: 100 },
|
|
403
|
+
side: { type: 'string', description: 'Order side.', enum: ['long', 'short'] },
|
|
404
|
+
triggerPriceUsd: { type: 'number', description: 'Trigger price in USD. Order fills when oracle reaches this price.', minimum: 0 },
|
|
405
|
+
limitPriceUsd: { type: 'number', description: 'Optional limit price cap. Omit for market price at fill.', minimum: 0 },
|
|
406
|
+
},
|
|
407
|
+
required: ['owner', 'principalToken', 'collateralToken', 'collateralAmount', 'leverage', 'side', 'triggerPriceUsd'],
|
|
408
|
+
additionalProperties: false,
|
|
409
|
+
};
|
|
410
|
+
registerTool(server, 'sap_adrena_build_add_limit_order', {
|
|
411
|
+
description: 'Build an unsigned transaction to place a limit order on Adrena. The order fills when the oracle price reaches the trigger price. Returns transactionBase64 for local signing.',
|
|
412
|
+
inputSchema: schema,
|
|
413
|
+
}, async (args) => {
|
|
414
|
+
try {
|
|
415
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
416
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
417
|
+
const collateralToken = String(args['collateralToken']).toUpperCase();
|
|
418
|
+
const collateralAmount = Number(args['collateralAmount']);
|
|
419
|
+
const leverage = Number(args['leverage']);
|
|
420
|
+
const side = args['side'] === 'short' ? 'short' : 'long';
|
|
421
|
+
const triggerPriceUsd = Number(args['triggerPriceUsd']);
|
|
422
|
+
const limitPriceUsd = args['limitPriceUsd'] !== undefined ? Number(args['limitPriceUsd']) : null;
|
|
423
|
+
const triggerPrice = priceToRaw(triggerPriceUsd);
|
|
424
|
+
const limitPrice = limitPriceUsd !== null ? priceToRaw(limitPriceUsd) : null;
|
|
425
|
+
const result = await buildAddLimitOrder(getConnection(context), owner, principalToken, collateralToken, collateralAmount, leverage, side, triggerPrice, limitPrice);
|
|
426
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
427
|
+
}
|
|
428
|
+
catch (err) {
|
|
429
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build add limit order transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* @name registerAdrenaCancelLimitOrderTool
|
|
435
|
+
* @description Register sap_adrena_build_cancel_limit_order.
|
|
436
|
+
* @internal
|
|
437
|
+
*/
|
|
438
|
+
function registerAdrenaCancelLimitOrderTool(server, context) {
|
|
439
|
+
const schema = {
|
|
440
|
+
type: 'object',
|
|
441
|
+
properties: {
|
|
442
|
+
owner: { type: 'string', description: 'Order owner wallet public key (base58).' },
|
|
443
|
+
collateralToken: { type: 'string', description: 'Collateral token used for the order.', enum: COLLATERAL_TOKENS },
|
|
444
|
+
orderId: { type: 'number', description: 'Limit order ID to cancel.' },
|
|
445
|
+
},
|
|
446
|
+
required: ['owner', 'collateralToken', 'orderId'],
|
|
447
|
+
additionalProperties: false,
|
|
448
|
+
};
|
|
449
|
+
registerTool(server, 'sap_adrena_build_cancel_limit_order', {
|
|
450
|
+
description: 'Build an unsigned transaction to cancel a limit order on Adrena. Returns transactionBase64 for local signing.',
|
|
451
|
+
inputSchema: schema,
|
|
452
|
+
}, async (args) => {
|
|
453
|
+
try {
|
|
454
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
455
|
+
const collateralToken = String(args['collateralToken']).toUpperCase();
|
|
456
|
+
const orderId = BigInt(Math.floor(Number(args['orderId'])));
|
|
457
|
+
const result = await buildCancelLimitOrder(getConnection(context), owner, collateralToken, orderId);
|
|
458
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
459
|
+
}
|
|
460
|
+
catch (err) {
|
|
461
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build cancel limit order transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
462
|
+
}
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
466
|
+
* Commodity Builders
|
|
467
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
468
|
+
/**
|
|
469
|
+
* @name registerAdrenaCommodityTools
|
|
470
|
+
* @description Register commodity (synthetic perp) builder tools.
|
|
471
|
+
* @internal
|
|
472
|
+
*/
|
|
473
|
+
function registerAdrenaCommodityTools(server, context) {
|
|
474
|
+
// Open commodity long
|
|
475
|
+
registerTool(server, 'sap_adrena_build_open_commodity_long', {
|
|
476
|
+
description: 'Build an unsigned transaction to open a long position on a synthetic commodity (XAU, XAG, WTI) on Adrena. Uses the commodities pool with USDC collateral. Returns transactionBase64 for local signing.',
|
|
477
|
+
inputSchema: {
|
|
478
|
+
type: 'object',
|
|
479
|
+
properties: {
|
|
480
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58).' },
|
|
481
|
+
principalToken: { type: 'string', description: 'Commodity to trade.', enum: COMMODITY_TOKENS },
|
|
482
|
+
collateralAmount: { type: 'number', description: 'USDC collateral amount in human-readable units.', minimum: 0 },
|
|
483
|
+
leverage: { type: 'number', description: 'Leverage multiplier.', minimum: 1, maximum: 100 },
|
|
484
|
+
priceUsd: { type: 'number', description: 'Optional limit price in USD.', minimum: 0 },
|
|
485
|
+
},
|
|
486
|
+
required: ['owner', 'principalToken', 'collateralAmount', 'leverage'],
|
|
487
|
+
additionalProperties: false,
|
|
488
|
+
},
|
|
489
|
+
}, async (args) => {
|
|
490
|
+
try {
|
|
491
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
492
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
493
|
+
const collateralAmount = Number(args['collateralAmount']);
|
|
494
|
+
const leverage = Number(args['leverage']);
|
|
495
|
+
const priceUsd = args['priceUsd'] !== undefined ? Number(args['priceUsd']) : null;
|
|
496
|
+
const price = priceUsd !== null ? priceToRaw(priceUsd) : null;
|
|
497
|
+
const result = await buildOpenCommodityLong(getConnection(context), owner, principalToken, collateralAmount, leverage, price);
|
|
498
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
499
|
+
}
|
|
500
|
+
catch (err) {
|
|
501
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build commodity long transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
502
|
+
}
|
|
503
|
+
});
|
|
504
|
+
// Open commodity short
|
|
505
|
+
registerTool(server, 'sap_adrena_build_open_commodity_short', {
|
|
506
|
+
description: 'Build an unsigned transaction to open a short position on a synthetic commodity (XAU, XAG, WTI) on Adrena. Uses the commodities pool with USDC collateral. Returns transactionBase64 for local signing.',
|
|
507
|
+
inputSchema: {
|
|
508
|
+
type: 'object',
|
|
509
|
+
properties: {
|
|
510
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58).' },
|
|
511
|
+
principalToken: { type: 'string', description: 'Commodity to short.', enum: COMMODITY_TOKENS },
|
|
512
|
+
collateralAmount: { type: 'number', description: 'USDC collateral amount.', minimum: 0 },
|
|
513
|
+
leverage: { type: 'number', description: 'Leverage multiplier.', minimum: 1, maximum: 100 },
|
|
514
|
+
priceUsd: { type: 'number', description: 'Optional limit price in USD.', minimum: 0 },
|
|
515
|
+
},
|
|
516
|
+
required: ['owner', 'principalToken', 'collateralAmount', 'leverage'],
|
|
517
|
+
additionalProperties: false,
|
|
518
|
+
},
|
|
519
|
+
}, async (args) => {
|
|
520
|
+
try {
|
|
521
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
522
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
523
|
+
const collateralAmount = Number(args['collateralAmount']);
|
|
524
|
+
const leverage = Number(args['leverage']);
|
|
525
|
+
const priceUsd = args['priceUsd'] !== undefined ? Number(args['priceUsd']) : null;
|
|
526
|
+
const price = priceUsd !== null ? priceToRaw(priceUsd) : null;
|
|
527
|
+
const result = await buildOpenCommodityShort(getConnection(context), owner, principalToken, collateralAmount, leverage, price);
|
|
528
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
529
|
+
}
|
|
530
|
+
catch (err) {
|
|
531
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build commodity short transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
// Close commodity long
|
|
535
|
+
registerTool(server, 'sap_adrena_build_close_commodity_long', {
|
|
536
|
+
description: 'Build an unsigned transaction to close a long commodity position on Adrena. Returns transactionBase64 for local signing.',
|
|
537
|
+
inputSchema: {
|
|
538
|
+
type: 'object',
|
|
539
|
+
properties: {
|
|
540
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58).' },
|
|
541
|
+
principalToken: { type: 'string', description: 'Commodity of the position.', enum: COMMODITY_TOKENS },
|
|
542
|
+
priceUsd: { type: 'number', description: 'Optional close price in USD.', minimum: 0 },
|
|
543
|
+
percentage: { type: 'number', description: 'Percentage to close (0-1000000). Default 1000000.', minimum: 0, maximum: 1000000 },
|
|
544
|
+
},
|
|
545
|
+
required: ['owner', 'principalToken'],
|
|
546
|
+
additionalProperties: false,
|
|
547
|
+
},
|
|
548
|
+
}, async (args) => {
|
|
549
|
+
try {
|
|
550
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
551
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
552
|
+
const priceUsd = args['priceUsd'] !== undefined ? Number(args['priceUsd']) : null;
|
|
553
|
+
const price = priceUsd !== null ? priceToRaw(priceUsd) : null;
|
|
554
|
+
const percentage = args['percentage'] !== undefined ? BigInt(Math.floor(Number(args['percentage']))) : 1000000n;
|
|
555
|
+
const result = await buildCloseCommodityLong(getConnection(context), owner, principalToken, price, percentage);
|
|
556
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
557
|
+
}
|
|
558
|
+
catch (err) {
|
|
559
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build close commodity long transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
// Close commodity short
|
|
563
|
+
registerTool(server, 'sap_adrena_build_close_commodity_short', {
|
|
564
|
+
description: 'Build an unsigned transaction to close a short commodity position on Adrena. Returns transactionBase64 for local signing.',
|
|
565
|
+
inputSchema: {
|
|
566
|
+
type: 'object',
|
|
567
|
+
properties: {
|
|
568
|
+
owner: { type: 'string', description: 'Position owner wallet public key (base58).' },
|
|
569
|
+
principalToken: { type: 'string', description: 'Commodity of the position.', enum: COMMODITY_TOKENS },
|
|
570
|
+
priceUsd: { type: 'number', description: 'Optional close price in USD.', minimum: 0 },
|
|
571
|
+
percentage: { type: 'number', description: 'Percentage to close (0-1000000). Default 1000000.', minimum: 0, maximum: 1000000 },
|
|
572
|
+
},
|
|
573
|
+
required: ['owner', 'principalToken'],
|
|
574
|
+
additionalProperties: false,
|
|
575
|
+
},
|
|
576
|
+
}, async (args) => {
|
|
577
|
+
try {
|
|
578
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
579
|
+
const principalToken = String(args['principalToken']).toUpperCase();
|
|
580
|
+
const priceUsd = args['priceUsd'] !== undefined ? Number(args['priceUsd']) : null;
|
|
581
|
+
const price = priceUsd !== null ? priceToRaw(priceUsd) : null;
|
|
582
|
+
const percentage = args['percentage'] !== undefined ? BigInt(Math.floor(Number(args['percentage']))) : 1000000n;
|
|
583
|
+
const result = await buildCloseCommodityShort(getConnection(context), owner, principalToken, price, percentage);
|
|
584
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
585
|
+
}
|
|
586
|
+
catch (err) {
|
|
587
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build close commodity short transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
592
|
+
* Liquidity & Swap Builders
|
|
593
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
594
|
+
/**
|
|
595
|
+
* @name registerAdrenaLiquiditySwapTools
|
|
596
|
+
* @description Register liquidity and swap builder tools.
|
|
597
|
+
* @internal
|
|
598
|
+
*/
|
|
599
|
+
function registerAdrenaLiquiditySwapTools(server, context) {
|
|
600
|
+
// Add liquidity
|
|
601
|
+
registerTool(server, 'sap_adrena_build_add_liquidity', {
|
|
602
|
+
description: 'Build an unsigned transaction to add liquidity to an Adrena pool. Deposits collateral and receives LP tokens. Returns transactionBase64 for local signing.',
|
|
603
|
+
inputSchema: {
|
|
604
|
+
type: 'object',
|
|
605
|
+
properties: {
|
|
606
|
+
owner: { type: 'string', description: 'Liquidity provider wallet public key (base58).' },
|
|
607
|
+
collateralToken: { type: 'string', description: 'Collateral token to deposit.', enum: COLLATERAL_TOKENS },
|
|
608
|
+
amount: { type: 'number', description: 'Amount in human-readable units.', minimum: 0 },
|
|
609
|
+
minLpAmountOut: { type: 'number', description: 'Minimum LP tokens to receive (raw). 0 for no slippage protection.', minimum: 0 },
|
|
610
|
+
poolName: { type: 'string', description: 'Pool to add liquidity to.', enum: ['main-pool', 'commodities-pool'] },
|
|
611
|
+
},
|
|
612
|
+
required: ['owner', 'collateralToken', 'amount'],
|
|
613
|
+
additionalProperties: false,
|
|
614
|
+
},
|
|
615
|
+
}, async (args) => {
|
|
616
|
+
try {
|
|
617
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
618
|
+
const collateralToken = String(args['collateralToken']).toUpperCase();
|
|
619
|
+
const amount = Number(args['amount']);
|
|
620
|
+
const minLpAmountOut = args['minLpAmountOut'] !== undefined ? BigInt(Math.floor(Number(args['minLpAmountOut']))) : 0n;
|
|
621
|
+
const poolName = (args['poolName'] === 'commodities-pool' ? 'commodities-pool' : 'main-pool');
|
|
622
|
+
const result = await buildAddLiquidity(getConnection(context), owner, collateralToken, amount, minLpAmountOut, poolName);
|
|
623
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
624
|
+
}
|
|
625
|
+
catch (err) {
|
|
626
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build add liquidity transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
// Remove liquidity
|
|
630
|
+
registerTool(server, 'sap_adrena_build_remove_liquidity', {
|
|
631
|
+
description: 'Build an unsigned transaction to remove liquidity from an Adrena pool. Burns LP tokens and receives collateral. Returns transactionBase64 for local signing.',
|
|
632
|
+
inputSchema: {
|
|
633
|
+
type: 'object',
|
|
634
|
+
properties: {
|
|
635
|
+
owner: { type: 'string', description: 'Liquidity provider wallet public key (base58).' },
|
|
636
|
+
collateralToken: { type: 'string', description: 'Collateral token to receive.', enum: COLLATERAL_TOKENS },
|
|
637
|
+
lpAmountIn: { type: 'number', description: 'LP tokens to burn (raw, 6 decimals).', minimum: 0 },
|
|
638
|
+
minAmountOut: { type: 'number', description: 'Minimum collateral to receive (raw). 0 for no slippage protection.', minimum: 0 },
|
|
639
|
+
poolName: { type: 'string', description: 'Pool to remove liquidity from.', enum: ['main-pool', 'commodities-pool'] },
|
|
640
|
+
},
|
|
641
|
+
required: ['owner', 'collateralToken', 'lpAmountIn'],
|
|
642
|
+
additionalProperties: false,
|
|
643
|
+
},
|
|
644
|
+
}, async (args) => {
|
|
645
|
+
try {
|
|
646
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
647
|
+
const collateralToken = String(args['collateralToken']).toUpperCase();
|
|
648
|
+
const lpAmountIn = BigInt(Math.floor(Number(args['lpAmountIn'])));
|
|
649
|
+
const minAmountOut = args['minAmountOut'] !== undefined ? BigInt(Math.floor(Number(args['minAmountOut']))) : 0n;
|
|
650
|
+
const poolName = (args['poolName'] === 'commodities-pool' ? 'commodities-pool' : 'main-pool');
|
|
651
|
+
const result = await buildRemoveLiquidity(getConnection(context), owner, collateralToken, lpAmountIn, minAmountOut, poolName);
|
|
652
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
653
|
+
}
|
|
654
|
+
catch (err) {
|
|
655
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build remove liquidity transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
656
|
+
}
|
|
657
|
+
});
|
|
658
|
+
// Swap
|
|
659
|
+
registerTool(server, 'sap_adrena_build_swap', {
|
|
660
|
+
description: 'Build an unsigned transaction to swap tokens through an Adrena pool. Uses zero-slippage oracle pricing. Returns transactionBase64 for local signing.',
|
|
661
|
+
inputSchema: {
|
|
662
|
+
type: 'object',
|
|
663
|
+
properties: {
|
|
664
|
+
owner: { type: 'string', description: 'Swapper wallet public key (base58).' },
|
|
665
|
+
fromToken: { type: 'string', description: 'Token to swap from.', enum: COLLATERAL_TOKENS },
|
|
666
|
+
toToken: { type: 'string', description: 'Token to swap to.', enum: COLLATERAL_TOKENS },
|
|
667
|
+
amount: { type: 'number', description: 'Amount to swap in human-readable units.', minimum: 0 },
|
|
668
|
+
minAmountOut: { type: 'number', description: 'Minimum amount to receive (raw). 0 for no slippage protection.', minimum: 0 },
|
|
669
|
+
},
|
|
670
|
+
required: ['owner', 'fromToken', 'toToken', 'amount'],
|
|
671
|
+
additionalProperties: false,
|
|
672
|
+
},
|
|
673
|
+
}, async (args) => {
|
|
674
|
+
try {
|
|
675
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
676
|
+
const fromToken = String(args['fromToken']).toUpperCase();
|
|
677
|
+
const toToken = String(args['toToken']).toUpperCase();
|
|
678
|
+
const amount = Number(args['amount']);
|
|
679
|
+
const minAmountOut = args['minAmountOut'] !== undefined ? BigInt(Math.floor(Number(args['minAmountOut']))) : 0n;
|
|
680
|
+
const result = await buildSwap(getConnection(context), owner, fromToken, toToken, amount, minAmountOut);
|
|
681
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
682
|
+
}
|
|
683
|
+
catch (err) {
|
|
684
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build swap transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
689
|
+
* Staking Builders
|
|
690
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
691
|
+
/**
|
|
692
|
+
* @name registerAdrenaStakingTools
|
|
693
|
+
* @description Register staking builder tools.
|
|
694
|
+
* @internal
|
|
695
|
+
*/
|
|
696
|
+
function registerAdrenaStakingTools(server, context) {
|
|
697
|
+
// Init user staking
|
|
698
|
+
registerTool(server, 'sap_adrena_build_init_user_staking', {
|
|
699
|
+
description: 'Build an unsigned transaction to initialize a user staking account on Adrena. Must be called before add_liquid_stake or add_locked_stake. Returns transactionBase64 for local signing.',
|
|
700
|
+
inputSchema: {
|
|
701
|
+
type: 'object',
|
|
702
|
+
properties: {
|
|
703
|
+
owner: { type: 'string', description: 'Staker wallet public key (base58).' },
|
|
704
|
+
},
|
|
705
|
+
required: ['owner'],
|
|
706
|
+
additionalProperties: false,
|
|
707
|
+
},
|
|
708
|
+
}, async (args) => {
|
|
709
|
+
try {
|
|
710
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
711
|
+
const result = await buildInitUserStaking(getConnection(context), owner);
|
|
712
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
713
|
+
}
|
|
714
|
+
catch (err) {
|
|
715
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build init user staking transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
// Add liquid stake
|
|
719
|
+
registerTool(server, 'sap_adrena_build_add_liquid_stake', {
|
|
720
|
+
description: 'Build an unsigned transaction to add a liquid stake on Adrena (stake LP tokens). Returns transactionBase64 for local signing.',
|
|
721
|
+
inputSchema: {
|
|
722
|
+
type: 'object',
|
|
723
|
+
properties: {
|
|
724
|
+
owner: { type: 'string', description: 'Staker wallet public key (base58).' },
|
|
725
|
+
amount: { type: 'number', description: 'Amount of LP tokens to stake (raw, 6 decimals).', minimum: 0 },
|
|
726
|
+
},
|
|
727
|
+
required: ['owner', 'amount'],
|
|
728
|
+
additionalProperties: false,
|
|
729
|
+
},
|
|
730
|
+
}, async (args) => {
|
|
731
|
+
try {
|
|
732
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
733
|
+
const amount = BigInt(Math.floor(Number(args['amount'])));
|
|
734
|
+
const result = await buildAddLiquidStake(getConnection(context), owner, amount);
|
|
735
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
736
|
+
}
|
|
737
|
+
catch (err) {
|
|
738
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build add liquid stake transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
739
|
+
}
|
|
740
|
+
});
|
|
741
|
+
// Remove liquid stake
|
|
742
|
+
registerTool(server, 'sap_adrena_build_remove_liquid_stake', {
|
|
743
|
+
description: 'Build an unsigned transaction to remove a liquid stake on Adrena (unstake LP tokens). Returns transactionBase64 for local signing.',
|
|
744
|
+
inputSchema: {
|
|
745
|
+
type: 'object',
|
|
746
|
+
properties: {
|
|
747
|
+
owner: { type: 'string', description: 'Staker wallet public key (base58).' },
|
|
748
|
+
amount: { type: 'number', description: 'Amount of staked LP tokens to withdraw (raw, 6 decimals).', minimum: 0 },
|
|
749
|
+
},
|
|
750
|
+
required: ['owner', 'amount'],
|
|
751
|
+
additionalProperties: false,
|
|
752
|
+
},
|
|
753
|
+
}, async (args) => {
|
|
754
|
+
try {
|
|
755
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
756
|
+
const amount = BigInt(Math.floor(Number(args['amount'])));
|
|
757
|
+
const result = await buildRemoveLiquidStake(getConnection(context), owner, amount);
|
|
758
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
759
|
+
}
|
|
760
|
+
catch (err) {
|
|
761
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build remove liquid stake transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
762
|
+
}
|
|
763
|
+
});
|
|
764
|
+
// Add locked stake
|
|
765
|
+
registerTool(server, 'sap_adrena_build_add_locked_stake', {
|
|
766
|
+
description: 'Build an unsigned transaction to add a locked stake on Adrena. LP tokens are locked for a specified duration. Returns transactionBase64 for local signing.',
|
|
767
|
+
inputSchema: {
|
|
768
|
+
type: 'object',
|
|
769
|
+
properties: {
|
|
770
|
+
owner: { type: 'string', description: 'Staker wallet public key (base58).' },
|
|
771
|
+
amount: { type: 'number', description: 'Amount of LP tokens to lock (raw, 6 decimals).', minimum: 0 },
|
|
772
|
+
lockedDays: { type: 'number', description: 'Lock duration in days.', minimum: 1 },
|
|
773
|
+
},
|
|
774
|
+
required: ['owner', 'amount', 'lockedDays'],
|
|
775
|
+
additionalProperties: false,
|
|
776
|
+
},
|
|
777
|
+
}, async (args) => {
|
|
778
|
+
try {
|
|
779
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
780
|
+
const amount = BigInt(Math.floor(Number(args['amount'])));
|
|
781
|
+
const lockedDays = Math.floor(Number(args['lockedDays']));
|
|
782
|
+
const result = await buildAddLockedStake(getConnection(context), owner, amount, lockedDays);
|
|
783
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
784
|
+
}
|
|
785
|
+
catch (err) {
|
|
786
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build add locked stake transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
787
|
+
}
|
|
788
|
+
});
|
|
789
|
+
// Claim stakes
|
|
790
|
+
registerTool(server, 'sap_adrena_build_claim_stakes', {
|
|
791
|
+
description: 'Build an unsigned transaction to claim staking rewards on Adrena. Returns transactionBase64 for local signing.',
|
|
792
|
+
inputSchema: {
|
|
793
|
+
type: 'object',
|
|
794
|
+
properties: {
|
|
795
|
+
owner: { type: 'string', description: 'Staker wallet public key (base58).' },
|
|
796
|
+
lockedStakeIndexes: { type: 'string', description: 'Optional comma-separated list of locked stake indexes to claim. Omit to claim all.' },
|
|
797
|
+
},
|
|
798
|
+
required: ['owner'],
|
|
799
|
+
additionalProperties: false,
|
|
800
|
+
},
|
|
801
|
+
}, async (args) => {
|
|
802
|
+
try {
|
|
803
|
+
const owner = parsePublicKey(String(args['owner']));
|
|
804
|
+
const indexesStr = typeof args['lockedStakeIndexes'] === 'string' ? args['lockedStakeIndexes'] : null;
|
|
805
|
+
const lockedStakeIndexes = indexesStr
|
|
806
|
+
? indexesStr.split(',').map(s => parseInt(s.trim(), 10)).filter(n => !isNaN(n))
|
|
807
|
+
: null;
|
|
808
|
+
const result = await buildClaimStakes(getConnection(context), owner, lockedStakeIndexes);
|
|
809
|
+
return createTextResponse(JSON.stringify(result, null, 2));
|
|
810
|
+
}
|
|
811
|
+
catch (err) {
|
|
812
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to build claim stakes transaction', message: err instanceof Error ? err.message : 'Unknown error' }), { isError: true });
|
|
813
|
+
}
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
817
|
+
* Data API Tools
|
|
818
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
819
|
+
/**
|
|
820
|
+
* @name registerAdrenaDataApiTools
|
|
821
|
+
* @description Register Adrena Data API (REST) tools for market data and analytics.
|
|
822
|
+
* @internal
|
|
823
|
+
*/
|
|
824
|
+
function registerAdrenaDataApiTools(server) {
|
|
825
|
+
// Get positions
|
|
826
|
+
registerTool(server, 'sap_adrena_get_positions', {
|
|
827
|
+
description: 'Fetch position history for a wallet from the Adrena Data API. Returns closed and open positions with P&L, entry/exit prices, and status.',
|
|
828
|
+
inputSchema: {
|
|
829
|
+
type: 'object',
|
|
830
|
+
properties: {
|
|
831
|
+
wallet: { type: 'string', description: 'Wallet public key (base58).' },
|
|
832
|
+
},
|
|
833
|
+
required: ['wallet'],
|
|
834
|
+
additionalProperties: false,
|
|
835
|
+
},
|
|
836
|
+
}, async (args) => {
|
|
837
|
+
const wallet = String(args['wallet'] ?? '').trim();
|
|
838
|
+
if (!wallet) {
|
|
839
|
+
return createTextResponse(JSON.stringify({ error: 'wallet is required' }), { isError: true });
|
|
840
|
+
}
|
|
841
|
+
const positions = await adrenaDataApi.getPositions(wallet);
|
|
842
|
+
if (positions === null) {
|
|
843
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to fetch positions from Adrena Data API', wallet }), { isError: true });
|
|
844
|
+
}
|
|
845
|
+
return createTextResponse(JSON.stringify({ wallet, positions, count: positions.length }, null, 2));
|
|
846
|
+
});
|
|
847
|
+
// Get pool info
|
|
848
|
+
registerTool(server, 'sap_adrena_get_pool_info', {
|
|
849
|
+
description: 'Fetch latest pool statistics from the Adrena Data API. Returns TVL, AUM, LP token price, volume, fees, and open interest.',
|
|
850
|
+
inputSchema: {
|
|
851
|
+
type: 'object',
|
|
852
|
+
properties: {
|
|
853
|
+
poolName: { type: 'string', description: 'Optional pool name filter.' },
|
|
854
|
+
},
|
|
855
|
+
additionalProperties: false,
|
|
856
|
+
},
|
|
857
|
+
}, async (args) => {
|
|
858
|
+
const poolName = typeof args['poolName'] === 'string' ? args['poolName'] : undefined;
|
|
859
|
+
const pool = await adrenaDataApi.getPoolInfo(poolName);
|
|
860
|
+
if (pool === null) {
|
|
861
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to fetch pool info from Adrena Data API' }), { isError: true });
|
|
862
|
+
}
|
|
863
|
+
return createTextResponse(JSON.stringify(pool, null, 2));
|
|
864
|
+
});
|
|
865
|
+
// Get custody info
|
|
866
|
+
registerTool(server, 'sap_adrena_get_custody_info', {
|
|
867
|
+
description: 'Fetch per-asset custody statistics from the Adrena Data API. Returns open interest, utilization, volume, and fees for each custody.',
|
|
868
|
+
inputSchema: {
|
|
869
|
+
type: 'object',
|
|
870
|
+
properties: {
|
|
871
|
+
symbol: { type: 'string', description: 'Optional symbol filter (e.g. JITOSOL, WBTC).' },
|
|
872
|
+
},
|
|
873
|
+
additionalProperties: false,
|
|
874
|
+
},
|
|
875
|
+
}, async (args) => {
|
|
876
|
+
const symbol = typeof args['symbol'] === 'string' ? args['symbol'] : undefined;
|
|
877
|
+
const custodies = await adrenaDataApi.getCustodyInfo(symbol);
|
|
878
|
+
if (custodies === null) {
|
|
879
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to fetch custody info from Adrena Data API' }), { isError: true });
|
|
880
|
+
}
|
|
881
|
+
return createTextResponse(JSON.stringify({ custodies, count: custodies.length }, null, 2));
|
|
882
|
+
});
|
|
883
|
+
// Get trader info
|
|
884
|
+
registerTool(server, 'sap_adrena_get_trader_info', {
|
|
885
|
+
description: 'Fetch trader performance metrics from the Adrena Data API. Returns total volume, P&L, fees, win rate, and rank.',
|
|
886
|
+
inputSchema: {
|
|
887
|
+
type: 'object',
|
|
888
|
+
properties: {
|
|
889
|
+
wallet: { type: 'string', description: 'Trader wallet public key (base58).' },
|
|
890
|
+
},
|
|
891
|
+
required: ['wallet'],
|
|
892
|
+
additionalProperties: false,
|
|
893
|
+
},
|
|
894
|
+
}, async (args) => {
|
|
895
|
+
const wallet = String(args['wallet'] ?? '').trim();
|
|
896
|
+
if (!wallet) {
|
|
897
|
+
return createTextResponse(JSON.stringify({ error: 'wallet is required' }), { isError: true });
|
|
898
|
+
}
|
|
899
|
+
const trader = await adrenaDataApi.getTraderInfo(wallet);
|
|
900
|
+
if (trader === null) {
|
|
901
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to fetch trader info from Adrena Data API', wallet }), { isError: true });
|
|
902
|
+
}
|
|
903
|
+
return createTextResponse(JSON.stringify(trader, null, 2));
|
|
904
|
+
});
|
|
905
|
+
// Get trader leaderboard
|
|
906
|
+
registerTool(server, 'sap_adrena_get_trader_leaderboard', {
|
|
907
|
+
description: 'Fetch trader leaderboard from the Adrena Data API. Returns top traders by volume and P&L.',
|
|
908
|
+
inputSchema: {
|
|
909
|
+
type: 'object',
|
|
910
|
+
properties: {
|
|
911
|
+
limit: { type: 'number', description: 'Optional limit. Default 50.', minimum: 1, maximum: 500 },
|
|
912
|
+
},
|
|
913
|
+
additionalProperties: false,
|
|
914
|
+
},
|
|
915
|
+
}, async (args) => {
|
|
916
|
+
const limit = typeof args['limit'] === 'number' ? args['limit'] : undefined;
|
|
917
|
+
const traders = await adrenaDataApi.getTraderProfiles(limit);
|
|
918
|
+
if (traders === null) {
|
|
919
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to fetch trader leaderboard from Adrena Data API' }), { isError: true });
|
|
920
|
+
}
|
|
921
|
+
return createTextResponse(JSON.stringify({ traders, count: traders.length }, null, 2));
|
|
922
|
+
});
|
|
923
|
+
// Get mutagen points
|
|
924
|
+
registerTool(server, 'sap_adrena_get_mutagen', {
|
|
925
|
+
description: 'Fetch Mutagen points for a wallet from the Adrena Data API. Returns total points, rank, and breakdown.',
|
|
926
|
+
inputSchema: {
|
|
927
|
+
type: 'object',
|
|
928
|
+
properties: {
|
|
929
|
+
wallet: { type: 'string', description: 'Wallet public key (base58).' },
|
|
930
|
+
},
|
|
931
|
+
required: ['wallet'],
|
|
932
|
+
additionalProperties: false,
|
|
933
|
+
},
|
|
934
|
+
}, async (args) => {
|
|
935
|
+
const wallet = String(args['wallet'] ?? '').trim();
|
|
936
|
+
if (!wallet) {
|
|
937
|
+
return createTextResponse(JSON.stringify({ error: 'wallet is required' }), { isError: true });
|
|
938
|
+
}
|
|
939
|
+
const mutagen = await adrenaDataApi.getMutagen(wallet);
|
|
940
|
+
if (mutagen === null) {
|
|
941
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to fetch mutagen points from Adrena Data API', wallet }), { isError: true });
|
|
942
|
+
}
|
|
943
|
+
return createTextResponse(JSON.stringify(mutagen, null, 2));
|
|
944
|
+
});
|
|
945
|
+
// Get mutagen leaderboard
|
|
946
|
+
registerTool(server, 'sap_adrena_get_mutagen_leaderboard', {
|
|
947
|
+
description: 'Fetch Mutagen points leaderboard from the Adrena Data API. Returns top wallets by points.',
|
|
948
|
+
inputSchema: {
|
|
949
|
+
type: 'object',
|
|
950
|
+
properties: {
|
|
951
|
+
limit: { type: 'number', description: 'Optional limit. Default 50.', minimum: 1, maximum: 500 },
|
|
952
|
+
},
|
|
953
|
+
additionalProperties: false,
|
|
954
|
+
},
|
|
955
|
+
}, async (args) => {
|
|
956
|
+
const limit = typeof args['limit'] === 'number' ? args['limit'] : undefined;
|
|
957
|
+
const leaderboard = await adrenaDataApi.getMutagenLeaderboard(limit);
|
|
958
|
+
if (leaderboard === null) {
|
|
959
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to fetch mutagen leaderboard from Adrena Data API' }), { isError: true });
|
|
960
|
+
}
|
|
961
|
+
return createTextResponse(JSON.stringify({ leaderboard, count: leaderboard.length }, null, 2));
|
|
962
|
+
});
|
|
963
|
+
// Get prices (ADX/ALP)
|
|
964
|
+
registerTool(server, 'sap_adrena_get_prices', {
|
|
965
|
+
description: 'Fetch current ADX and ALP token prices from the Adrena Data API.',
|
|
966
|
+
inputSchema: {
|
|
967
|
+
type: 'object',
|
|
968
|
+
properties: {},
|
|
969
|
+
additionalProperties: false,
|
|
970
|
+
},
|
|
971
|
+
}, async () => {
|
|
972
|
+
const prices = await adrenaDataApi.getPrice();
|
|
973
|
+
if (prices === null) {
|
|
974
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to fetch prices from Adrena Data API' }), { isError: true });
|
|
975
|
+
}
|
|
976
|
+
return createTextResponse(JSON.stringify(prices, null, 2));
|
|
977
|
+
});
|
|
978
|
+
// Get last trading prices
|
|
979
|
+
registerTool(server, 'sap_adrena_get_trading_prices', {
|
|
980
|
+
description: 'Fetch latest oracle trading prices for all Adrena assets. Returns price and custody address for each traded asset.',
|
|
981
|
+
inputSchema: {
|
|
982
|
+
type: 'object',
|
|
983
|
+
properties: {},
|
|
984
|
+
additionalProperties: false,
|
|
985
|
+
},
|
|
986
|
+
}, async () => {
|
|
987
|
+
const prices = await adrenaDataApi.getLastTradingPrices();
|
|
988
|
+
if (prices === null) {
|
|
989
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to fetch trading prices from Adrena Data API' }), { isError: true });
|
|
990
|
+
}
|
|
991
|
+
return createTextResponse(JSON.stringify({ prices, count: prices.length }, null, 2));
|
|
992
|
+
});
|
|
993
|
+
// Get position status (live P&L)
|
|
994
|
+
registerTool(server, 'sap_adrena_get_position_status', {
|
|
995
|
+
description: 'Fetch live position status (P&L, size, liquidation price, entry price, oracle price) from the Adrena Data API for a specific wallet and token.',
|
|
996
|
+
inputSchema: {
|
|
997
|
+
type: 'object',
|
|
998
|
+
properties: {
|
|
999
|
+
wallet: { type: 'string', description: 'Wallet public key (base58).' },
|
|
1000
|
+
principalToken: { type: 'string', description: 'Principal token symbol (e.g. JITOSOL, WBTC, BONK, XAU).' },
|
|
1001
|
+
side: { type: 'string', description: 'Position side.', enum: ['long', 'short'] },
|
|
1002
|
+
},
|
|
1003
|
+
required: ['wallet', 'principalToken', 'side'],
|
|
1004
|
+
additionalProperties: false,
|
|
1005
|
+
},
|
|
1006
|
+
}, async (args) => {
|
|
1007
|
+
const wallet = String(args['wallet'] ?? '').trim();
|
|
1008
|
+
const principalToken = String(args['principalToken'] ?? '').trim().toUpperCase();
|
|
1009
|
+
const side = args['side'] === 'short' ? 'short' : 'long';
|
|
1010
|
+
if (!wallet || !principalToken) {
|
|
1011
|
+
return createTextResponse(JSON.stringify({ error: 'wallet and principalToken are required' }), { isError: true });
|
|
1012
|
+
}
|
|
1013
|
+
const positions = await adrenaDataApi.getPositions(wallet);
|
|
1014
|
+
if (positions === null) {
|
|
1015
|
+
return createTextResponse(JSON.stringify({ error: 'Failed to fetch positions from Adrena Data API' }), { isError: true });
|
|
1016
|
+
}
|
|
1017
|
+
const matching = positions.filter(p => p.principalToken?.toUpperCase() === principalToken &&
|
|
1018
|
+
p.side?.toLowerCase() === side);
|
|
1019
|
+
if (matching.length === 0) {
|
|
1020
|
+
return createTextResponse(JSON.stringify({ wallet, principalToken, side, status: 'no_open_position', message: `No ${side} position found for ${principalToken}` }));
|
|
1021
|
+
}
|
|
1022
|
+
return createTextResponse(JSON.stringify({ wallet, principalToken, side, positions: matching, count: matching.length }, null, 2));
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
/* ═══════════════════════════════════════════════════════════════════
|
|
1026
|
+
* Main registration function
|
|
1027
|
+
* ═══════════════════════════════════════════════════════════════════ */
|
|
1028
|
+
/**
|
|
1029
|
+
* @name registerAdrenaTools
|
|
1030
|
+
* @description Register all Adrena perps protocol tools: trading builders, commodity builders, liquidity/swap, staking, and Data API.
|
|
1031
|
+
*
|
|
1032
|
+
* @param server — MCP server instance.
|
|
1033
|
+
* @param context — Shared runtime context with Solana connection.
|
|
1034
|
+
*
|
|
1035
|
+
* @usedBy `register-tools.ts`
|
|
1036
|
+
*/
|
|
1037
|
+
export function registerAdrenaTools(server, context) {
|
|
1038
|
+
logger.debug('Registering Adrena perps protocol tools');
|
|
1039
|
+
// Trading builders
|
|
1040
|
+
registerAdrenaOpenLongTool(server, context);
|
|
1041
|
+
registerAdrenaOpenShortTool(server, context);
|
|
1042
|
+
registerAdrenaCloseLongTool(server, context);
|
|
1043
|
+
registerAdrenaCloseShortTool(server, context);
|
|
1044
|
+
// SL / TP builders
|
|
1045
|
+
registerAdrenaSetStopLossTool(server, context);
|
|
1046
|
+
registerAdrenaSetTakeProfitTool(server, context);
|
|
1047
|
+
registerAdrenaCancelStopLossTool(server, context);
|
|
1048
|
+
registerAdrenaCancelTakeProfitTool(server, context);
|
|
1049
|
+
// Limit order builders
|
|
1050
|
+
registerAdrenaAddLimitOrderTool(server, context);
|
|
1051
|
+
registerAdrenaCancelLimitOrderTool(server, context);
|
|
1052
|
+
// Commodity builders
|
|
1053
|
+
registerAdrenaCommodityTools(server, context);
|
|
1054
|
+
// Liquidity & swap builders
|
|
1055
|
+
registerAdrenaLiquiditySwapTools(server, context);
|
|
1056
|
+
// Staking builders
|
|
1057
|
+
registerAdrenaStakingTools(server, context);
|
|
1058
|
+
// Data API tools
|
|
1059
|
+
registerAdrenaDataApiTools(server);
|
|
1060
|
+
logger.debug('Adrena perps tools registered', { count: 32 });
|
|
1061
|
+
}
|
|
1062
|
+
//# sourceMappingURL=adrena-tools.js.map
|