solana-traderclaw 1.0.40 → 1.0.43
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 +67 -87
- package/bin/installer-step-engine.mjs +108 -5
- package/bin/openclaw-trader.mjs +60 -0
- package/config/gateway-v1-upgraded.json5 +160 -0
- package/config/gateway-v1.json5 +71 -57
- package/dist/chunk-3RG5ZIWI.js +10 -0
- package/dist/chunk-AI6MTHUN.js +88 -0
- package/dist/chunk-CMZLPU3Z.js +164 -0
- package/dist/{chunk-A7UG5RGA.js → chunk-F3UKCPA4.js} +0 -9
- package/dist/chunk-IYD3TCSE.js +366 -0
- package/dist/chunk-NZTB624I.js +366 -0
- package/dist/chunk-Q5AWKXY3.js +97 -0
- package/dist/chunk-YBURTADE.js +169 -0
- package/dist/index.js +797 -531
- package/dist/src/intelligence-lab.js +7 -0
- package/dist/src/prompt-scrub.js +6 -0
- package/dist/src/runtime-layout.js +28 -0
- package/dist/src/tool-envelope.js +12 -0
- package/lib/x-client.mjs +2 -69
- package/lib/x-tools.mjs +19 -84
- package/openclaw.plugin.json +53 -2
- package/package.json +4 -4
- package/skills/solana-trader/HEARTBEAT.md +383 -41
- package/skills/solana-trader/SKILL.md +240 -2541
- package/skills/solana-trader/refs/alpha-signals.md +172 -0
- package/skills/solana-trader/refs/api-reference.md +158 -0
- package/skills/solana-trader/refs/bitquery-intelligence.md +75 -0
- package/skills/solana-trader/refs/cron-jobs.md +140 -0
- package/skills/solana-trader/refs/decision-framework.md +157 -0
- package/skills/solana-trader/refs/memory-tags.md +90 -0
- package/skills/solana-trader/refs/position-management.md +88 -0
- package/skills/solana-trader/refs/review-learning.md +117 -0
- package/skills/solana-trader/refs/strategy-evolution.md +160 -0
- package/skills/solana-trader/refs/trade-execution.md +148 -0
- package/skills/solana-trader/workspace/AGENTS.md +113 -0
- package/skills/solana-trader/workspace/BOOTSTRAP.md +22 -0
- package/skills/solana-trader/workspace/DEPLOYMENT.md +69 -0
- package/skills/solana-trader/workspace/IDENTITY.md +21 -0
- package/skills/solana-trader/workspace/MEMORY.md +6 -0
- package/skills/solana-trader/workspace/SOUL.md +46 -0
- package/skills/solana-trader/workspace/TOOLS.md +209 -0
- package/skills/solana-trader/workspace/USER.md +17 -0
- package/skills/solana-trader/refs/x-credentials.md +0 -169
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
# solana-traderclaw (
|
|
1
|
+
# solana-traderclaw (V1-Upgraded)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Public edition of the upgraded TraderClaw V1 plugin for autonomous Solana memecoin trading. Identical to the team edition with one difference: X/Twitter tools are read-only (social intel only, no posting). 94 Solana tools + 3 X/Twitter read tools = 97 total. Full trading lifecycle. Connects OpenClaw to a trading orchestrator that handles market data, risk enforcement, and trade execution. Includes a full memory layer with local persistence, episodic logging, deterministic compute tools, intelligence lab, standardized tool envelopes, prompt scrubbing, and OpenClaw-native memory integration.
|
|
4
4
|
|
|
5
5
|
## Architecture
|
|
6
6
|
|
|
7
7
|
```
|
|
8
8
|
OpenClaw Agent (brain: reasoning, decisions, strategy evolution)
|
|
9
9
|
│
|
|
10
|
-
│ calls
|
|
10
|
+
│ calls 97 typed tools (94 trading + 3 X read-only)
|
|
11
11
|
▼
|
|
12
12
|
Plugin (this package)
|
|
13
13
|
├── HTTP ──→ Orchestrator (data + risk + execution)
|
|
@@ -18,9 +18,8 @@ Plugin (this package)
|
|
|
18
18
|
├── Local persistence (state, decisions, bulletin, patterns)
|
|
19
19
|
│ └── .traderclaw-v1-data/
|
|
20
20
|
│
|
|
21
|
-
└── OpenClaw
|
|
22
|
-
├──
|
|
23
|
-
├── MEMORY.md (optional — your narrative notes; not overwritten by state save)
|
|
21
|
+
└── OpenClaw native memory (auto-loaded every session)
|
|
22
|
+
├── MEMORY.md (durable facts — always in context)
|
|
24
23
|
└── memory/YYYY-MM-DD.md (daily logs — today + yesterday)
|
|
25
24
|
```
|
|
26
25
|
|
|
@@ -35,19 +34,20 @@ The plugin gives OpenClaw tools to interact with the Solana trading orchestrator
|
|
|
35
34
|
|
|
36
35
|
### 1. Install the plugin
|
|
37
36
|
|
|
38
|
-
Install the **npm package** **`solana-traderclaw`**. The **OpenClaw plugin id** in `openclaw.json` stays **`solana-trader`** (same as `openclaw.plugin.json`). The global CLI binary is **`traderclaw`**.
|
|
39
|
-
|
|
40
37
|
```bash
|
|
41
|
-
npm install -g solana-traderclaw
|
|
38
|
+
npm install -g solana-traderclaw
|
|
42
39
|
```
|
|
43
40
|
|
|
44
41
|
Or install directly into OpenClaw:
|
|
45
42
|
|
|
46
43
|
```bash
|
|
47
|
-
openclaw plugins install solana-traderclaw
|
|
44
|
+
openclaw plugins install solana-traderclaw
|
|
48
45
|
```
|
|
49
46
|
|
|
50
|
-
|
|
47
|
+
Install name and config id are intentionally different:
|
|
48
|
+
- npm package / install command: `solana-traderclaw`
|
|
49
|
+
- OpenClaw plugin id in `openclaw.json`: `solana-trader`
|
|
50
|
+
- OpenClaw allowlist entry: `plugins.allow: ["solana-trader"]`
|
|
51
51
|
|
|
52
52
|
### 2. Run setup
|
|
53
53
|
|
|
@@ -73,7 +73,7 @@ openclaw gateway restart
|
|
|
73
73
|
traderclaw install --wizard
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
-
This opens a localhost UI that runs prechecks, lane-aware setup, gateway validation, optional Telegram setup, and final verification.
|
|
76
|
+
This opens a localhost UI that runs prechecks, lane-aware setup, gateway validation, optional Telegram setup, and final verification.
|
|
77
77
|
|
|
78
78
|
### Optional: Run CLI prechecks directly
|
|
79
79
|
|
|
@@ -148,15 +148,7 @@ traderclaw config set <key> <v> # Update a value
|
|
|
148
148
|
traderclaw config reset # Remove all plugin config
|
|
149
149
|
```
|
|
150
150
|
|
|
151
|
-
Available config keys: `orchestratorUrl`, `walletId`, `apiKey`, `apiTimeout`, `refreshToken`, `walletPublicKey`, `walletPrivateKey`, `gatewayBaseUrl`, `gatewayToken`, `agentId`
|
|
152
|
-
|
|
153
|
-
Wallet proof note: if login/session challenge requires wallet ownership proof, provide the key at runtime with `--wallet-private-key` or `TRADERCLAW_WALLET_PRIVATE_KEY`. It is used for local signing only and is not stored in `~/.openclaw/openclaw.json`.
|
|
154
|
-
|
|
155
|
-
**Gateway process:** Telegram and other channels talk to the **OpenClaw gateway** process. That process must be able to read `TRADERCLAW_WALLET_PRIVATE_KEY` when the session refresh fails and a new challenge runs. Exporting the variable only in your SSH session does **not** set it for **systemd** (or Docker, etc.). Configure it in the gateway unit’s environment per the troubleshooting guide below.
|
|
156
|
-
|
|
157
|
-
**`traderclaw login`:** Uses the saved refresh token when valid (no wallet key needed). Use `traderclaw login --force-reauth` when you intentionally want a full API challenge (e.g. after `traderclaw logout`).
|
|
158
|
-
|
|
159
|
-
**Session / auth / startup issues:** follow the official guide — [Installation → Troubleshooting (session expired, auth, logged out)](https://docs.traderclaw.ai/docs/installation#troubleshooting-session-expired-auth-errors-or-the-agent-logged-out).
|
|
151
|
+
Available config keys: `orchestratorUrl`, `walletId`, `apiKey`, `apiTimeout`, `refreshToken`, `recoverySecret`, `walletPublicKey`, `walletPrivateKey`, `gatewayBaseUrl`, `gatewayToken`, `agentId`
|
|
160
152
|
|
|
161
153
|
### `traderclaw --help`
|
|
162
154
|
|
|
@@ -173,6 +165,7 @@ If you prefer to configure manually instead of using the CLI, add to `~/.opencla
|
|
|
173
165
|
```json5
|
|
174
166
|
{
|
|
175
167
|
plugins: {
|
|
168
|
+
allow: ["solana-trader"],
|
|
176
169
|
entries: {
|
|
177
170
|
"solana-trader": {
|
|
178
171
|
enabled: true,
|
|
@@ -199,9 +192,9 @@ openclaw gateway restart
|
|
|
199
192
|
|
|
200
193
|
The plugin implements a 3-layer memory architecture that uses OpenClaw's native infrastructure plus custom tools to eliminate amnesia between sessions.
|
|
201
194
|
|
|
202
|
-
### Layer 1: Durable
|
|
195
|
+
### Layer 1: Durable Facts (`MEMORY.md`)
|
|
203
196
|
|
|
204
|
-
OpenClaw loads
|
|
197
|
+
OpenClaw automatically loads `MEMORY.md` into agent context at every session start — zero tool calls needed. When `solana_state_save` is called, it writes both a JSON state file AND updates `MEMORY.md` with curated durable facts: tier, wallet, mode, strategy version, watchlist, permanent learnings, and regime canary.
|
|
205
198
|
|
|
206
199
|
### Layer 2: Episodic Memory (Daily Logs + Bootstrap Injection)
|
|
207
200
|
|
|
@@ -215,7 +208,7 @@ Unlimited retention via the orchestrator API. `solana_memory_write` / `solana_me
|
|
|
215
208
|
|
|
216
209
|
### Memory Flush Hook
|
|
217
210
|
|
|
218
|
-
The `memory:flush` hook fires automatically when OpenClaw is about to trim context. It syncs
|
|
211
|
+
The `memory:flush` hook fires automatically when OpenClaw is about to trim context. It syncs `MEMORY.md` from the last persisted state and writes a compaction marker to the daily log. This is an automatic safety net — no agent action needed.
|
|
219
212
|
|
|
220
213
|
### Bootstrap Hook (`agent:bootstrap`)
|
|
221
214
|
|
|
@@ -241,29 +234,20 @@ Entitlement fallback chain: live API fetch → cached file → durable state →
|
|
|
241
234
|
│ └── shared/ # Team bulletin (JSONL)
|
|
242
235
|
```
|
|
243
236
|
|
|
244
|
-
Plus OpenClaw
|
|
237
|
+
Plus OpenClaw-native paths at project root:
|
|
245
238
|
```
|
|
246
|
-
|
|
247
|
-
MEMORY.md # Optional agent narrative (not overwritten by the plugin)
|
|
239
|
+
MEMORY.md # Curated durable facts (auto-loaded by OpenClaw)
|
|
248
240
|
memory/
|
|
249
241
|
├── 2026-03-19.md # Today's daily log (auto-loaded by OpenClaw)
|
|
250
242
|
├── 2026-03-18.md # Yesterday's daily log (auto-loaded by OpenClaw)
|
|
251
243
|
└── ... # Auto-pruned after 7 days
|
|
252
244
|
```
|
|
253
245
|
|
|
254
|
-
## X/Twitter Setup
|
|
255
|
-
|
|
256
|
-
The team edition includes 5 X/Twitter tools for trade journaling and community engagement. Setup requires an X Developer App.
|
|
257
|
-
|
|
258
|
-
### 1. Create an X Developer App
|
|
246
|
+
## X/Twitter Setup (Read-Only Social Intel)
|
|
259
247
|
|
|
260
|
-
|
|
261
|
-
2. Create a new App (Free tier is sufficient for posting — 1,500 tweets/month)
|
|
262
|
-
3. Note your **Consumer Key** and **Consumer Secret**
|
|
263
|
-
4. Under "User authentication settings", enable OAuth 1.0a with Read and Write permissions
|
|
264
|
-
5. Generate **Access Token** and **Access Token Secret** for the account that will post
|
|
248
|
+
The public edition includes 3 read-only X/Twitter tools for social intelligence gathering (search tweets, read mentions, get threads). X posting is not included in the public edition.
|
|
265
249
|
|
|
266
|
-
###
|
|
250
|
+
### Configure via Environment Variables
|
|
267
251
|
|
|
268
252
|
```bash
|
|
269
253
|
export X_CONSUMER_KEY="your-app-consumer-key"
|
|
@@ -272,9 +256,7 @@ export X_ACCESS_TOKEN_MAIN="your-access-token"
|
|
|
272
256
|
export X_ACCESS_TOKEN_MAIN_SECRET="your-access-token-secret"
|
|
273
257
|
```
|
|
274
258
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
### 3. Or Configure via Plugin Config
|
|
259
|
+
### Or Configure via Plugin Config
|
|
278
260
|
|
|
279
261
|
Add to `~/.openclaw/openclaw.json` under the plugin entry:
|
|
280
262
|
|
|
@@ -297,17 +279,17 @@ Add to `~/.openclaw/openclaw.json` under the plugin entry:
|
|
|
297
279
|
|
|
298
280
|
| Tier | Cost | Capabilities |
|
|
299
281
|
|------|------|-------------|
|
|
300
|
-
| Free | $0 | 1,500 posts/month (write-only) |
|
|
301
282
|
| Pay-as-you-go | Per-credit | Read access (mentions, search, threads) |
|
|
302
283
|
| Basic | $200/month | Higher limits, more read access |
|
|
303
284
|
|
|
304
|
-
|
|
285
|
+
Pay-as-you-go or Basic tier is required for the read-only social intel tools.
|
|
305
286
|
|
|
306
|
-
## Available Tools (
|
|
287
|
+
## Available Tools (97 — 94 trading + 3 X read-only)
|
|
307
288
|
|
|
308
289
|
### Scanning
|
|
309
290
|
| Tool | Description |
|
|
310
291
|
|------|-------------|
|
|
292
|
+
| `solana_scan` | Broad market scan — launches + hot pairs combined |
|
|
311
293
|
| `solana_scan_launches` | Find new Solana token launches |
|
|
312
294
|
| `solana_scan_hot_pairs` | Find high-volume trading pairs |
|
|
313
295
|
| `solana_market_regime` | Get macro market state (bullish/bearish/neutral) |
|
|
@@ -330,7 +312,8 @@ Free tier is sufficient for daily trade journaling. Pay-as-you-go is recommended
|
|
|
330
312
|
| Tool | Description |
|
|
331
313
|
|------|-------------|
|
|
332
314
|
| `solana_trade_precheck` | Pre-trade risk validation |
|
|
333
|
-
| `solana_trade_execute` | Execute trade via SpyFly bot |
|
|
315
|
+
| `solana_trade_execute` | Execute trade via SpyFly bot (full params) |
|
|
316
|
+
| `solana_trade` | Execute trade (shorthand) |
|
|
334
317
|
|
|
335
318
|
### Reflection & Server-Side Memory
|
|
336
319
|
| Tool | Description |
|
|
@@ -361,6 +344,8 @@ Free tier is sufficient for daily trade journaling. Pay-as-you-go is recommended
|
|
|
361
344
|
| `solana_funding_instructions` | Deposit instructions |
|
|
362
345
|
| `solana_wallets` | List all wallets |
|
|
363
346
|
| `solana_wallet_create` | Create a new wallet |
|
|
347
|
+
| `solana_wallet_token_balance` | Get SPL token balance for a specific mint |
|
|
348
|
+
| `solana_sweep_dead_tokens` | Sell losing positions below loss threshold to cut losses and reclaim SOL |
|
|
364
349
|
|
|
365
350
|
### Entitlements
|
|
366
351
|
| Tool | Description |
|
|
@@ -385,6 +370,13 @@ Free tier is sufficient for daily trade journaling. Pay-as-you-go is recommended
|
|
|
385
370
|
| `solana_alpha_signals` | Retrieve buffered alpha signals |
|
|
386
371
|
| `solana_alpha_history` | Query historical alpha signals |
|
|
387
372
|
| `solana_alpha_sources` | Get source reputation statistics |
|
|
373
|
+
| `solana_alpha_submit` | Submit candidate to alpha buffer for next heartbeat evaluation |
|
|
374
|
+
|
|
375
|
+
### Firehose
|
|
376
|
+
| Tool | Description |
|
|
377
|
+
|------|-------------|
|
|
378
|
+
| `solana_firehose_config` | Configure firehose filter parameters (volume, buyers, whale detection) |
|
|
379
|
+
| `solana_firehose_status` | Check firehose health, throughput, and connection state |
|
|
388
380
|
|
|
389
381
|
### Bitquery Deep Scans
|
|
390
382
|
| Tool | Description |
|
|
@@ -412,7 +404,7 @@ Free tier is sufficient for daily trade journaling. Pay-as-you-go is recommended
|
|
|
412
404
|
### Local Durable State
|
|
413
405
|
| Tool | Description |
|
|
414
406
|
|------|-------------|
|
|
415
|
-
| `solana_state_save` | Save agent state to local JSON (also writes
|
|
407
|
+
| `solana_state_save` | Save agent state to local JSON (also writes MEMORY.md) |
|
|
416
408
|
| `solana_state_read` | Read agent state from local JSON |
|
|
417
409
|
|
|
418
410
|
### Episodic Decision Log
|
|
@@ -438,7 +430,29 @@ Free tier is sufficient for daily trade journaling. Pay-as-you-go is recommended
|
|
|
438
430
|
| `solana_compute_confidence` | Weighted confidence score (on-chain, signal, social, smart money, risk penalty) |
|
|
439
431
|
| `solana_compute_freshness_decay` | Freshness decay factor by signal age |
|
|
440
432
|
| `solana_compute_position_limits` | Full position sizing ladder with reduction breakdown |
|
|
441
|
-
| `
|
|
433
|
+
| `solana_compute_deployer_risk` | Deployer wallet risk classification (LOW/MEDIUM/HIGH) |
|
|
434
|
+
| `solana_classify_deployer_risk` | Backward-compatible alias for solana_compute_deployer_risk |
|
|
435
|
+
|
|
436
|
+
### Intelligence Lab (New in V1-Upgraded)
|
|
437
|
+
| Tool | Description |
|
|
438
|
+
|------|-------------|
|
|
439
|
+
| `solana_candidate_write` | Write a trading candidate for evaluation |
|
|
440
|
+
| `solana_candidate_get` | Get a trading candidate by ID |
|
|
441
|
+
| `solana_candidate_label_outcome` | Label a candidate with actual outcome |
|
|
442
|
+
| `solana_candidate_delta` | Compute prediction delta for a candidate |
|
|
443
|
+
| `solana_source_trust_refresh` | Refresh trust scores for intelligence sources |
|
|
444
|
+
| `solana_source_trust_get` | Get current trust score for a source |
|
|
445
|
+
| `solana_model_score_candidate` | Score a candidate using the active model |
|
|
446
|
+
| `solana_model_registry` | List registered scoring models |
|
|
447
|
+
| `solana_model_promote` | Promote a challenger model to active |
|
|
448
|
+
| `solana_contradiction_check` | Check for contradictions in signal data |
|
|
449
|
+
| `solana_dataset_export` | Export labeled dataset for analysis |
|
|
450
|
+
| `solana_deployer_trust_get` | Get deployer trust profile |
|
|
451
|
+
| `solana_deployer_trust_refresh` | Refresh deployer trust from on-chain data |
|
|
452
|
+
| `solana_evaluation_report` | Generate intelligence evaluation report |
|
|
453
|
+
| `solana_replay_run` | Run a replay of historical decisions |
|
|
454
|
+
| `solana_replay_report` | Get results of a replay run |
|
|
455
|
+
| `solana_scrub_untrusted_text` | Scrub untrusted text for prompt injection |
|
|
442
456
|
|
|
443
457
|
### Deep Analysis
|
|
444
458
|
| Tool | Description |
|
|
@@ -451,13 +465,11 @@ Free tier is sufficient for daily trade journaling. Pay-as-you-go is recommended
|
|
|
451
465
|
|------|-------------|
|
|
452
466
|
| `solana_daily_log` | Append to today's daily log (auto-loaded by OpenClaw next session, 7-day prune) |
|
|
453
467
|
|
|
454
|
-
### X/Twitter
|
|
468
|
+
### X/Twitter (Read-Only Social Intel)
|
|
455
469
|
| Tool | Description |
|
|
456
470
|
|------|-------------|
|
|
457
|
-
| `x_post_tweet` | Post a tweet from the agent's configured X profile (max 280 chars) |
|
|
458
|
-
| `x_reply_tweet` | Reply to a specific tweet |
|
|
459
|
-
| `x_read_mentions` | Read recent @mentions (pay-as-you-go tier) |
|
|
460
471
|
| `x_search_tweets` | Search recent tweets by keyword/hashtag |
|
|
472
|
+
| `x_read_mentions` | Read recent @mentions (pay-as-you-go tier) |
|
|
461
473
|
| `x_get_thread` | Read a full conversation thread |
|
|
462
474
|
|
|
463
475
|
## Hooks (2)
|
|
@@ -465,7 +477,7 @@ Free tier is sufficient for daily trade journaling. Pay-as-you-go is recommended
|
|
|
465
477
|
| Hook | Trigger | What It Does |
|
|
466
478
|
|------|---------|--------------|
|
|
467
479
|
| `agent:bootstrap` | Every session start | Injects durable state, decisions, bulletin, snapshot, and entitlements into context |
|
|
468
|
-
| `memory:flush` | Before OpenClaw context compaction | Syncs
|
|
480
|
+
| `memory:flush` | Before OpenClaw context compaction | Syncs MEMORY.md from persisted state, writes compaction marker to daily log |
|
|
469
481
|
|
|
470
482
|
## Skills
|
|
471
483
|
|
|
@@ -473,7 +485,7 @@ Free tier is sufficient for daily trade journaling. Pay-as-you-go is recommended
|
|
|
473
485
|
The primary skill that teaches OpenClaw the complete trading lifecycle:
|
|
474
486
|
|
|
475
487
|
1. **SCAN** — Find opportunities with launch/hot-pair scanners
|
|
476
|
-
2. **ANALYZE** — Deep dive with
|
|
488
|
+
2. **ANALYZE** — Deep dive with 6 token analysis tools
|
|
477
489
|
3. **THESIS** — Assemble full context with build_thesis
|
|
478
490
|
4. **DECIDE** — Agent reasons over data using confidence scoring
|
|
479
491
|
5. **PRECHECK** — Validate against risk rules
|
|
@@ -527,13 +539,6 @@ Trade executed. TradeId: 15, PositionId: 4, TX: 5xK...
|
|
|
527
539
|
I'll monitor this position and review after exit.
|
|
528
540
|
```
|
|
529
541
|
|
|
530
|
-
## Session and file reload
|
|
531
|
-
|
|
532
|
-
- **Telegram:** use **`/new`** to start a fresh chat thread or **`/reset`** to reset session state with your provider, as supported by your Telegram bot integration.
|
|
533
|
-
- **After editing workspace files** (`HEARTBEAT.md`, `STATE.md`, `MEMORY.md`, skills): restart the gateway so changes are picked up consistently: `openclaw gateway restart`.
|
|
534
|
-
- **History:** OpenClaw may not ship `openclaw agents clear-history` on your build — do not rely on that subcommand; prefer Telegram session commands and gateway restart.
|
|
535
|
-
- **Heartbeats:** fresh installs set `heartbeat.target: "telegram"`, `isolatedSession: true`, `lightContext: true`, and `channels.defaults.heartbeat.showOk: true` so scheduled cycles deliver reliably (see installer `configureGatewayScheduling`).
|
|
536
|
-
|
|
537
542
|
## Troubleshooting
|
|
538
543
|
|
|
539
544
|
**Plugin won't load:**
|
|
@@ -554,29 +559,6 @@ I'll monitor this position and review after exit.
|
|
|
554
559
|
- Run `traderclaw setup` to create or select a wallet
|
|
555
560
|
- Verify the wallet ID: `traderclaw config show`
|
|
556
561
|
|
|
557
|
-
**Wizard (`traderclaw install --wizard`) fails on `install_plugin_package` with `ENOENT` / `…/solana-traderclaw/package.json` / `file:solana-traderclaw`:**
|
|
558
|
-
- Older installers used `spawn` with `shell: true`, which on Linux could drop npm’s argv so npm treated the package as a **local folder** under cwd (`/root` or `/tmp`). Current installers use **`shell: false`**, explicit **`--registry https://registry.npmjs.org/`** for registry installs, **`solana-traderclaw@latest`**, and a temp **`cwd`**. Upgrade `solana-traderclaw` and retry. If a stray directory `./solana-traderclaw` exists under that cwd, remove it: `rm -rf /tmp/solana-traderclaw` (and under `/root` if present).
|
|
559
|
-
|
|
560
|
-
**Heartbeat not sending messages to Telegram:**
|
|
561
|
-
- **Fresh `traderclaw setup`:** the installer runs `configureGatewayScheduling`, which sets a custom `heartbeat.prompt` on the `main` agent (no `HEARTBEAT_OK` escape). You only need the manual `openclaw config set` command below if you are on an older install or overwrote `agents.list`.
|
|
562
|
-
- **`HEARTBEAT.md` must live in the agent workspace root** (default `~/.openclaw/workspace/HEARTBEAT.md`, next to `AGENTS.md`). A copy under `workspace/.openclaw/` or only inside the plugin package is **not** loaded as the heartbeat checklist. Copy from `skills/solana-trader/HEARTBEAT.md` in the installed package if needed. See [OpenClaw agent workspace](https://docs.openclaw.ai/concepts/agent-workspace).
|
|
563
|
-
- OpenClaw's default heartbeat prompt tells the model "If nothing needs attention, reply HEARTBEAT_OK" — which is stripped and never delivered. Run `traderclaw setup` again (v1.0.16+) to set a custom prompt, or apply manually:
|
|
564
|
-
|
|
565
|
-
```bash
|
|
566
|
-
openclaw config set agents.list '[{"id":"main","default":true,"heartbeat":{"every":"30m","target":"telegram","isolatedSession":true,"lightContext":true,"prompt":"Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Execute a full trading cycle: Steps 0 through 10. The cycle is NOT complete until all 10 steps are done including Step 8 (memory write-back), Step 9 (X post), and Step 10 (report). Do not stop early. Do not infer or repeat old tasks from prior chats. Never reply HEARTBEAT_OK. Never end your message with a question."}}]'
|
|
567
|
-
openclaw gateway restart
|
|
568
|
-
```
|
|
569
|
-
|
|
570
|
-
- Verify with `openclaw config get agents` — the `main` agent should have `heartbeat.prompt`, `target`, `isolatedSession`, and `lightContext`.
|
|
571
|
-
- Confirm Telegram is healthy: `openclaw channels status --probe`
|
|
572
|
-
- Prefer `target: "telegram"` over `"last"` so delivery does not depend on a prior channel contact.
|
|
573
|
-
|
|
574
|
-
**Scheduled cron jobs run but you never see Telegram/WhatsApp output:**
|
|
575
|
-
- The installer merges **six** prescriptive managed jobs (`alpha-scan`, `dead-money-sweep`, `source-reputation-recalc`, `meta-rotation-analysis`, `strategy-evolution`, `daily-performance-report`). Older templates such as `subscription-cleanup` or `whale-watch` are no longer in that managed set; re-run **`traderclaw setup`** to refresh `~/.openclaw/cron/jobs.json`, or edit jobs manually. User-defined cron jobs whose ids are not in the template set are preserved on merge.
|
|
576
|
-
- TraderClaw templates merged into `~/.openclaw/cron/jobs.json` use **`delivery.mode: "announce"`** with **`channel: "last"`** so each completed isolated job posts a summary to the same channel you last used (see [OpenClaw cron delivery](https://docs.clawd.bot/automation/cron-jobs)).
|
|
577
|
-
- If you installed before this behavior: run **`traderclaw setup`** again so the installer re-merges cron jobs, or stop the gateway and edit managed job entries in `~/.openclaw/cron/jobs.json` — set **`delivery`** to `{ "mode": "announce", "channel": "last", "bestEffort": true }` for each TraderClaw job (or remove `delivery` entirely; isolated jobs default to announce when omitted).
|
|
578
|
-
- The same **`last`** requirement as heartbeat applies: message the bot at least once so the gateway knows where to deliver.
|
|
579
|
-
|
|
580
562
|
**Tools returning errors:**
|
|
581
563
|
- Run `traderclaw status` to check system health
|
|
582
564
|
- Check if kill switch is enabled
|
|
@@ -585,7 +567,5 @@ openclaw gateway restart
|
|
|
585
567
|
**Memory/state not persisting:**
|
|
586
568
|
- Check that the `dataDir` config points to a writable location
|
|
587
569
|
- Default is `<cwd>/.traderclaw-v1-data` — verify permissions
|
|
588
|
-
- Check
|
|
589
|
-
- Check `memory/`
|
|
590
|
-
|
|
591
|
-
**X / Twitter posting:** with X credentials and skills aligned, `x_post_tweet` has been validated end-to-end in production installs after config + workspace updates.
|
|
570
|
+
- Check `MEMORY.md` exists at project root after first `solana_state_save` call
|
|
571
|
+
- Check `memory/` directory for daily log files
|
|
@@ -55,8 +55,105 @@ function getNpmGlobalInstallCwd() {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
/** Older `plugins.entries` keys / npm-era ids
|
|
59
|
-
const LEGACY_TRADER_PLUGIN_IDS = ["traderclaw-v1", "solana-traderclaw-v1", "solana-
|
|
58
|
+
/** Older `plugins.entries` keys / npm-era ids for the v1 plugin. */
|
|
59
|
+
const LEGACY_TRADER_PLUGIN_IDS = ["traderclaw-v1", "solana-traderclaw-v1", "solana-traderclaw"];
|
|
60
|
+
|
|
61
|
+
function isRecord(value) {
|
|
62
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getLegacyTraderPluginIds(pluginId) {
|
|
66
|
+
return pluginId === "solana-trader" ? LEGACY_TRADER_PLUGIN_IDS : [];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function normalizeTraderPluginEntries(config, pluginId) {
|
|
70
|
+
if (!isRecord(config)) return false;
|
|
71
|
+
if (!isRecord(config.plugins)) config.plugins = {};
|
|
72
|
+
if (!isRecord(config.plugins.entries)) config.plugins.entries = {};
|
|
73
|
+
|
|
74
|
+
const entries = config.plugins.entries;
|
|
75
|
+
const legacyIds = getLegacyTraderPluginIds(pluginId);
|
|
76
|
+
if (legacyIds.length === 0) return false;
|
|
77
|
+
|
|
78
|
+
let touched = false;
|
|
79
|
+
let hasSource = false;
|
|
80
|
+
let enabledSeen = false;
|
|
81
|
+
let enabledValue = false;
|
|
82
|
+
let mergedConfig = {};
|
|
83
|
+
|
|
84
|
+
for (const sourceId of [...legacyIds, pluginId]) {
|
|
85
|
+
const entry = entries[sourceId];
|
|
86
|
+
if (!isRecord(entry)) continue;
|
|
87
|
+
hasSource = true;
|
|
88
|
+
if (typeof entry.enabled === "boolean") {
|
|
89
|
+
enabledSeen = true;
|
|
90
|
+
enabledValue = enabledValue || entry.enabled;
|
|
91
|
+
}
|
|
92
|
+
if (isRecord(entry.config)) {
|
|
93
|
+
mergedConfig = { ...mergedConfig, ...entry.config };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!hasSource) return false;
|
|
98
|
+
|
|
99
|
+
const canonicalEntry = isRecord(entries[pluginId]) ? entries[pluginId] : {};
|
|
100
|
+
const nextEntry = {
|
|
101
|
+
...canonicalEntry,
|
|
102
|
+
enabled: typeof canonicalEntry.enabled === "boolean" ? canonicalEntry.enabled : (enabledSeen ? enabledValue : true),
|
|
103
|
+
config: mergedConfig,
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
if (entries[pluginId] !== nextEntry) {
|
|
107
|
+
entries[pluginId] = nextEntry;
|
|
108
|
+
touched = true;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
for (const legacyId of legacyIds) {
|
|
112
|
+
if (Object.prototype.hasOwnProperty.call(entries, legacyId)) {
|
|
113
|
+
delete entries[legacyId];
|
|
114
|
+
touched = true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return touched;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function normalizeTraderAllowlist(config, pluginId) {
|
|
122
|
+
if (!isRecord(config?.plugins)) return false;
|
|
123
|
+
const legacyIds = new Set(getLegacyTraderPluginIds(pluginId));
|
|
124
|
+
if (legacyIds.size === 0 || !Array.isArray(config.plugins.allow)) return false;
|
|
125
|
+
|
|
126
|
+
const nextAllow = [];
|
|
127
|
+
const seen = new Set();
|
|
128
|
+
let touched = false;
|
|
129
|
+
|
|
130
|
+
for (const id of config.plugins.allow) {
|
|
131
|
+
if (typeof id !== "string") {
|
|
132
|
+
touched = true;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const trimmed = id.trim();
|
|
136
|
+
if (!trimmed) {
|
|
137
|
+
touched = true;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (legacyIds.has(trimmed)) {
|
|
141
|
+
touched = true;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (seen.has(trimmed)) {
|
|
145
|
+
touched = true;
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
seen.add(trimmed);
|
|
149
|
+
nextAllow.push(trimmed);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (touched) {
|
|
153
|
+
config.plugins.allow = nextAllow;
|
|
154
|
+
}
|
|
155
|
+
return touched;
|
|
156
|
+
}
|
|
60
157
|
|
|
61
158
|
function stripAnsi(text) {
|
|
62
159
|
if (typeof text !== "string") return text;
|
|
@@ -433,6 +530,9 @@ function seedPluginConfig(modeConfig, orchestratorUrl, configPath = CONFIG_FILE)
|
|
|
433
530
|
if (!config.plugins || typeof config.plugins !== "object") config.plugins = {};
|
|
434
531
|
if (!config.plugins.entries || typeof config.plugins.entries !== "object") config.plugins.entries = {};
|
|
435
532
|
|
|
533
|
+
normalizeTraderPluginEntries(config, modeConfig.pluginId);
|
|
534
|
+
normalizeTraderAllowlist(config, modeConfig.pluginId);
|
|
535
|
+
|
|
436
536
|
const entries = config.plugins.entries;
|
|
437
537
|
|
|
438
538
|
const mergeOrchestratorForId = (pluginId) => {
|
|
@@ -453,9 +553,6 @@ function seedPluginConfig(modeConfig, orchestratorUrl, configPath = CONFIG_FILE)
|
|
|
453
553
|
};
|
|
454
554
|
|
|
455
555
|
mergeOrchestratorForId(modeConfig.pluginId);
|
|
456
|
-
for (const legacyId of LEGACY_TRADER_PLUGIN_IDS) {
|
|
457
|
-
if (entries[legacyId]) mergeOrchestratorForId(legacyId);
|
|
458
|
-
}
|
|
459
556
|
|
|
460
557
|
// Do not set plugins.allow here: OpenClaw validates allow[] against the plugin registry, and
|
|
461
558
|
// the id is not registered until after `openclaw plugins install`. Pre-seeding allow caused:
|
|
@@ -596,6 +693,8 @@ function mergePluginsAllowlist(modeConfig, configPath = CONFIG_FILE) {
|
|
|
596
693
|
return;
|
|
597
694
|
}
|
|
598
695
|
if (!config.plugins || typeof config.plugins !== "object") config.plugins = {};
|
|
696
|
+
normalizeTraderPluginEntries(config, modeConfig.pluginId);
|
|
697
|
+
normalizeTraderAllowlist(config, modeConfig.pluginId);
|
|
599
698
|
const allowSet = new Set(
|
|
600
699
|
Array.isArray(config.plugins.allow) ? config.plugins.allow.filter((id) => typeof id === "string" && id.trim()) : [],
|
|
601
700
|
);
|
|
@@ -972,6 +1071,8 @@ function seedXConfig(modeConfig, configPath = CONFIG_FILE, wizardOpts = {}) {
|
|
|
972
1071
|
|
|
973
1072
|
if (!config.plugins || typeof config.plugins !== "object") config.plugins = {};
|
|
974
1073
|
if (!config.plugins.entries || typeof config.plugins.entries !== "object") config.plugins.entries = {};
|
|
1074
|
+
normalizeTraderPluginEntries(config, modeConfig.pluginId);
|
|
1075
|
+
normalizeTraderAllowlist(config, modeConfig.pluginId);
|
|
975
1076
|
|
|
976
1077
|
const entry = config.plugins.entries[modeConfig.pluginId];
|
|
977
1078
|
if (!entry || typeof entry !== "object") return { skipped: true, reason: "plugin entry not found" };
|
|
@@ -1047,6 +1148,8 @@ function persistXProfileIdentities(configPath, modeConfig, identities) {
|
|
|
1047
1148
|
} catch {
|
|
1048
1149
|
return { written: 0 };
|
|
1049
1150
|
}
|
|
1151
|
+
normalizeTraderPluginEntries(config, modeConfig.pluginId);
|
|
1152
|
+
normalizeTraderAllowlist(config, modeConfig.pluginId);
|
|
1050
1153
|
const entry = config?.plugins?.entries?.[modeConfig.pluginId];
|
|
1051
1154
|
if (!entry?.config?.x?.profiles || typeof entry.config.x.profiles !== "object") return { written: 0 };
|
|
1052
1155
|
|
package/bin/openclaw-trader.mjs
CHANGED
|
@@ -13,6 +13,7 @@ const PACKAGE_JSON = JSON.parse(readFileSync(new URL("../package.json", import.m
|
|
|
13
13
|
const VERSION = PACKAGE_JSON.version;
|
|
14
14
|
const NPM_PACKAGE_NAME = typeof PACKAGE_JSON.name === "string" ? PACKAGE_JSON.name : "solana-traderclaw";
|
|
15
15
|
const PLUGIN_ID = "solana-trader";
|
|
16
|
+
const LEGACY_PLUGIN_IDS = ["traderclaw-v1", "solana-traderclaw-v1", "solana-traderclaw"];
|
|
16
17
|
const CONFIG_DIR = join(homedir(), ".openclaw");
|
|
17
18
|
const CONFIG_FILE = join(CONFIG_DIR, "openclaw.json");
|
|
18
19
|
const WALLET_PRIVATE_KEY_ENV = "TRADERCLAW_WALLET_PRIVATE_KEY";
|
|
@@ -166,11 +167,69 @@ function readConfig() {
|
|
|
166
167
|
}
|
|
167
168
|
|
|
168
169
|
function writeConfig(config) {
|
|
170
|
+
normalizePluginConfigShape(config);
|
|
169
171
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
170
172
|
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
171
173
|
}
|
|
172
174
|
|
|
175
|
+
function isRecord(value) {
|
|
176
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function normalizePluginConfigShape(config) {
|
|
180
|
+
if (!isRecord(config)) return config;
|
|
181
|
+
if (!isRecord(config.plugins)) config.plugins = {};
|
|
182
|
+
const plugins = config.plugins;
|
|
183
|
+
if (!isRecord(plugins.entries)) plugins.entries = {};
|
|
184
|
+
const entries = plugins.entries;
|
|
185
|
+
|
|
186
|
+
let enabledSeen = false;
|
|
187
|
+
let enabledValue = false;
|
|
188
|
+
let mergedConfig = {};
|
|
189
|
+
let found = false;
|
|
190
|
+
|
|
191
|
+
for (const sourceId of [...LEGACY_PLUGIN_IDS, PLUGIN_ID]) {
|
|
192
|
+
const entry = entries[sourceId];
|
|
193
|
+
if (!isRecord(entry)) continue;
|
|
194
|
+
found = true;
|
|
195
|
+
if (typeof entry.enabled === "boolean") {
|
|
196
|
+
enabledSeen = true;
|
|
197
|
+
enabledValue = enabledValue || entry.enabled;
|
|
198
|
+
}
|
|
199
|
+
if (isRecord(entry.config)) {
|
|
200
|
+
mergedConfig = { ...mergedConfig, ...entry.config };
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (found) {
|
|
205
|
+
const canonical = isRecord(entries[PLUGIN_ID]) ? entries[PLUGIN_ID] : {};
|
|
206
|
+
entries[PLUGIN_ID] = {
|
|
207
|
+
...canonical,
|
|
208
|
+
enabled: typeof canonical.enabled === "boolean" ? canonical.enabled : (enabledSeen ? enabledValue : true),
|
|
209
|
+
config: mergedConfig,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
for (const legacyId of LEGACY_PLUGIN_IDS) {
|
|
214
|
+
delete entries[legacyId];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (Array.isArray(plugins.allow)) {
|
|
218
|
+
const seen = new Set();
|
|
219
|
+
plugins.allow = plugins.allow.filter((id) => {
|
|
220
|
+
if (typeof id !== "string") return false;
|
|
221
|
+
const trimmed = id.trim();
|
|
222
|
+
if (!trimmed || LEGACY_PLUGIN_IDS.includes(trimmed) || seen.has(trimmed)) return false;
|
|
223
|
+
seen.add(trimmed);
|
|
224
|
+
return true;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return config;
|
|
229
|
+
}
|
|
230
|
+
|
|
173
231
|
function getPluginConfig(config) {
|
|
232
|
+
normalizePluginConfigShape(config);
|
|
174
233
|
const plugins = config.plugins;
|
|
175
234
|
if (!plugins) return null;
|
|
176
235
|
const entries = plugins.entries;
|
|
@@ -181,6 +240,7 @@ function getPluginConfig(config) {
|
|
|
181
240
|
}
|
|
182
241
|
|
|
183
242
|
function setPluginConfig(config, pluginConfig) {
|
|
243
|
+
normalizePluginConfigShape(config);
|
|
184
244
|
if (!config.plugins) config.plugins = {};
|
|
185
245
|
if (!config.plugins.entries) config.plugins.entries = {};
|
|
186
246
|
config.plugins.entries[PLUGIN_ID] = {
|