kinetic-mcp 1.2.3 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -5
- package/build/index.js +27 -1
- package/build/index.js.map +1 -1
- package/build/suppress-warnings.js +14 -0
- package/build/suppress-warnings.js.map +1 -0
- package/build/tools/balance.js +5 -5
- package/build/tools/balance.js.map +1 -1
- package/build/tools/send-sol.js +140 -0
- package/build/tools/send-sol.js.map +1 -0
- package/build/tools/swap.js +73 -26
- package/build/tools/swap.js.map +1 -1
- package/build/tools/token-price.js +12 -7
- package/build/tools/token-price.js.map +1 -1
- package/build/tools/transaction-history.js +2 -14
- package/build/tools/transaction-history.js.map +1 -1
- package/build/utils/api-client.js +123 -74
- package/build/utils/api-client.js.map +1 -1
- package/build/utils/constants.js +35 -0
- package/build/utils/constants.js.map +1 -0
- package/build/utils/solana.js +26 -2
- package/build/utils/solana.js.map +1 -1
- package/build/utils/token-resolver.js +6 -13
- package/build/utils/token-resolver.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Kinetic MCP — Solana Trading for Claude Desktop
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/kinetic-mcp)
|
|
4
|
+
|
|
3
5
|
An MCP server that lets you check balances and swap tokens on Solana through natural language in Claude Desktop. Runs locally on your machine, powered by the [Kinetic](https://kinetic.xyz) trading platform.
|
|
4
6
|
|
|
5
7
|
**Prerequisites:** [Node.js 20+](https://nodejs.org)
|
|
@@ -82,19 +84,25 @@ Try these prompts in Claude Desktop:
|
|
|
82
84
|
- "Show me all my token holdings"
|
|
83
85
|
- "Swap 0.01 SOL for USDC" — Claude shows a quote preview and asks for confirmation
|
|
84
86
|
- "Swap 100 USDC for SOL with 1% slippage" — specify custom slippage
|
|
87
|
+
- "Send 0.1 SOL to Abc123..." — previews transfer details, then confirms
|
|
88
|
+
- "What's the price of BONK?" — get current token prices in USDC
|
|
89
|
+
- "Show my recent transactions" — view last 10 transactions
|
|
85
90
|
|
|
86
91
|
Claude will ask for permission the first time it uses a tool. Click "Allow for This Chat" or "Allow Always".
|
|
87
92
|
|
|
88
93
|
## Available Tools
|
|
89
94
|
|
|
90
|
-
| Tool
|
|
91
|
-
|
|
|
92
|
-
| `get_wallet_balance`
|
|
93
|
-
| `swap_tokens`
|
|
95
|
+
| Tool | Description | Inputs |
|
|
96
|
+
| ------------------------- | -------------------------------------- | ------------------------------------------------------------------------ |
|
|
97
|
+
| `get_wallet_balance` | Get SOL balance and all token holdings | None |
|
|
98
|
+
| `swap_tokens` | Swap one token for another | `from_token`, `to_token`, `amount`, `slippage_bps` (optional), `confirm` |
|
|
99
|
+
| `send_sol` | Send SOL to another wallet | `recipient`, `amount`, `confirm` |
|
|
100
|
+
| `get_token_price` | Get current token prices in USDC | `tokens` (array of symbols or mints) |
|
|
101
|
+
| `get_transaction_history` | Get 10 most recent wallet transactions | None |
|
|
94
102
|
|
|
95
103
|
## Safety Guardrails
|
|
96
104
|
|
|
97
|
-
- **Two-step confirmation** — swaps always show a
|
|
105
|
+
- **Two-step confirmation** — swaps and transfers always show a preview first; you must confirm before execution
|
|
98
106
|
- **Max trade size** — `MAX_TRADE_SOL` limits swap size in SOL-equivalent (default: 10 SOL)
|
|
99
107
|
- **Slippage cap** — maximum 10% (1000 bps) enforced by input validation
|
|
100
108
|
- **No private key exposure** — keypair is loaded from a local file only, never accepted as tool input
|
package/build/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import "./suppress-warnings.js";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
3
4
|
import { execSync } from "node:child_process";
|
|
4
5
|
import { resolve, dirname } from "node:path";
|
|
@@ -12,6 +13,7 @@ import { initSolana, loadKeypair, getWalletAddress } from "./utils/solana.js";
|
|
|
12
13
|
import { initApiClient } from "./utils/api-client.js";
|
|
13
14
|
import { initTokenResolver } from "./utils/token-resolver.js";
|
|
14
15
|
import { initSwap, swapTokens } from "./tools/swap.js";
|
|
16
|
+
import { initSendSol, sendSol } from "./tools/send-sol.js";
|
|
15
17
|
import { getWalletBalance } from "./tools/balance.js";
|
|
16
18
|
import { getTokenPrice } from "./tools/token-price.js";
|
|
17
19
|
import { getTransactionHistory } from "./tools/transaction-history.js";
|
|
@@ -38,6 +40,7 @@ async function main() {
|
|
|
38
40
|
initApiClient(config, logger);
|
|
39
41
|
initTokenResolver(logger);
|
|
40
42
|
initSwap(config);
|
|
43
|
+
initSendSol(config, logger);
|
|
41
44
|
// Validate keypair at startup
|
|
42
45
|
try {
|
|
43
46
|
loadKeypair(config.solanaKeypairPath);
|
|
@@ -86,6 +89,21 @@ async function main() {
|
|
|
86
89
|
}, async (params) => {
|
|
87
90
|
return swapTokens(params);
|
|
88
91
|
});
|
|
92
|
+
// --- Tool: send_sol ---
|
|
93
|
+
server.tool("send_sol", "Send SOL to another wallet. IMPORTANT: Always call first with confirm=false to preview the transfer details, then call again with confirm=true and identical parameters to execute. Never set confirm=true without previewing first.", {
|
|
94
|
+
recipient: z.string().describe("Destination wallet address (base58 Solana public key)"),
|
|
95
|
+
amount: z
|
|
96
|
+
.number()
|
|
97
|
+
.positive()
|
|
98
|
+
.finite()
|
|
99
|
+
.describe("Amount of SOL to send, in human-readable units (e.g. 0.5 = half a SOL)"),
|
|
100
|
+
confirm: z
|
|
101
|
+
.boolean()
|
|
102
|
+
.default(false)
|
|
103
|
+
.describe("false = preview transfer details (always do this first); true = execute the transfer with same parameters"),
|
|
104
|
+
}, async (params) => {
|
|
105
|
+
return sendSol(params);
|
|
106
|
+
});
|
|
89
107
|
// --- Tool: get_token_price ---
|
|
90
108
|
server.tool("get_token_price", "Get the current price of one or more tokens in USDC. Accepts token symbols (e.g. 'SOL') or mint addresses.", {
|
|
91
109
|
tokens: z
|
|
@@ -100,7 +118,15 @@ async function main() {
|
|
|
100
118
|
server.tool("get_transaction_history", "Get the 10 most recent transactions for the connected wallet. Shows signature, type, status, and timestamp for each transaction.", {}, async () => {
|
|
101
119
|
return getTransactionHistory();
|
|
102
120
|
});
|
|
103
|
-
logger.info({
|
|
121
|
+
logger.info({
|
|
122
|
+
tools: [
|
|
123
|
+
"get_wallet_balance",
|
|
124
|
+
"swap_tokens",
|
|
125
|
+
"send_sol",
|
|
126
|
+
"get_token_price",
|
|
127
|
+
"get_transaction_history",
|
|
128
|
+
],
|
|
129
|
+
}, "Tools registered");
|
|
104
130
|
// Graceful shutdown
|
|
105
131
|
const shutdown = () => {
|
|
106
132
|
logger.info("Shutting down...");
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAEvE,4DAA4D;AAC5D,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IACrE,IAAI,CAAC;QACH,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,MAAM,WAAW,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAEtE,KAAK,UAAU,IAAI;IACjB,2BAA2B;IAC3B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAEpC,0CAA0C;IAC1C,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,wBAAwB,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAEvE,4DAA4D;AAC5D,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO,EAAE,CAAC;IAChC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1D,MAAM,WAAW,GAAG,OAAO,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;IACrE,IAAI,CAAC;QACH,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,MAAM,WAAW,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAwB,CAAC;AAEtE,KAAK,UAAU,IAAI;IACjB,2BAA2B;IAC3B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAEpC,0CAA0C;IAC1C,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,CAAC;IACjB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE5B,8BAA8B;IAC9B,IAAI,CAAC;QACH,WAAW,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,sBAAsB,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,aAAa;IACb,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAC;IACzC,MAAM,CAAC,IAAI,CACT;QACE,MAAM,EAAE,aAAa;QACrB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,MAAM,EAAE,MAAM,CAAC,YAAY;QAC3B,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM;QAC1B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,OAAO;KACR,EACD,oCAAoC,CACrC,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,aAAa;QACnB,OAAO;KACR,CAAC,CAAC;IAEH,mCAAmC;IACnC,MAAM,CAAC,IAAI,CACT,oBAAoB,EACpB,iEAAiE,EACjE,EAAE,EACF,KAAK,IAAI,EAAE;QACT,OAAO,gBAAgB,EAAE,CAAC;IAC5B,CAAC,CACF,CAAC;IAEF,4BAA4B;IAC5B,MAAM,CAAC,IAAI,CACT,aAAa,EACb,kOAAkO,EAClO;QACE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;QACtF,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;QACpF,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,qEAAqE,CAAC;QAClF,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,IAAI,CAAC;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,uEAAuE,CAAC;QACpF,OAAO,EAAE,CAAC;aACP,OAAO,EAAE;aACT,OAAO,CAAC,KAAK,CAAC;aACd,QAAQ,CACP,iGAAiG,CAClG;KACJ,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;IAC5B,CAAC,CACF,CAAC;IAEF,yBAAyB;IACzB,MAAM,CAAC,IAAI,CACT,UAAU,EACV,sOAAsO,EACtO;QACE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uDAAuD,CAAC;QACvF,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,MAAM,EAAE;aACR,QAAQ,CAAC,wEAAwE,CAAC;QACrF,OAAO,EAAE,CAAC;aACP,OAAO,EAAE;aACT,OAAO,CAAC,KAAK,CAAC;aACd,QAAQ,CACP,2GAA2G,CAC5G;KACJ,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,CAAC,CACF,CAAC;IAEF,gCAAgC;IAChC,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,4GAA4G,EAC5G;QACE,MAAM,EAAE,CAAC;aACN,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;aACjC,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,CAAC,4DAA4D,CAAC;KAC1E,EACD,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,OAAO,aAAa,CAAC,MAAM,CAAC,CAAC;IAC/B,CAAC,CACF,CAAC;IAEF,wCAAwC;IACxC,MAAM,CAAC,IAAI,CACT,yBAAyB,EACzB,kIAAkI,EAClI,EAAE,EACF,KAAK,IAAI,EAAE;QACT,OAAO,qBAAqB,EAAE,CAAC;IACjC,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT;QACE,KAAK,EAAE;YACL,oBAAoB;YACpB,aAAa;YACb,UAAU;YACV,iBAAiB;YACjB,yBAAyB;SAC1B;KACF,EACD,kBAAkB,CACnB,CAAC;IAEF,oBAAoB;IACpB,MAAM,QAAQ,GAAG,GAAG,EAAE;QACpB,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAChC,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAChC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAE/B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;AAChC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,qDAAqD;IACrD,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Suppress the "bigint: Failed to load bindings, pure JS will be used" warning
|
|
2
|
+
// from bigint-buffer (transitive dep of @solana/web3.js). The pure JS fallback
|
|
3
|
+
// works fine — this is cosmetic noise in MCP server logs.
|
|
4
|
+
// Must be imported before @solana/web3.js to catch the warning at module load.
|
|
5
|
+
const originalWrite = process.stderr.write.bind(process.stderr);
|
|
6
|
+
process.stderr.write = function (chunk, ...args) {
|
|
7
|
+
if (typeof chunk === "string" && chunk.startsWith("bigint: Failed to load bindings")) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
11
|
+
return originalWrite(chunk, ...args);
|
|
12
|
+
};
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=suppress-warnings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suppress-warnings.js","sourceRoot":"","sources":["../src/suppress-warnings.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+EAA+E;AAC/E,0DAA0D;AAC1D,+EAA+E;AAE/E,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AAEhE,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,UAAU,KAA0B,EAAE,GAAG,IAAe;IAC7E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,UAAU,CAAC,iCAAiC,CAAC,EAAE,CAAC;QACrF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,8DAA8D;IAC9D,OAAQ,aAAqB,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;AAChD,CAAC,CAAC"}
|
package/build/tools/balance.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PublicKey } from "@solana/web3.js";
|
|
2
2
|
import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from "@solana/spl-token";
|
|
3
3
|
import { getConnection, getWalletAddress } from "../utils/solana.js";
|
|
4
|
+
import { LAMPORTS_PER_SOL } from "../utils/constants.js";
|
|
4
5
|
import { resolveTokenByMint } from "../utils/token-resolver.js";
|
|
5
6
|
import { formatError } from "../utils/errors.js";
|
|
6
7
|
async function fetchTokenAccounts(publicKey, programId) {
|
|
@@ -27,14 +28,13 @@ export async function getWalletBalance() {
|
|
|
27
28
|
const address = getWalletAddress();
|
|
28
29
|
const publicKey = new PublicKey(address);
|
|
29
30
|
const connection = getConnection();
|
|
30
|
-
// Fetch SOL balance
|
|
31
|
-
const lamports = await
|
|
32
|
-
|
|
33
|
-
// Fetch SPL token accounts (both programs in parallel)
|
|
34
|
-
const [splAccounts, token2022Accounts] = await Promise.all([
|
|
31
|
+
// Fetch SOL balance and SPL token accounts in parallel
|
|
32
|
+
const [lamports, splAccounts, token2022Accounts] = await Promise.all([
|
|
33
|
+
connection.getBalance(publicKey),
|
|
35
34
|
fetchTokenAccounts(publicKey, TOKEN_PROGRAM_ID),
|
|
36
35
|
fetchTokenAccounts(publicKey, TOKEN_2022_PROGRAM_ID),
|
|
37
36
|
]);
|
|
37
|
+
const solBalance = lamports / LAMPORTS_PER_SOL;
|
|
38
38
|
const allAccounts = [...splAccounts, ...token2022Accounts];
|
|
39
39
|
// Resolve token info
|
|
40
40
|
const tokens = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"balance.js","sourceRoot":"","sources":["../../src/tools/balance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAUjD,KAAK,UAAU,kBAAkB,CAC/B,SAAoB,EACpB,SAAoB;IAEpB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,6BAA6B,CAAC,SAAS,EAAE;QACvE,SAAS;KACV,CAAC,CAAC;IAEH,MAAM,QAAQ,GAA8D,EAAE,CAAC;IAE/E,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;QAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;QAE3C,IAAI,QAAQ,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;YAC7B,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,IAAI,CAAC,IAAI;gBACf,MAAM,EAAE,QAAQ;gBAChB,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ;aACpC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;QACnC,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC;QACzC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;QAEnC,
|
|
1
|
+
{"version":3,"file":"balance.js","sourceRoot":"","sources":["../../src/tools/balance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { PublicKey, SystemProgram, Transaction } from "@solana/web3.js";
|
|
2
|
+
import { loadKeypair, getConnection, getWalletAddress } from "../utils/solana.js";
|
|
3
|
+
import { LAMPORTS_PER_SOL, SOLSCAN_TX_URL } from "../utils/constants.js";
|
|
4
|
+
import { toBaseUnits } from "../utils/math.js";
|
|
5
|
+
import { formatError } from "../utils/errors.js";
|
|
6
|
+
let cfg;
|
|
7
|
+
let log;
|
|
8
|
+
export function initSendSol(config, logger) {
|
|
9
|
+
cfg = config;
|
|
10
|
+
log = logger;
|
|
11
|
+
}
|
|
12
|
+
const BASE_FEE_LAMPORTS = 5000;
|
|
13
|
+
const BASE_FEE_SOL = BASE_FEE_LAMPORTS / LAMPORTS_PER_SOL;
|
|
14
|
+
/** Validate a recipient address. Returns a PublicKey or throws. */
|
|
15
|
+
export function parseRecipientAddress(recipient) {
|
|
16
|
+
try {
|
|
17
|
+
return new PublicKey(recipient);
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
throw new Error(`Invalid recipient address: "${recipient}". Expected a base58-encoded Solana public key.`, { cause: err });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function sendSol(params) {
|
|
24
|
+
try {
|
|
25
|
+
const { recipient, amount, confirm } = params;
|
|
26
|
+
// 1. Validate recipient address
|
|
27
|
+
const recipientPubkey = parseRecipientAddress(recipient);
|
|
28
|
+
// 2. Collect warnings
|
|
29
|
+
const warnings = [];
|
|
30
|
+
// Off-curve check (likely a PDA or program address)
|
|
31
|
+
if (!PublicKey.isOnCurve(recipientPubkey.toBytes())) {
|
|
32
|
+
warnings.push("WARNING: This address appears to be a program-derived address (PDA). SOL sent here may not be recoverable.");
|
|
33
|
+
}
|
|
34
|
+
// Self-send check
|
|
35
|
+
const walletAddress = getWalletAddress();
|
|
36
|
+
if (recipient === walletAddress) {
|
|
37
|
+
warnings.push("WARNING: You are sending SOL to your own wallet. This has no net effect but costs a transaction fee.");
|
|
38
|
+
}
|
|
39
|
+
// 3. Trade size safety check
|
|
40
|
+
if (amount > cfg.maxTradeSol) {
|
|
41
|
+
return {
|
|
42
|
+
content: [
|
|
43
|
+
{
|
|
44
|
+
type: "text",
|
|
45
|
+
text: `Transfer size (${amount} SOL) exceeds maximum of ${cfg.maxTradeSol} SOL.`,
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
isError: true,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
// 4-5. Fetch balance and rent-exempt minimum in parallel
|
|
52
|
+
const connection = getConnection();
|
|
53
|
+
const walletPubkey = new PublicKey(walletAddress);
|
|
54
|
+
const [balanceLamports, rentExemptLamports] = await Promise.all([
|
|
55
|
+
connection.getBalance(walletPubkey),
|
|
56
|
+
connection.getMinimumBalanceForRentExemption(0),
|
|
57
|
+
]);
|
|
58
|
+
const balanceSol = balanceLamports / LAMPORTS_PER_SOL;
|
|
59
|
+
const rentExemptSol = rentExemptLamports / LAMPORTS_PER_SOL;
|
|
60
|
+
// 6. Check sufficient balance
|
|
61
|
+
if (amount + BASE_FEE_SOL > balanceSol) {
|
|
62
|
+
const maxSendable = Math.max(0, balanceSol - BASE_FEE_SOL - rentExemptSol);
|
|
63
|
+
return {
|
|
64
|
+
content: [
|
|
65
|
+
{
|
|
66
|
+
type: "text",
|
|
67
|
+
text: [
|
|
68
|
+
`Insufficient balance to send ${amount} SOL.`,
|
|
69
|
+
`Current balance: ${balanceSol.toFixed(9)} SOL`,
|
|
70
|
+
`Transaction fee: ~${BASE_FEE_SOL} SOL`,
|
|
71
|
+
`Maximum sendable (preserving rent-exempt minimum): ${maxSendable.toFixed(9)} SOL`,
|
|
72
|
+
].join("\n"),
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
isError: true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// 7. Rent buffer warning
|
|
79
|
+
const remainingSol = balanceSol - amount - BASE_FEE_SOL;
|
|
80
|
+
if (remainingSol < rentExemptSol) {
|
|
81
|
+
warnings.push(`WARNING: After this transfer, your remaining balance (~${remainingSol.toFixed(9)} SOL) ` +
|
|
82
|
+
`will be below the rent-exempt minimum (${rentExemptSol.toFixed(9)} SOL). ` +
|
|
83
|
+
`Your account may be garbage-collected by the Solana runtime.`);
|
|
84
|
+
}
|
|
85
|
+
// Preview mode
|
|
86
|
+
if (!confirm) {
|
|
87
|
+
const preview = [
|
|
88
|
+
"SOL Transfer Preview",
|
|
89
|
+
"─".repeat(30),
|
|
90
|
+
`Amount: ${amount} SOL`,
|
|
91
|
+
`Recipient: ${recipient}`,
|
|
92
|
+
`Current balance: ${balanceSol.toFixed(9)} SOL`,
|
|
93
|
+
`Estimated fee: ~${BASE_FEE_SOL} SOL`,
|
|
94
|
+
`Remaining after transfer: ~${remainingSol.toFixed(9)} SOL`,
|
|
95
|
+
];
|
|
96
|
+
if (warnings.length > 0) {
|
|
97
|
+
preview.push("", ...warnings);
|
|
98
|
+
}
|
|
99
|
+
preview.push("", "To execute this transfer, call again with confirm=true and the same parameters.");
|
|
100
|
+
return { content: [{ type: "text", text: preview.join("\n") }] };
|
|
101
|
+
}
|
|
102
|
+
// Execute mode
|
|
103
|
+
const keypair = loadKeypair(cfg.solanaKeypairPath);
|
|
104
|
+
const lamports = BigInt(toBaseUnits(amount, 9));
|
|
105
|
+
// Get fresh blockhash
|
|
106
|
+
const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
|
|
107
|
+
// Build transaction
|
|
108
|
+
const transaction = new Transaction().add(SystemProgram.transfer({
|
|
109
|
+
fromPubkey: walletPubkey,
|
|
110
|
+
toPubkey: recipientPubkey,
|
|
111
|
+
lamports,
|
|
112
|
+
}));
|
|
113
|
+
transaction.recentBlockhash = blockhash;
|
|
114
|
+
transaction.feePayer = walletPubkey;
|
|
115
|
+
// Sign
|
|
116
|
+
transaction.sign(keypair);
|
|
117
|
+
// Send (no retry — double-spend prevention)
|
|
118
|
+
const signature = await connection.sendRawTransaction(transaction.serialize(), {
|
|
119
|
+
skipPreflight: false,
|
|
120
|
+
preflightCommitment: "confirmed",
|
|
121
|
+
maxRetries: 0,
|
|
122
|
+
});
|
|
123
|
+
// Wait for confirmation
|
|
124
|
+
await connection.confirmTransaction({ signature, blockhash, lastValidBlockHeight }, "confirmed");
|
|
125
|
+
log.info({ amount, recipient: recipient.slice(0, 8) + "...", signature }, "SOL transfer confirmed");
|
|
126
|
+
const result = [
|
|
127
|
+
"SOL Transfer Confirmed",
|
|
128
|
+
"─".repeat(30),
|
|
129
|
+
`Amount: ${amount} SOL`,
|
|
130
|
+
`Recipient: ${recipient}`,
|
|
131
|
+
`Transaction: ${signature}`,
|
|
132
|
+
`Solscan: ${SOLSCAN_TX_URL}${signature}`,
|
|
133
|
+
].join("\n");
|
|
134
|
+
return { content: [{ type: "text", text: result }] };
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
return formatError(error, "send_sol");
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=send-sol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"send-sol.js","sourceRoot":"","sources":["../../src/tools/send-sol.ts"],"names":[],"mappings":"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"}
|
package/build/tools/swap.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { VersionedTransaction } from "@solana/web3.js";
|
|
2
2
|
import { resolveToken } from "../utils/token-resolver.js";
|
|
3
|
-
import { loadKeypair
|
|
3
|
+
import { loadKeypair } from "../utils/solana.js";
|
|
4
|
+
import { SOL_MINT, SOLSCAN_TX_URL, LAMPORTS_PER_SOL } from "../utils/constants.js";
|
|
4
5
|
import { toBaseUnits } from "../utils/math.js";
|
|
5
6
|
import { getQuote, buildSwapTransaction, sendTransaction } from "../utils/api-client.js";
|
|
6
7
|
import { formatError } from "../utils/errors.js";
|
|
@@ -8,14 +9,12 @@ let cfg;
|
|
|
8
9
|
export function initSwap(config) {
|
|
9
10
|
cfg = config;
|
|
10
11
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
// Use a Kinetic quote to convert token amount to SOL-equivalent
|
|
12
|
+
/**
|
|
13
|
+
* Check trade size using a separate from→SOL quote.
|
|
14
|
+
* Only used for non-SOL→non-SOL swaps where we can't derive SOL equivalent
|
|
15
|
+
* from the actual swap quote.
|
|
16
|
+
*/
|
|
17
|
+
async function checkTradeSizeBySolQuote(amount, fromMint, fromSymbol, fromDecimals) {
|
|
19
18
|
const baseUnits = Number(toBaseUnits(amount, fromDecimals));
|
|
20
19
|
try {
|
|
21
20
|
const quote = await getQuote({
|
|
@@ -27,7 +26,7 @@ async function checkTradeSize(amount, fromMint, fromSymbol, fromDecimals) {
|
|
|
27
26
|
if (Number.isNaN(solOutRaw)) {
|
|
28
27
|
return `Cannot verify trade size for ${fromSymbol}: invalid quote response. Trade blocked for safety.`;
|
|
29
28
|
}
|
|
30
|
-
const solEquiv = solOutRaw /
|
|
29
|
+
const solEquiv = solOutRaw / LAMPORTS_PER_SOL;
|
|
31
30
|
if (solEquiv > cfg.maxTradeSol) {
|
|
32
31
|
return `Trade size (${amount} ${fromSymbol} ≈ ${solEquiv.toFixed(2)} SOL) exceeds maximum of ${cfg.maxTradeSol} SOL.`;
|
|
33
32
|
}
|
|
@@ -45,7 +44,7 @@ function formatStreamEvents(events) {
|
|
|
45
44
|
}
|
|
46
45
|
else if ("txHash" in event) {
|
|
47
46
|
lines.push(`Transaction: ${event.txHash}`);
|
|
48
|
-
lines.push(`Solscan:
|
|
47
|
+
lines.push(`Solscan: ${SOLSCAN_TX_URL}${event.txHash}`);
|
|
49
48
|
}
|
|
50
49
|
else if ("walletTransactionInfo" in event) {
|
|
51
50
|
lines.push("Status: finalized");
|
|
@@ -60,26 +59,74 @@ export async function swapTokens(params) {
|
|
|
60
59
|
try {
|
|
61
60
|
const { from_token, to_token, amount, confirm } = params;
|
|
62
61
|
const slippageBps = params.slippage_bps ?? 200;
|
|
63
|
-
// Resolve tokens
|
|
64
|
-
const fromToken = await
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (tradeSizeError) {
|
|
69
|
-
return {
|
|
70
|
-
content: [{ type: "text", text: tradeSizeError }],
|
|
71
|
-
isError: true,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
// Convert to base units (string-based to avoid floating-point precision loss)
|
|
62
|
+
// Resolve both tokens in parallel
|
|
63
|
+
const [fromToken, toToken] = await Promise.all([
|
|
64
|
+
resolveToken(from_token),
|
|
65
|
+
resolveToken(to_token),
|
|
66
|
+
]);
|
|
75
67
|
const baseUnits = Number(toBaseUnits(amount, fromToken.decimals));
|
|
76
|
-
|
|
77
|
-
const quote = await getQuote({
|
|
68
|
+
const quoteReq = {
|
|
78
69
|
inputToken: fromToken.mint,
|
|
79
70
|
outputToken: toToken.mint,
|
|
80
71
|
amount: baseUnits,
|
|
81
72
|
slippageBps,
|
|
82
|
-
}
|
|
73
|
+
};
|
|
74
|
+
// Trade size safety check + quote, optimized to minimize API round-trips:
|
|
75
|
+
// - SOL input: instant size check, then get quote (1 API call)
|
|
76
|
+
// - SOL output: get quote, derive SOL equivalent from outAmount (1 API call, saves 1)
|
|
77
|
+
// - Non-SOL→non-SOL: run size check and quote in parallel (2 API calls, but concurrent)
|
|
78
|
+
let quote;
|
|
79
|
+
if (fromToken.mint === SOL_MINT) {
|
|
80
|
+
if (amount > cfg.maxTradeSol) {
|
|
81
|
+
return {
|
|
82
|
+
content: [
|
|
83
|
+
{
|
|
84
|
+
type: "text",
|
|
85
|
+
text: `Trade size (${amount} SOL) exceeds maximum of ${cfg.maxTradeSol} SOL.`,
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
isError: true,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
quote = await getQuote(quoteReq);
|
|
92
|
+
}
|
|
93
|
+
else if (toToken.mint === SOL_MINT) {
|
|
94
|
+
quote = await getQuote(quoteReq);
|
|
95
|
+
const solOutRaw = parseInt(quote.outAmount, 10);
|
|
96
|
+
if (Number.isNaN(solOutRaw)) {
|
|
97
|
+
return {
|
|
98
|
+
content: [
|
|
99
|
+
{
|
|
100
|
+
type: "text",
|
|
101
|
+
text: `Cannot verify trade size for ${fromToken.symbol}: invalid quote response. Trade blocked for safety.`,
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
isError: true,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
const solOut = solOutRaw / LAMPORTS_PER_SOL;
|
|
108
|
+
if (solOut > cfg.maxTradeSol) {
|
|
109
|
+
return {
|
|
110
|
+
content: [
|
|
111
|
+
{
|
|
112
|
+
type: "text",
|
|
113
|
+
text: `Trade size (${amount} ${fromToken.symbol} ≈ ${solOut.toFixed(2)} SOL) exceeds maximum of ${cfg.maxTradeSol} SOL.`,
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
isError: true,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const [tradeSizeError, quoteResult] = await Promise.all([
|
|
122
|
+
checkTradeSizeBySolQuote(amount, fromToken.mint, fromToken.symbol, fromToken.decimals),
|
|
123
|
+
getQuote(quoteReq),
|
|
124
|
+
]);
|
|
125
|
+
if (tradeSizeError) {
|
|
126
|
+
return { content: [{ type: "text", text: tradeSizeError }], isError: true };
|
|
127
|
+
}
|
|
128
|
+
quote = quoteResult;
|
|
129
|
+
}
|
|
83
130
|
// Calculate human-readable amounts
|
|
84
131
|
const outAmountRaw = parseInt(quote.outAmount, 10);
|
|
85
132
|
const minReceivedRaw = parseInt(quote.otherAmountThreshold, 10);
|
package/build/tools/swap.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"swap.js","sourceRoot":"","sources":["../../src/tools/swap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"swap.js","sourceRoot":"","sources":["../../src/tools/swap.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { resolveToken } from "../utils/token-resolver.js";
|
|
2
2
|
import { getQuote } from "../utils/api-client.js";
|
|
3
|
+
import { USDC_MINT, USDC_DECIMALS } from "../utils/constants.js";
|
|
3
4
|
import { toBaseUnits } from "../utils/math.js";
|
|
4
|
-
|
|
5
|
+
import { formatError } from "../utils/errors.js";
|
|
5
6
|
async function fetchPriceLine(input) {
|
|
6
7
|
try {
|
|
7
8
|
const token = await resolveToken(input);
|
|
@@ -20,8 +21,7 @@ async function fetchPriceLine(input) {
|
|
|
20
21
|
if (Number.isNaN(outRaw)) {
|
|
21
22
|
return `${token.symbol}: Price unavailable`;
|
|
22
23
|
}
|
|
23
|
-
|
|
24
|
-
const price = (outRaw / 1e6).toFixed(6);
|
|
24
|
+
const price = (outRaw / 10 ** USDC_DECIMALS).toFixed(6);
|
|
25
25
|
return `${token.symbol}: $${price}`;
|
|
26
26
|
}
|
|
27
27
|
catch (err) {
|
|
@@ -36,9 +36,14 @@ async function fetchPriceLine(input) {
|
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
export async function getTokenPrice(params) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
try {
|
|
40
|
+
const { tokens } = params;
|
|
41
|
+
const pricelines = await Promise.all(tokens.map(fetchPriceLine));
|
|
42
|
+
const lines = ["Token Prices (USDC)", "─".repeat(30), ...pricelines];
|
|
43
|
+
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
return formatError(error, "get_token_price");
|
|
47
|
+
}
|
|
43
48
|
}
|
|
44
49
|
//# sourceMappingURL=token-price.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-price.js","sourceRoot":"","sources":["../../src/tools/token-price.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"token-price.js","sourceRoot":"","sources":["../../src/tools/token-price.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,KAAK,UAAU,cAAc,CAAC,KAAa;IACzC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,CAAC;QAExC,qBAAqB;QACrB,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO,GAAG,KAAK,CAAC,MAAM,aAAa,CAAC;QACtC,CAAC;QAED,0CAA0C;QAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;QACvD,MAAM,KAAK,GAAG,MAAM,QAAQ,CAAC;YAC3B,UAAU,EAAE,KAAK,CAAC,IAAI;YACtB,WAAW,EAAE,SAAS;YACtB,MAAM,EAAE,OAAO;SAChB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QAC7C,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YACzB,OAAO,GAAG,KAAK,CAAC,MAAM,qBAAqB,CAAC;QAC9C,CAAC;QAED,MAAM,KAAK,GAAG,CAAC,MAAM,GAAG,EAAE,IAAI,aAAa,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACxD,OAAO,GAAG,KAAK,CAAC,MAAM,MAAM,KAAK,EAAE,CAAC;IACtC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QACrE,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YAClE,OAAO,GAAG,MAAM,+CAA+C,CAAC;QAClE,CAAC;QACD,IAAI,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YAClE,OAAO,GAAG,MAAM,iBAAiB,CAAC;QACpC,CAAC;QACD,OAAO,GAAG,MAAM,uBAAuB,CAAC;IAC1C,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAA4B;IAC9D,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;QAE1B,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC;QAEjE,MAAM,KAAK,GAAG,CAAC,qBAAqB,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,GAAG,UAAU,CAAC,CAAC;QAErE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;IACjE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,WAAW,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
|
|
@@ -1,19 +1,7 @@
|
|
|
1
1
|
import { PublicKey } from "@solana/web3.js";
|
|
2
2
|
import { getConnection, getWalletAddress } from "../utils/solana.js";
|
|
3
|
+
import { SOLSCAN_TX_URL, PROGRAM_LABELS } from "../utils/constants.js";
|
|
3
4
|
import { formatError } from "../utils/errors.js";
|
|
4
|
-
// Known program IDs for transaction type inference
|
|
5
|
-
const PROGRAM_LABELS = {
|
|
6
|
-
"11111111111111111111111111111111": "SOL Transfer",
|
|
7
|
-
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA: "Token Transfer",
|
|
8
|
-
TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb: "Token Transfer",
|
|
9
|
-
"675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8": "Swap",
|
|
10
|
-
JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4: "Swap",
|
|
11
|
-
KiNetiCAToLExLv5w7PrfiiKK1iYHNjrUM3RAF2V3A4: "Swap",
|
|
12
|
-
whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc: "Swap",
|
|
13
|
-
CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK: "Swap",
|
|
14
|
-
routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS: "Swap",
|
|
15
|
-
LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo: "Swap",
|
|
16
|
-
};
|
|
17
5
|
export async function getTransactionHistory() {
|
|
18
6
|
try {
|
|
19
7
|
const address = getWalletAddress();
|
|
@@ -42,7 +30,7 @@ export async function getTransactionHistory() {
|
|
|
42
30
|
const sig = signatures[i];
|
|
43
31
|
const txResult = txResults[i];
|
|
44
32
|
const sigShort = sig.signature.slice(0, 8) + "...";
|
|
45
|
-
const solscanUrl =
|
|
33
|
+
const solscanUrl = `${SOLSCAN_TX_URL}${sig.signature}`;
|
|
46
34
|
const status = sig.err ? "Failed" : "Success";
|
|
47
35
|
const timestamp = sig.blockTime ? new Date(sig.blockTime * 1000).toISOString() : "Unknown";
|
|
48
36
|
let txType = "Transaction";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction-history.js","sourceRoot":"","sources":["../../src/tools/transaction-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"transaction-history.js","sourceRoot":"","sources":["../../src/tools/transaction-history.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ let log;
|
|
|
5
5
|
const JWT_REFRESH_BUFFER_MS = 5 * 60 * 1000;
|
|
6
6
|
const MAX_STREAM_EVENTS = 100;
|
|
7
7
|
let cachedJwt = null;
|
|
8
|
+
let authInFlight = null;
|
|
8
9
|
export function initApiClient(config, logger) {
|
|
9
10
|
cfg = config;
|
|
10
11
|
log = logger;
|
|
@@ -32,22 +33,33 @@ async function authenticate() {
|
|
|
32
33
|
if (cachedJwt && Date.now() < cachedJwt.expiresAt) {
|
|
33
34
|
return cachedJwt.token;
|
|
34
35
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
36
|
+
// Deduplicate concurrent auth requests — if one is already in flight, reuse it
|
|
37
|
+
if (authInFlight)
|
|
38
|
+
return authInFlight;
|
|
39
|
+
authInFlight = (async () => {
|
|
40
|
+
try {
|
|
41
|
+
const response = await fetch(`${cfg.authBaseUrl}/v1/token`, {
|
|
42
|
+
method: "POST",
|
|
43
|
+
headers: { "Content-Type": "application/json" },
|
|
44
|
+
body: JSON.stringify({ apiKey: cfg.apiKey }),
|
|
45
|
+
signal: AbortSignal.timeout(cfg.requestTimeoutMs),
|
|
46
|
+
});
|
|
47
|
+
if (!response.ok) {
|
|
48
|
+
throw new Error(`Auth failed: ${response.status} ${response.statusText}`);
|
|
49
|
+
}
|
|
50
|
+
const data = (await response.json());
|
|
51
|
+
const ttlMs = data.expiresIn * 1000;
|
|
52
|
+
cachedJwt = {
|
|
53
|
+
token: data.accessToken,
|
|
54
|
+
expiresAt: Date.now() + ttlMs - JWT_REFRESH_BUFFER_MS,
|
|
55
|
+
};
|
|
56
|
+
return cachedJwt.token;
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
authInFlight = null;
|
|
60
|
+
}
|
|
61
|
+
})();
|
|
62
|
+
return authInFlight;
|
|
51
63
|
}
|
|
52
64
|
async function getHeaders() {
|
|
53
65
|
const headers = {
|
|
@@ -97,6 +109,99 @@ async function fetchWithAuthAndRetry(url, options) {
|
|
|
97
109
|
}
|
|
98
110
|
return resp;
|
|
99
111
|
}
|
|
112
|
+
function logStreamEvent(event) {
|
|
113
|
+
if ("status" in event) {
|
|
114
|
+
log.debug({ status: event.status }, "sendTransaction status");
|
|
115
|
+
}
|
|
116
|
+
else if ("txHash" in event) {
|
|
117
|
+
log.debug({ txHash: event.txHash }, "sendTransaction txHash");
|
|
118
|
+
}
|
|
119
|
+
else if ("error" in event) {
|
|
120
|
+
log.debug({ error: event.error }, "sendTransaction error");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** Push a parsed JSON value into the events array, handling both objects and arrays. */
|
|
124
|
+
function pushParsedEvents(parsed, events) {
|
|
125
|
+
if (Array.isArray(parsed)) {
|
|
126
|
+
for (const item of parsed) {
|
|
127
|
+
if (events.length >= MAX_STREAM_EVENTS)
|
|
128
|
+
break;
|
|
129
|
+
events.push(item);
|
|
130
|
+
logStreamEvent(item);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
events.push(parsed);
|
|
135
|
+
logStreamEvent(parsed);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Parse a response body that may be either NDJSON (one JSON object per line)
|
|
140
|
+
* or a regular JSON array. Handles both formats transparently.
|
|
141
|
+
*/
|
|
142
|
+
export async function parseStreamResponse(body) {
|
|
143
|
+
const events = [];
|
|
144
|
+
const reader = body.getReader();
|
|
145
|
+
const decoder = new TextDecoder();
|
|
146
|
+
let buffer = "";
|
|
147
|
+
const rawChunks = [];
|
|
148
|
+
try {
|
|
149
|
+
while (true) {
|
|
150
|
+
const { done, value } = await reader.read();
|
|
151
|
+
if (done)
|
|
152
|
+
break;
|
|
153
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
154
|
+
buffer += chunk;
|
|
155
|
+
rawChunks.push(chunk);
|
|
156
|
+
const lines = buffer.split("\n");
|
|
157
|
+
buffer = lines.pop() || "";
|
|
158
|
+
for (const line of lines) {
|
|
159
|
+
if (events.length >= MAX_STREAM_EVENTS)
|
|
160
|
+
break;
|
|
161
|
+
const trimmed = line.trim();
|
|
162
|
+
if (!trimmed)
|
|
163
|
+
continue;
|
|
164
|
+
try {
|
|
165
|
+
pushParsedEvents(JSON.parse(trimmed), events);
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
log.debug({ raw: trimmed.slice(0, 200) }, "Skipped non-JSON line in stream");
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (events.length >= MAX_STREAM_EVENTS) {
|
|
172
|
+
log.warn("Event limit reached, stopping read");
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Handle remaining buffer for NDJSON
|
|
177
|
+
if (buffer.trim() && events.length < MAX_STREAM_EVENTS) {
|
|
178
|
+
try {
|
|
179
|
+
pushParsedEvents(JSON.parse(buffer.trim()), events);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// Will try full-body parse below
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Fallback: if no events were parsed via NDJSON, try parsing the full body as a JSON array.
|
|
186
|
+
// Kinetic sometimes returns a pretty-printed JSON array instead of NDJSON.
|
|
187
|
+
if (events.length === 0 && rawChunks.length > 0) {
|
|
188
|
+
const fullBody = rawChunks.join("").trim();
|
|
189
|
+
if (fullBody) {
|
|
190
|
+
try {
|
|
191
|
+
pushParsedEvents(JSON.parse(fullBody), events);
|
|
192
|
+
log.debug({ count: events.length }, "Parsed response as non-NDJSON format");
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
log.warn({ err, raw: fullBody.slice(0, 500) }, "Failed to parse sendTransaction response");
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
finally {
|
|
201
|
+
reader.releaseLock();
|
|
202
|
+
}
|
|
203
|
+
return events;
|
|
204
|
+
}
|
|
100
205
|
// --- Public API ---
|
|
101
206
|
export async function getQuote(req) {
|
|
102
207
|
const baseUrl = cfg.apiBaseUrl.replace(/\/$/, "");
|
|
@@ -160,65 +265,9 @@ export async function sendTransaction(params) {
|
|
|
160
265
|
if (!response.ok) {
|
|
161
266
|
await throwApiError(response, "Kinetic sendTransaction");
|
|
162
267
|
}
|
|
163
|
-
|
|
164
|
-
const events = [];
|
|
165
|
-
const body = response.body;
|
|
166
|
-
if (!body) {
|
|
268
|
+
if (!response.body) {
|
|
167
269
|
throw new Error("No response body from sendTransaction.");
|
|
168
270
|
}
|
|
169
|
-
|
|
170
|
-
const decoder = new TextDecoder();
|
|
171
|
-
let buffer = "";
|
|
172
|
-
try {
|
|
173
|
-
while (true) {
|
|
174
|
-
const { done, value } = await reader.read();
|
|
175
|
-
if (done)
|
|
176
|
-
break;
|
|
177
|
-
buffer += decoder.decode(value, { stream: true });
|
|
178
|
-
const lines = buffer.split("\n");
|
|
179
|
-
buffer = lines.pop() || "";
|
|
180
|
-
for (const line of lines) {
|
|
181
|
-
if (events.length >= MAX_STREAM_EVENTS)
|
|
182
|
-
break;
|
|
183
|
-
const trimmed = line.trim();
|
|
184
|
-
if (!trimmed)
|
|
185
|
-
continue;
|
|
186
|
-
try {
|
|
187
|
-
const event = JSON.parse(trimmed);
|
|
188
|
-
events.push(event);
|
|
189
|
-
if ("status" in event) {
|
|
190
|
-
log.debug({ status: event.status }, "sendTransaction status");
|
|
191
|
-
}
|
|
192
|
-
else if ("txHash" in event) {
|
|
193
|
-
log.debug({ txHash: event.txHash }, "sendTransaction txHash");
|
|
194
|
-
}
|
|
195
|
-
else if ("error" in event) {
|
|
196
|
-
log.debug({ error: event.error }, "sendTransaction error");
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
catch (err) {
|
|
200
|
-
log.warn({ err, raw: trimmed.slice(0, 500) }, "Failed to parse NDJSON stream line");
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
if (events.length >= MAX_STREAM_EVENTS) {
|
|
204
|
-
log.warn("Event limit reached, stopping read");
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
// Handle remaining buffer
|
|
209
|
-
if (buffer.trim() && events.length < MAX_STREAM_EVENTS) {
|
|
210
|
-
try {
|
|
211
|
-
const event = JSON.parse(buffer.trim());
|
|
212
|
-
events.push(event);
|
|
213
|
-
}
|
|
214
|
-
catch (err) {
|
|
215
|
-
log.warn({ err, raw: buffer.trim().slice(0, 500) }, "Failed to parse NDJSON final buffer");
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
finally {
|
|
220
|
-
reader.releaseLock();
|
|
221
|
-
}
|
|
222
|
-
return events;
|
|
271
|
+
return parseStreamResponse(response.body);
|
|
223
272
|
}
|
|
224
273
|
//# sourceMappingURL=api-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/utils/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,GAKpB,MAAM,iBAAiB,CAAC;AAIzB,uDAAuD;AAEvD,IAAI,GAAW,CAAC;AAChB,IAAI,GAAW,CAAC;AAEhB,MAAM,qBAAqB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5C,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B,IAAI,SAAS,GAAgD,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../../src/utils/api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// Token mint addresses
|
|
2
|
+
export const SOL_MINT = "So11111111111111111111111111111111111111112";
|
|
3
|
+
export const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
4
|
+
// Token decimals
|
|
5
|
+
export const SOL_DECIMALS = 9;
|
|
6
|
+
export const USDC_DECIMALS = 6;
|
|
7
|
+
export const LAMPORTS_PER_SOL = 10 ** SOL_DECIMALS;
|
|
8
|
+
// External URLs
|
|
9
|
+
export const SOLSCAN_TX_URL = "https://solscan.io/tx/";
|
|
10
|
+
export const WELL_KNOWN_TOKENS = [
|
|
11
|
+
{ mint: SOL_MINT, symbol: "SOL", decimals: SOL_DECIMALS },
|
|
12
|
+
{ mint: USDC_MINT, symbol: "USDC", decimals: USDC_DECIMALS },
|
|
13
|
+
{ mint: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", symbol: "USDT", decimals: 6 },
|
|
14
|
+
{ mint: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263", symbol: "BONK", decimals: 5 },
|
|
15
|
+
{ mint: "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", symbol: "JUP", decimals: 6 },
|
|
16
|
+
{ mint: "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", symbol: "mSOL", decimals: 9 },
|
|
17
|
+
{ mint: "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", symbol: "ETH", decimals: 8 },
|
|
18
|
+
{ mint: "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh", symbol: "wBTC", decimals: 8 },
|
|
19
|
+
{ mint: "jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL", symbol: "JTO", decimals: 9 },
|
|
20
|
+
{ mint: "rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof", symbol: "RNDR", decimals: 8 },
|
|
21
|
+
];
|
|
22
|
+
// Known program IDs for transaction type inference
|
|
23
|
+
export const PROGRAM_LABELS = {
|
|
24
|
+
"11111111111111111111111111111111": "SOL Transfer",
|
|
25
|
+
TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA: "Token Transfer",
|
|
26
|
+
TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb: "Token Transfer",
|
|
27
|
+
"675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8": "Swap",
|
|
28
|
+
JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4: "Swap",
|
|
29
|
+
KiNetiCAToLExLv5w7PrfiiKK1iYHNjrUM3RAF2V3A4: "Swap",
|
|
30
|
+
whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc: "Swap",
|
|
31
|
+
CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK: "Swap",
|
|
32
|
+
routeUGWgWzqBWFcrCfv8tritsqukccJPu3q5GPP3xS: "Swap",
|
|
33
|
+
LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo: "Swap",
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/utils/constants.ts"],"names":[],"mappings":"AAAA,uBAAuB;AACvB,MAAM,CAAC,MAAM,QAAQ,GAAG,6CAA6C,CAAC;AACtE,MAAM,CAAC,MAAM,SAAS,GAAG,8CAA8C,CAAC;AAExE,iBAAiB;AACjB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAC9B,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC;AAC/B,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,IAAI,YAAY,CAAC;AAEnD,gBAAgB;AAChB,MAAM,CAAC,MAAM,cAAc,GAAG,wBAAwB,CAAC;AASvD,MAAM,CAAC,MAAM,iBAAiB,GAAgB;IAC5C,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE;IACzD,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE;IAC5D,EAAE,IAAI,EAAE,8CAA8C,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE;IACrF,EAAE,IAAI,EAAE,8CAA8C,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE;IACrF,EAAE,IAAI,EAAE,6CAA6C,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE;IACnF,EAAE,IAAI,EAAE,6CAA6C,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE;IACpF,EAAE,IAAI,EAAE,8CAA8C,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE;IACpF,EAAE,IAAI,EAAE,8CAA8C,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE;IACrF,EAAE,IAAI,EAAE,6CAA6C,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE;IACnF,EAAE,IAAI,EAAE,6CAA6C,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE;CACrF,CAAC;AAEF,mDAAmD;AACnD,MAAM,CAAC,MAAM,cAAc,GAA2B;IACpD,kCAAkC,EAAE,cAAc;IAClD,2CAA2C,EAAE,gBAAgB;IAC7D,2CAA2C,EAAE,gBAAgB;IAC7D,8CAA8C,EAAE,MAAM;IACtD,2CAA2C,EAAE,MAAM;IACnD,2CAA2C,EAAE,MAAM;IACnD,2CAA2C,EAAE,MAAM;IACnD,4CAA4C,EAAE,MAAM;IACpD,2CAA2C,EAAE,MAAM;IACnD,2CAA2C,EAAE,MAAM;CACpD,CAAC"}
|
package/build/utils/solana.js
CHANGED
|
@@ -2,7 +2,8 @@ import { Connection, Keypair } from "@solana/web3.js";
|
|
|
2
2
|
import { readFileSync } from "node:fs";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
|
-
|
|
5
|
+
const RPC_MAX_RETRIES = 3;
|
|
6
|
+
const RPC_BASE_DELAY_MS = 1000;
|
|
6
7
|
let cfg;
|
|
7
8
|
let log;
|
|
8
9
|
let cachedKeypair = null;
|
|
@@ -11,6 +12,26 @@ export function initSolana(config, logger) {
|
|
|
11
12
|
cfg = config;
|
|
12
13
|
log = logger;
|
|
13
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Fetch wrapper that retries 429/503 responses with exponential backoff.
|
|
17
|
+
* Used as the custom `fetch` for Solana RPC Connection to handle rate limits.
|
|
18
|
+
*/
|
|
19
|
+
async function rpcFetchWithRetry(input, init) {
|
|
20
|
+
for (let attempt = 0; attempt < RPC_MAX_RETRIES; attempt++) {
|
|
21
|
+
const resp = await fetch(input, init);
|
|
22
|
+
if (resp.status !== 429 && resp.status !== 503) {
|
|
23
|
+
return resp;
|
|
24
|
+
}
|
|
25
|
+
// Drain the response body to release the underlying socket
|
|
26
|
+
await resp.body?.cancel();
|
|
27
|
+
const jitter = Math.random() * RPC_BASE_DELAY_MS;
|
|
28
|
+
const delay = RPC_BASE_DELAY_MS * Math.pow(2, attempt) + jitter;
|
|
29
|
+
log.warn({ status: resp.status, attempt: attempt + 1, delayMs: Math.round(delay) }, "Solana RPC rate limited, retrying");
|
|
30
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
31
|
+
}
|
|
32
|
+
// Final attempt — return whatever we get
|
|
33
|
+
return fetch(input, init);
|
|
34
|
+
}
|
|
14
35
|
function expandHome(p) {
|
|
15
36
|
if (p.startsWith("~/") || p.startsWith("~\\")) {
|
|
16
37
|
return resolve(homedir(), p.slice(2));
|
|
@@ -42,7 +63,10 @@ export function loadKeypair(path) {
|
|
|
42
63
|
export function getConnection() {
|
|
43
64
|
if (cachedConnection)
|
|
44
65
|
return cachedConnection;
|
|
45
|
-
cachedConnection = new Connection(cfg.solanaRpcUrl,
|
|
66
|
+
cachedConnection = new Connection(cfg.solanaRpcUrl, {
|
|
67
|
+
commitment: "confirmed",
|
|
68
|
+
fetch: rpcFetchWithRetry,
|
|
69
|
+
});
|
|
46
70
|
return cachedConnection;
|
|
47
71
|
}
|
|
48
72
|
export function getWalletAddress() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"solana.js","sourceRoot":"","sources":["../../src/utils/solana.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"solana.js","sourceRoot":"","sources":["../../src/utils/solana.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,29 +1,22 @@
|
|
|
1
1
|
import { PublicKey } from "@solana/web3.js";
|
|
2
2
|
import { getMint } from "@solana/spl-token";
|
|
3
3
|
import { getConnection } from "./solana.js";
|
|
4
|
+
import { WELL_KNOWN_TOKENS } from "./constants.js";
|
|
4
5
|
let log;
|
|
5
6
|
export function initTokenResolver(logger) {
|
|
6
7
|
log = logger;
|
|
7
8
|
}
|
|
8
|
-
// Well-known tokens (fast path, no API call)
|
|
9
|
-
const WELL_KNOWN_TOKENS = [
|
|
10
|
-
{ mint: "So11111111111111111111111111111111111111112", symbol: "SOL", decimals: 9 },
|
|
11
|
-
{ mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", symbol: "USDC", decimals: 6 },
|
|
12
|
-
{ mint: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB", symbol: "USDT", decimals: 6 },
|
|
13
|
-
{ mint: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263", symbol: "BONK", decimals: 5 },
|
|
14
|
-
{ mint: "JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN", symbol: "JUP", decimals: 6 },
|
|
15
|
-
{ mint: "mSoLzYCxHdYgdzU16g5QSh3i5K3z3KZK7ytfqcJm7So", symbol: "mSOL", decimals: 9 },
|
|
16
|
-
{ mint: "7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs", symbol: "ETH", decimals: 8 },
|
|
17
|
-
{ mint: "3NZ9JMVBmGAqocybic2c7LQCJScmgsAZ6vQqTDzcqmJh", symbol: "wBTC", decimals: 8 },
|
|
18
|
-
{ mint: "jtojtomepa8beP8AuQc6eXt5FriJwfFMwQx2v2f9mCL", symbol: "JTO", decimals: 9 },
|
|
19
|
-
{ mint: "rndrizKT3MK1iimdxRdWabcF7Zg7AR5T4nud4EkHBof", symbol: "RNDR", decimals: 8 },
|
|
20
|
-
];
|
|
21
9
|
function isBase58MintAddress(input) {
|
|
22
10
|
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(input);
|
|
23
11
|
}
|
|
12
|
+
const mintDecimalsCache = new Map();
|
|
24
13
|
async function fetchOnChainDecimals(mint) {
|
|
14
|
+
const cached = mintDecimalsCache.get(mint);
|
|
15
|
+
if (cached !== undefined)
|
|
16
|
+
return cached;
|
|
25
17
|
try {
|
|
26
18
|
const mintInfo = await getMint(getConnection(), new PublicKey(mint));
|
|
19
|
+
mintDecimalsCache.set(mint, mintInfo.decimals);
|
|
27
20
|
return mintInfo.decimals;
|
|
28
21
|
}
|
|
29
22
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token-resolver.js","sourceRoot":"","sources":["../../src/utils/token-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"token-resolver.js","sourceRoot":"","sources":["../../src/utils/token-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAkB,MAAM,gBAAgB,CAAC;AAGnE,IAAI,GAAW,CAAC;AAEhB,MAAM,UAAU,iBAAiB,CAAC,MAAc;IAC9C,GAAG,GAAG,MAAM,CAAC;AACf,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAkB,CAAC;AAEpD,KAAK,UAAU,oBAAoB,CAAC,IAAY;IAC9C,MAAM,MAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC;IAExC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,aAAa,EAAE,EAAE,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,iBAAiB,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAC/C,OAAO,QAAQ,CAAC,QAAQ,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,wCAAwC,CAAC,CAAC;QACnE,MAAM,IAAI,KAAK,CACb,kDAAkD,IAAI,mCAAmC,EACzF,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAa;IAC9C,2CAA2C;IAC3C,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IACvC,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,UAAU,CAAC,CAAC;IAC/F,IAAI,iBAAiB;QAAE,OAAO,iBAAiB,CAAC;IAEhD,MAAM,eAAe,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC;IACxE,IAAI,eAAe;QAAE,OAAO,eAAe,CAAC;IAE5C,sDAAsD;IACtD,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CACb,kBAAkB,KAAK,uHAAuH,CAC/I,CAAC;IACJ,CAAC;IAED,0CAA0C;IAC1C,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,CAAC;IACnD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,EAAE,QAAQ,EAAE,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,IAAY;IAC7C,MAAM,SAAS,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACjE,OAAO,SAAS,IAAI,IAAI,CAAC;AAC3B,CAAC"}
|