cryptoiz-mcp 4.16.7 → 4.16.9
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/index.js +128 -20
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
-
var VERSION = 'v4.16.
|
|
2
|
+
var VERSION = 'v4.16.9';
|
|
3
3
|
var GATEWAY = 'https://rehqwsypjnjirhuiapqh.supabase.co/functions/v1/mcp-x402-gateway';
|
|
4
4
|
var TOOL_ENDPOINTS = {
|
|
5
5
|
get_whale_alpha: 'https://rehqwsypjnjirhuiapqh.supabase.co/functions/v1/mcp-alpha-scanner',
|
|
@@ -18,6 +18,7 @@ var SOL_RPC = 'https://api.mainnet-beta.solana.com';
|
|
|
18
18
|
var TOKEN_PROGRAM = 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA';
|
|
19
19
|
var ATA_PROGRAM = 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL';
|
|
20
20
|
var MEMO_PROGRAM = 'MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr';
|
|
21
|
+
var COMPUTE_BUDGET_PROGRAM = 'ComputeBudget111111111111111111111111111111';
|
|
21
22
|
|
|
22
23
|
var _updateNotified = false;
|
|
23
24
|
function notifyUpdate(data, headers) {
|
|
@@ -29,11 +30,16 @@ function notifyUpdate(data, headers) {
|
|
|
29
30
|
console.error('[cryptoiz-mcp] UPDATE: ' + VERSION + ' -> ' + latest + ' | Run: ' + cmd);
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
var
|
|
33
|
-
var
|
|
34
|
-
var
|
|
35
|
-
var
|
|
36
|
-
var
|
|
33
|
+
var solana = require('@solana/web3.js');
|
|
34
|
+
var Connection = solana.Connection;
|
|
35
|
+
var PublicKey = solana.PublicKey;
|
|
36
|
+
var Transaction = solana.Transaction;
|
|
37
|
+
var TransactionMessage = solana.TransactionMessage;
|
|
38
|
+
var VersionedTransaction = solana.VersionedTransaction;
|
|
39
|
+
var Keypair = solana.Keypair;
|
|
40
|
+
// Fix bs58 v6 ESM-only issue: support both CJS (v5) and ESM-compiled (v6)
|
|
41
|
+
var _bs58mod = require('bs58');
|
|
42
|
+
var bs58 = _bs58mod.default || _bs58mod;
|
|
37
43
|
var Server = require('@modelcontextprotocol/sdk/server/index.js').Server;
|
|
38
44
|
var StdioServerTransport = require('@modelcontextprotocol/sdk/server/stdio.js').StdioServerTransport;
|
|
39
45
|
var CallToolRequestSchema = require('@modelcontextprotocol/sdk/types.js').CallToolRequestSchema;
|
|
@@ -53,13 +59,65 @@ function findATA(wallet, mint) {
|
|
|
53
59
|
return PublicKey.findProgramAddressSync([walletPk.toBuffer(), tokPk.toBuffer(), mintPk.toBuffer()], ataPk)[0];
|
|
54
60
|
}
|
|
55
61
|
|
|
56
|
-
//
|
|
62
|
+
// V2: Dexter gas-sponsored. 4-ix tx: Limit + Price + TransferChecked + Memo(nonce)
|
|
63
|
+
// Dexter pays SOL gas — user only needs USDC
|
|
64
|
+
async function buildV2PaymentPayload(amount, feePayerAddr) {
|
|
65
|
+
var kp = getKeypair();
|
|
66
|
+
var conn = new Connection(SOL_RPC, 'confirmed');
|
|
67
|
+
var userATA = findATA(kp.publicKey.toBase58(), USDC_MINT);
|
|
68
|
+
var recipientATA = findATA(RECIPIENT, USDC_MINT);
|
|
69
|
+
var feePayerPk = new PublicKey(feePayerAddr);
|
|
70
|
+
var computeBudgetPk = new PublicKey(COMPUTE_BUDGET_PROGRAM);
|
|
71
|
+
var memoProgramPk = new PublicKey(MEMO_PROGRAM);
|
|
72
|
+
var tokenProgramPk = new PublicKey(TOKEN_PROGRAM);
|
|
73
|
+
var usdcMintPk = new PublicKey(USDC_MINT);
|
|
74
|
+
// ComputeUnitLimit(20000)
|
|
75
|
+
var setLimitData = Buffer.alloc(5);
|
|
76
|
+
setLimitData[0] = 0x02;
|
|
77
|
+
setLimitData.writeUInt32LE(20000, 1);
|
|
78
|
+
var setLimitIx = { programId: computeBudgetPk, keys: [], data: setLimitData };
|
|
79
|
+
// ComputeUnitPrice(1)
|
|
80
|
+
var setPriceData = Buffer.alloc(9);
|
|
81
|
+
setPriceData[0] = 0x03;
|
|
82
|
+
setPriceData.writeBigUInt64LE(BigInt(1), 1);
|
|
83
|
+
var setPriceIx = { programId: computeBudgetPk, keys: [], data: setPriceData };
|
|
84
|
+
// TransferChecked
|
|
85
|
+
var transferKeys = [
|
|
86
|
+
{ pubkey: userATA, isSigner: false, isWritable: true },
|
|
87
|
+
{ pubkey: usdcMintPk, isSigner: false, isWritable: false },
|
|
88
|
+
{ pubkey: recipientATA, isSigner: false, isWritable: true },
|
|
89
|
+
{ pubkey: kp.publicKey, isSigner: true, isWritable: false },
|
|
90
|
+
];
|
|
91
|
+
var transferData = Buffer.alloc(10);
|
|
92
|
+
transferData[0] = 0x0c;
|
|
93
|
+
transferData.writeUInt32LE(amount & 0xFFFFFFFF, 1);
|
|
94
|
+
transferData.writeUInt32LE(Math.floor(amount / 0x100000000) & 0xFFFFFFFF, 5);
|
|
95
|
+
transferData[9] = 6;
|
|
96
|
+
var transferIx = { programId: tokenProgramPk, keys: transferKeys, data: transferData };
|
|
97
|
+
// Memo with nonce
|
|
98
|
+
var nonceBytes = new Uint8Array(16);
|
|
99
|
+
for (var i = 0; i < 16; i++) nonceBytes[i] = Math.floor(Math.random() * 256);
|
|
100
|
+
var nonceHex = Array.from(nonceBytes).map(function(b) { return b.toString(16).padStart(2,'0'); }).join('');
|
|
101
|
+
var memoIx = { programId: memoProgramPk, keys: [], data: Buffer.from(nonceHex, 'utf8') };
|
|
102
|
+
var bh = await conn.getLatestBlockhash('confirmed');
|
|
103
|
+
var message = new TransactionMessage({
|
|
104
|
+
payerKey: feePayerPk,
|
|
105
|
+
recentBlockhash: bh.blockhash,
|
|
106
|
+
instructions: [setLimitIx, setPriceIx, transferIx, memoIx],
|
|
107
|
+
}).compileToV0Message();
|
|
108
|
+
var vtx = new VersionedTransaction(message);
|
|
109
|
+
vtx.sign([kp]);
|
|
110
|
+
var txB64 = Buffer.from(vtx.serialize()).toString('base64');
|
|
111
|
+
console.error('[cryptoiz-mcp] V2 tx built (Dexter gas-sponsored), nonce=' + nonceHex.substring(0,8) + '...');
|
|
112
|
+
return txB64;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// V1: direct on-chain, user pays SOL gas (fallback only)
|
|
57
116
|
async function sendUSDC(amount, toolName) {
|
|
58
117
|
var kp = getKeypair();
|
|
59
118
|
var conn = new Connection(SOL_RPC, 'confirmed');
|
|
60
119
|
var userATA = findATA(kp.publicKey.toBase58(), USDC_MINT);
|
|
61
120
|
var recipientATA = findATA(RECIPIENT, USDC_MINT);
|
|
62
|
-
// TransferChecked ix
|
|
63
121
|
var keys = [
|
|
64
122
|
{ pubkey: userATA, isSigner: false, isWritable: true },
|
|
65
123
|
{ pubkey: new PublicKey(USDC_MINT), isSigner: false, isWritable: false },
|
|
@@ -72,8 +130,7 @@ async function sendUSDC(amount, toolName) {
|
|
|
72
130
|
data.writeUInt32LE(Math.floor(amount / 0x100000000) & 0xFFFFFFFF, 5);
|
|
73
131
|
data[8] = 6;
|
|
74
132
|
var transferIx = { programId: new PublicKey(TOKEN_PROGRAM), keys: keys, data: data };
|
|
75
|
-
|
|
76
|
-
var nonce = Date.now().toString(16) + Math.floor(Math.random() * 0xffff).toString(16);
|
|
133
|
+
var nonce = Date.now().toString(16) + Math.floor(Math.random()*0xffff).toString(16);
|
|
77
134
|
var memoIx = {
|
|
78
135
|
programId: new PublicKey(MEMO_PROGRAM),
|
|
79
136
|
keys: [],
|
|
@@ -86,7 +143,7 @@ async function sendUSDC(amount, toolName) {
|
|
|
86
143
|
tx.sign(kp);
|
|
87
144
|
var sig = await conn.sendRawTransaction(tx.serialize(), { skipPreflight: false });
|
|
88
145
|
await conn.confirmTransaction({ signature: sig, blockhash: bh.blockhash, lastValidBlockHeight: bh.lastValidBlockHeight }, 'confirmed');
|
|
89
|
-
console.error('[cryptoiz-mcp] TX: ' + sig);
|
|
146
|
+
console.error('[cryptoiz-mcp] V1 TX: ' + sig);
|
|
90
147
|
return sig;
|
|
91
148
|
}
|
|
92
149
|
|
|
@@ -101,22 +158,73 @@ async function callTool(toolName, args) {
|
|
|
101
158
|
if (toolName === 'get_whale_divergence' && args && args.timeframe) queryParts.push('tf=' + args.timeframe);
|
|
102
159
|
if (toolName === 'get_token_ca' && args && args.name) queryParts.push('name=' + encodeURIComponent(args.name));
|
|
103
160
|
var url = (TOOL_ENDPOINTS[toolName] || GATEWAY) + '?' + queryParts.join('&');
|
|
161
|
+
|
|
104
162
|
// Step 1: discovery
|
|
105
163
|
var resp1 = await fetch(url, { headers: clientHeaders() });
|
|
106
164
|
if (resp1.status === 200) { var d = await resp1.json(); notifyUpdate(d, resp1.headers); return d; }
|
|
107
165
|
if (resp1.status !== 402) throw new Error('Server error ' + resp1.status + ': ' + (await resp1.text()).substring(0, 200));
|
|
166
|
+
|
|
108
167
|
// Step 2: parse payment requirements
|
|
109
168
|
var payReq = null;
|
|
169
|
+
var useV2 = false;
|
|
110
170
|
var prHeader = resp1.headers.get('payment-required');
|
|
111
|
-
if (prHeader) {
|
|
112
|
-
|
|
171
|
+
if (prHeader) {
|
|
172
|
+
try {
|
|
173
|
+
var arr = JSON.parse(Buffer.from(prHeader, 'base64').toString('utf8'));
|
|
174
|
+
if (arr && arr[0]) { payReq = arr[0]; useV2 = true; }
|
|
175
|
+
} catch(_e) {}
|
|
176
|
+
}
|
|
177
|
+
if (!payReq) {
|
|
178
|
+
var b402 = await resp1.json();
|
|
179
|
+
if (b402 && b402.accepts && b402.accepts[0]) payReq = b402.accepts[0];
|
|
180
|
+
}
|
|
113
181
|
if (!payReq) throw new Error('No payment requirements in 402');
|
|
182
|
+
|
|
114
183
|
var amount = parseInt(payReq.maxAmountRequired || payReq.amount || '10000');
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
var
|
|
118
|
-
|
|
119
|
-
|
|
184
|
+
var hasFeePayer = payReq.extra && payReq.extra.feePayer;
|
|
185
|
+
var paymentHeader = '';
|
|
186
|
+
var headerName = '';
|
|
187
|
+
|
|
188
|
+
// Step 3: Try V2 Dexter (gas-sponsored by Dexter — user only needs USDC)
|
|
189
|
+
if (useV2 && hasFeePayer) {
|
|
190
|
+
console.error('[cryptoiz-mcp] V2 mode: Dexter gas-sponsored, paying ' + (amount/1000000).toFixed(4) + ' USDC');
|
|
191
|
+
try {
|
|
192
|
+
var txB64 = await buildV2PaymentPayload(amount, payReq.extra.feePayer);
|
|
193
|
+
var v2Payload = {
|
|
194
|
+
x402Version: 1,
|
|
195
|
+
scheme: 'exact',
|
|
196
|
+
network: payReq.network || 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
|
|
197
|
+
payload: { transaction: txB64, signature: '' }
|
|
198
|
+
};
|
|
199
|
+
paymentHeader = Buffer.from(JSON.stringify(v2Payload)).toString('base64');
|
|
200
|
+
headerName = 'payment-signature';
|
|
201
|
+
} catch(v2Err) {
|
|
202
|
+
console.error('[cryptoiz-mcp] V2 build failed: ' + v2Err.message + ' -> fallback V1');
|
|
203
|
+
useV2 = false;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Step 4: V1 fallback (user pays gas — only if V2 failed)
|
|
208
|
+
if (!paymentHeader) {
|
|
209
|
+
console.error('[cryptoiz-mcp] V1 fallback: direct on-chain transfer');
|
|
210
|
+
var sig = await sendUSDC(amount, toolName);
|
|
211
|
+
paymentHeader = Buffer.from(JSON.stringify({ signature: sig })).toString('base64');
|
|
212
|
+
headerName = 'x-payment';
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Step 5: submit payment
|
|
216
|
+
var headers2 = {};
|
|
217
|
+
headers2[headerName] = paymentHeader;
|
|
218
|
+
var resp2 = await fetch(url, { headers: clientHeaders(headers2) });
|
|
219
|
+
|
|
220
|
+
// Step 6: if V2 failed at server, retry with V1
|
|
221
|
+
if (resp2.status !== 200 && useV2) {
|
|
222
|
+
console.error('[cryptoiz-mcp] V2 settle failed, trying V1 fallback...');
|
|
223
|
+
var fallbackSig = await sendUSDC(amount, toolName);
|
|
224
|
+
var v1Header = Buffer.from(JSON.stringify({ signature: fallbackSig })).toString('base64');
|
|
225
|
+
resp2 = await fetch(url, { headers: clientHeaders({ 'x-payment': v1Header }) });
|
|
226
|
+
}
|
|
227
|
+
|
|
120
228
|
if (resp2.status !== 200) throw new Error('Payment failed ' + resp2.status + ': ' + (await resp2.text()).substring(0, 300));
|
|
121
229
|
var data = await resp2.json();
|
|
122
230
|
notifyUpdate(data, resp2.headers);
|
|
@@ -131,7 +239,7 @@ var TOOLS = [
|
|
|
131
239
|
{ name: 'get_whale_distribution', description: 'Distribution phase tokens. Cost: $0.02 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
|
|
132
240
|
{ name: 'get_btc_regime', description: 'BTC macro regime. Cost: $0.01 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
|
|
133
241
|
{ name: 'get_btc_futures_signal', description: 'BTC futures signal. Cost: $0.03 USDC', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
|
|
134
|
-
{ name: 'get_token_ca', description: 'Token contract address
|
|
242
|
+
{ name: 'get_token_ca', description: 'Token contract address. FREE', inputSchema: { type: 'object', properties: { name: { type: 'string' } }, required: ['name'], additionalProperties: false } },
|
|
135
243
|
{ name: 'get_status', description: 'CryptoIZ MCP status. FREE', inputSchema: { type: 'object', properties: {}, additionalProperties: false } },
|
|
136
244
|
];
|
|
137
245
|
|
|
@@ -149,6 +257,6 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
149
257
|
async function main() {
|
|
150
258
|
var transport = new StdioServerTransport();
|
|
151
259
|
await server.connect(transport);
|
|
152
|
-
console.error('[cryptoiz-mcp] ' + VERSION + ' running (V1
|
|
260
|
+
console.error('[cryptoiz-mcp] ' + VERSION + ' running (V2 Dexter gas-sponsored + V1 fallback)');
|
|
153
261
|
}
|
|
154
262
|
main().catch(console.error);
|