pandora-cli-skills 1.1.13 → 1.1.15
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.
|
@@ -115,13 +115,18 @@ async function buildMirrorPlan(options = {}) {
|
|
|
115
115
|
const distribution = computeDistributionHint(sourceYesProbability === null ? 0.5 : sourceYesProbability);
|
|
116
116
|
const rules = buildRuleTemplate(sourceMarket);
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
118
|
+
let match = { best: null, diagnostics: [] };
|
|
119
|
+
try {
|
|
120
|
+
match = await findBestPandoraMatch({
|
|
121
|
+
indexerUrl: options.indexerUrl,
|
|
122
|
+
timeoutMs: options.timeoutMs,
|
|
123
|
+
chainId: options.chainId,
|
|
124
|
+
sourceQuestion: sourceMarket.question,
|
|
125
|
+
limit: 150,
|
|
126
|
+
});
|
|
127
|
+
} catch (err) {
|
|
128
|
+
diagnostics.push(`Duplicate-check fallback: ${err && err.message ? err.message : String(err)}`);
|
|
129
|
+
}
|
|
125
130
|
|
|
126
131
|
if (Number.isFinite(sourceMarket.closeTimestamp)) {
|
|
127
132
|
const nowSec = Math.floor(Date.now() / 1000);
|
|
@@ -405,20 +410,24 @@ async function browseMirrorMarkets(options = {}) {
|
|
|
405
410
|
for (const entry of polymarket.items || []) {
|
|
406
411
|
let existingMirror = null;
|
|
407
412
|
if (options.indexerUrl) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
413
|
+
try {
|
|
414
|
+
const match = await findBestPandoraMatch({
|
|
415
|
+
indexerUrl: options.indexerUrl,
|
|
416
|
+
timeoutMs: options.timeoutMs,
|
|
417
|
+
chainId: options.chainId,
|
|
418
|
+
sourceQuestion: entry.question,
|
|
419
|
+
limit: 100,
|
|
420
|
+
});
|
|
421
|
+
if (match.best && match.best.similarity && Number(match.best.similarity.score) >= 0.86) {
|
|
422
|
+
existingMirror = {
|
|
423
|
+
marketAddress: match.best.marketAddress,
|
|
424
|
+
similarity: match.best.similarity.score,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
diagnostics.push(...(match.diagnostics || []));
|
|
428
|
+
} catch (err) {
|
|
429
|
+
diagnostics.push(`Duplicate-check skipped for "${entry.slug || entry.marketId || entry.question || 'market'}": ${err && err.message ? err.message : String(err)}`);
|
|
420
430
|
}
|
|
421
|
-
diagnostics.push(...(match.diagnostics || []));
|
|
422
431
|
}
|
|
423
432
|
|
|
424
433
|
items.push({
|
|
@@ -133,7 +133,8 @@ function evaluateStrictGates(context) {
|
|
|
133
133
|
);
|
|
134
134
|
|
|
135
135
|
const depthRequired = toNumber(context.plannedHedgeUsdc) || 0;
|
|
136
|
-
const
|
|
136
|
+
const explicitHedgeDepth = toNumber(context.hedgeDepthWithinSlippageUsd);
|
|
137
|
+
const depthAvailable = explicitHedgeDepth === null ? toNumber(context.depthWithinSlippageUsd) || 0 : explicitHedgeDepth;
|
|
137
138
|
add(
|
|
138
139
|
'DEPTH_COVERAGE',
|
|
139
140
|
depthRequired <= 0 ? true : depthAvailable >= depthRequired,
|
|
@@ -209,6 +210,7 @@ async function runMirrorSync(options, deps = {}) {
|
|
|
209
210
|
hedgeEnabled: options.hedgeEnabled,
|
|
210
211
|
hedgeRatio: options.hedgeRatio,
|
|
211
212
|
hedgeTriggerUsdc: options.hedgeTriggerUsdc,
|
|
213
|
+
forceGate: Boolean(options.forceGate),
|
|
212
214
|
};
|
|
213
215
|
|
|
214
216
|
const hash = strategyHash(strategy);
|
|
@@ -354,6 +356,12 @@ async function runMirrorSync(options, deps = {}) {
|
|
|
354
356
|
minTimeToExpirySec: snapshotMetrics.minTimeToExpirySec,
|
|
355
357
|
minimumTimeToCloseSec,
|
|
356
358
|
depthWithinSlippageUsd: depth.depthWithinSlippageUsd,
|
|
359
|
+
hedgeDepthWithinSlippageUsd:
|
|
360
|
+
plannedHedgeUsdc > 0
|
|
361
|
+
? gapUsdc >= 0
|
|
362
|
+
? depth.yesDepth && depth.yesDepth.depthUsd
|
|
363
|
+
: depth.noDepth && depth.noDepth.depthUsd
|
|
364
|
+
: null,
|
|
357
365
|
depthSlippageBps: options.depthSlippageBps,
|
|
358
366
|
maxOpenExposureUsdc: options.maxOpenExposureUsdc,
|
|
359
367
|
maxTradesPerDay: options.maxTradesPerDay,
|
|
@@ -380,6 +388,16 @@ async function runMirrorSync(options, deps = {}) {
|
|
|
380
388
|
plannedRebalanceUsdc,
|
|
381
389
|
plannedSpendUsdc,
|
|
382
390
|
depthWithinSlippageUsd: depth.depthWithinSlippageUsd,
|
|
391
|
+
hedgeDepthWithinSlippageUsd:
|
|
392
|
+
plannedHedgeUsdc > 0
|
|
393
|
+
? gapUsdc >= 0
|
|
394
|
+
? toNumber(depth.yesDepth && depth.yesDepth.depthUsd) || 0
|
|
395
|
+
: toNumber(depth.noDepth && depth.noDepth.depthUsd) || 0
|
|
396
|
+
: null,
|
|
397
|
+
yesDepthWithinSlippageUsd: toNumber(depth.yesDepth && depth.yesDepth.depthUsd),
|
|
398
|
+
noDepthWithinSlippageUsd: toNumber(depth.noDepth && depth.noDepth.depthUsd),
|
|
399
|
+
minDepthWithinSlippageUsd: toNumber(depth.minDepthWithinSlippageUsd),
|
|
400
|
+
bestDepthWithinSlippageUsd: toNumber(depth.bestDepthWithinSlippageUsd),
|
|
383
401
|
},
|
|
384
402
|
actionPlan: {
|
|
385
403
|
rebalanceSide: plannedRebalanceUsdc > 0 ? rebalanceSide : null,
|
|
@@ -400,7 +418,7 @@ async function runMirrorSync(options, deps = {}) {
|
|
|
400
418
|
reason: 'Duplicate trigger bucket (idempotency key already processed).',
|
|
401
419
|
idempotencyKey,
|
|
402
420
|
};
|
|
403
|
-
} else if (!gate.ok) {
|
|
421
|
+
} else if (!gate.ok && !options.forceGate) {
|
|
404
422
|
snapshot.action = {
|
|
405
423
|
mode: options.executeLive ? 'live' : 'paper',
|
|
406
424
|
status: 'blocked',
|
|
@@ -413,6 +431,8 @@ async function runMirrorSync(options, deps = {}) {
|
|
|
413
431
|
mode: options.executeLive ? 'live' : 'paper',
|
|
414
432
|
status: options.executeLive ? 'executed' : 'simulated',
|
|
415
433
|
idempotencyKey,
|
|
434
|
+
forcedGateBypass: Boolean(!gate.ok && options.forceGate),
|
|
435
|
+
failedChecks: !gate.ok ? gate.failedChecks : [],
|
|
416
436
|
rebalance: null,
|
|
417
437
|
hedge: null,
|
|
418
438
|
};
|
|
@@ -578,6 +598,7 @@ async function runMirrorSync(options, deps = {}) {
|
|
|
578
598
|
polymarketMarketId: options.polymarketMarketId,
|
|
579
599
|
polymarketSlug: options.polymarketSlug,
|
|
580
600
|
trustDeploy: Boolean(options.trustDeploy),
|
|
601
|
+
forceGate: Boolean(options.forceGate),
|
|
581
602
|
intervalMs: options.intervalMs,
|
|
582
603
|
minimumTimeToCloseSec,
|
|
583
604
|
driftTriggerBps: options.driftTriggerBps,
|
|
@@ -3,6 +3,7 @@ const { createIndexerClient } = require('./indexer_client.cjs');
|
|
|
3
3
|
const { resolvePolymarketMarket } = require('./polymarket_trade_adapter.cjs');
|
|
4
4
|
|
|
5
5
|
const MIRROR_VERIFY_SCHEMA_VERSION = '1.0.0';
|
|
6
|
+
const USDC_DECIMALS = 6;
|
|
6
7
|
|
|
7
8
|
function toNumber(value) {
|
|
8
9
|
const numeric = Number(value);
|
|
@@ -16,6 +17,12 @@ function round(value, decimals = 6) {
|
|
|
16
17
|
return Math.round(value * factor) / factor;
|
|
17
18
|
}
|
|
18
19
|
|
|
20
|
+
function normalizeUsdcRawToUsd(value) {
|
|
21
|
+
const numeric = toNumber(value);
|
|
22
|
+
if (numeric === null) return null;
|
|
23
|
+
return round(numeric / (10 ** USDC_DECIMALS), 6);
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
function normalizeQuestion(question) {
|
|
20
27
|
return String(question || '')
|
|
21
28
|
.toLowerCase()
|
|
@@ -125,8 +132,8 @@ function derivePandoraYesPct(market) {
|
|
|
125
132
|
return round(yesFromChance * 100, 6);
|
|
126
133
|
}
|
|
127
134
|
|
|
128
|
-
const reserveYes =
|
|
129
|
-
const reserveNo =
|
|
135
|
+
const reserveYes = normalizeUsdcRawToUsd(market && market.reserveYes);
|
|
136
|
+
const reserveNo = normalizeUsdcRawToUsd(market && market.reserveNo);
|
|
130
137
|
if (reserveYes === null || reserveNo === null) return null;
|
|
131
138
|
|
|
132
139
|
const total = reserveYes + reserveNo;
|
|
@@ -251,8 +258,8 @@ async function fetchPandoraMarketContext(options = {}) {
|
|
|
251
258
|
closeTimestamp: toNumber(market.marketCloseTimestamp) || toNumber(poll && poll.deadlineEpoch),
|
|
252
259
|
yesPct,
|
|
253
260
|
noPct,
|
|
254
|
-
reserveYes:
|
|
255
|
-
reserveNo:
|
|
261
|
+
reserveYes: normalizeUsdcRawToUsd(market.reserveYes),
|
|
262
|
+
reserveNo: normalizeUsdcRawToUsd(market.reserveNo),
|
|
256
263
|
totalVolumeUsd: toNumber(market.totalVolume),
|
|
257
264
|
tvlUsd: toNumber(market.currentTvl),
|
|
258
265
|
diagnostics,
|
|
@@ -288,17 +295,20 @@ function buildGateChecks({
|
|
|
288
295
|
const strictRuleCheckOk = bothRulesPresent && rulesEqual;
|
|
289
296
|
checks.push({
|
|
290
297
|
code: 'RULE_HASH_MATCH',
|
|
291
|
-
ok: allowRuleMismatch ? true : strictRuleCheckOk,
|
|
292
|
-
message:
|
|
293
|
-
? 'Rule hash mismatch bypassed by
|
|
294
|
-
:
|
|
295
|
-
? 'Rule
|
|
296
|
-
:
|
|
298
|
+
ok: trustDeploy ? true : allowRuleMismatch ? true : strictRuleCheckOk,
|
|
299
|
+
message: trustDeploy
|
|
300
|
+
? 'Rule hash mismatch bypassed by trusted deploy pairing.'
|
|
301
|
+
: allowRuleMismatch
|
|
302
|
+
? 'Rule hash mismatch bypassed by --allow-rule-mismatch.'
|
|
303
|
+
: bothRulesPresent
|
|
304
|
+
? 'Rule hashes must match.'
|
|
305
|
+
: 'Rule text missing on one or both sides.',
|
|
297
306
|
meta: {
|
|
298
307
|
left: ruleHashes.left,
|
|
299
308
|
right: ruleHashes.right,
|
|
300
309
|
bothRulesPresent,
|
|
301
310
|
rulesEqual: bothRulesPresent ? rulesEqual : null,
|
|
311
|
+
trustDeploy: Boolean(trustDeploy),
|
|
302
312
|
},
|
|
303
313
|
});
|
|
304
314
|
|
|
@@ -751,7 +751,15 @@ function calculateExecutableDepthUsd(orderbook, side, slippageBps) {
|
|
|
751
751
|
|
|
752
752
|
const limitPriceFactor = slippageBps / 10_000;
|
|
753
753
|
const entries = side === 'buy' ? normalized.asks : normalized.bids;
|
|
754
|
-
const
|
|
754
|
+
const bestBid = normalized.bids.length ? normalized.bids[0].price : null;
|
|
755
|
+
const bestAsk = normalized.asks.length ? normalized.asks[0].price : null;
|
|
756
|
+
const referencePrice =
|
|
757
|
+
side === 'buy'
|
|
758
|
+
? (bestAsk !== null ? bestAsk : mid)
|
|
759
|
+
: (bestBid !== null ? bestBid : mid);
|
|
760
|
+
const priceLimit = side === 'buy'
|
|
761
|
+
? referencePrice * (1 + limitPriceFactor)
|
|
762
|
+
: referencePrice * (1 - limitPriceFactor);
|
|
755
763
|
|
|
756
764
|
let depthUsd = 0;
|
|
757
765
|
let depthShares = 0;
|
|
@@ -770,6 +778,7 @@ function calculateExecutableDepthUsd(orderbook, side, slippageBps) {
|
|
|
770
778
|
depthShares: round(depthShares, 6) || 0,
|
|
771
779
|
worstPrice: worstPrice === null ? null : round(worstPrice, 8),
|
|
772
780
|
midPrice: round(mid, 8),
|
|
781
|
+
referencePrice: round(referencePrice, 8),
|
|
773
782
|
diagnostics: [],
|
|
774
783
|
};
|
|
775
784
|
}
|
|
@@ -850,7 +859,11 @@ async function fetchDepthForMarket(market, options = {}) {
|
|
|
850
859
|
const noDepth = noBook ? calculateExecutableDepthUsd(noBook, 'buy', slippageBps) : null;
|
|
851
860
|
|
|
852
861
|
const candidates = [yesDepth && yesDepth.depthUsd, noDepth && noDepth.depthUsd].filter((value) => Number.isFinite(value));
|
|
853
|
-
const
|
|
862
|
+
const minDepthWithinSlippageUsd = candidates.length ? Math.min(...candidates) : 0;
|
|
863
|
+
const bestDepthWithinSlippageUsd = candidates.length ? Math.max(...candidates) : 0;
|
|
864
|
+
// Keep the legacy/conservative aggregate as min depth (used by sizing paths),
|
|
865
|
+
// while exposing best-depth separately for hedge-side diagnostics.
|
|
866
|
+
const depthWithinSlippageUsd = minDepthWithinSlippageUsd;
|
|
854
867
|
|
|
855
868
|
if (!yesDepth) diagnostics.push('YES token orderbook unavailable.');
|
|
856
869
|
if (!noDepth) diagnostics.push('NO token orderbook unavailable.');
|
|
@@ -884,6 +897,8 @@ async function fetchDepthForMarket(market, options = {}) {
|
|
|
884
897
|
slippageBps,
|
|
885
898
|
host: hostUsed || null,
|
|
886
899
|
depthWithinSlippageUsd: round(depthWithinSlippageUsd, 6) || 0,
|
|
900
|
+
minDepthWithinSlippageUsd: round(minDepthWithinSlippageUsd, 6) || 0,
|
|
901
|
+
bestDepthWithinSlippageUsd: round(bestDepthWithinSlippageUsd, 6) || 0,
|
|
887
902
|
yesDepth,
|
|
888
903
|
noDepth,
|
|
889
904
|
cacheFile,
|
package/cli/pandora.cjs
CHANGED
|
@@ -21,7 +21,12 @@ const {
|
|
|
21
21
|
daemonStatus: mirrorDaemonStatus,
|
|
22
22
|
} = require('./lib/mirror_daemon_service.cjs');
|
|
23
23
|
const { buildMirrorClosePlan } = require('./lib/mirror_close_service.cjs');
|
|
24
|
-
const {
|
|
24
|
+
const {
|
|
25
|
+
fetchPolymarketPositionSummary,
|
|
26
|
+
resolvePolymarketMarket,
|
|
27
|
+
placeHedgeOrder,
|
|
28
|
+
readTradingCredsFromEnv,
|
|
29
|
+
} = require('./lib/polymarket_trade_adapter.cjs');
|
|
25
30
|
const {
|
|
26
31
|
runPolymarketCheck,
|
|
27
32
|
runPolymarketApprove,
|
|
@@ -238,7 +243,7 @@ Usage:
|
|
|
238
243
|
pandora [--output table|json] arbitrage [--chain-id <id>] [--venues pandora,polymarket] [--limit <n>] [--min-spread-pct <n>] [--min-liquidity-usdc <n>] [--max-close-diff-hours <n>] [--similarity-threshold <0-1>] [--cross-venue-only|--allow-same-venue] [--with-rules] [--include-similarity] [--question-contains <text>] [--polymarket-host <url>] [--polymarket-mock-url <url>]
|
|
239
244
|
pandora [--output table|json] autopilot run|once --market-address <address> --side yes|no --amount-usdc <amount> [--trigger-yes-below <0-100>] [--trigger-yes-above <0-100>] [--paper|--execute-live] [--interval-ms <ms>] [--cooldown-ms <ms>] [--max-amount-usdc <amount>] [--max-open-exposure-usdc <amount>] [--max-trades-per-day <n>] [--state-file <path>] [--kill-switch-file <path>] [--webhook-url <url>] [--telegram-bot-token <token>] [--telegram-chat-id <id>] [--discord-webhook-url <url>]
|
|
240
245
|
pandora [--output table|json] mirror browse|plan|deploy|verify|go|sync|status|close ...
|
|
241
|
-
pandora [--output table|json] polymarket check|approve|preflight ...
|
|
246
|
+
pandora [--output table|json] polymarket check|approve|preflight|trade ...
|
|
242
247
|
pandora [--output table|json] webhook test [--webhook-url <url>] [--webhook-template <json>] [--webhook-secret <secret>] [--telegram-bot-token <token>] [--telegram-chat-id <id>] [--discord-webhook-url <url>] [--webhook-timeout-ms <ms>] [--webhook-retries <n>]
|
|
243
248
|
pandora [--output table|json] leaderboard [--metric profit|volume|win-rate] [--chain-id <id>] [--limit <n>] [--min-trades <n>]
|
|
244
249
|
pandora [--output table|json] analyze --market-address <address> [--provider <name>] [--model <id>] [--max-cost-usd <n>] [--temperature <n>] [--timeout-ms <ms>]
|
|
@@ -269,10 +274,11 @@ Examples:
|
|
|
269
274
|
pandora mirror browse --min-yes-pct 20 --max-yes-pct 80 --min-volume-24h 100000 --limit 10
|
|
270
275
|
pandora mirror verify --pandora-market-address 0xabc... --polymarket-market-id 0xdef... --include-similarity
|
|
271
276
|
pandora mirror go --polymarket-slug nba-mia-phi-2026-02-28 --liquidity-usdc 10 --paper
|
|
272
|
-
pandora mirror sync once --pandora-market-address 0xabc... --polymarket-market-id 0xdef... --paper --hedge-ratio 1.0
|
|
277
|
+
pandora mirror sync once --pandora-market-address 0xabc... --polymarket-market-id 0xdef... --paper --hedge-ratio 1.0 --force-gate
|
|
273
278
|
pandora polymarket check --rpc-url https://polygon-bor-rpc.publicnode.com --private-key 0x... --funder 0xproxy...
|
|
274
279
|
pandora polymarket approve --dry-run --rpc-url https://polygon-bor-rpc.publicnode.com --private-key 0x... --funder 0xproxy...
|
|
275
280
|
pandora polymarket preflight --rpc-url https://polygon-bor-rpc.publicnode.com --private-key 0x... --funder 0xproxy...
|
|
281
|
+
pandora polymarket trade --condition-id 0xabc... --token yes --amount-usdc 2 --dry-run
|
|
276
282
|
pandora mirror close --pandora-market-address 0xabc... --polymarket-market-id 0xdef... --dry-run
|
|
277
283
|
pandora webhook test --webhook-url https://example.com/hook --webhook-template '{\"text\":\"{{message}}\"}'
|
|
278
284
|
pandora leaderboard --metric profit --limit 20
|
|
@@ -487,7 +493,7 @@ function helpJsonPayload() {
|
|
|
487
493
|
'pandora [--output table|json] arbitrage ...',
|
|
488
494
|
'pandora [--output table|json] autopilot run|once ...',
|
|
489
495
|
'pandora [--output table|json] mirror plan|deploy|verify|sync|status ...',
|
|
490
|
-
'pandora [--output table|json] polymarket check|approve|preflight ...',
|
|
496
|
+
'pandora [--output table|json] polymarket check|approve|preflight|trade ...',
|
|
491
497
|
'pandora [--output table|json] webhook test ...',
|
|
492
498
|
'pandora [--output table|json] leaderboard ...',
|
|
493
499
|
'pandora [--output table|json] analyze ...',
|
|
@@ -3261,6 +3267,7 @@ function parseMirrorSyncFlags(args) {
|
|
|
3261
3267
|
discordWebhookUrl: null,
|
|
3262
3268
|
failOnWebhookError: false,
|
|
3263
3269
|
daemon: false,
|
|
3270
|
+
forceGate: false,
|
|
3264
3271
|
};
|
|
3265
3272
|
let sawPaperModeFlag = false;
|
|
3266
3273
|
let sawExecuteLiveModeFlag = false;
|
|
@@ -3451,6 +3458,10 @@ function parseMirrorSyncFlags(args) {
|
|
|
3451
3458
|
options.trustDeploy = true;
|
|
3452
3459
|
continue;
|
|
3453
3460
|
}
|
|
3461
|
+
if (token === '--force-gate' || token === '--skip-gate') {
|
|
3462
|
+
options.forceGate = true;
|
|
3463
|
+
continue;
|
|
3464
|
+
}
|
|
3454
3465
|
if (token === '--manifest-file') {
|
|
3455
3466
|
options.manifestFile = requireFlagValue(rest, i, '--manifest-file');
|
|
3456
3467
|
i += 1;
|
|
@@ -3508,6 +3519,7 @@ function parseMirrorSyncFlags(args) {
|
|
|
3508
3519
|
hedgeEnabled: options.hedgeEnabled,
|
|
3509
3520
|
hedgeRatio: options.hedgeRatio,
|
|
3510
3521
|
hedgeTriggerUsdc: options.hedgeTriggerUsdc,
|
|
3522
|
+
forceGate: options.forceGate,
|
|
3511
3523
|
});
|
|
3512
3524
|
}
|
|
3513
3525
|
if (options.killSwitchFile === null) {
|
|
@@ -3563,6 +3575,7 @@ function buildMirrorSyncStrategy(options) {
|
|
|
3563
3575
|
hedgeEnabled: options.hedgeEnabled,
|
|
3564
3576
|
hedgeRatio: options.hedgeRatio,
|
|
3565
3577
|
hedgeTriggerUsdc: options.hedgeTriggerUsdc,
|
|
3578
|
+
forceGate: options.forceGate,
|
|
3566
3579
|
};
|
|
3567
3580
|
}
|
|
3568
3581
|
|
|
@@ -3628,6 +3641,7 @@ function buildMirrorSyncDaemonCliArgs(options, shared) {
|
|
|
3628
3641
|
if (options.polymarketGammaMockUrl) args.push('--polymarket-gamma-mock-url', options.polymarketGammaMockUrl);
|
|
3629
3642
|
if (options.polymarketMockUrl) args.push('--polymarket-mock-url', options.polymarketMockUrl);
|
|
3630
3643
|
if (options.trustDeploy) args.push('--trust-deploy');
|
|
3644
|
+
if (options.forceGate) args.push('--force-gate');
|
|
3631
3645
|
if (options.manifestFile) args.push('--manifest-file', options.manifestFile);
|
|
3632
3646
|
|
|
3633
3647
|
if (options.webhookUrl) args.push('--webhook-url', options.webhookUrl);
|
|
@@ -3676,6 +3690,7 @@ function parseMirrorGoFlags(args) {
|
|
|
3676
3690
|
sources: [],
|
|
3677
3691
|
manifestFile: null,
|
|
3678
3692
|
trustDeploy: false,
|
|
3693
|
+
forceGate: false,
|
|
3679
3694
|
polymarketHost: null,
|
|
3680
3695
|
polymarketGammaUrl: null,
|
|
3681
3696
|
polymarketGammaMockUrl: null,
|
|
@@ -3857,6 +3872,10 @@ function parseMirrorGoFlags(args) {
|
|
|
3857
3872
|
options.trustDeploy = true;
|
|
3858
3873
|
continue;
|
|
3859
3874
|
}
|
|
3875
|
+
if (token === '--force-gate' || token === '--skip-gate') {
|
|
3876
|
+
options.forceGate = true;
|
|
3877
|
+
continue;
|
|
3878
|
+
}
|
|
3860
3879
|
if (token === '--polymarket-host') {
|
|
3861
3880
|
options.polymarketHost = requireFlagValue(args, i, '--polymarket-host');
|
|
3862
3881
|
i += 1;
|
|
@@ -4041,6 +4060,102 @@ function parsePolymarketApproveFlags(args) {
|
|
|
4041
4060
|
return options;
|
|
4042
4061
|
}
|
|
4043
4062
|
|
|
4063
|
+
function parsePolymarketTradeFlags(args) {
|
|
4064
|
+
const options = {
|
|
4065
|
+
conditionId: null,
|
|
4066
|
+
slug: null,
|
|
4067
|
+
token: null,
|
|
4068
|
+
tokenId: null,
|
|
4069
|
+
side: 'buy',
|
|
4070
|
+
amountUsdc: null,
|
|
4071
|
+
dryRun: false,
|
|
4072
|
+
execute: false,
|
|
4073
|
+
host: null,
|
|
4074
|
+
rpcUrl: null,
|
|
4075
|
+
privateKey: null,
|
|
4076
|
+
funder: null,
|
|
4077
|
+
};
|
|
4078
|
+
|
|
4079
|
+
const sharedArgs = [];
|
|
4080
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
4081
|
+
const token = args[i];
|
|
4082
|
+
if (token === '--condition-id' || token === '--market-id') {
|
|
4083
|
+
options.conditionId = requireFlagValue(args, i, token);
|
|
4084
|
+
i += 1;
|
|
4085
|
+
continue;
|
|
4086
|
+
}
|
|
4087
|
+
if (token === '--slug') {
|
|
4088
|
+
options.slug = requireFlagValue(args, i, '--slug');
|
|
4089
|
+
i += 1;
|
|
4090
|
+
continue;
|
|
4091
|
+
}
|
|
4092
|
+
if (token === '--token') {
|
|
4093
|
+
const value = String(requireFlagValue(args, i, '--token')).trim().toLowerCase();
|
|
4094
|
+
if (!['yes', 'no'].includes(value)) {
|
|
4095
|
+
throw new CliError('INVALID_FLAG_VALUE', '--token must be yes|no.');
|
|
4096
|
+
}
|
|
4097
|
+
options.token = value;
|
|
4098
|
+
i += 1;
|
|
4099
|
+
continue;
|
|
4100
|
+
}
|
|
4101
|
+
if (token === '--token-id') {
|
|
4102
|
+
options.tokenId = requireFlagValue(args, i, '--token-id');
|
|
4103
|
+
i += 1;
|
|
4104
|
+
continue;
|
|
4105
|
+
}
|
|
4106
|
+
if (token === '--side') {
|
|
4107
|
+
const value = String(requireFlagValue(args, i, '--side')).trim().toLowerCase();
|
|
4108
|
+
if (!['buy', 'sell'].includes(value)) {
|
|
4109
|
+
throw new CliError('INVALID_FLAG_VALUE', '--side must be buy|sell.');
|
|
4110
|
+
}
|
|
4111
|
+
options.side = value;
|
|
4112
|
+
i += 1;
|
|
4113
|
+
continue;
|
|
4114
|
+
}
|
|
4115
|
+
if (token === '--amount-usdc') {
|
|
4116
|
+
options.amountUsdc = parsePositiveNumber(requireFlagValue(args, i, '--amount-usdc'), '--amount-usdc');
|
|
4117
|
+
i += 1;
|
|
4118
|
+
continue;
|
|
4119
|
+
}
|
|
4120
|
+
if (token === '--polymarket-host') {
|
|
4121
|
+
options.host = requireFlagValue(args, i, '--polymarket-host');
|
|
4122
|
+
i += 1;
|
|
4123
|
+
continue;
|
|
4124
|
+
}
|
|
4125
|
+
if (token === '--dry-run') {
|
|
4126
|
+
options.dryRun = true;
|
|
4127
|
+
continue;
|
|
4128
|
+
}
|
|
4129
|
+
if (token === '--execute') {
|
|
4130
|
+
options.execute = true;
|
|
4131
|
+
continue;
|
|
4132
|
+
}
|
|
4133
|
+
sharedArgs.push(token);
|
|
4134
|
+
}
|
|
4135
|
+
|
|
4136
|
+
if (options.dryRun === options.execute) {
|
|
4137
|
+
throw new CliError('INVALID_ARGS', 'polymarket trade requires exactly one mode: --dry-run or --execute.');
|
|
4138
|
+
}
|
|
4139
|
+
if (options.amountUsdc === null) {
|
|
4140
|
+
throw new CliError('MISSING_REQUIRED_FLAG', 'Missing --amount-usdc <amount>.');
|
|
4141
|
+
}
|
|
4142
|
+
if (!options.tokenId && !options.token) {
|
|
4143
|
+
throw new CliError('MISSING_REQUIRED_FLAG', 'Provide --token yes|no (or --token-id <id>).');
|
|
4144
|
+
}
|
|
4145
|
+
if (!options.tokenId && !options.conditionId && !options.slug) {
|
|
4146
|
+
throw new CliError(
|
|
4147
|
+
'MISSING_REQUIRED_FLAG',
|
|
4148
|
+
'Provide --condition-id <id> or --slug <slug> when --token-id is not set.',
|
|
4149
|
+
);
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4152
|
+
const shared = parsePolymarketSharedFlags(sharedArgs, 'trade');
|
|
4153
|
+
options.rpcUrl = shared.rpcUrl;
|
|
4154
|
+
options.privateKey = shared.privateKey;
|
|
4155
|
+
options.funder = shared.funder;
|
|
4156
|
+
return options;
|
|
4157
|
+
}
|
|
4158
|
+
|
|
4044
4159
|
function parseWebhookTestFlags(args) {
|
|
4045
4160
|
const options = {
|
|
4046
4161
|
webhookUrl: null,
|
|
@@ -4486,7 +4601,8 @@ async function rpcRequest(rpcUrl, method, params, timeoutMs) {
|
|
|
4486
4601
|
return payload.result;
|
|
4487
4602
|
}
|
|
4488
4603
|
|
|
4489
|
-
async function probeHttpEndpoint(url, timeoutMs, method = 'HEAD') {
|
|
4604
|
+
async function probeHttpEndpoint(url, timeoutMs, method = 'HEAD', options = {}) {
|
|
4605
|
+
const acceptAnyHttpStatus = Boolean(options.acceptAnyHttpStatus);
|
|
4490
4606
|
const controller = new AbortController();
|
|
4491
4607
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
4492
4608
|
try {
|
|
@@ -4494,10 +4610,13 @@ async function probeHttpEndpoint(url, timeoutMs, method = 'HEAD') {
|
|
|
4494
4610
|
method,
|
|
4495
4611
|
signal: controller.signal,
|
|
4496
4612
|
});
|
|
4613
|
+
const reachable = acceptAnyHttpStatus
|
|
4614
|
+
? response.status >= 100 && response.status < 500
|
|
4615
|
+
: response.ok;
|
|
4497
4616
|
return {
|
|
4498
|
-
ok:
|
|
4617
|
+
ok: reachable,
|
|
4499
4618
|
status: response.status,
|
|
4500
|
-
error:
|
|
4619
|
+
error: reachable ? null : `HTTP ${response.status}`,
|
|
4501
4620
|
};
|
|
4502
4621
|
} catch (err) {
|
|
4503
4622
|
if (err && err.name === 'AbortError') {
|
|
@@ -4707,10 +4826,15 @@ async function buildDoctorReport(options) {
|
|
|
4707
4826
|
}
|
|
4708
4827
|
|
|
4709
4828
|
if (shouldCheckPolymarket) {
|
|
4710
|
-
const
|
|
4829
|
+
const polymarketProbeTarget = `${String(report.polymarket.host).replace(/\/+$/, '')}/time`;
|
|
4830
|
+
const hostProbe = await probeHttpEndpoint(polymarketProbeTarget, options.rpcTimeoutMs, 'GET', {
|
|
4831
|
+
acceptAnyHttpStatus: true,
|
|
4832
|
+
});
|
|
4711
4833
|
report.polymarket.hostReachability = hostProbe;
|
|
4712
4834
|
if (!hostProbe.ok) {
|
|
4713
|
-
report.polymarket.failures.push(
|
|
4835
|
+
report.polymarket.failures.push(
|
|
4836
|
+
`Polymarket host reachability failed (${polymarketProbeTarget}): ${hostProbe.error || 'unknown error'}`,
|
|
4837
|
+
);
|
|
4714
4838
|
}
|
|
4715
4839
|
|
|
4716
4840
|
let polyCheck = null;
|
|
@@ -5735,7 +5859,26 @@ function renderSuggestTable(data) {
|
|
|
5735
5859
|
}
|
|
5736
5860
|
|
|
5737
5861
|
function renderSingleEntityTable(data) {
|
|
5738
|
-
|
|
5862
|
+
if (data && typeof data.item === 'object' && data.item !== null) {
|
|
5863
|
+
printRecord(data.item);
|
|
5864
|
+
return;
|
|
5865
|
+
}
|
|
5866
|
+
if (Array.isArray(data && data.items)) {
|
|
5867
|
+
if (!data.items.length) {
|
|
5868
|
+
console.log('No items found.');
|
|
5869
|
+
return;
|
|
5870
|
+
}
|
|
5871
|
+
for (const item of data.items) {
|
|
5872
|
+
printRecord(item);
|
|
5873
|
+
console.log('');
|
|
5874
|
+
}
|
|
5875
|
+
return;
|
|
5876
|
+
}
|
|
5877
|
+
if (data && typeof data === 'object') {
|
|
5878
|
+
printRecord(data);
|
|
5879
|
+
return;
|
|
5880
|
+
}
|
|
5881
|
+
console.log(String(data));
|
|
5739
5882
|
}
|
|
5740
5883
|
|
|
5741
5884
|
function renderMarketsGetTable(data) {
|
|
@@ -8086,7 +8229,11 @@ function renderMirrorSyncTickLine(tickContext, outputMode) {
|
|
|
8086
8229
|
const action = snapshot.action || null;
|
|
8087
8230
|
const actionStatus = action && action.status ? action.status : 'idle';
|
|
8088
8231
|
const gateCode =
|
|
8089
|
-
action && Array.isArray(action.failedChecks) && action.failedChecks.length
|
|
8232
|
+
action && Array.isArray(action.failedChecks) && action.failedChecks.length
|
|
8233
|
+
? action.forcedGateBypass
|
|
8234
|
+
? `forced:${action.failedChecks[0]}`
|
|
8235
|
+
: action.failedChecks[0]
|
|
8236
|
+
: '';
|
|
8090
8237
|
|
|
8091
8238
|
if (outputMode === 'json') {
|
|
8092
8239
|
console.log(
|
|
@@ -8166,10 +8313,10 @@ async function runMirrorCommand(args, context) {
|
|
|
8166
8313
|
' verify --pandora-market-address <address> --polymarket-market-id <id>|--polymarket-slug <slug> [--trust-deploy] [--manifest-file <path>] [--include-similarity] [--with-rules] [--allow-rule-mismatch]',
|
|
8167
8314
|
);
|
|
8168
8315
|
console.log(
|
|
8169
|
-
' go --polymarket-market-id <id>|--polymarket-slug <slug> [--liquidity-usdc <n>] [--paper|--execute-live] [--private-key <hex>] [--funder <address>] [--auto-sync] [--sync-once]',
|
|
8316
|
+
' go --polymarket-market-id <id>|--polymarket-slug <slug> [--liquidity-usdc <n>] [--paper|--execute-live] [--private-key <hex>] [--funder <address>] [--auto-sync] [--sync-once] [--force-gate]',
|
|
8170
8317
|
);
|
|
8171
8318
|
console.log(
|
|
8172
|
-
' sync run|once|start|stop|status --pandora-market-address <address> --polymarket-market-id <id>|--polymarket-slug <slug> [--paper|--execute-live] [--private-key <hex>] [--funder <address>] [--trust-deploy] [--daemon] [--stream] [--interval-ms <ms>] [--drift-trigger-bps <n>] [--hedge-trigger-usdc <n>] [--hedge-ratio <n>] [--no-hedge] [--max-rebalance-usdc <n>] [--max-hedge-usdc <n>] [--max-open-exposure-usdc <n>] [--max-trades-per-day <n>] [--cooldown-ms <ms>] [--state-file <path>] [--kill-switch-file <path>]',
|
|
8319
|
+
' sync run|once|start|stop|status --pandora-market-address <address> --polymarket-market-id <id>|--polymarket-slug <slug> [--paper|--execute-live] [--private-key <hex>] [--funder <address>] [--trust-deploy] [--force-gate] [--daemon] [--stream] [--interval-ms <ms>] [--drift-trigger-bps <n>] [--hedge-trigger-usdc <n>] [--hedge-ratio <n>] [--no-hedge] [--max-rebalance-usdc <n>] [--max-hedge-usdc <n>] [--max-open-exposure-usdc <n>] [--max-trades-per-day <n>] [--cooldown-ms <ms>] [--state-file <path>] [--kill-switch-file <path>]',
|
|
8173
8320
|
);
|
|
8174
8321
|
console.log(' status --state-file <path>|--strategy-hash <hash> [--with-live] [--trust-deploy]');
|
|
8175
8322
|
console.log(' close --pandora-market-address <address> --polymarket-market-id <id>|--polymarket-slug <slug> --dry-run|--execute');
|
|
@@ -8470,7 +8617,7 @@ async function runMirrorCommand(args, context) {
|
|
|
8470
8617
|
if (action === 'go') {
|
|
8471
8618
|
if (includesHelpFlag(shared.rest)) {
|
|
8472
8619
|
const usage =
|
|
8473
|
-
'pandora [--output table|json] mirror go --polymarket-market-id <id>|--polymarket-slug <slug> [--liquidity-usdc <n>] [--paper|--execute-live] [--private-key <hex>] [--funder <address>] [--auto-sync] [--sync-once]';
|
|
8620
|
+
'pandora [--output table|json] mirror go --polymarket-market-id <id>|--polymarket-slug <slug> [--liquidity-usdc <n>] [--paper|--execute-live] [--private-key <hex>] [--funder <address>] [--auto-sync] [--sync-once] [--force-gate]';
|
|
8474
8621
|
if (context.outputMode === 'json') {
|
|
8475
8622
|
emitSuccess(context.outputMode, 'mirror.go.help', commandHelpPayload(usage));
|
|
8476
8623
|
} else {
|
|
@@ -8611,6 +8758,7 @@ async function runMirrorCommand(args, context) {
|
|
|
8611
8758
|
polymarketGammaMockUrl: options.polymarketGammaMockUrl,
|
|
8612
8759
|
polymarketMockUrl: options.polymarketMockUrl,
|
|
8613
8760
|
trustDeploy,
|
|
8761
|
+
forceGate: options.forceGate,
|
|
8614
8762
|
webhookUrl: null,
|
|
8615
8763
|
webhookTemplate: null,
|
|
8616
8764
|
webhookSecret: null,
|
|
@@ -8672,6 +8820,7 @@ async function runMirrorCommand(args, context) {
|
|
|
8672
8820
|
'--paper',
|
|
8673
8821
|
`--drift-trigger-bps ${options.driftTriggerBps}`,
|
|
8674
8822
|
`--hedge-trigger-usdc ${options.hedgeTriggerUsdc}`,
|
|
8823
|
+
options.forceGate ? '--force-gate' : null,
|
|
8675
8824
|
]
|
|
8676
8825
|
.filter(Boolean)
|
|
8677
8826
|
.join(' ');
|
|
@@ -8714,7 +8863,7 @@ async function runMirrorCommand(args, context) {
|
|
|
8714
8863
|
'mirror.sync.help',
|
|
8715
8864
|
{
|
|
8716
8865
|
usage:
|
|
8717
|
-
'pandora [--output table|json] mirror sync run|once|start|stop|status --pandora-market-address <address> --polymarket-market-id <id>|--polymarket-slug <slug> [--paper|--execute-live] [--private-key <hex>] [--funder <address>] [--trust-deploy] [--daemon] [--stream] [--interval-ms <ms>] [--drift-trigger-bps <n>] [--hedge-trigger-usdc <n>] [--hedge-ratio <n>] [--no-hedge] [--max-rebalance-usdc <n>] [--max-hedge-usdc <n>] [--max-open-exposure-usdc <n>] [--max-trades-per-day <n>] [--cooldown-ms <ms>] [--min-time-to-close-sec <n>] [--state-file <path>] [--kill-switch-file <path>]',
|
|
8866
|
+
'pandora [--output table|json] mirror sync run|once|start|stop|status --pandora-market-address <address> --polymarket-market-id <id>|--polymarket-slug <slug> [--paper|--execute-live] [--private-key <hex>] [--funder <address>] [--trust-deploy] [--force-gate] [--daemon] [--stream] [--interval-ms <ms>] [--drift-trigger-bps <n>] [--hedge-trigger-usdc <n>] [--hedge-ratio <n>] [--no-hedge] [--max-rebalance-usdc <n>] [--max-hedge-usdc <n>] [--max-open-exposure-usdc <n>] [--max-trades-per-day <n>] [--cooldown-ms <ms>] [--min-time-to-close-sec <n>] [--state-file <path>] [--kill-switch-file <path>]',
|
|
8718
8867
|
daemonLifecycle: {
|
|
8719
8868
|
start:
|
|
8720
8869
|
'pandora [--output table|json] mirror sync start --pandora-market-address <address> --polymarket-market-id <id>|--polymarket-slug <slug> [run flags]',
|
|
@@ -8743,7 +8892,7 @@ async function runMirrorCommand(args, context) {
|
|
|
8743
8892
|
);
|
|
8744
8893
|
} else {
|
|
8745
8894
|
console.log(
|
|
8746
|
-
'Usage: pandora [--output table|json] mirror sync run|once|start|stop|status --pandora-market-address <address> --polymarket-market-id <id>|--polymarket-slug <slug> [--paper|--execute-live] [--private-key <hex>] [--funder <address>] [--trust-deploy] [--daemon] [--stream] [--interval-ms <ms>] [--drift-trigger-bps <n>] [--hedge-trigger-usdc <n>] [--hedge-ratio <n>] [--no-hedge] [--max-rebalance-usdc <n>] [--max-hedge-usdc <n>] [--max-open-exposure-usdc <n>] [--max-trades-per-day <n>] [--cooldown-ms <ms>] [--min-time-to-close-sec <n>] [--state-file <path>] [--kill-switch-file <path>]',
|
|
8895
|
+
'Usage: pandora [--output table|json] mirror sync run|once|start|stop|status --pandora-market-address <address> --polymarket-market-id <id>|--polymarket-slug <slug> [--paper|--execute-live] [--private-key <hex>] [--funder <address>] [--trust-deploy] [--force-gate] [--daemon] [--stream] [--interval-ms <ms>] [--drift-trigger-bps <n>] [--hedge-trigger-usdc <n>] [--hedge-ratio <n>] [--no-hedge] [--max-rebalance-usdc <n>] [--max-hedge-usdc <n>] [--max-open-exposure-usdc <n>] [--max-trades-per-day <n>] [--cooldown-ms <ms>] [--min-time-to-close-sec <n>] [--state-file <path>] [--kill-switch-file <path>]',
|
|
8747
8896
|
);
|
|
8748
8897
|
console.log('Daemon stop: pandora mirror sync stop --pid-file <path>|--strategy-hash <hash>');
|
|
8749
8898
|
console.log('Daemon status: pandora mirror sync status --pid-file <path>|--strategy-hash <hash>');
|
|
@@ -8980,7 +9129,7 @@ async function runPolymarketCommand(args, context) {
|
|
|
8980
9129
|
const actionArgs = args.slice(1);
|
|
8981
9130
|
|
|
8982
9131
|
if (!action || action === '--help' || action === '-h') {
|
|
8983
|
-
const usage = 'pandora [--output table|json] polymarket check|approve|preflight ...';
|
|
9132
|
+
const usage = 'pandora [--output table|json] polymarket check|approve|preflight|trade ...';
|
|
8984
9133
|
if (context.outputMode === 'json') {
|
|
8985
9134
|
emitSuccess(context.outputMode, 'polymarket.help', commandHelpPayload(usage));
|
|
8986
9135
|
} else {
|
|
@@ -8990,6 +9139,9 @@ async function runPolymarketCommand(args, context) {
|
|
|
8990
9139
|
console.log(' check [--rpc-url <url>] [--private-key <hex>] [--funder <address>]');
|
|
8991
9140
|
console.log(' approve --dry-run|--execute [--rpc-url <url>] [--private-key <hex>] [--funder <address>]');
|
|
8992
9141
|
console.log(' preflight [--rpc-url <url>] [--private-key <hex>] [--funder <address>]');
|
|
9142
|
+
console.log(
|
|
9143
|
+
' trade --condition-id <id>|--slug <slug>|--token-id <id> --token yes|no --amount-usdc <n> --dry-run|--execute [--side buy|sell] [--polymarket-host <url>] [--rpc-url <url>] [--private-key <hex>] [--funder <address>]',
|
|
9144
|
+
);
|
|
8993
9145
|
}
|
|
8994
9146
|
return;
|
|
8995
9147
|
}
|
|
@@ -9064,7 +9216,102 @@ async function runPolymarketCommand(args, context) {
|
|
|
9064
9216
|
return;
|
|
9065
9217
|
}
|
|
9066
9218
|
|
|
9067
|
-
|
|
9219
|
+
if (action === 'trade') {
|
|
9220
|
+
if (includesHelpFlag(actionArgs)) {
|
|
9221
|
+
const usage =
|
|
9222
|
+
'pandora [--output table|json] polymarket trade --condition-id <id>|--slug <slug>|--token-id <id> --token yes|no --amount-usdc <n> --dry-run|--execute [--side buy|sell] [--polymarket-host <url>] [--rpc-url <url>] [--private-key <hex>] [--funder <address>]';
|
|
9223
|
+
if (context.outputMode === 'json') {
|
|
9224
|
+
emitSuccess(context.outputMode, 'polymarket.trade.help', commandHelpPayload(usage));
|
|
9225
|
+
} else {
|
|
9226
|
+
console.log(`Usage: ${usage}`);
|
|
9227
|
+
}
|
|
9228
|
+
return;
|
|
9229
|
+
}
|
|
9230
|
+
|
|
9231
|
+
const options = parsePolymarketTradeFlags(actionArgs);
|
|
9232
|
+
let market = null;
|
|
9233
|
+
let tokenId = options.tokenId;
|
|
9234
|
+
if (!tokenId) {
|
|
9235
|
+
market = await resolvePolymarketMarket({
|
|
9236
|
+
host: options.host || process.env.POLYMARKET_HOST || null,
|
|
9237
|
+
timeoutMs: DEFAULT_INDEXER_TIMEOUT_MS,
|
|
9238
|
+
marketId: options.conditionId,
|
|
9239
|
+
slug: options.slug,
|
|
9240
|
+
});
|
|
9241
|
+
tokenId = options.token === 'yes' ? market.yesTokenId : market.noTokenId;
|
|
9242
|
+
if (!tokenId) {
|
|
9243
|
+
throw new CliError(
|
|
9244
|
+
'POLYMARKET_TOKEN_MAPPING_FAILED',
|
|
9245
|
+
`Unable to resolve ${String(options.token || '').toUpperCase()} token id for target market.`,
|
|
9246
|
+
{
|
|
9247
|
+
conditionId: options.conditionId,
|
|
9248
|
+
slug: options.slug,
|
|
9249
|
+
market,
|
|
9250
|
+
},
|
|
9251
|
+
);
|
|
9252
|
+
}
|
|
9253
|
+
}
|
|
9254
|
+
|
|
9255
|
+
if (options.dryRun) {
|
|
9256
|
+
emitSuccess(context.outputMode, 'polymarket.trade', {
|
|
9257
|
+
mode: 'dry-run',
|
|
9258
|
+
status: 'planned',
|
|
9259
|
+
conditionId: options.conditionId || (market && market.marketId) || null,
|
|
9260
|
+
slug: options.slug || (market && market.slug) || null,
|
|
9261
|
+
token: options.token || null,
|
|
9262
|
+
tokenId,
|
|
9263
|
+
side: options.side,
|
|
9264
|
+
amountUsdc: options.amountUsdc,
|
|
9265
|
+
host: options.host || process.env.POLYMARKET_HOST || null,
|
|
9266
|
+
}, renderSingleEntityTable);
|
|
9267
|
+
return;
|
|
9268
|
+
}
|
|
9269
|
+
|
|
9270
|
+
const envCreds = readTradingCredsFromEnv();
|
|
9271
|
+
let result;
|
|
9272
|
+
try {
|
|
9273
|
+
result = await placeHedgeOrder({
|
|
9274
|
+
host: options.host || envCreds.host || null,
|
|
9275
|
+
tokenId,
|
|
9276
|
+
side: options.side,
|
|
9277
|
+
amountUsd: options.amountUsdc,
|
|
9278
|
+
privateKey: options.privateKey || envCreds.privateKey,
|
|
9279
|
+
funder: options.funder || envCreds.funder,
|
|
9280
|
+
apiKey: envCreds.apiKey,
|
|
9281
|
+
apiSecret: envCreds.apiSecret,
|
|
9282
|
+
apiPassphrase: envCreds.apiPassphrase,
|
|
9283
|
+
});
|
|
9284
|
+
} catch (err) {
|
|
9285
|
+
throw new CliError(
|
|
9286
|
+
'POLYMARKET_TRADE_FAILED',
|
|
9287
|
+
err && err.message ? err.message : 'Polymarket trade execution failed.',
|
|
9288
|
+
{ cause: err && err.message ? err.message : String(err) },
|
|
9289
|
+
);
|
|
9290
|
+
}
|
|
9291
|
+
|
|
9292
|
+
if (!result || result.ok === false) {
|
|
9293
|
+
throw new CliError(
|
|
9294
|
+
'POLYMARKET_TRADE_FAILED',
|
|
9295
|
+
result && result.error && result.error.message ? result.error.message : 'Polymarket order was rejected.',
|
|
9296
|
+
{ result },
|
|
9297
|
+
);
|
|
9298
|
+
}
|
|
9299
|
+
|
|
9300
|
+
emitSuccess(context.outputMode, 'polymarket.trade', {
|
|
9301
|
+
mode: 'execute',
|
|
9302
|
+
status: 'submitted',
|
|
9303
|
+
conditionId: options.conditionId || (market && market.marketId) || null,
|
|
9304
|
+
slug: options.slug || (market && market.slug) || null,
|
|
9305
|
+
token: options.token || null,
|
|
9306
|
+
tokenId,
|
|
9307
|
+
side: options.side,
|
|
9308
|
+
amountUsdc: options.amountUsdc,
|
|
9309
|
+
result,
|
|
9310
|
+
}, renderSingleEntityTable);
|
|
9311
|
+
return;
|
|
9312
|
+
}
|
|
9313
|
+
|
|
9314
|
+
throw new CliError('INVALID_ARGS', 'polymarket requires subcommand: check|approve|preflight|trade');
|
|
9068
9315
|
}
|
|
9069
9316
|
|
|
9070
9317
|
async function runWebhookCommand(args, context) {
|