solana-traderclaw 1.0.139 → 1.0.141
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.
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
// src/http-client.ts
|
|
2
2
|
import kayba, { SpanType } from "@kayba_ai/tracing";
|
|
3
|
+
var OrchestratorRateLimitError = class extends Error {
|
|
4
|
+
code = "RATE_LIMIT_EXCEEDED";
|
|
5
|
+
retryAfterMs;
|
|
6
|
+
status;
|
|
7
|
+
constructor(message, retryAfterMs, status) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "OrchestratorRateLimitError";
|
|
10
|
+
this.retryAfterMs = retryAfterMs;
|
|
11
|
+
this.status = status;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function parseRetryAfterMs(headerValue, maxMs) {
|
|
15
|
+
if (!headerValue) return null;
|
|
16
|
+
const trimmed = headerValue.trim();
|
|
17
|
+
if (trimmed === "") return null;
|
|
18
|
+
const asSeconds = Number(trimmed);
|
|
19
|
+
if (Number.isFinite(asSeconds) && asSeconds >= 0) {
|
|
20
|
+
return Math.min(Math.round(asSeconds * 1e3), maxMs);
|
|
21
|
+
}
|
|
22
|
+
const asDate = Date.parse(trimmed);
|
|
23
|
+
if (Number.isFinite(asDate)) {
|
|
24
|
+
return Math.max(0, Math.min(asDate - Date.now(), maxMs));
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
function sleep(ms) {
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
const t = setTimeout(resolve, ms);
|
|
31
|
+
if (t && typeof t === "object" && "unref" in t) {
|
|
32
|
+
t.unref();
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
3
36
|
async function orchestratorRequest(opts) {
|
|
4
37
|
if (!kayba.isConfigured()) {
|
|
5
38
|
return doRequest(opts);
|
|
@@ -21,7 +54,7 @@ async function orchestratorRequest(opts) {
|
|
|
21
54
|
throw err;
|
|
22
55
|
}
|
|
23
56
|
}
|
|
24
|
-
async function doRequest(opts, isRetry = false) {
|
|
57
|
+
async function doRequest(opts, isRetry = false, rateLimitAttempt = 0) {
|
|
25
58
|
const url = `${opts.baseUrl.replace(/\/$/, "")}${opts.path}`;
|
|
26
59
|
const controller = new AbortController();
|
|
27
60
|
const timeoutId = setTimeout(
|
|
@@ -64,7 +97,25 @@ async function doRequest(opts, isRetry = false) {
|
|
|
64
97
|
if ((res.status === 401 || res.status === 403) && !isRetry && opts.onUnauthorized) {
|
|
65
98
|
clearTimeout(timeoutId);
|
|
66
99
|
const newToken = await opts.onUnauthorized();
|
|
67
|
-
return doRequest({ ...opts, accessToken: newToken }, true);
|
|
100
|
+
return doRequest({ ...opts, accessToken: newToken }, true, rateLimitAttempt);
|
|
101
|
+
}
|
|
102
|
+
const bodyCodeIsRateLimit = typeof dataObj?.code === "string" && /\bRATE_LIMIT\b/i.test(dataObj.code);
|
|
103
|
+
const isRateLimited = res.status === 429 || !res.ok && bodyCodeIsRateLimit;
|
|
104
|
+
if (isRateLimited) {
|
|
105
|
+
clearTimeout(timeoutId);
|
|
106
|
+
const maxWait = opts.rateLimitMaxRetryWaitMs ?? 3e4;
|
|
107
|
+
const maxRetries = opts.rateLimitMaxRetries ?? 1;
|
|
108
|
+
const retryAfter = parseRetryAfterMs(res.headers.get("Retry-After"), maxWait) ?? Math.min(maxWait, 1e3 * Math.pow(2, rateLimitAttempt));
|
|
109
|
+
const bodyMessage = typeof dataObj?.message === "string" ? dataObj.message : typeof dataObj?.error === "string" ? dataObj.error : `HTTP ${res.status}`;
|
|
110
|
+
if (rateLimitAttempt < maxRetries) {
|
|
111
|
+
await sleep(retryAfter);
|
|
112
|
+
return doRequest(opts, isRetry, rateLimitAttempt + 1);
|
|
113
|
+
}
|
|
114
|
+
throw new OrchestratorRateLimitError(
|
|
115
|
+
`RATE_LIMIT_EXCEEDED: ${bodyMessage}`,
|
|
116
|
+
retryAfter,
|
|
117
|
+
res.status
|
|
118
|
+
);
|
|
68
119
|
}
|
|
69
120
|
if (!res.ok) {
|
|
70
121
|
const errBody = data && typeof data === "object" && !Array.isArray(data) ? data : null;
|
|
@@ -87,5 +138,6 @@ async function doRequest(opts, isRetry = false) {
|
|
|
87
138
|
}
|
|
88
139
|
|
|
89
140
|
export {
|
|
141
|
+
OrchestratorRateLimitError,
|
|
90
142
|
orchestratorRequest
|
|
91
143
|
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// src/session-manager.ts
|
|
2
2
|
var TRADERCLAW_SESSION_TROUBLESHOOTING = "https://docs.traderclaw.ai/docs/installation#troubleshooting-session-expired-auth-errors-or-the-agent-logged-out";
|
|
3
|
+
var TRADERCLAW_MANAGED_INSTALL_CONSOLE_PANEL_URL = "https://install.traderclaw.ai/panel";
|
|
4
|
+
var TRADERCLAW_MANAGED_INSTALL_LOGIN_HINT = `If you installed via install.traderclaw.ai's managed VPS console, re-authenticate in Panel \u2192 TraderClaw login (${TRADERCLAW_MANAGED_INSTALL_CONSOLE_PANEL_URL}), then openclaw gateway restart when convenient.`;
|
|
3
5
|
var BS58_CHARS = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
4
6
|
function b58Decode(str) {
|
|
5
7
|
let num = BigInt(0);
|
|
@@ -357,7 +359,7 @@ var SessionManager = class _SessionManager {
|
|
|
357
359
|
const walletPrivateKey = (await this.walletPrivateKeyProvider?.())?.trim();
|
|
358
360
|
if (!walletPrivateKey) {
|
|
359
361
|
throw new Error(
|
|
360
|
-
`Wallet proof required but the gateway cannot sign interactively \u2014 no wallet key is wired into this process. This account already has a wallet. On the host that runs OpenClaw (with a normal terminal / TTY), run: traderclaw login \u2014 complete wallet proof when prompted \u2014 then openclaw gateway restart. That persists new session tokens without putting a private key in the gateway configuration. Do not paste private keys into openclaw.json. Troubleshooting: ${TRADERCLAW_SESSION_TROUBLESHOOTING}`
|
|
362
|
+
`Wallet proof required but the gateway cannot sign interactively \u2014 no wallet key is wired into this process. This account already has a wallet. On the host that runs OpenClaw (with a normal terminal / TTY), run: traderclaw login \u2014 complete wallet proof when prompted \u2014 then openclaw gateway restart. That persists new session tokens without putting a private key in the gateway configuration. Do not paste private keys into openclaw.json. Troubleshooting: ${TRADERCLAW_SESSION_TROUBLESHOOTING} ${TRADERCLAW_MANAGED_INSTALL_LOGIN_HINT}`
|
|
361
363
|
);
|
|
362
364
|
}
|
|
363
365
|
walletPubKey = challenge.walletPublicKey || this.walletPublicKey || void 0;
|
|
@@ -387,7 +389,7 @@ var SessionManager = class _SessionManager {
|
|
|
387
389
|
await this.unifiedRefresh();
|
|
388
390
|
if (!this.accessToken) {
|
|
389
391
|
throw new Error(
|
|
390
|
-
`Session expired and could not be refreshed. Re-authentication required. On the gateway host try: traderclaw login \u2014 then openclaw gateway restart. Troubleshooting: ${TRADERCLAW_SESSION_TROUBLESHOOTING}`
|
|
392
|
+
`Session expired and could not be refreshed. Re-authentication required. On the gateway host try: traderclaw login \u2014 then openclaw gateway restart. Troubleshooting: ${TRADERCLAW_SESSION_TROUBLESHOOTING} ${TRADERCLAW_MANAGED_INSTALL_LOGIN_HINT}`
|
|
391
393
|
);
|
|
392
394
|
}
|
|
393
395
|
return this.accessToken;
|
|
@@ -398,7 +400,7 @@ var SessionManager = class _SessionManager {
|
|
|
398
400
|
await this.unifiedRefresh();
|
|
399
401
|
if (!this.accessToken) {
|
|
400
402
|
throw new Error(
|
|
401
|
-
`Session expired and could not be refreshed. Re-authentication required. On the gateway host try: traderclaw login \u2014 then openclaw gateway restart. Troubleshooting: ${TRADERCLAW_SESSION_TROUBLESHOOTING}`
|
|
403
|
+
`Session expired and could not be refreshed. Re-authentication required. On the gateway host try: traderclaw login \u2014 then openclaw gateway restart. Troubleshooting: ${TRADERCLAW_SESSION_TROUBLESHOOTING} ${TRADERCLAW_MANAGED_INSTALL_LOGIN_HINT}`
|
|
402
404
|
);
|
|
403
405
|
}
|
|
404
406
|
return this.accessToken;
|
|
@@ -541,5 +543,7 @@ var SessionManager = class _SessionManager {
|
|
|
541
543
|
};
|
|
542
544
|
|
|
543
545
|
export {
|
|
546
|
+
TRADERCLAW_MANAGED_INSTALL_CONSOLE_PANEL_URL,
|
|
547
|
+
TRADERCLAW_MANAGED_INSTALL_LOGIN_HINT,
|
|
544
548
|
SessionManager
|
|
545
549
|
};
|
package/dist/index.js
CHANGED
|
@@ -4,8 +4,9 @@ import {
|
|
|
4
4
|
writeRefreshTokenToOpenclawAtomic
|
|
5
5
|
} from "./chunk-IAQC34O7.js";
|
|
6
6
|
import {
|
|
7
|
-
SessionManager
|
|
8
|
-
|
|
7
|
+
SessionManager,
|
|
8
|
+
TRADERCLAW_MANAGED_INSTALL_LOGIN_HINT
|
|
9
|
+
} from "./chunk-OKBHBUZ7.js";
|
|
9
10
|
import {
|
|
10
11
|
looksLikeTelegramChatId,
|
|
11
12
|
resolveTelegramRecipientToChatId
|
|
@@ -29,7 +30,7 @@ import {
|
|
|
29
30
|
} from "./chunk-R24UDHQG.js";
|
|
30
31
|
import {
|
|
31
32
|
orchestratorRequest
|
|
32
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-E7QOPXSU.js";
|
|
33
34
|
import {
|
|
34
35
|
IntelligenceLab
|
|
35
36
|
} from "./chunk-FBS5FGW2.js";
|
|
@@ -774,6 +775,26 @@ function registerWebFetchTool(api, Type2, logPrefix, options) {
|
|
|
774
775
|
}
|
|
775
776
|
|
|
776
777
|
// index.ts
|
|
778
|
+
var SOLANA_TRADER_LIFECYCLE_SINGLETON_KEY = Symbol.for(
|
|
779
|
+
"openclaw.solana-trader.lifecycle.v1"
|
|
780
|
+
);
|
|
781
|
+
var __solanaTraderGlobalSingletonHolder = globalThis;
|
|
782
|
+
function __solanaTraderDisposePreviousLifecycle(logger) {
|
|
783
|
+
const prev = __solanaTraderGlobalSingletonHolder[SOLANA_TRADER_LIFECYCLE_SINGLETON_KEY];
|
|
784
|
+
if (!prev) return;
|
|
785
|
+
__solanaTraderGlobalSingletonHolder[SOLANA_TRADER_LIFECYCLE_SINGLETON_KEY] = void 0;
|
|
786
|
+
try {
|
|
787
|
+
logger?.info("[solana-trader] Disposing previous plugin lifecycle before re-register");
|
|
788
|
+
prev.dispose();
|
|
789
|
+
} catch (err) {
|
|
790
|
+
logger?.warn(
|
|
791
|
+
`[solana-trader] Previous lifecycle dispose error: ${err instanceof Error ? err.message : String(err)}`
|
|
792
|
+
);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
function __solanaTraderSetCurrentLifecycle(lc) {
|
|
796
|
+
__solanaTraderGlobalSingletonHolder[SOLANA_TRADER_LIFECYCLE_SINGLETON_KEY] = lc;
|
|
797
|
+
}
|
|
777
798
|
var TRADERCLAW_WALLET_PRIVATE_KEY_ENV = "TRADERCLAW_WALLET_PRIVATE_KEY";
|
|
778
799
|
function walletPrivateKeyFromPluginConfigRecord(obj) {
|
|
779
800
|
const w = typeof obj.walletPrivateKey === "string" ? obj.walletPrivateKey.trim() : "";
|
|
@@ -922,6 +943,8 @@ var solanaTraderPlugin = {
|
|
|
922
943
|
name: "Solana Trader",
|
|
923
944
|
description: "Autonomous Solana memecoin trading agent \u2014 V1-Upgraded with intelligence lab, tool envelopes, prompt scrubbing, and split skill architecture",
|
|
924
945
|
register(api) {
|
|
946
|
+
__solanaTraderDisposePreviousLifecycle(api.logger);
|
|
947
|
+
const __solanaTraderDisposers = [];
|
|
925
948
|
const pluginConfigRaw = api.pluginConfig && typeof api.pluginConfig === "object" && !Array.isArray(api.pluginConfig) ? api.pluginConfig : {};
|
|
926
949
|
const walletPrivateKeyFromPluginJsonOnly = walletPrivateKeyFromPluginConfigRecord(pluginConfigRaw);
|
|
927
950
|
const config = parseConfig(api.pluginConfig);
|
|
@@ -932,7 +955,7 @@ var solanaTraderPlugin = {
|
|
|
932
955
|
}
|
|
933
956
|
if (!apiKey && !config.refreshToken) {
|
|
934
957
|
api.logger.error(
|
|
935
|
-
|
|
958
|
+
`[solana-trader] apiKey or refreshToken is required. Tell the user to run on their machine: traderclaw setup --signup (or traderclaw signup) for a new account, or traderclaw setup / traderclaw login if they already have an API key. The agent cannot sign up or edit credentials. ${TRADERCLAW_MANAGED_INSTALL_LOGIN_HINT}`
|
|
936
959
|
);
|
|
937
960
|
return;
|
|
938
961
|
}
|
|
@@ -1049,6 +1072,12 @@ var solanaTraderPlugin = {
|
|
|
1049
1072
|
error: (msg) => api.logger.error(`[solana-trader] ${msg}`)
|
|
1050
1073
|
}
|
|
1051
1074
|
});
|
|
1075
|
+
__solanaTraderDisposers.push(() => {
|
|
1076
|
+
try {
|
|
1077
|
+
sessionManager.destroy();
|
|
1078
|
+
} catch {
|
|
1079
|
+
}
|
|
1080
|
+
});
|
|
1052
1081
|
const onUnauthorized = async () => {
|
|
1053
1082
|
api.logger.warn("[solana-trader] Received 401 \u2014 refreshing session...");
|
|
1054
1083
|
return sessionManager.handleUnauthorized();
|
|
@@ -2434,6 +2463,12 @@ ${notes}
|
|
|
2434
2463
|
error: (msg) => api.logger.error(`[solana-trader] ${msg}`)
|
|
2435
2464
|
}
|
|
2436
2465
|
});
|
|
2466
|
+
__solanaTraderDisposers.push(() => {
|
|
2467
|
+
try {
|
|
2468
|
+
bitqueryStreamManager.close();
|
|
2469
|
+
} catch {
|
|
2470
|
+
}
|
|
2471
|
+
});
|
|
2437
2472
|
api.registerTool({
|
|
2438
2473
|
name: "solana_bitquery_subscribe",
|
|
2439
2474
|
description: "Subscribe to a managed real-time Bitquery data stream. The orchestrator manages the WebSocket connection and broadcasts events. Available templates: realtimeTokenPricesSolana, ohlc1s, dexPoolLiquidityChanges, pumpFunTokenCreation, pumpFunTrades, pumpSwapTrades, raydiumNewPools. Returns a subscriptionId for tracking. Pass agentId to enable event-to-agent forwarding \u2014 orchestrator delivers each event to your Gateway via /v1/responses in addition to normal WS delivery. Subscriptions expire after 24h and emit subscription_expiring/subscription_expired events. See websocket-streaming.md in the solana-trader skill for the full message contract and usage patterns.",
|
|
@@ -2567,6 +2602,12 @@ ${notes}
|
|
|
2567
2602
|
error: (msg) => api.logger.error(`[solana-trader] ${msg}`)
|
|
2568
2603
|
}
|
|
2569
2604
|
});
|
|
2605
|
+
__solanaTraderDisposers.push(() => {
|
|
2606
|
+
try {
|
|
2607
|
+
void alphaStreamManager.unsubscribe().catch(() => void 0);
|
|
2608
|
+
} catch {
|
|
2609
|
+
}
|
|
2610
|
+
});
|
|
2570
2611
|
let startupGateRunning = null;
|
|
2571
2612
|
let startupGateState = { ok: false, ts: 0, steps: [] };
|
|
2572
2613
|
let lastForwardProbeState = null;
|
|
@@ -4296,6 +4337,12 @@ Context compaction triggered. STATE.md synced from last persisted state. Decisio
|
|
|
4296
4337
|
}
|
|
4297
4338
|
);
|
|
4298
4339
|
let solanaTraderSessionWatchdogTimer = null;
|
|
4340
|
+
__solanaTraderDisposers.push(() => {
|
|
4341
|
+
if (solanaTraderSessionWatchdogTimer !== null) {
|
|
4342
|
+
clearInterval(solanaTraderSessionWatchdogTimer);
|
|
4343
|
+
solanaTraderSessionWatchdogTimer = null;
|
|
4344
|
+
}
|
|
4345
|
+
});
|
|
4299
4346
|
api.registerService({
|
|
4300
4347
|
id: "solana-trader-session",
|
|
4301
4348
|
start: async () => {
|
|
@@ -4310,7 +4357,7 @@ Context compaction triggered. STATE.md synced from last persisted state. Decisio
|
|
|
4310
4357
|
`[solana-trader] Session initialization failed: ${err instanceof Error ? err.message : String(err)}`
|
|
4311
4358
|
);
|
|
4312
4359
|
api.logger.error(
|
|
4313
|
-
|
|
4360
|
+
`[solana-trader] Trading tools will fail until session is established. User should run on this machine: traderclaw login (after logout) or traderclaw setup / traderclaw signup for a new account. Wallet proof uses local signing only \u2014 private key never leaves this system. ${TRADERCLAW_MANAGED_INSTALL_LOGIN_HINT}`
|
|
4314
4361
|
);
|
|
4315
4362
|
return;
|
|
4316
4363
|
}
|
|
@@ -4546,6 +4593,16 @@ Context compaction triggered. STATE.md synced from last persisted state. Decisio
|
|
|
4546
4593
|
api.logger.info(
|
|
4547
4594
|
`[solana-trader] V1-Upgraded-Public: Registered ${totalToolCount} tools (${baseToolCount} base + ${intelligenceToolCount} intelligence + ${webFetchCount} web_fetch = ${totalRegistered} Solana + ${xToolCount} X/Twitter read-only) for walletId ${walletId} (session auth mode)`
|
|
4548
4595
|
);
|
|
4596
|
+
__solanaTraderSetCurrentLifecycle({
|
|
4597
|
+
dispose: () => {
|
|
4598
|
+
for (let i = __solanaTraderDisposers.length - 1; i >= 0; i--) {
|
|
4599
|
+
try {
|
|
4600
|
+
__solanaTraderDisposers[i]();
|
|
4601
|
+
} catch {
|
|
4602
|
+
}
|
|
4603
|
+
}
|
|
4604
|
+
}
|
|
4605
|
+
});
|
|
4549
4606
|
}
|
|
4550
4607
|
};
|
|
4551
4608
|
var index_default = solanaTraderPlugin;
|
package/dist/src/http-client.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
SessionManager
|
|
3
|
-
|
|
2
|
+
SessionManager,
|
|
3
|
+
TRADERCLAW_MANAGED_INSTALL_CONSOLE_PANEL_URL,
|
|
4
|
+
TRADERCLAW_MANAGED_INSTALL_LOGIN_HINT
|
|
5
|
+
} from "../chunk-OKBHBUZ7.js";
|
|
4
6
|
export {
|
|
5
|
-
SessionManager
|
|
7
|
+
SessionManager,
|
|
8
|
+
TRADERCLAW_MANAGED_INSTALL_CONSOLE_PANEL_URL,
|
|
9
|
+
TRADERCLAW_MANAGED_INSTALL_LOGIN_HINT
|
|
6
10
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solana-traderclaw",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.141",
|
|
4
4
|
"description": "TraderClaw V1-Upgraded — Solana trading for OpenClaw with intelligence lab, tool envelopes, prompt scrubbing, read-only X social intel, and split skill docs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|