pandora-cli-skills 1.1.16 → 1.1.18
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 +40 -0
- package/README_FOR_SHARING.md +6 -5
- package/SKILL.md +10 -3
- package/cli/lib/mirror_econ_service.cjs +1 -2
- package/cli/lib/mirror_service.cjs +9 -0
- package/cli/lib/mirror_sync_service.cjs +36 -11
- package/cli/lib/polymarket_trade_adapter.cjs +12 -6
- package/cli/pandora.cjs +25 -4
- package/package.json +2 -1
package/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Pandora CLI & Skills
|
|
2
|
+
|
|
3
|
+
Production CLI for Pandora prediction markets with mirror + hedge tooling.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i -g pandora-cli-skills
|
|
9
|
+
pandora --help
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Or run without installing:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx pandora-cli-skills@latest --help
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Core commands
|
|
19
|
+
|
|
20
|
+
- `pandora markets list|get`
|
|
21
|
+
- `pandora quote`
|
|
22
|
+
- `pandora trade`
|
|
23
|
+
- `pandora history`
|
|
24
|
+
- `pandora export`
|
|
25
|
+
- `pandora arbitrage`
|
|
26
|
+
- `pandora autopilot run|once`
|
|
27
|
+
- `pandora mirror browse|plan|deploy|verify|lp-explain|hedge-calc|simulate|go|sync|status|close`
|
|
28
|
+
- `pandora polymarket check|approve|preflight|trade`
|
|
29
|
+
|
|
30
|
+
## Mirror economics commands
|
|
31
|
+
|
|
32
|
+
- `pandora mirror lp-explain --liquidity-usdc 10000 --source-yes-pct 58`
|
|
33
|
+
- `pandora mirror hedge-calc --reserve-yes-usdc 8 --reserve-no-usdc 12 --excess-no-usdc 2 --polymarket-yes-pct 60`
|
|
34
|
+
- `pandora mirror simulate --liquidity-usdc 10000 --source-yes-pct 58 --target-yes-pct 58 --volume-scenarios 1000,5000,10000`
|
|
35
|
+
|
|
36
|
+
## Notes
|
|
37
|
+
|
|
38
|
+
- Node.js `>=18` required.
|
|
39
|
+
- Full operational and JSON contract documentation is in
|
|
40
|
+
[`README_FOR_SHARING.md`](./README_FOR_SHARING.md).
|
package/README_FOR_SHARING.md
CHANGED
|
@@ -96,7 +96,8 @@ Prerequisite: Node.js `>=18`.
|
|
|
96
96
|
- `pandora leaderboard --metric profit|volume|win-rate`
|
|
97
97
|
- `pandora analyze --market-address <0x...> --provider <name>`
|
|
98
98
|
- `pandora suggest --wallet <0x...> --risk low|medium|high --budget <amount>`
|
|
99
|
-
-
|
|
99
|
+
- `pandora resolve`
|
|
100
|
+
- `pandora lp add|remove|positions`
|
|
100
101
|
|
|
101
102
|
## Read-only examples
|
|
102
103
|
- `pandora markets list --limit 20 --order-by createdAt --order-direction desc`
|
|
@@ -235,8 +236,8 @@ Prerequisite: Node.js `>=18`.
|
|
|
235
236
|
- `suggest`:
|
|
236
237
|
- envelope is `ok=true`, `command="suggest"`, with ranked suggestions, sizing, and risk notes.
|
|
237
238
|
|
|
238
|
-
##
|
|
239
|
-
- `resolve` and `lp` are
|
|
239
|
+
## Resolve/LP commands
|
|
240
|
+
- `resolve` and `lp` are active command paths with strict flag validation, runtime preflight checks, and decoded on-chain revert reporting.
|
|
240
241
|
|
|
241
242
|
## Pandora Mainnet Reference
|
|
242
243
|
- PredictionOracle (Factory): `0x259308E7d8557e4Ba192De1aB8Cf7e0E21896442`
|
|
@@ -282,8 +283,8 @@ Prerequisite: Node.js `>=18`.
|
|
|
282
283
|
- `pandora leaderboard`
|
|
283
284
|
- `pandora analyze`
|
|
284
285
|
- `pandora suggest`
|
|
285
|
-
- `pandora resolve`
|
|
286
|
-
- `pandora lp`
|
|
286
|
+
- `pandora resolve`
|
|
287
|
+
- `pandora lp add|remove|positions`
|
|
287
288
|
- `pandora polls list|get`
|
|
288
289
|
- `pandora events list|get`
|
|
289
290
|
- `pandora positions list`
|
package/SKILL.md
CHANGED
|
@@ -45,12 +45,13 @@ npm link
|
|
|
45
45
|
- `pandora export`
|
|
46
46
|
- `pandora arbitrage`
|
|
47
47
|
- `pandora autopilot run|once`
|
|
48
|
-
- `pandora mirror browse|plan|deploy|verify|go|sync|status|close`
|
|
48
|
+
- `pandora mirror browse|plan|deploy|verify|lp-explain|hedge-calc|simulate|go|sync|status|close`
|
|
49
49
|
- `pandora webhook test`
|
|
50
50
|
- `pandora leaderboard`
|
|
51
51
|
- `pandora analyze`
|
|
52
52
|
- `pandora suggest`
|
|
53
|
-
-
|
|
53
|
+
- `pandora resolve`
|
|
54
|
+
- `pandora lp add|remove|positions`
|
|
54
55
|
- Doctor checks:
|
|
55
56
|
- env presence + format validation
|
|
56
57
|
- RPC reachability and chain id match
|
|
@@ -100,6 +101,9 @@ pandora --output json arbitrage --venues pandora,polymarket --min-spread-pct 3 -
|
|
|
100
101
|
pandora --output json autopilot once --market-address <0x...> --side no --amount-usdc 10 --trigger-yes-below 15 --paper
|
|
101
102
|
pandora --output json mirror browse --min-yes-pct 20 --max-yes-pct 80 --min-volume-24h 100000 --limit 10
|
|
102
103
|
pandora --output json mirror plan --source polymarket --polymarket-market-id <id> --with-rules --include-similarity
|
|
104
|
+
pandora --output json mirror lp-explain --liquidity-usdc 10000 --source-yes-pct 58
|
|
105
|
+
pandora --output json mirror hedge-calc --reserve-yes-usdc 8 --reserve-no-usdc 12 --excess-no-usdc 2 --polymarket-yes-pct 60
|
|
106
|
+
pandora --output json mirror simulate --liquidity-usdc 10000 --source-yes-pct 58 --target-yes-pct 58 --volume-scenarios 1000,5000,10000
|
|
103
107
|
pandora --output json mirror go --polymarket-slug <slug> --liquidity-usdc 10 --paper
|
|
104
108
|
pandora --output json mirror verify --pandora-market-address <0x...> --polymarket-market-id <id> --include-similarity
|
|
105
109
|
pandora --output json mirror sync once --pandora-market-address <0x...> --polymarket-market-id <id> --paper --hedge-ratio 1.0
|
|
@@ -168,6 +172,9 @@ pandora --output json suggest --wallet <0x...> --risk medium --budget 50 --inclu
|
|
|
168
172
|
- `mirror browse`: Polymarket candidate discovery with optional Pandora mirror hints.
|
|
169
173
|
- `mirror deploy`: dry-run/execute Pandora AMM deployment from mirror plan inputs, with execute-time wallet preflight and trust-manifest persistence.
|
|
170
174
|
- `mirror verify`: explicit question/rules similarity endpoint for AI-subagent validation, with optional `--trust-deploy` manifest bypass for similarity.
|
|
175
|
+
- `mirror lp-explain`: complete-set liquidity walkthrough (minted YES/NO, seeded pool reserves, returned excess inventory).
|
|
176
|
+
- `mirror hedge-calc`: reserve/excess-driven hedge sizing (`deltaTotalUsdc`, target hedge leg, break-even volume).
|
|
177
|
+
- `mirror simulate`: planning-grade LP + hedge scenario simulation with customizable `--volume-scenarios`.
|
|
171
178
|
- `mirror go`: one-command orchestration for plan → deploy → verify, with optional auto-sync start.
|
|
172
179
|
- `mirror sync`: paper-first delta-neutral loop with strict gates, state persistence, and optional live hedging (`--hedge-ratio <n>`, `--no-hedge`).
|
|
173
180
|
- live hedge env: `POLYMARKET_PRIVATE_KEY`, `POLYMARKET_FUNDER`, `POLYMARKET_API_KEY`, `POLYMARKET_API_SECRET`, `POLYMARKET_API_PASSPHRASE`, `POLYMARKET_HOST`.
|
|
@@ -184,7 +191,7 @@ pandora --output json suggest --wallet <0x...> --risk medium --budget 50 --inclu
|
|
|
184
191
|
- invalid indexer aggregates are sanitized (win-rate capped to 0-100%) and emitted in diagnostics.
|
|
185
192
|
- `analyze`: provider-agnostic market analysis interface (fails with structured error when provider is not configured).
|
|
186
193
|
- `suggest`: risk/budget-ranked opportunities seeded from arbitrage output and wallet history.
|
|
187
|
-
- `resolve` and `lp`:
|
|
194
|
+
- `resolve` and `lp`: enabled command paths with strict flag/runtime validation and decoded on-chain revert reporting.
|
|
188
195
|
|
|
189
196
|
## Pandora mainnet deployment reference
|
|
190
197
|
- PredictionOracle (Factory): `0x259308E7d8557e4Ba192De1aB8Cf7e0E21896442`
|
|
@@ -37,7 +37,6 @@ function rawUsdcToNumber(rawValue) {
|
|
|
37
37
|
function toPercent(value) {
|
|
38
38
|
const numeric = toNumber(value);
|
|
39
39
|
if (numeric === null) return null;
|
|
40
|
-
if (numeric >= 0 && numeric <= 1) return round(numeric * 100, 6);
|
|
41
40
|
if (numeric >= 0 && numeric <= 100) return round(numeric, 6);
|
|
42
41
|
return null;
|
|
43
42
|
}
|
|
@@ -71,7 +70,7 @@ function resolveDistribution(options = {}) {
|
|
|
71
70
|
};
|
|
72
71
|
}
|
|
73
72
|
|
|
74
|
-
const distribution = computeDistributionHint(sourceYesPct === null ?
|
|
73
|
+
const distribution = computeDistributionHint(sourceYesPct === null ? 0.5 : sourceYesPct / 100);
|
|
75
74
|
if (sourceYesPct === null) {
|
|
76
75
|
diagnostics.push('No source YES probability supplied; defaulted to balanced 50/50 distribution hint.');
|
|
77
76
|
}
|
|
@@ -65,9 +65,18 @@ function buildPlanDigest(planData) {
|
|
|
65
65
|
sourceMarket: {
|
|
66
66
|
marketId: planData.sourceMarket && planData.sourceMarket.marketId,
|
|
67
67
|
slug: planData.sourceMarket && planData.sourceMarket.slug,
|
|
68
|
+
question: planData.sourceMarket && planData.sourceMarket.question,
|
|
69
|
+
description: planData.sourceMarket && planData.sourceMarket.description,
|
|
68
70
|
yesPct: planData.sourceMarket && planData.sourceMarket.yesPct,
|
|
69
71
|
closeTimestamp: planData.sourceMarket && planData.sourceMarket.closeTimestamp,
|
|
70
72
|
},
|
|
73
|
+
rules: planData.rules
|
|
74
|
+
? {
|
|
75
|
+
sourceRules: planData.rules.sourceRules || null,
|
|
76
|
+
proposedPandoraRules: planData.rules.proposedPandoraRules || null,
|
|
77
|
+
sourceCount: planData.rules.sourceCount || null,
|
|
78
|
+
}
|
|
79
|
+
: null,
|
|
71
80
|
liquidityRecommendation: planData.liquidityRecommendation,
|
|
72
81
|
distributionHint: planData.distributionHint,
|
|
73
82
|
}));
|
|
@@ -449,17 +449,30 @@ async function runMirrorSync(options, deps = {}) {
|
|
|
449
449
|
saveState(loaded.filePath, state);
|
|
450
450
|
|
|
451
451
|
if (snapshotMetrics.driftTriggered && plannedRebalanceUsdc > 0) {
|
|
452
|
+
let rebalanceResultOk = true;
|
|
452
453
|
if (options.executeLive) {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
454
|
+
let rebalanceResult;
|
|
455
|
+
try {
|
|
456
|
+
rebalanceResult = await rebalanceFn({
|
|
457
|
+
marketAddress: options.pandoraMarketAddress,
|
|
458
|
+
side: rebalanceSide,
|
|
459
|
+
amountUsdc: plannedRebalanceUsdc,
|
|
460
|
+
});
|
|
461
|
+
} catch (err) {
|
|
462
|
+
rebalanceResult = {
|
|
463
|
+
ok: false,
|
|
464
|
+
error: {
|
|
465
|
+
code: err && err.code ? String(err.code) : null,
|
|
466
|
+
message: err && err.message ? String(err.message) : String(err),
|
|
467
|
+
},
|
|
468
|
+
};
|
|
469
|
+
}
|
|
458
470
|
action.rebalance = {
|
|
459
471
|
side: rebalanceSide,
|
|
460
472
|
amountUsdc: plannedRebalanceUsdc,
|
|
461
473
|
result: rebalanceResult,
|
|
462
474
|
};
|
|
475
|
+
rebalanceResultOk = Boolean(rebalanceResult && rebalanceResult.ok !== false);
|
|
463
476
|
} else {
|
|
464
477
|
action.rebalance = {
|
|
465
478
|
side: rebalanceSide,
|
|
@@ -467,10 +480,22 @@ async function runMirrorSync(options, deps = {}) {
|
|
|
467
480
|
result: { status: 'simulated' },
|
|
468
481
|
};
|
|
469
482
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
483
|
+
if (rebalanceResultOk) {
|
|
484
|
+
actualRebalanceUsdc = plannedRebalanceUsdc;
|
|
485
|
+
state.cumulativeLpFeesApproxUsdc =
|
|
486
|
+
round((toNumber(state.cumulativeLpFeesApproxUsdc) || 0) + plannedRebalanceUsdc * 0.003, 6) || 0;
|
|
487
|
+
} else {
|
|
488
|
+
action.status = 'failed';
|
|
489
|
+
const rebalanceError =
|
|
490
|
+
action.rebalance && action.rebalance.result && action.rebalance.result.error
|
|
491
|
+
? action.rebalance.result.error
|
|
492
|
+
: { message: 'Pandora rebalance execution failed.' };
|
|
493
|
+
action.error = {
|
|
494
|
+
code: 'REBALANCE_EXECUTION_FAILED',
|
|
495
|
+
message: rebalanceError.message || 'Pandora rebalance execution failed.',
|
|
496
|
+
details: rebalanceError,
|
|
497
|
+
};
|
|
498
|
+
}
|
|
474
499
|
}
|
|
475
500
|
|
|
476
501
|
if (hedgeTriggered && plannedHedgeUsdc > 0) {
|
|
@@ -539,8 +564,8 @@ async function runMirrorSync(options, deps = {}) {
|
|
|
539
564
|
|
|
540
565
|
const actualSpendUsdc = round(actualRebalanceUsdc + actualHedgeUsdc, 6) || 0;
|
|
541
566
|
state.dailySpendUsdc = round((toNumber(state.dailySpendUsdc) || 0) + actualSpendUsdc, 6) || 0;
|
|
542
|
-
const executedLegCount = (
|
|
543
|
-
state.tradesToday += executedLegCount
|
|
567
|
+
const executedLegCount = (actualRebalanceUsdc > 0 ? 1 : 0) + (actualHedgeUsdc > 0 ? 1 : 0);
|
|
568
|
+
state.tradesToday += executedLegCount;
|
|
544
569
|
state.lastExecution = action;
|
|
545
570
|
|
|
546
571
|
snapshot.action = action;
|
|
@@ -113,6 +113,12 @@ function resolveSignatureType(options = {}) {
|
|
|
113
113
|
return options.funder ? POLYMARKET_SIG_TYPE_PROXY : POLYMARKET_SIG_TYPE_EOA;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
function hashSensitiveCachePart(value) {
|
|
117
|
+
const raw = String(value || '').trim();
|
|
118
|
+
if (!raw) return '';
|
|
119
|
+
return crypto.createHash('sha256').update(raw).digest('hex');
|
|
120
|
+
}
|
|
121
|
+
|
|
116
122
|
function buildTradingCacheKey(host, chain, options = {}) {
|
|
117
123
|
const signatureType = resolveSignatureType(options);
|
|
118
124
|
return [
|
|
@@ -120,10 +126,10 @@ function buildTradingCacheKey(host, chain, options = {}) {
|
|
|
120
126
|
String(chain || ''),
|
|
121
127
|
String(signatureType),
|
|
122
128
|
String(options.funder || ''),
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
hashSensitiveCachePart(options.privateKey),
|
|
130
|
+
hashSensitiveCachePart(options.apiKey),
|
|
131
|
+
hashSensitiveCachePart(options.apiSecret),
|
|
132
|
+
hashSensitiveCachePart(options.apiPassphrase),
|
|
127
133
|
].join('|');
|
|
128
134
|
}
|
|
129
135
|
|
|
@@ -142,7 +148,7 @@ function responseContainsError(response) {
|
|
|
142
148
|
}
|
|
143
149
|
|
|
144
150
|
function responseIndicatesSuccess(response) {
|
|
145
|
-
if (!response || typeof response !== 'object') return
|
|
151
|
+
if (!response || typeof response !== 'object') return false;
|
|
146
152
|
if (Object.prototype.hasOwnProperty.call(response, 'success')) {
|
|
147
153
|
return Boolean(response.success) && !responseContainsError(response);
|
|
148
154
|
}
|
|
@@ -990,7 +996,7 @@ async function browsePolymarketMarkets(options = {}) {
|
|
|
990
996
|
|
|
991
997
|
function readTradingCredsFromEnv(env = process.env) {
|
|
992
998
|
const creds = {
|
|
993
|
-
privateKey: env.POLYMARKET_PRIVATE_KEY ||
|
|
999
|
+
privateKey: env.POLYMARKET_PRIVATE_KEY || null,
|
|
994
1000
|
funder: env.POLYMARKET_FUNDER || null,
|
|
995
1001
|
apiKey: env.POLYMARKET_API_KEY || null,
|
|
996
1002
|
apiSecret: env.POLYMARKET_API_SECRET || null,
|
package/cli/pandora.cjs
CHANGED
|
@@ -854,6 +854,16 @@ function parseAddressFlag(value, flagName) {
|
|
|
854
854
|
return value.toLowerCase();
|
|
855
855
|
}
|
|
856
856
|
|
|
857
|
+
function parsePrivateKeyFlag(value, flagName = '--private-key') {
|
|
858
|
+
if (!isValidPrivateKey(value)) {
|
|
859
|
+
throw new CliError(
|
|
860
|
+
'INVALID_FLAG_VALUE',
|
|
861
|
+
`${flagName} must be a valid private key (0x + 64 hex chars). Received: "${value}"`,
|
|
862
|
+
);
|
|
863
|
+
}
|
|
864
|
+
return value;
|
|
865
|
+
}
|
|
866
|
+
|
|
857
867
|
function parsePositionsOrderBy(value) {
|
|
858
868
|
if (!POSITIONS_ORDER_BY_FIELD_SET.has(value)) {
|
|
859
869
|
throw new CliError(
|
|
@@ -1497,7 +1507,7 @@ function parseTradeFlags(args) {
|
|
|
1497
1507
|
}
|
|
1498
1508
|
|
|
1499
1509
|
if (token === '--private-key') {
|
|
1500
|
-
options.privateKey = requireFlagValue(args, i, '--private-key');
|
|
1510
|
+
options.privateKey = parsePrivateKeyFlag(requireFlagValue(args, i, '--private-key'), '--private-key');
|
|
1501
1511
|
i += 1;
|
|
1502
1512
|
continue;
|
|
1503
1513
|
}
|
|
@@ -3450,7 +3460,7 @@ function parseMirrorSyncFlags(args) {
|
|
|
3450
3460
|
continue;
|
|
3451
3461
|
}
|
|
3452
3462
|
if (token === '--private-key') {
|
|
3453
|
-
options.privateKey = requireFlagValue(rest, i, '--private-key');
|
|
3463
|
+
options.privateKey = parsePrivateKeyFlag(requireFlagValue(rest, i, '--private-key'), '--private-key');
|
|
3454
3464
|
i += 1;
|
|
3455
3465
|
continue;
|
|
3456
3466
|
}
|
|
@@ -3855,7 +3865,7 @@ function parseMirrorGoFlags(args) {
|
|
|
3855
3865
|
continue;
|
|
3856
3866
|
}
|
|
3857
3867
|
if (token === '--private-key') {
|
|
3858
|
-
options.privateKey = requireFlagValue(args, i, '--private-key');
|
|
3868
|
+
options.privateKey = parsePrivateKeyFlag(requireFlagValue(args, i, '--private-key'), '--private-key');
|
|
3859
3869
|
i += 1;
|
|
3860
3870
|
continue;
|
|
3861
3871
|
}
|
|
@@ -5277,6 +5287,17 @@ function formatTimestamp(raw) {
|
|
|
5277
5287
|
return date.toISOString();
|
|
5278
5288
|
}
|
|
5279
5289
|
|
|
5290
|
+
function formatUnixTimestampIfLikely(raw) {
|
|
5291
|
+
if (raw === null || raw === undefined || raw === '') return '';
|
|
5292
|
+
const numeric = Number(raw);
|
|
5293
|
+
if (!Number.isFinite(numeric)) return String(raw);
|
|
5294
|
+
if (numeric <= 0) return String(raw);
|
|
5295
|
+
const seconds = numeric > 1e12 ? numeric / 1000 : numeric;
|
|
5296
|
+
// Guard against block-number-like values rendered as 1970 dates.
|
|
5297
|
+
if (seconds < 946684800) return String(raw); // 2000-01-01T00:00:00Z
|
|
5298
|
+
return formatTimestamp(raw);
|
|
5299
|
+
}
|
|
5300
|
+
|
|
5280
5301
|
function valueToCell(value) {
|
|
5281
5302
|
if (value === null || value === undefined) return '';
|
|
5282
5303
|
if (typeof value === 'object') return JSON.stringify(value);
|
|
@@ -5538,7 +5559,7 @@ function renderPollsListTable(data) {
|
|
|
5538
5559
|
short(item.id, 18),
|
|
5539
5560
|
item.status,
|
|
5540
5561
|
short(item.creator, 16),
|
|
5541
|
-
|
|
5562
|
+
formatUnixTimestampIfLikely(item.deadlineEpoch),
|
|
5542
5563
|
short(item.question, 56),
|
|
5543
5564
|
]),
|
|
5544
5565
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pandora-cli-skills",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.18",
|
|
4
4
|
"description": "Pandora CLI & Skills",
|
|
5
5
|
"main": "cli/pandora.cjs",
|
|
6
6
|
"bin": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"references/contracts.md",
|
|
17
17
|
"references/creation-script.md",
|
|
18
18
|
"SKILL.md",
|
|
19
|
+
"README.md",
|
|
19
20
|
"README_FOR_SHARING.md",
|
|
20
21
|
"tsconfig.json"
|
|
21
22
|
],
|