pandora-cli-skills 1.1.21 → 1.1.23
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/cli/lib/autopilot_state_store.cjs +6 -1
- package/cli/lib/mirror_daemon_service.cjs +44 -3
- package/cli/lib/mirror_state_store.cjs +7 -2
- package/cli/lib/mirror_sync_service.cjs +26 -16
- package/cli/lib/polymarket_trade_adapter.cjs +68 -22
- package/cli/pandora.cjs +32 -8
- package/package.json +1 -1
- package/scripts/.env.example +3 -0
|
@@ -111,8 +111,13 @@ function saveState(filePath, state) {
|
|
|
111
111
|
const lockFd = acquireLock(lockPath);
|
|
112
112
|
try {
|
|
113
113
|
const tmp = `${resolved}.${process.pid}.${Date.now()}.${crypto.randomBytes(4).toString('hex')}.tmp`;
|
|
114
|
-
fs.writeFileSync(tmp, JSON.stringify(state, null, 2));
|
|
114
|
+
fs.writeFileSync(tmp, JSON.stringify(state, null, 2), { mode: 0o600 });
|
|
115
115
|
fs.renameSync(tmp, resolved);
|
|
116
|
+
try {
|
|
117
|
+
fs.chmodSync(resolved, 0o600);
|
|
118
|
+
} catch {
|
|
119
|
+
// best-effort permission hardening
|
|
120
|
+
}
|
|
116
121
|
} finally {
|
|
117
122
|
try {
|
|
118
123
|
fs.closeSync(lockFd);
|
|
@@ -8,6 +8,13 @@ const { expandHome } = require('./mirror_state_store.cjs');
|
|
|
8
8
|
const MIRROR_DAEMON_SCHEMA_VERSION = '1.0.0';
|
|
9
9
|
const STOP_TIMEOUT_MS = 5_000;
|
|
10
10
|
const STOP_POLL_MS = 100;
|
|
11
|
+
const SENSITIVE_CLI_FLAGS = new Set([
|
|
12
|
+
'--private-key',
|
|
13
|
+
'--webhook-secret',
|
|
14
|
+
'--telegram-bot-token',
|
|
15
|
+
'--discord-webhook-url',
|
|
16
|
+
'--webhook-template',
|
|
17
|
+
]);
|
|
11
18
|
|
|
12
19
|
function createServiceError(code, message, details = undefined) {
|
|
13
20
|
const err = new Error(message);
|
|
@@ -30,6 +37,34 @@ function resolvePath(filePath) {
|
|
|
30
37
|
return path.resolve(expandHome(String(filePath || '').trim()));
|
|
31
38
|
}
|
|
32
39
|
|
|
40
|
+
function sanitizeCliArgs(args = []) {
|
|
41
|
+
const sanitized = [];
|
|
42
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
43
|
+
const token = String(args[i] || '');
|
|
44
|
+
const eqIndex = token.indexOf('=');
|
|
45
|
+
if (eqIndex > 0) {
|
|
46
|
+
const flag = token.slice(0, eqIndex);
|
|
47
|
+
if (SENSITIVE_CLI_FLAGS.has(flag)) {
|
|
48
|
+
sanitized.push(`${flag}=[redacted]`);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (SENSITIVE_CLI_FLAGS.has(token)) {
|
|
54
|
+
sanitized.push(token);
|
|
55
|
+
const next = i + 1 < args.length ? String(args[i + 1] || '') : '';
|
|
56
|
+
if (next && !next.startsWith('--')) {
|
|
57
|
+
sanitized.push('[redacted]');
|
|
58
|
+
i += 1;
|
|
59
|
+
}
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
sanitized.push(token);
|
|
64
|
+
}
|
|
65
|
+
return sanitized;
|
|
66
|
+
}
|
|
67
|
+
|
|
33
68
|
function defaultPidFile(strategyHash) {
|
|
34
69
|
const hash = normalizeStrategyHash(strategyHash);
|
|
35
70
|
return path.join(os.homedir(), '.pandora', 'mirror', 'daemon', `${hash}.json`);
|
|
@@ -44,8 +79,13 @@ function writeJsonFile(filePath, payload) {
|
|
|
44
79
|
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
45
80
|
const tmpPath = `${filePath}.${process.pid}.${Date.now()}.${crypto.randomBytes(4).toString('hex')}.tmp`;
|
|
46
81
|
const serialized = JSON.stringify(payload, null, 2);
|
|
47
|
-
fs.writeFileSync(tmpPath, serialized);
|
|
82
|
+
fs.writeFileSync(tmpPath, serialized, { mode: 0o600 });
|
|
48
83
|
fs.renameSync(tmpPath, filePath);
|
|
84
|
+
try {
|
|
85
|
+
fs.chmodSync(filePath, 0o600);
|
|
86
|
+
} catch {
|
|
87
|
+
// best-effort permission hardening
|
|
88
|
+
}
|
|
49
89
|
}
|
|
50
90
|
|
|
51
91
|
function readJsonFile(filePath) {
|
|
@@ -131,6 +171,7 @@ function startDaemon(options = {}) {
|
|
|
131
171
|
});
|
|
132
172
|
child.unref();
|
|
133
173
|
fs.closeSync(logFd);
|
|
174
|
+
const sanitizedCliArgs = sanitizeCliArgs(cliArgs);
|
|
134
175
|
|
|
135
176
|
const metadata = {
|
|
136
177
|
schemaVersion: MIRROR_DAEMON_SCHEMA_VERSION,
|
|
@@ -143,7 +184,7 @@ function startDaemon(options = {}) {
|
|
|
143
184
|
pidFile,
|
|
144
185
|
logFile,
|
|
145
186
|
cliPath,
|
|
146
|
-
cliArgs,
|
|
187
|
+
cliArgs: sanitizedCliArgs,
|
|
147
188
|
stateFile: options.stateFile || null,
|
|
148
189
|
killSwitchFile: options.killSwitchFile || null,
|
|
149
190
|
mode: options.mode || 'run',
|
|
@@ -151,7 +192,7 @@ function startDaemon(options = {}) {
|
|
|
151
192
|
pandoraMarketAddress: options.pandoraMarketAddress || null,
|
|
152
193
|
polymarketMarketId: options.polymarketMarketId || null,
|
|
153
194
|
polymarketSlug: options.polymarketSlug || null,
|
|
154
|
-
launchCommand: [process.execPath, cliPath, ...
|
|
195
|
+
launchCommand: [process.execPath, cliPath, ...sanitizedCliArgs].join(' '),
|
|
155
196
|
};
|
|
156
197
|
writeJsonFile(pidFile, metadata);
|
|
157
198
|
|
|
@@ -84,13 +84,18 @@ function saveState(filePath, state) {
|
|
|
84
84
|
fs.mkdirSync(path.dirname(resolved), { recursive: true });
|
|
85
85
|
const tmpPath = `${resolved}.${process.pid}.${Date.now()}.${crypto.randomBytes(4).toString('hex')}.tmp`;
|
|
86
86
|
const serialized = JSON.stringify(state, null, 2);
|
|
87
|
-
fs.writeFileSync(tmpPath, serialized);
|
|
87
|
+
fs.writeFileSync(tmpPath, serialized, { mode: 0o600 });
|
|
88
88
|
try {
|
|
89
89
|
fs.renameSync(tmpPath, resolved);
|
|
90
|
+
try {
|
|
91
|
+
fs.chmodSync(resolved, 0o600);
|
|
92
|
+
} catch {
|
|
93
|
+
// best-effort permission hardening
|
|
94
|
+
}
|
|
90
95
|
} catch (err) {
|
|
91
96
|
if (err && err.code === 'ENOENT') {
|
|
92
97
|
fs.mkdirSync(path.dirname(resolved), { recursive: true });
|
|
93
|
-
fs.writeFileSync(resolved, serialized);
|
|
98
|
+
fs.writeFileSync(resolved, serialized, { mode: 0o600 });
|
|
94
99
|
if (fs.existsSync(tmpPath)) {
|
|
95
100
|
try {
|
|
96
101
|
fs.unlinkSync(tmpPath);
|
|
@@ -504,27 +504,37 @@ async function runMirrorSync(options, deps = {}) {
|
|
|
504
504
|
if (options.executeLive) {
|
|
505
505
|
const envCreds = readTradingCredsFromEnv();
|
|
506
506
|
let hedgeResult;
|
|
507
|
-
|
|
508
|
-
hedgeResult = await hedgeFn({
|
|
509
|
-
host: options.polymarketHost,
|
|
510
|
-
mockUrl: options.polymarketMockUrl,
|
|
511
|
-
tokenId,
|
|
512
|
-
side: hedgeSide,
|
|
513
|
-
amountUsd: plannedHedgeUsdc,
|
|
514
|
-
privateKey: options.privateKey || envCreds.privateKey,
|
|
515
|
-
funder: options.funder || envCreds.funder,
|
|
516
|
-
apiKey: envCreds.apiKey,
|
|
517
|
-
apiSecret: envCreds.apiSecret,
|
|
518
|
-
apiPassphrase: envCreds.apiPassphrase,
|
|
519
|
-
});
|
|
520
|
-
} catch (err) {
|
|
507
|
+
if (!options.privateKey && envCreds.privateKeyInvalid) {
|
|
521
508
|
hedgeResult = {
|
|
522
509
|
ok: false,
|
|
523
510
|
error: {
|
|
524
|
-
code:
|
|
525
|
-
message:
|
|
511
|
+
code: 'INVALID_ENV',
|
|
512
|
+
message: 'POLYMARKET_PRIVATE_KEY must be a valid private key (0x + 64 hex chars).',
|
|
526
513
|
},
|
|
527
514
|
};
|
|
515
|
+
} else {
|
|
516
|
+
try {
|
|
517
|
+
hedgeResult = await hedgeFn({
|
|
518
|
+
host: options.polymarketHost,
|
|
519
|
+
mockUrl: options.polymarketMockUrl,
|
|
520
|
+
tokenId,
|
|
521
|
+
side: hedgeSide,
|
|
522
|
+
amountUsd: plannedHedgeUsdc,
|
|
523
|
+
privateKey: options.privateKey || envCreds.privateKey,
|
|
524
|
+
funder: options.funder || envCreds.funder,
|
|
525
|
+
apiKey: envCreds.apiKey,
|
|
526
|
+
apiSecret: envCreds.apiSecret,
|
|
527
|
+
apiPassphrase: envCreds.apiPassphrase,
|
|
528
|
+
});
|
|
529
|
+
} catch (err) {
|
|
530
|
+
hedgeResult = {
|
|
531
|
+
ok: false,
|
|
532
|
+
error: {
|
|
533
|
+
code: err && err.code ? String(err.code) : null,
|
|
534
|
+
message: err && err.message ? String(err.message) : String(err),
|
|
535
|
+
},
|
|
536
|
+
};
|
|
537
|
+
}
|
|
528
538
|
}
|
|
529
539
|
action.hedge = {
|
|
530
540
|
tokenId,
|
|
@@ -35,6 +35,10 @@ function isConditionId(value) {
|
|
|
35
35
|
return /^0x[a-fA-F0-9]{64}$/.test(String(value || '').trim());
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
function isValidPrivateKey(value) {
|
|
39
|
+
return /^0x[a-fA-F0-9]{64}$/.test(String(value || '').trim());
|
|
40
|
+
}
|
|
41
|
+
|
|
38
42
|
function toStringOrNull(value) {
|
|
39
43
|
const normalized = String(value || '').trim();
|
|
40
44
|
return normalized || null;
|
|
@@ -1032,8 +1036,11 @@ async function browsePolymarketMarkets(options = {}) {
|
|
|
1032
1036
|
}
|
|
1033
1037
|
|
|
1034
1038
|
function readTradingCredsFromEnv(env = process.env) {
|
|
1039
|
+
const rawPrivateKey = String(env.POLYMARKET_PRIVATE_KEY || '').trim();
|
|
1040
|
+
const privateKey = rawPrivateKey && isValidPrivateKey(rawPrivateKey) ? rawPrivateKey : null;
|
|
1035
1041
|
const creds = {
|
|
1036
|
-
privateKey
|
|
1042
|
+
privateKey,
|
|
1043
|
+
privateKeyInvalid: Boolean(rawPrivateKey && !privateKey),
|
|
1037
1044
|
funder: env.POLYMARKET_FUNDER || null,
|
|
1038
1045
|
apiKey: env.POLYMARKET_API_KEY || null,
|
|
1039
1046
|
apiSecret: env.POLYMARKET_API_SECRET || null,
|
|
@@ -1281,6 +1288,9 @@ async function fetchPolymarketPositionSummary(options = {}) {
|
|
|
1281
1288
|
}
|
|
1282
1289
|
|
|
1283
1290
|
const envCreds = readTradingCredsFromEnv(options.env || process.env);
|
|
1291
|
+
if (!options.privateKey && envCreds.privateKeyInvalid) {
|
|
1292
|
+
diagnostics.push('POLYMARKET_PRIVATE_KEY is set but invalid (expected 0x + 64 hex chars).');
|
|
1293
|
+
}
|
|
1284
1294
|
const privateKey = options.privateKey || envCreds.privateKey;
|
|
1285
1295
|
const funder = options.funder || envCreds.funder;
|
|
1286
1296
|
const apiKey = options.apiKey || envCreds.apiKey;
|
|
@@ -1413,6 +1423,8 @@ async function buildTradingClient(options = {}) {
|
|
|
1413
1423
|
const signatureType = resolveSignatureType(options);
|
|
1414
1424
|
const cacheKey = buildTradingCacheKey(host, chain, options);
|
|
1415
1425
|
const allowCache = options.disableCache !== true;
|
|
1426
|
+
const timeoutMs = Number.isInteger(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : 12_000;
|
|
1427
|
+
const ClobCtor = options.clobClientClass || ClobClient;
|
|
1416
1428
|
|
|
1417
1429
|
if (allowCache && tradingClientCache.has(cacheKey)) {
|
|
1418
1430
|
return tradingClientCache.get(cacheKey);
|
|
@@ -1443,7 +1455,7 @@ async function buildTradingClient(options = {}) {
|
|
|
1443
1455
|
if (allowCache && derivedCredsCache.has(cacheKey)) {
|
|
1444
1456
|
creds = derivedCredsCache.get(cacheKey);
|
|
1445
1457
|
} else {
|
|
1446
|
-
const bootstrap = new
|
|
1458
|
+
const bootstrap = new ClobCtor(
|
|
1447
1459
|
host,
|
|
1448
1460
|
chain,
|
|
1449
1461
|
signer,
|
|
@@ -1459,12 +1471,27 @@ async function buildTradingClient(options = {}) {
|
|
|
1459
1471
|
if (typeof bootstrap.deriveApiKey === 'function') {
|
|
1460
1472
|
try {
|
|
1461
1473
|
// deriveApiKey expects nonce, not signature type; default to nonce 0.
|
|
1462
|
-
creds = await
|
|
1463
|
-
|
|
1464
|
-
|
|
1474
|
+
creds = await callWithTimeout(
|
|
1475
|
+
() => bootstrap.deriveApiKey(0),
|
|
1476
|
+
timeoutMs,
|
|
1477
|
+
'Polymarket deriveApiKey(0)',
|
|
1478
|
+
);
|
|
1479
|
+
} catch (err) {
|
|
1480
|
+
if (err && typeof err.message === 'string' && err.message.includes('timed out')) {
|
|
1481
|
+
throw err;
|
|
1482
|
+
}
|
|
1483
|
+
creds = await callWithTimeout(
|
|
1484
|
+
() => bootstrap.deriveApiKey(),
|
|
1485
|
+
timeoutMs,
|
|
1486
|
+
'Polymarket deriveApiKey()',
|
|
1487
|
+
);
|
|
1465
1488
|
}
|
|
1466
1489
|
} else if (typeof bootstrap.createOrDeriveApiKey === 'function') {
|
|
1467
|
-
creds = await
|
|
1490
|
+
creds = await callWithTimeout(
|
|
1491
|
+
() => bootstrap.createOrDeriveApiKey(),
|
|
1492
|
+
timeoutMs,
|
|
1493
|
+
'Polymarket createOrDeriveApiKey()',
|
|
1494
|
+
);
|
|
1468
1495
|
} else {
|
|
1469
1496
|
throw new Error('CLOB client does not support API key derivation.');
|
|
1470
1497
|
}
|
|
@@ -1474,7 +1501,7 @@ async function buildTradingClient(options = {}) {
|
|
|
1474
1501
|
}
|
|
1475
1502
|
}
|
|
1476
1503
|
|
|
1477
|
-
const client = new
|
|
1504
|
+
const client = new ClobCtor(
|
|
1478
1505
|
host,
|
|
1479
1506
|
chain,
|
|
1480
1507
|
signer,
|
|
@@ -1528,25 +1555,44 @@ async function placeHedgeOrder(options = {}) {
|
|
|
1528
1555
|
const host = options.host || DEFAULT_POLYMARKET_HOST;
|
|
1529
1556
|
const chain = options.chain || DEFAULT_POLYMARKET_CHAIN;
|
|
1530
1557
|
const cacheKey = buildTradingCacheKey(host, chain, options);
|
|
1558
|
+
const timeoutMs = Number.isInteger(options.timeoutMs) && options.timeoutMs > 0 ? options.timeoutMs : 12_000;
|
|
1531
1559
|
const client = options.client || (await buildTradingClient(options));
|
|
1532
1560
|
const side = resolveOrderSide(options.side || 'buy');
|
|
1533
1561
|
try {
|
|
1534
|
-
const tickSize =
|
|
1535
|
-
|
|
1562
|
+
const tickSize =
|
|
1563
|
+
options.tickSize ||
|
|
1564
|
+
(await callWithTimeout(
|
|
1565
|
+
() => client.getTickSize(tokenId),
|
|
1566
|
+
timeoutMs,
|
|
1567
|
+
`Polymarket getTickSize(${tokenId})`,
|
|
1568
|
+
));
|
|
1569
|
+
const negRisk =
|
|
1570
|
+
typeof options.negRisk === 'boolean'
|
|
1571
|
+
? options.negRisk
|
|
1572
|
+
: await callWithTimeout(
|
|
1573
|
+
() => client.getNegRisk(tokenId),
|
|
1574
|
+
timeoutMs,
|
|
1575
|
+
`Polymarket getNegRisk(${tokenId})`,
|
|
1576
|
+
);
|
|
1536
1577
|
|
|
1537
|
-
const response = await
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1578
|
+
const response = await callWithTimeout(
|
|
1579
|
+
() =>
|
|
1580
|
+
client.createAndPostMarketOrder(
|
|
1581
|
+
{
|
|
1582
|
+
tokenID: tokenId,
|
|
1583
|
+
amount: amountUsd,
|
|
1584
|
+
side,
|
|
1585
|
+
orderType: OrderType.FAK,
|
|
1586
|
+
},
|
|
1587
|
+
{
|
|
1588
|
+
tickSize,
|
|
1589
|
+
negRisk,
|
|
1590
|
+
},
|
|
1591
|
+
OrderType.FAK,
|
|
1592
|
+
false,
|
|
1593
|
+
),
|
|
1594
|
+
timeoutMs,
|
|
1595
|
+
`Polymarket createAndPostMarketOrder(${tokenId})`,
|
|
1550
1596
|
);
|
|
1551
1597
|
const ok = responseIndicatesSuccess(response);
|
|
1552
1598
|
if (!ok && classifyAuthFailure(response)) {
|
package/cli/pandora.cjs
CHANGED
|
@@ -572,7 +572,7 @@ function emitJson(payload) {
|
|
|
572
572
|
}
|
|
573
573
|
|
|
574
574
|
function emitJsonError(payload) {
|
|
575
|
-
console.
|
|
575
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
576
576
|
}
|
|
577
577
|
|
|
578
578
|
function toErrorEnvelope(error) {
|
|
@@ -861,11 +861,17 @@ function parseAddressFlag(value, flagName) {
|
|
|
861
861
|
return value.toLowerCase();
|
|
862
862
|
}
|
|
863
863
|
|
|
864
|
+
function redactSensitiveValue(value) {
|
|
865
|
+
const text = String(value || '').trim();
|
|
866
|
+
if (!text || text.length <= 10) return '[redacted]';
|
|
867
|
+
return `${text.slice(0, 6)}...${text.slice(-4)}`;
|
|
868
|
+
}
|
|
869
|
+
|
|
864
870
|
function parsePrivateKeyFlag(value, flagName = '--private-key') {
|
|
865
871
|
if (!isValidPrivateKey(value)) {
|
|
866
872
|
throw new CliError(
|
|
867
873
|
'INVALID_FLAG_VALUE',
|
|
868
|
-
`${flagName} must be a valid private key (0x + 64 hex chars). Received: "${value}"`,
|
|
874
|
+
`${flagName} must be a valid private key (0x + 64 hex chars). Received: "${redactSensitiveValue(value)}"`,
|
|
869
875
|
);
|
|
870
876
|
}
|
|
871
877
|
return value;
|
|
@@ -5018,7 +5024,14 @@ function hasPolymarketDoctorInputs() {
|
|
|
5018
5024
|
}
|
|
5019
5025
|
|
|
5020
5026
|
function validateEnvValues() {
|
|
5021
|
-
const missing = REQUIRED_ENV_KEYS.filter((key) =>
|
|
5027
|
+
const missing = REQUIRED_ENV_KEYS.filter((key) => {
|
|
5028
|
+
if (key === 'PRIVATE_KEY') {
|
|
5029
|
+
const primary = String(process.env.PANDORA_PRIVATE_KEY || '').trim();
|
|
5030
|
+
const legacy = String(process.env.PRIVATE_KEY || '').trim();
|
|
5031
|
+
return !primary && !legacy;
|
|
5032
|
+
}
|
|
5033
|
+
return !process.env[key] || !String(process.env[key]).trim();
|
|
5034
|
+
});
|
|
5022
5035
|
const missingSet = new Set(missing);
|
|
5023
5036
|
const errors = [];
|
|
5024
5037
|
|
|
@@ -5038,9 +5051,11 @@ function validateEnvValues() {
|
|
|
5038
5051
|
errors.push(`RPC_URL must be a valid http/https URL. Received: "${rpcUrl}"`);
|
|
5039
5052
|
}
|
|
5040
5053
|
|
|
5041
|
-
const privateKey = String(process.env.PRIVATE_KEY || '').trim();
|
|
5054
|
+
const privateKey = String(process.env.PANDORA_PRIVATE_KEY || process.env.PRIVATE_KEY || '').trim();
|
|
5042
5055
|
if (!missingSet.has('PRIVATE_KEY') && !isValidPrivateKey(privateKey)) {
|
|
5043
|
-
errors.push(
|
|
5056
|
+
errors.push(
|
|
5057
|
+
'PANDORA_PRIVATE_KEY (preferred) or PRIVATE_KEY must be a full 32-byte hex key (0x + 64 hex chars), not a placeholder.',
|
|
5058
|
+
);
|
|
5044
5059
|
}
|
|
5045
5060
|
|
|
5046
5061
|
for (const key of ['ORACLE', 'FACTORY', 'USDC']) {
|
|
@@ -7240,9 +7255,12 @@ function resolveTradeRuntimeConfig(options) {
|
|
|
7240
7255
|
throw new CliError('INVALID_FLAG_VALUE', `RPC URL must be a valid http/https URL. Received: "${rpcUrl}"`);
|
|
7241
7256
|
}
|
|
7242
7257
|
|
|
7243
|
-
const privateKey = options.privateKey || process.env.
|
|
7258
|
+
const privateKey = options.privateKey || process.env.PANDORA_PRIVATE_KEY || process.env.PRIVATE_KEY;
|
|
7244
7259
|
if (!privateKey || !isValidPrivateKey(privateKey)) {
|
|
7245
|
-
throw new CliError(
|
|
7260
|
+
throw new CliError(
|
|
7261
|
+
'INVALID_FLAG_VALUE',
|
|
7262
|
+
'Missing or invalid private key. Set PANDORA_PRIVATE_KEY (preferred) or PRIVATE_KEY, or pass --private-key.',
|
|
7263
|
+
);
|
|
7246
7264
|
}
|
|
7247
7265
|
|
|
7248
7266
|
const usdc = options.usdc || String(process.env.USDC || '').trim();
|
|
@@ -9909,6 +9927,12 @@ async function runPolymarketCommand(args, context) {
|
|
|
9909
9927
|
}
|
|
9910
9928
|
|
|
9911
9929
|
const envCreds = readTradingCredsFromEnv();
|
|
9930
|
+
if (!options.privateKey && envCreds.privateKeyInvalid) {
|
|
9931
|
+
throw new CliError(
|
|
9932
|
+
'INVALID_FLAG_VALUE',
|
|
9933
|
+
'POLYMARKET_PRIVATE_KEY must be a valid private key (0x + 64 hex chars).',
|
|
9934
|
+
);
|
|
9935
|
+
}
|
|
9912
9936
|
let result;
|
|
9913
9937
|
try {
|
|
9914
9938
|
result = await placeHedgeOrder({
|
|
@@ -10530,7 +10554,7 @@ async function main() {
|
|
|
10530
10554
|
outputMode = parsed.outputMode;
|
|
10531
10555
|
args = parsed.args;
|
|
10532
10556
|
} catch (err) {
|
|
10533
|
-
emitFailure(
|
|
10557
|
+
emitFailure('json', err);
|
|
10534
10558
|
return;
|
|
10535
10559
|
}
|
|
10536
10560
|
|
package/package.json
CHANGED
package/scripts/.env.example
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
# Runtime variables for market launcher scripts
|
|
2
2
|
CHAIN_ID=1
|
|
3
3
|
RPC_URL=https://ethereum.publicnode.com
|
|
4
|
+
# Preferred key name for Pandora execution commands:
|
|
5
|
+
PANDORA_PRIVATE_KEY=0x...
|
|
6
|
+
# Backward-compatible legacy key name (still supported):
|
|
4
7
|
PRIVATE_KEY=0x...
|
|
5
8
|
ORACLE=0x259308E7d8557e4Ba192De1aB8Cf7e0E21896442
|
|
6
9
|
FACTORY=0xaB120F1FD31FB1EC39893B75d80a3822b1Cd8d0c
|