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 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).
@@ -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
- - ABI-gated placeholders: `pandora resolve`, `pandora lp`
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
- ## ABI-gated commands
239
- - `resolve` and `lp` are intentionally gated and return `ABI_READY_REQUIRED` until verified ABI signatures/events and integration tests are committed.
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` (ABI-gated)
286
- - `pandora lp` (ABI-gated)
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
- - ABI-gated placeholders: `pandora resolve`, `pandora lp`
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`: intentionally return `ABI_READY_REQUIRED` until ABI readiness sign-off.
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 ? 50 : sourceYesPct);
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
- const rebalanceResult = await rebalanceFn({
454
- marketAddress: options.pandoraMarketAddress,
455
- side: rebalanceSide,
456
- amountUsdc: plannedRebalanceUsdc,
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
- actualRebalanceUsdc = plannedRebalanceUsdc;
471
-
472
- state.cumulativeLpFeesApproxUsdc =
473
- round((toNumber(state.cumulativeLpFeesApproxUsdc) || 0) + plannedRebalanceUsdc * 0.003, 6) || 0;
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 = (action.rebalance ? 1 : 0) + (action.hedge ? 1 : 0);
543
- state.tradesToday += executedLegCount || 1;
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
- String(options.privateKey || ''),
124
- String(options.apiKey || ''),
125
- String(options.apiSecret || ''),
126
- String(options.apiPassphrase || ''),
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 true;
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 || env.PRIVATE_KEY || null,
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
- formatTimestamp(item.deadlineEpoch),
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.16",
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
  ],