traderclaw-v1 1.0.3 → 1.0.4
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/bin/openclaw-trader.mjs +114 -8
- package/package.json +1 -1
package/bin/openclaw-trader.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from "path";
|
|
|
6
6
|
import { homedir } from "os";
|
|
7
7
|
import { randomUUID, createPrivateKey, sign as cryptoSign } from "crypto";
|
|
8
8
|
|
|
9
|
-
const VERSION = "
|
|
9
|
+
const VERSION = "1.0.4";
|
|
10
10
|
const PLUGIN_ID = "solana-trader";
|
|
11
11
|
const CONFIG_DIR = join(homedir(), ".openclaw");
|
|
12
12
|
const CONFIG_FILE = join(CONFIG_DIR, "openclaw.json");
|
|
@@ -138,6 +138,49 @@ function setPluginConfig(config, pluginConfig) {
|
|
|
138
138
|
};
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
function extractWalletId(payload) {
|
|
142
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return null;
|
|
143
|
+
if (typeof payload.id === "string" || typeof payload.id === "number") return String(payload.id);
|
|
144
|
+
if (typeof payload.walletId === "string" || typeof payload.walletId === "number") return String(payload.walletId);
|
|
145
|
+
if (payload.wallet && typeof payload.wallet === "object" && !Array.isArray(payload.wallet)) {
|
|
146
|
+
if (typeof payload.wallet.id === "string" || typeof payload.wallet.id === "number") return String(payload.wallet.id);
|
|
147
|
+
if (typeof payload.wallet.walletId === "string" || typeof payload.wallet.walletId === "number") return String(payload.wallet.walletId);
|
|
148
|
+
}
|
|
149
|
+
if (payload.data && typeof payload.data === "object" && !Array.isArray(payload.data)) {
|
|
150
|
+
if (typeof payload.data.id === "string" || typeof payload.data.id === "number") return String(payload.data.id);
|
|
151
|
+
if (typeof payload.data.walletId === "string" || typeof payload.data.walletId === "number") return String(payload.data.walletId);
|
|
152
|
+
}
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function extractWalletKeys(payload) {
|
|
157
|
+
const scopes = [];
|
|
158
|
+
if (payload && typeof payload === "object" && !Array.isArray(payload)) {
|
|
159
|
+
scopes.push(payload);
|
|
160
|
+
if (payload.wallet && typeof payload.wallet === "object" && !Array.isArray(payload.wallet)) {
|
|
161
|
+
scopes.push(payload.wallet);
|
|
162
|
+
}
|
|
163
|
+
if (payload.data && typeof payload.data === "object" && !Array.isArray(payload.data)) {
|
|
164
|
+
scopes.push(payload.data);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const pick = (keys) => {
|
|
169
|
+
for (const scope of scopes) {
|
|
170
|
+
for (const key of keys) {
|
|
171
|
+
const val = scope[key];
|
|
172
|
+
if (typeof val === "string" && val.length > 0) return val;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return undefined;
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
publicKey: pick(["walletPublicKey", "publicKey", "address"]),
|
|
180
|
+
privateKey: pick(["walletPrivateKey", "privateKey", "secretKey"]),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
141
184
|
const BS58_CHARS = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
142
185
|
|
|
143
186
|
function b58Decode(str) {
|
|
@@ -334,6 +377,9 @@ async function cmdSetup(args) {
|
|
|
334
377
|
let apiKey = "";
|
|
335
378
|
let orchestratorUrl = "";
|
|
336
379
|
let externalUserId = "";
|
|
380
|
+
let walletPrivateKey = "";
|
|
381
|
+
let showApiKey = false;
|
|
382
|
+
let showWalletPrivateKey = false;
|
|
337
383
|
let doSignupFlow = false;
|
|
338
384
|
|
|
339
385
|
for (let i = 0; i < args.length; i++) {
|
|
@@ -346,6 +392,15 @@ async function cmdSetup(args) {
|
|
|
346
392
|
if ((args[i] === "--user-id") && args[i + 1]) {
|
|
347
393
|
externalUserId = args[++i];
|
|
348
394
|
}
|
|
395
|
+
if (args[i] === "--wallet-private-key" && args[i + 1]) {
|
|
396
|
+
walletPrivateKey = args[++i];
|
|
397
|
+
}
|
|
398
|
+
if (args[i] === "--show-api-key") {
|
|
399
|
+
showApiKey = true;
|
|
400
|
+
}
|
|
401
|
+
if (args[i] === "--show-wallet-private-key") {
|
|
402
|
+
showWalletPrivateKey = true;
|
|
403
|
+
}
|
|
349
404
|
if (args[i] === "--signup") {
|
|
350
405
|
doSignupFlow = true;
|
|
351
406
|
}
|
|
@@ -376,6 +431,7 @@ async function cmdSetup(args) {
|
|
|
376
431
|
apiKey = signupResult.apiKey;
|
|
377
432
|
printSuccess(` Signup successful!`);
|
|
378
433
|
printInfo(` API Key: ${maskKey(apiKey)}`);
|
|
434
|
+
if (showApiKey) printWarn(` Full API Key: ${apiKey}`);
|
|
379
435
|
printInfo(` Tier: ${signupResult.tier}`);
|
|
380
436
|
printInfo(` Scopes: ${signupResult.scopes.join(", ")}`);
|
|
381
437
|
} catch (err) {
|
|
@@ -398,6 +454,7 @@ async function cmdSetup(args) {
|
|
|
398
454
|
apiTimeout: 30000,
|
|
399
455
|
refreshToken: undefined,
|
|
400
456
|
walletPublicKey: undefined,
|
|
457
|
+
walletPrivateKey: walletPrivateKey || undefined,
|
|
401
458
|
};
|
|
402
459
|
|
|
403
460
|
let sessionTokens;
|
|
@@ -437,6 +494,7 @@ async function cmdSetup(args) {
|
|
|
437
494
|
|
|
438
495
|
let walletId = null;
|
|
439
496
|
let walletLabel = "";
|
|
497
|
+
let createdNewWallet = false;
|
|
440
498
|
|
|
441
499
|
try {
|
|
442
500
|
const walletsRes = await httpRequest(`${orchestratorUrl}/api/wallets`, { accessToken });
|
|
@@ -453,11 +511,18 @@ async function cmdSetup(args) {
|
|
|
453
511
|
walletLabel = await prompt("Wallet label", "Trading Wallet");
|
|
454
512
|
const createRes = await httpRequest(`${orchestratorUrl}/api/wallet/create`, {
|
|
455
513
|
method: "POST",
|
|
456
|
-
body: { label: walletLabel, strategyProfile: "aggressive" },
|
|
514
|
+
body: { label: walletLabel, strategyProfile: "aggressive", includePrivateKey: true },
|
|
457
515
|
accessToken,
|
|
458
516
|
});
|
|
459
517
|
if (createRes.ok) {
|
|
460
|
-
|
|
518
|
+
createdNewWallet = true;
|
|
519
|
+
walletId = extractWalletId(createRes.data);
|
|
520
|
+
if (!walletId) {
|
|
521
|
+
throw new Error(`Wallet create response missing wallet ID: ${JSON.stringify(createRes.data)}`);
|
|
522
|
+
}
|
|
523
|
+
const keys = extractWalletKeys(createRes.data);
|
|
524
|
+
if (keys.publicKey) pluginConfig.walletPublicKey = keys.publicKey;
|
|
525
|
+
if (keys.privateKey && !pluginConfig.walletPrivateKey) pluginConfig.walletPrivateKey = keys.privateKey;
|
|
461
526
|
printSuccess(` Wallet created (ID: ${walletId})`);
|
|
462
527
|
} else {
|
|
463
528
|
printError("Failed to create wallet");
|
|
@@ -467,12 +532,16 @@ async function cmdSetup(args) {
|
|
|
467
532
|
} else {
|
|
468
533
|
const idx = parseInt(choice, 10) - 1;
|
|
469
534
|
if (idx >= 0 && idx < wallets.length) {
|
|
470
|
-
walletId = wallets[idx].id;
|
|
535
|
+
walletId = extractWalletId(wallets[idx]) || String(wallets[idx].id);
|
|
471
536
|
walletLabel = wallets[idx].label || "Unnamed";
|
|
537
|
+
const keys = extractWalletKeys(wallets[idx]);
|
|
538
|
+
if (keys.publicKey) pluginConfig.walletPublicKey = keys.publicKey;
|
|
472
539
|
printSuccess(` Using wallet: ${walletLabel} (ID: ${walletId})`);
|
|
473
540
|
} else {
|
|
474
|
-
walletId = wallets[0].id;
|
|
541
|
+
walletId = extractWalletId(wallets[0]) || String(wallets[0].id);
|
|
475
542
|
walletLabel = wallets[0].label || "Unnamed";
|
|
543
|
+
const keys = extractWalletKeys(wallets[0]);
|
|
544
|
+
if (keys.publicKey) pluginConfig.walletPublicKey = keys.publicKey;
|
|
476
545
|
printSuccess(` Using wallet: ${walletLabel} (ID: ${walletId})`);
|
|
477
546
|
}
|
|
478
547
|
}
|
|
@@ -481,11 +550,18 @@ async function cmdSetup(args) {
|
|
|
481
550
|
walletLabel = await prompt("Wallet label", "Trading Wallet");
|
|
482
551
|
const createRes = await httpRequest(`${orchestratorUrl}/api/wallet/create`, {
|
|
483
552
|
method: "POST",
|
|
484
|
-
body: { label: walletLabel, strategyProfile: "aggressive" },
|
|
553
|
+
body: { label: walletLabel, strategyProfile: "aggressive", includePrivateKey: true },
|
|
485
554
|
accessToken,
|
|
486
555
|
});
|
|
487
556
|
if (createRes.ok) {
|
|
488
|
-
|
|
557
|
+
createdNewWallet = true;
|
|
558
|
+
walletId = extractWalletId(createRes.data);
|
|
559
|
+
if (!walletId) {
|
|
560
|
+
throw new Error(`Wallet create response missing wallet ID: ${JSON.stringify(createRes.data)}`);
|
|
561
|
+
}
|
|
562
|
+
const keys = extractWalletKeys(createRes.data);
|
|
563
|
+
if (keys.publicKey) pluginConfig.walletPublicKey = keys.publicKey;
|
|
564
|
+
if (keys.privateKey && !pluginConfig.walletPrivateKey) pluginConfig.walletPrivateKey = keys.privateKey;
|
|
489
565
|
printSuccess(` Wallet created (ID: ${walletId})`);
|
|
490
566
|
} else {
|
|
491
567
|
printError("Failed to create wallet");
|
|
@@ -509,13 +585,39 @@ async function cmdSetup(args) {
|
|
|
509
585
|
|
|
510
586
|
printSuccess(` Config written to ${CONFIG_FILE}`);
|
|
511
587
|
|
|
588
|
+
if (createdNewWallet) {
|
|
589
|
+
print("\n" + "=".repeat(60));
|
|
590
|
+
printWarn(" IMPORTANT: New wallet credentials");
|
|
591
|
+
print("=".repeat(60));
|
|
592
|
+
print(` Wallet Public Key: ${pluginConfig.walletPublicKey || "not returned by API"}`);
|
|
593
|
+
if (pluginConfig.walletPrivateKey) {
|
|
594
|
+
printWarn(` Wallet Private Key: ${pluginConfig.walletPrivateKey}`);
|
|
595
|
+
printWarn(" Save this private key now in a secure password manager.");
|
|
596
|
+
printWarn(" You may not be able to retrieve this private key again.");
|
|
597
|
+
} else {
|
|
598
|
+
printWarn(" Wallet private key was not returned by the API.");
|
|
599
|
+
printWarn(" If this is expected custody behavior, backup via your wallet provider.");
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if (pluginConfig.walletPrivateKey) {
|
|
603
|
+
const ack = await prompt("Type BACKED_UP to continue", "");
|
|
604
|
+
if (ack !== "BACKED_UP") {
|
|
605
|
+
printError("Backup confirmation not provided. Aborting setup to prevent key loss.");
|
|
606
|
+
process.exit(1);
|
|
607
|
+
}
|
|
608
|
+
printSuccess(" Backup confirmation received.");
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
512
612
|
print("\n" + "=".repeat(60));
|
|
513
613
|
printSuccess("\n Setup complete!\n");
|
|
514
614
|
print("=".repeat(60));
|
|
515
615
|
print(`
|
|
516
616
|
Orchestrator: ${orchestratorUrl}
|
|
517
617
|
Wallet: ${walletLabel} (ID: ${walletId})
|
|
518
|
-
|
|
618
|
+
Wallet PubKey: ${pluginConfig.walletPublicKey || "not set"}
|
|
619
|
+
Wallet PrivKey:${pluginConfig.walletPrivateKey ? (createdNewWallet || showWalletPrivateKey ? " " + pluginConfig.walletPrivateKey : " " + maskKey(pluginConfig.walletPrivateKey)) : " not set"}
|
|
620
|
+
API Key: ${showApiKey ? apiKey : maskKey(apiKey)}
|
|
519
621
|
Session: Active (tier: ${sessionTokens.session?.tier || "?"})
|
|
520
622
|
Config: ${CONFIG_FILE}
|
|
521
623
|
`);
|
|
@@ -748,6 +850,7 @@ async function cmdConfig(subArgs) {
|
|
|
748
850
|
print(` API Key: ${pluginConfig.apiKey ? maskKey(pluginConfig.apiKey) : "not set"}`);
|
|
749
851
|
print(` Refresh Token: ${pluginConfig.refreshToken ? maskKey(pluginConfig.refreshToken) : "not set"}`);
|
|
750
852
|
print(` Wallet Pub Key: ${pluginConfig.walletPublicKey || "not set"}`);
|
|
853
|
+
print(` Wallet Priv Key: ${pluginConfig.walletPrivateKey ? maskKey(pluginConfig.walletPrivateKey) : "not set"}`);
|
|
751
854
|
print(` API Timeout: ${pluginConfig.apiTimeout || 30000}ms`);
|
|
752
855
|
print("=".repeat(45));
|
|
753
856
|
print("");
|
|
@@ -835,6 +938,9 @@ Setup options:
|
|
|
835
938
|
--api-key, -k API key (skip interactive prompt)
|
|
836
939
|
--url, -u Orchestrator URL (skip interactive prompt)
|
|
837
940
|
--user-id External user ID for signup
|
|
941
|
+
--wallet-private-key Optional base58 private key for wallet proof flow
|
|
942
|
+
--show-api-key Reveal full API key in setup output
|
|
943
|
+
--show-wallet-private-key Reveal full wallet private key in setup output
|
|
838
944
|
--signup Force signup flow (create new account)
|
|
839
945
|
|
|
840
946
|
Config subcommands:
|