perp-cli 0.11.0 → 0.12.0
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 +30 -25
- package/dist/_stderr-filter.d.ts +0 -0
- package/dist/_stderr-filter.js +30 -0
- package/dist/agent-wallet/expiry.d.ts +15 -0
- package/dist/agent-wallet/expiry.js +26 -0
- package/dist/agent-wallet/lighter-keystore.d.ts +34 -0
- package/dist/agent-wallet/lighter-keystore.js +232 -0
- package/dist/agent-wallet/passphrase.d.ts +13 -0
- package/dist/agent-wallet/passphrase.js +54 -0
- package/dist/agent-wallet/signing-strategy.d.ts +67 -0
- package/dist/agent-wallet/signing-strategy.js +51 -0
- package/dist/agent-wallet/store.d.ts +37 -0
- package/dist/agent-wallet/store.js +172 -0
- package/dist/api/public/_http.d.ts +15 -0
- package/dist/api/public/_http.js +24 -0
- package/dist/api/public/hyperliquid.js +36 -24
- package/dist/api/public/lighter.d.ts +7 -1
- package/dist/api/public/lighter.js +85 -37
- package/dist/api/public/pacifica.js +47 -18
- package/dist/bridge-engine.js +102 -49
- package/dist/cli-spec.js +1 -2
- package/dist/commands/account.js +2 -500
- package/dist/commands/agent.d.ts +8 -2
- package/dist/commands/agent.js +1903 -366
- package/dist/commands/alerts.js +3 -1
- package/dist/commands/arb/index.js +37 -7
- package/dist/commands/arb-auto.js +44 -11
- package/dist/commands/arb.js +83 -34
- package/dist/commands/bot.d.ts +1 -1
- package/dist/commands/bot.js +18 -14
- package/dist/commands/bridge.d.ts +1 -1
- package/dist/commands/bridge.js +4 -4
- package/dist/commands/funds.d.ts +1 -1
- package/dist/commands/funds.js +18 -68
- package/dist/commands/jobs.d.ts +1 -1
- package/dist/commands/jobs.js +2 -2
- package/dist/commands/manage.d.ts +1 -1
- package/dist/commands/manage.js +12 -84
- package/dist/commands/plan.d.ts +1 -1
- package/dist/commands/plan.js +2 -2
- package/dist/commands/portfolio.d.ts +19 -3
- package/dist/commands/portfolio.js +747 -163
- package/dist/commands/rebalance.d.ts +1 -1
- package/dist/commands/rebalance.js +18 -12
- package/dist/commands/risk.js +2 -6
- package/dist/commands/settings.js +30 -53
- package/dist/commands/trade.js +16 -15
- package/dist/commands/wallet.d.ts +2 -1
- package/dist/commands/wallet.js +756 -28
- package/dist/errors.d.ts +64 -0
- package/dist/errors.js +82 -2
- package/dist/event-stream.js +12 -1
- package/dist/exchanges/aster-typed-data.d.ts +156 -0
- package/dist/exchanges/aster-typed-data.js +189 -0
- package/dist/exchanges/aster.d.ts +60 -11
- package/dist/exchanges/aster.js +278 -136
- package/dist/exchanges/hyperliquid.d.ts +14 -0
- package/dist/exchanges/hyperliquid.js +84 -34
- package/dist/exchanges/lighter-spot.js +14 -3
- package/dist/exchanges/lighter.d.ts +66 -0
- package/dist/exchanges/lighter.js +199 -27
- package/dist/exchanges/pacifica-typed-data.d.ts +75 -0
- package/dist/exchanges/pacifica-typed-data.js +74 -0
- package/dist/exchanges/pacifica.d.ts +29 -1
- package/dist/exchanges/pacifica.js +94 -6
- package/dist/funding/rates.js +59 -21
- package/dist/guardrail/perp-guardrail.js +9 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +255 -360
- package/dist/jobs.js +3 -1
- package/dist/mcp-server.js +85 -83
- package/dist/position-history.js +47 -4
- package/dist/settings.d.ts +67 -3
- package/dist/settings.js +1 -2
- package/dist/signer/ows-evm.d.ts +14 -0
- package/dist/signer/ows-evm.js +28 -9
- package/dist/smart-order.d.ts +8 -2
- package/dist/smart-order.js +46 -11
- package/dist/strategies/funding-arb.js +29 -8
- package/dist/trade-validator.js +30 -5
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +19 -0
- package/package.json +2 -2
- package/skills/perp-cli/SKILL.md +23 -14
- package/skills/perp-cli/references/agent-operations.md +6 -4
- package/skills/perp-cli/references/commands.md +55 -34
- package/skills/perp-cli/scripts/preflight.sh +4 -4
- package/skills/perp-cli/scripts/spot-perp-scan.sh +2 -2
- package/dist/__tests__/alert-logic.test.d.ts +0 -1
- package/dist/__tests__/alert-logic.test.js +0 -107
- package/dist/__tests__/arb-auto-3dex.test.d.ts +0 -1
- package/dist/__tests__/arb-auto-3dex.test.js +0 -397
- package/dist/__tests__/arb-history-stats.test.d.ts +0 -1
- package/dist/__tests__/arb-history-stats.test.js +0 -176
- package/dist/__tests__/arb-logic.test.d.ts +0 -1
- package/dist/__tests__/arb-logic.test.js +0 -84
- package/dist/__tests__/arb-manage.test.d.ts +0 -1
- package/dist/__tests__/arb-manage.test.js +0 -253
- package/dist/__tests__/arb-new-features.test.d.ts +0 -1
- package/dist/__tests__/arb-new-features.test.js +0 -457
- package/dist/__tests__/arb-sizing.test.d.ts +0 -1
- package/dist/__tests__/arb-sizing.test.js +0 -48
- package/dist/__tests__/arb-state.test.d.ts +0 -1
- package/dist/__tests__/arb-state.test.js +0 -284
- package/dist/__tests__/arb-userflow.test.d.ts +0 -1
- package/dist/__tests__/arb-userflow.test.js +0 -945
- package/dist/__tests__/arb-utils.test.d.ts +0 -1
- package/dist/__tests__/arb-utils.test.js +0 -264
- package/dist/__tests__/bot-conditions.test.d.ts +0 -1
- package/dist/__tests__/bot-conditions.test.js +0 -341
- package/dist/__tests__/client-id-tracker.test.d.ts +0 -1
- package/dist/__tests__/client-id-tracker.test.js +0 -137
- package/dist/__tests__/commands/new-atomic-commands.test.d.ts +0 -1
- package/dist/__tests__/commands/new-atomic-commands.test.js +0 -502
- package/dist/__tests__/commands/order-intent.test.d.ts +0 -1
- package/dist/__tests__/commands/order-intent.test.js +0 -600
- package/dist/__tests__/commands/trade-commands.test.d.ts +0 -1
- package/dist/__tests__/commands/trade-commands.test.js +0 -821
- package/dist/__tests__/config.test.d.ts +0 -1
- package/dist/__tests__/config.test.js +0 -86
- package/dist/__tests__/cross-chain-margin.test.d.ts +0 -1
- package/dist/__tests__/cross-chain-margin.test.js +0 -287
- package/dist/__tests__/dex-asset-map.test.d.ts +0 -1
- package/dist/__tests__/dex-asset-map.test.js +0 -191
- package/dist/__tests__/errors.test.d.ts +0 -1
- package/dist/__tests__/errors.test.js +0 -110
- package/dist/__tests__/event-stream.test.d.ts +0 -1
- package/dist/__tests__/event-stream.test.js +0 -276
- package/dist/__tests__/exchanges/interface.test.d.ts +0 -1
- package/dist/__tests__/exchanges/interface.test.js +0 -132
- package/dist/__tests__/exchanges/mock-adapter.d.ts +0 -69
- package/dist/__tests__/exchanges/mock-adapter.js +0 -137
- package/dist/__tests__/execution-log.test.d.ts +0 -1
- package/dist/__tests__/execution-log.test.js +0 -106
- package/dist/__tests__/funding-calc.test.d.ts +0 -1
- package/dist/__tests__/funding-calc.test.js +0 -71
- package/dist/__tests__/funding-history.test.d.ts +0 -1
- package/dist/__tests__/funding-history.test.js +0 -343
- package/dist/__tests__/funding-rates.test.d.ts +0 -1
- package/dist/__tests__/funding-rates.test.js +0 -342
- package/dist/__tests__/funding.test.d.ts +0 -1
- package/dist/__tests__/funding.test.js +0 -173
- package/dist/__tests__/gap-logic.test.d.ts +0 -1
- package/dist/__tests__/gap-logic.test.js +0 -43
- package/dist/__tests__/hip3-dex.test.d.ts +0 -1
- package/dist/__tests__/hip3-dex.test.js +0 -234
- package/dist/__tests__/integration/agent-features.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/agent-features.integration.test.js +0 -553
- package/dist/__tests__/integration/atomic-commands.integration.test.d.ts +0 -13
- package/dist/__tests__/integration/atomic-commands.integration.test.js +0 -246
- package/dist/__tests__/integration/bridge-simulation.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/bridge-simulation.integration.test.js +0 -453
- package/dist/__tests__/integration/bridge-strict.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/bridge-strict.integration.test.js +0 -812
- package/dist/__tests__/integration/bridge.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/bridge.integration.test.js +0 -309
- package/dist/__tests__/integration/cli-e2e.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/cli-e2e.integration.test.js +0 -202
- package/dist/__tests__/integration/dex-arb.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/dex-arb.integration.test.js +0 -116
- package/dist/__tests__/integration/envelope-consistency.integration.test.d.ts +0 -13
- package/dist/__tests__/integration/envelope-consistency.integration.test.js +0 -205
- package/dist/__tests__/integration/hip3-dex.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/hip3-dex.integration.test.js +0 -147
- package/dist/__tests__/integration/hyperliquid.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/hyperliquid.integration.test.js +0 -79
- package/dist/__tests__/integration/lighter.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/lighter.integration.test.js +0 -53
- package/dist/__tests__/integration/new-commands-e2e.integration.test.d.ts +0 -9
- package/dist/__tests__/integration/new-commands-e2e.integration.test.js +0 -236
- package/dist/__tests__/integration/order-verification.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/order-verification.integration.test.js +0 -321
- package/dist/__tests__/integration/pacifica.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/pacifica.integration.test.js +0 -75
- package/dist/__tests__/integration/response-shapes.integration.test.d.ts +0 -1
- package/dist/__tests__/integration/response-shapes.integration.test.js +0 -278
- package/dist/__tests__/liquidity.test.d.ts +0 -1
- package/dist/__tests__/liquidity.test.js +0 -225
- package/dist/__tests__/plan-executor.test.d.ts +0 -1
- package/dist/__tests__/plan-executor.test.js +0 -314
- package/dist/__tests__/position-history.test.d.ts +0 -1
- package/dist/__tests__/position-history.test.js +0 -367
- package/dist/__tests__/retry.test.d.ts +0 -1
- package/dist/__tests__/retry.test.js +0 -310
- package/dist/__tests__/risk-assessment.test.d.ts +0 -1
- package/dist/__tests__/risk-assessment.test.js +0 -288
- package/dist/__tests__/security-adversarial.test.d.ts +0 -1
- package/dist/__tests__/security-adversarial.test.js +0 -574
- package/dist/__tests__/strategies.test.d.ts +0 -1
- package/dist/__tests__/strategies.test.js +0 -539
- package/dist/__tests__/trade-execution.test.d.ts +0 -1
- package/dist/__tests__/trade-execution.test.js +0 -129
- package/dist/__tests__/trade-validator.test.d.ts +0 -1
- package/dist/__tests__/trade-validator.test.js +0 -655
- package/dist/__tests__/utils.test.d.ts +0 -1
- package/dist/__tests__/utils.test.js +0 -76
- package/dist/arb/reconcile.d.ts +0 -28
- package/dist/arb/reconcile.js +0 -162
- package/dist/commands/alert.d.ts +0 -2
- package/dist/commands/alert.js +0 -421
- package/dist/commands/analytics.d.ts +0 -3
- package/dist/commands/analytics.js +0 -311
- package/dist/commands/arb-manage.d.ts +0 -5
- package/dist/commands/arb-manage.js +0 -5
- package/dist/commands/dashboard.d.ts +0 -3
- package/dist/commands/dashboard.js +0 -176
- package/dist/commands/deposit.d.ts +0 -4
- package/dist/commands/deposit.js +0 -573
- package/dist/commands/dex.d.ts +0 -3
- package/dist/commands/dex.js +0 -120
- package/dist/commands/env.d.ts +0 -2
- package/dist/commands/env.js +0 -136
- package/dist/commands/funding.d.ts +0 -3
- package/dist/commands/funding.js +0 -554
- package/dist/commands/gap.d.ts +0 -2
- package/dist/commands/gap.js +0 -305
- package/dist/commands/health.d.ts +0 -2
- package/dist/commands/health.js +0 -67
- package/dist/commands/multileg.d.ts +0 -16
- package/dist/commands/multileg.js +0 -174
- package/dist/commands/ows.d.ts +0 -2
- package/dist/commands/ows.js +0 -887
- package/dist/commands/pnl.d.ts +0 -12
- package/dist/commands/pnl.js +0 -243
- package/dist/commands/run.d.ts +0 -3
- package/dist/commands/run.js +0 -202
- package/dist/commands/stream.d.ts +0 -5
- package/dist/commands/stream.js +0 -200
- package/dist/commands/withdraw.d.ts +0 -3
- package/dist/commands/withdraw.js +0 -187
- package/dist/exchanges/edgex.d.ts +0 -62
- package/dist/exchanges/edgex.js +0 -552
- package/dist/exchanges/nado.d.ts +0 -52
- package/dist/exchanges/nado.js +0 -223
- package/dist/funding/index.d.ts +0 -3
- package/dist/funding/index.js +0 -3
- package/dist/retry.d.ts +0 -74
- package/dist/retry.js +0 -129
- package/dist/ws/market-feed.d.ts +0 -74
- package/dist/ws/market-feed.js +0 -227
package/dist/jobs.js
CHANGED
|
@@ -138,7 +138,9 @@ export function removeJob(id) {
|
|
|
138
138
|
*/
|
|
139
139
|
function buildEnvString() {
|
|
140
140
|
const keys = [
|
|
141
|
-
|
|
141
|
+
// L2 agent key now lives in ~/.perp/lighter-agents/*.json (SSOT Rule #3),
|
|
142
|
+
// accountIndex/apiKeyIndex live in settings.agents.lighter — none need env passthrough.
|
|
143
|
+
"LIGHTER_PRIVATE_KEY",
|
|
142
144
|
"PRIVATE_KEY", "pk",
|
|
143
145
|
"PACIFICA_BUILDER_CODE", "NEXT_PUBLIC_BUILDER_CODE",
|
|
144
146
|
"HL_REFERRAL_CODE", "LIGHTER_REFERRAL_CODE",
|
package/dist/mcp-server.js
CHANGED
|
@@ -436,15 +436,15 @@ server.tool("suggest_command", "Given a natural language trading goal, suggest t
|
|
|
436
436
|
else if (g.includes("grid") || g.includes("dca") || g.includes("bot")) {
|
|
437
437
|
const symbol = extractSymbol(g) || "<symbol>";
|
|
438
438
|
if (g.includes("grid")) {
|
|
439
|
-
steps.push({ step: 1, command: `perp -e ${ex} --json market book ${symbol}`, description: "Check current price" }, { step: 2, command: `perp -e ${ex} --json
|
|
439
|
+
steps.push({ step: 1, command: `perp -e ${ex} --json market book ${symbol}`, description: "Check current price" }, { step: 2, command: `perp -e ${ex} --json strategy quick-grid ${symbol}`, description: "Start grid bot", dangerous: true }, { step: 3, command: "perp --json background list", description: "Verify bot is running" });
|
|
440
440
|
}
|
|
441
441
|
else if (g.includes("dca")) {
|
|
442
442
|
const amount = extractNumber(g) || "<amount>";
|
|
443
443
|
const side = g.includes("sell") || g.includes("short") ? "sell" : "buy";
|
|
444
|
-
steps.push({ step: 1, command: `perp -e ${ex} --json account balance`, description: "Check available balance" }, { step: 2, command: `perp -e ${ex} --json
|
|
444
|
+
steps.push({ step: 1, command: `perp -e ${ex} --json account balance`, description: "Check available balance" }, { step: 2, command: `perp -e ${ex} --json strategy quick-dca ${symbol} ${side} ${amount} <interval>`, description: "Start DCA bot", dangerous: true }, { step: 3, command: "perp --json background list", description: "Verify bot is running" });
|
|
445
445
|
}
|
|
446
446
|
else {
|
|
447
|
-
steps.push({ step: 1, command: "perp --json
|
|
447
|
+
steps.push({ step: 1, command: "perp --json strategy preset-list", description: "List available bot presets" }, { step: 2, command: `perp -e ${ex} --json strategy quick-arb`, description: "Start arb bot", dangerous: true }, { step: 3, command: "perp --json background list", description: "Verify bot is running" });
|
|
448
448
|
}
|
|
449
449
|
}
|
|
450
450
|
else if (g.includes("backtest")) {
|
|
@@ -486,13 +486,13 @@ server.tool("suggest_command", "Given a natural language trading goal, suggest t
|
|
|
486
486
|
steps.push({ step: 1, command: "perp --json rebalance check", description: "Check balance distribution" }, { step: 2, command: "perp --json rebalance plan", description: "Generate rebalance plan" }, { step: 3, command: "perp --json rebalance execute", description: "Execute rebalance", dangerous: true });
|
|
487
487
|
}
|
|
488
488
|
else if (g.includes("job") || g.includes("running") || g.includes("background")) {
|
|
489
|
-
steps.push({ step: 1, command: "perp --json
|
|
489
|
+
steps.push({ step: 1, command: "perp --json background list", description: "List running background jobs" });
|
|
490
490
|
}
|
|
491
491
|
else if (g.includes("dex") || g.includes("hip-3") || g.includes("hip3")) {
|
|
492
492
|
steps.push({ step: 1, command: "perp --json -e hl market hip3", description: "List HIP-3 deployed dexes" }, { step: 2, command: "perp --json -e hl --dex <name> market list", description: "Show markets on a specific dex" });
|
|
493
493
|
}
|
|
494
494
|
else if (g.includes("plan") || g.includes("composite") || g.includes("multi-step")) {
|
|
495
|
-
steps.push({ step: 1, command: "perp plan example", description: "Show example execution plan format" }, { step: 2, command: "perp --json plan validate <file>", description: "Validate plan file" }, { step: 3, command: "perp --json plan execute <file> --dry-run", description: "Dry-run the plan", dangerous: true });
|
|
495
|
+
steps.push({ step: 1, command: "perp strategy plan example", description: "Show example execution plan format" }, { step: 2, command: "perp --json strategy plan validate <file>", description: "Validate plan file" }, { step: 3, command: "perp --json strategy plan execute <file> --dry-run", description: "Dry-run the plan", dangerous: true });
|
|
496
496
|
}
|
|
497
497
|
else if (g.includes("status") || g.includes("check") || g.includes("overview") || g.includes("portfolio")) {
|
|
498
498
|
steps.push({ step: 1, command: `perp -e ${ex} --json status`, description: "Full account overview" }, { step: 2, command: `perp -e ${ex} --json account positions`, description: "Detailed positions" }, { step: 3, command: `perp -e ${ex} --json account orders`, description: "Open orders" }, { step: 4, command: "perp --json portfolio", description: "Cross-exchange portfolio summary" });
|
|
@@ -532,7 +532,7 @@ server.tool("suggest_command", "Given a natural language trading goal, suggest t
|
|
|
532
532
|
steps.push({ step: 1, command: "perp settings show", description: "Show current settings" }, { step: 2, command: "perp settings referrals on", description: "Enable referral codes (no extra fees, just volume tracking)" });
|
|
533
533
|
}
|
|
534
534
|
else {
|
|
535
|
-
steps.push({ step: 1, command:
|
|
535
|
+
steps.push({ step: 1, command: `perp -e ${ex} --json status`, description: "Check account status" }, { step: 2, command: `perp -e ${ex} --json account balance`, description: "Check exchange connectivity via balance fetch" });
|
|
536
536
|
}
|
|
537
537
|
return {
|
|
538
538
|
content: [{
|
|
@@ -831,7 +831,7 @@ server.tool("explain_command", "Explain what a perp CLI command does, its parame
|
|
|
831
831
|
parameters: [],
|
|
832
832
|
risks: sub === "send" || sub === "exchange" ? ["Transfers real funds cross-chain — verify addresses carefully"] : [],
|
|
833
833
|
category: sub === "send" || sub === "exchange" ? "write" : "read",
|
|
834
|
-
relatedCommands: ["perp bridge chains", "perp bridge quote"],
|
|
834
|
+
relatedCommands: ["perp funds bridge chains", "perp funds bridge quote"],
|
|
835
835
|
};
|
|
836
836
|
}
|
|
837
837
|
else if (category === "funds") {
|
|
@@ -855,14 +855,14 @@ server.tool("explain_command", "Explain what a perp CLI command does, its parame
|
|
|
855
855
|
relatedCommands: ["perp account positions", "perp portfolio"],
|
|
856
856
|
};
|
|
857
857
|
}
|
|
858
|
-
else if (category === "
|
|
858
|
+
else if (category === "strategy" || category === "run") {
|
|
859
859
|
explanation = {
|
|
860
860
|
command,
|
|
861
861
|
description: `Automated strategy: ${sub}. Runs as a background job.`,
|
|
862
862
|
parameters: args.slice(2).map((a, i) => ({ name: `arg${i}`, value: a, description: "See --help" })),
|
|
863
|
-
risks: ["Runs automated trades — monitor with 'perp
|
|
863
|
+
risks: ["Runs automated trades — monitor with 'perp background list'", "Use --dry-run to simulate first"],
|
|
864
864
|
category: "write",
|
|
865
|
-
relatedCommands: ["perp
|
|
865
|
+
relatedCommands: ["perp background list", "perp background stop"],
|
|
866
866
|
};
|
|
867
867
|
}
|
|
868
868
|
else if (category === "history") {
|
|
@@ -878,11 +878,11 @@ server.tool("explain_command", "Explain what a perp CLI command does, its parame
|
|
|
878
878
|
else if (category === "wallet") {
|
|
879
879
|
explanation = {
|
|
880
880
|
command,
|
|
881
|
-
description: { show: "Show configured wallets with public addresses", list: "List all wallets (OWS vault + legacy)", balance: "Check on-chain USDC/SOL/ETH balances", generate: "Generate a new OWS wallet (encrypted, multi-chain)", import: "Import key into OWS vault", migrate: "Migrate legacy wallets to OWS encrypted vault", set: "Set private key for an exchange (legacy)", use: "Set active wallet (OWS or legacy)", remove: "Remove a wallet", rename: "Rename a wallet",
|
|
881
|
+
description: { show: "Show configured wallets with public addresses", list: "List all wallets (OWS vault + legacy)", balance: "Check on-chain USDC/SOL/ETH balances", generate: "Generate a new OWS wallet (encrypted, multi-chain)", import: "Import key into OWS vault", migrate: "Migrate legacy wallets to OWS encrypted vault", set: "Set private key for an exchange (legacy)", use: "Set active wallet (OWS or legacy)", remove: "Remove a wallet", rename: "Rename a wallet", policy: "OWS signing policy: create/list/show/delete", key: "OWS API key: create/list/revoke", agent: "DEX-side agent delegation: approve/list/revoke/rotate/verify", deposit: "MoonPay multi-chain deposit (auto-converts to USDC)", setup: "One-click setup: wallet + guardrail policy + agent API key", backup: "Backup encrypted OWS vault", restore: "Restore OWS vault from encrypted backup", rotate: "Rotate wallet keys (new wallet + transfer assets)" }[sub] || `Wallet: ${sub}`,
|
|
882
882
|
parameters: [],
|
|
883
883
|
risks: sub === "generate" ? ["Save the mnemonic securely — it cannot be recovered. Keys are stored in ~/.ows/ encrypted vault."] : sub === "remove" ? ["Wallet will be removed — ensure you have backups"] : [],
|
|
884
884
|
category: "read",
|
|
885
|
-
relatedCommands: ["perp wallet list", "perp wallet balance", "perp wallet
|
|
885
|
+
relatedCommands: ["perp wallet list", "perp wallet balance", "perp wallet agent list"],
|
|
886
886
|
};
|
|
887
887
|
}
|
|
888
888
|
else if (category === "backtest") {
|
|
@@ -906,14 +906,14 @@ server.tool("explain_command", "Explain what a perp CLI command does, its parame
|
|
|
906
906
|
};
|
|
907
907
|
}
|
|
908
908
|
else {
|
|
909
|
-
const writeCommands = new Set(["trade", "funds", "manage"
|
|
909
|
+
const writeCommands = new Set(["trade", "funds", "manage"]);
|
|
910
910
|
explanation = {
|
|
911
911
|
command,
|
|
912
912
|
description: `CLI command: ${command}. Run 'perp ${category} --help' for detailed usage.`,
|
|
913
913
|
parameters: args.slice(1).map((a, i) => ({ name: `arg${i}`, value: a, description: "See --help for details" })),
|
|
914
914
|
risks: writeCommands.has(category) ? ["This command may modify account state — review carefully"] : [],
|
|
915
915
|
category: writeCommands.has(category) ? "write" : "read",
|
|
916
|
-
relatedCommands: [
|
|
916
|
+
relatedCommands: [`perp ${category} --help`],
|
|
917
917
|
};
|
|
918
918
|
}
|
|
919
919
|
return { content: [{ type: "text", text: ok(explanation) }] };
|
|
@@ -1096,35 +1096,28 @@ server.resource("cli_schema", "perp://schema", { mimeType: "application/json", d
|
|
|
1096
1096
|
check: { usage: "perp risk check --notional <usd> --leverage <n>", description: "Pre-trade risk check" },
|
|
1097
1097
|
},
|
|
1098
1098
|
},
|
|
1099
|
-
|
|
1100
|
-
description: "
|
|
1099
|
+
strategy: {
|
|
1100
|
+
description: "Trading strategies — long-running bot algorithms + one-shot scripted plans",
|
|
1101
1101
|
subcommands: {
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
"
|
|
1117
|
-
"trailing-stop": { usage: "perp bot trailing-stop <symbol>", description: "Trailing stop bot" },
|
|
1118
|
-
"quick-grid": { usage: "perp bot quick-grid <symbol>", description: "Quick grid bot" },
|
|
1119
|
-
"quick-dca": { usage: "perp bot quick-dca <symbol> <side> <amount> <interval>", description: "Quick DCA bot" },
|
|
1120
|
-
"quick-arb": { usage: "perp bot quick-arb", description: "Quick arb bot" },
|
|
1121
|
-
"preset-list": { usage: "perp bot preset-list", description: "List available bot presets" },
|
|
1122
|
-
preset: { usage: "perp bot preset <name> [symbol]", description: "Run a bot preset" },
|
|
1123
|
-
example: { usage: "perp bot example", description: "Show example bot config" },
|
|
1102
|
+
start: { usage: "perp strategy start <config>", description: "Start bot from config file" },
|
|
1103
|
+
twap: { usage: "perp strategy twap <symbol> <side> <size> <duration>", description: "TWAP execution" },
|
|
1104
|
+
grid: { usage: "perp strategy grid <symbol> --range <pct> --grids <n> --size <usd>", description: "Grid trading bot" },
|
|
1105
|
+
dca: { usage: "perp strategy dca <symbol> <side> <amount> <interval>", description: "DCA bot" },
|
|
1106
|
+
"funding-arb": { usage: "perp strategy funding-arb", description: "Funding arb bot" },
|
|
1107
|
+
"trailing-stop": { usage: "perp strategy trailing-stop <symbol>", description: "Trailing stop bot" },
|
|
1108
|
+
"quick-grid": { usage: "perp strategy quick-grid <symbol>", description: "Quick grid bot" },
|
|
1109
|
+
"quick-dca": { usage: "perp strategy quick-dca <symbol> <side> <amount> <interval>", description: "Quick DCA bot" },
|
|
1110
|
+
"quick-arb": { usage: "perp strategy quick-arb", description: "Quick arb bot" },
|
|
1111
|
+
"preset-list": { usage: "perp strategy preset-list", description: "List available bot presets" },
|
|
1112
|
+
preset: { usage: "perp strategy preset <name> [symbol]", description: "Run a bot preset" },
|
|
1113
|
+
example: { usage: "perp strategy example", description: "Show example bot config" },
|
|
1114
|
+
"plan validate": { usage: "perp strategy plan validate <file>", description: "Validate scripted execution plan" },
|
|
1115
|
+
"plan execute": { usage: "perp strategy plan execute <file>", description: "Execute scripted plan" },
|
|
1116
|
+
"plan example": { usage: "perp strategy plan example", description: "Show plan format" },
|
|
1124
1117
|
},
|
|
1125
1118
|
},
|
|
1126
1119
|
wallet: {
|
|
1127
|
-
description: "Wallet management (OWS encrypted vault + legacy)",
|
|
1120
|
+
description: "Wallet management (OWS encrypted vault + legacy + agent delegation + lifecycle)",
|
|
1128
1121
|
subcommands: {
|
|
1129
1122
|
show: { usage: "perp wallet show", description: "Show configured wallets with public addresses" },
|
|
1130
1123
|
list: { usage: "perp wallet list", description: "List all wallets (OWS vault + legacy)" },
|
|
@@ -1136,7 +1129,14 @@ server.resource("cli_schema", "perp://schema", { mimeType: "application/json", d
|
|
|
1136
1129
|
use: { usage: "perp wallet use <name>", description: "Set active wallet (OWS or legacy)" },
|
|
1137
1130
|
remove: { usage: "perp wallet remove <name>", description: "Remove a wallet" },
|
|
1138
1131
|
rename: { usage: "perp wallet rename <oldName> <newName>", description: "Rename a wallet" },
|
|
1139
|
-
|
|
1132
|
+
policy: { usage: "perp wallet policy <create|list|show|delete>", description: "OWS signing policies (guardrails for agent signing)" },
|
|
1133
|
+
key: { usage: "perp wallet key <create|list|revoke>", description: "OWS API keys (scoped agent access tokens)" },
|
|
1134
|
+
agent: { usage: "perp wallet agent <approve|list|revoke|rotate|verify>", description: "DEX-side agent wallet delegation (per-exchange)" },
|
|
1135
|
+
deposit: { usage: "perp wallet deposit <walletName>", description: "MoonPay multi-chain deposit (auto-converts to USDC)" },
|
|
1136
|
+
setup: { usage: "perp wallet setup", description: "One-click: wallet + guardrail policy + agent API key" },
|
|
1137
|
+
backup: { usage: "perp wallet backup", description: "Backup encrypted OWS vault" },
|
|
1138
|
+
restore: { usage: "perp wallet restore <file>", description: "Restore OWS vault from encrypted backup" },
|
|
1139
|
+
rotate: { usage: "perp wallet rotate --from <a> --to <b>", description: "Rotate wallet keys (create new + transfer assets)" },
|
|
1140
1140
|
},
|
|
1141
1141
|
},
|
|
1142
1142
|
history: {
|
|
@@ -1162,44 +1162,37 @@ server.resource("cli_schema", "perp://schema", { mimeType: "application/json", d
|
|
|
1162
1162
|
grid: { usage: "perp backtest grid", description: "Backtest grid strategy" },
|
|
1163
1163
|
},
|
|
1164
1164
|
},
|
|
1165
|
-
|
|
1166
|
-
description: "
|
|
1167
|
-
subcommands: {
|
|
1168
|
-
validate: { usage: "perp plan validate <file>", description: "Validate plan" },
|
|
1169
|
-
execute: { usage: "perp plan execute <file>", description: "Execute plan" },
|
|
1170
|
-
example: { usage: "perp plan example", description: "Show plan format" },
|
|
1171
|
-
},
|
|
1172
|
-
},
|
|
1173
|
-
rebalance: {
|
|
1174
|
-
description: "Cross-exchange balance rebalancing",
|
|
1175
|
-
subcommands: {
|
|
1176
|
-
check: { usage: "perp rebalance check", description: "Check distribution" },
|
|
1177
|
-
plan: { usage: "perp rebalance plan", description: "Generate plan" },
|
|
1178
|
-
execute: { usage: "perp rebalance execute", description: "Execute rebalance" },
|
|
1179
|
-
},
|
|
1180
|
-
},
|
|
1181
|
-
jobs: {
|
|
1182
|
-
description: "Background job management",
|
|
1165
|
+
background: {
|
|
1166
|
+
description: "Background process supervisor (tmux sessions for strategies, alerts, etc.)",
|
|
1183
1167
|
subcommands: {
|
|
1184
|
-
list: { usage: "perp
|
|
1185
|
-
stop: { usage: "perp
|
|
1186
|
-
logs: { usage: "perp
|
|
1168
|
+
list: { usage: "perp background list", description: "List running jobs" },
|
|
1169
|
+
stop: { usage: "perp background stop <id>", description: "Stop a job" },
|
|
1170
|
+
logs: { usage: "perp background logs <id>", description: "View job logs" },
|
|
1171
|
+
remove: { usage: "perp background remove <id>", description: "Remove a job entry and its logs" },
|
|
1172
|
+
clean: { usage: "perp background clean", description: "Remove all stopped/done jobs" },
|
|
1187
1173
|
},
|
|
1188
1174
|
},
|
|
1189
1175
|
funds: {
|
|
1190
|
-
usage: "perp funds <deposit|withdraw|transfer|bridge> ...",
|
|
1191
|
-
description: "
|
|
1176
|
+
usage: "perp funds <deposit|withdraw|transfer|bridge|rebalance|info> ...",
|
|
1177
|
+
description: "Fund movement — deposit, withdraw, transfer, cross-chain bridge, inter-exchange rebalance",
|
|
1192
1178
|
subcommands: {
|
|
1193
|
-
"deposit <exchange> <amount>": "Deposit USDC to exchange",
|
|
1194
|
-
"withdraw <exchange> <amount>": "Withdraw USDC from exchange",
|
|
1195
|
-
"transfer <amount> <address>": "HL internal transfer",
|
|
1196
|
-
"bridge
|
|
1197
|
-
|
|
1179
|
+
"deposit <exchange> <amount>": "Deposit USDC to exchange (pacifica, hyperliquid, lighter)",
|
|
1180
|
+
"withdraw <exchange> <amount>": "Withdraw USDC from exchange (pacifica, hyperliquid, lighter)",
|
|
1181
|
+
"transfer <amount> <address>": "HL internal transfer (instant)",
|
|
1182
|
+
"bridge chains": "List supported chains and USDC addresses",
|
|
1183
|
+
"bridge quote --from <chain> --to <chain> --amount <n>": "Get bridge quotes from all providers",
|
|
1184
|
+
"bridge send --from <chain> --to <chain> --amount <n> [--provider cctp|relay|debridge]": "Execute bridge (auto-cheapest by default)",
|
|
1185
|
+
"bridge exchange --from <ex> --to <ex> --amount <n>": "Bridge USDC between exchanges (shortcut)",
|
|
1186
|
+
"bridge status <orderId>": "Check bridge order status",
|
|
1187
|
+
"rebalance check": "Show balances across exchanges",
|
|
1188
|
+
"rebalance plan": "Calculate optimal rebalancing moves",
|
|
1189
|
+
"rebalance execute [--auto-bridge]": "Execute rebalancing (withdraw → bridge → deposit)",
|
|
1190
|
+
info: "Show all deposit/withdraw/bridge/rebalance routes & limits",
|
|
1198
1191
|
},
|
|
1199
1192
|
},
|
|
1200
1193
|
portfolio: { usage: "perp portfolio", description: "Cross-exchange portfolio summary" },
|
|
1201
1194
|
status: { usage: "perp portfolio", description: "Full account overview" },
|
|
1202
|
-
health: { usage: "perp
|
|
1195
|
+
health: { usage: "perp account balance --json", description: "Exchange connectivity check via balance fetch" },
|
|
1203
1196
|
settings: {
|
|
1204
1197
|
description: "CLI settings",
|
|
1205
1198
|
subcommands: {
|
|
@@ -1207,16 +1200,7 @@ server.resource("cli_schema", "perp://schema", { mimeType: "application/json", d
|
|
|
1207
1200
|
referrals: { usage: "perp settings referrals on|off", description: "Toggle referral codes (no extra fees)" },
|
|
1208
1201
|
},
|
|
1209
1202
|
},
|
|
1210
|
-
agent
|
|
1211
|
-
description: "Agent discovery & execution",
|
|
1212
|
-
subcommands: {
|
|
1213
|
-
schema: { usage: "perp agent schema", description: "Full CLI schema as JSON" },
|
|
1214
|
-
capabilities: { usage: "perp agent capabilities", description: "Capability list" },
|
|
1215
|
-
plan: { usage: "perp agent plan '<goal>'", description: "Suggest commands for goal" },
|
|
1216
|
-
exec: { usage: "perp agent exec <command...>", description: "Execute with JSON output" },
|
|
1217
|
-
ping: { usage: "perp agent ping", description: "Health check" },
|
|
1218
|
-
},
|
|
1219
|
-
},
|
|
1203
|
+
// `agent` is now `wallet agent ...` — see `wallet.subcommands.agent` above.
|
|
1220
1204
|
},
|
|
1221
1205
|
tips: [
|
|
1222
1206
|
"Always use --json for structured output when automating",
|
|
@@ -1255,12 +1239,30 @@ server.tool("trade_preview", "Preview a trade WITHOUT executing. Returns estimat
|
|
|
1255
1239
|
const notional = estPrice ? Number(estPrice) * Number(size) : 0;
|
|
1256
1240
|
const existingPos = positions.find(p => p.symbol.toUpperCase().includes(symbol.toUpperCase()));
|
|
1257
1241
|
// Run validation
|
|
1242
|
+
// SSOT rule #2: validation failure must surface as a structured invalid
|
|
1243
|
+
// result, NOT be swallowed into a fake `{ valid: true }`. The previous
|
|
1244
|
+
// shape silently green-lit trades when the underlying balance/orderbook
|
|
1245
|
+
// fetches errored out.
|
|
1258
1246
|
let validation;
|
|
1247
|
+
// For a preview the user has not yet committed leverage, so 1x is the
|
|
1248
|
+
// documented default exposed in the preview shape (no silent fallback —
|
|
1249
|
+
// the caller can override via existingPos.leverage when re-entering an
|
|
1250
|
+
// open position).
|
|
1251
|
+
const previewLeverage = existingPos?.leverage ?? 1;
|
|
1259
1252
|
try {
|
|
1260
|
-
validation = await validateTrade(adapter, { symbol, side, size: Number(size), leverage:
|
|
1261
|
-
}
|
|
1262
|
-
catch {
|
|
1263
|
-
|
|
1253
|
+
validation = await validateTrade(adapter, { symbol, side, size: Number(size), leverage: previewLeverage });
|
|
1254
|
+
}
|
|
1255
|
+
catch (err) {
|
|
1256
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1257
|
+
validation = {
|
|
1258
|
+
valid: false,
|
|
1259
|
+
checks: [{
|
|
1260
|
+
check: "symbol_valid",
|
|
1261
|
+
passed: false,
|
|
1262
|
+
message: `Validation could not run: ${msg}`,
|
|
1263
|
+
}],
|
|
1264
|
+
warnings: [],
|
|
1265
|
+
};
|
|
1264
1266
|
}
|
|
1265
1267
|
const preview = {
|
|
1266
1268
|
order: { exchange, symbol, side, size, orderType, price: price ?? estPrice },
|
package/dist/position-history.js
CHANGED
|
@@ -13,6 +13,32 @@ function ensureDir() {
|
|
|
13
13
|
function genId() {
|
|
14
14
|
return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* Validate position side from a stream event. SSOT rule #2: the stream must
|
|
18
|
+
* deliver a real side, never silently default to "long" — defaulting can flip
|
|
19
|
+
* a short into a long in the position history and corrupt P&L analytics.
|
|
20
|
+
*/
|
|
21
|
+
function requireSide(value, eventType, exchange, symbol) {
|
|
22
|
+
if (value === "long" || value === "short")
|
|
23
|
+
return value;
|
|
24
|
+
throw new Error(`position_${eventType} for ${exchange}:${symbol} has missing/invalid side ` +
|
|
25
|
+
`(received ${JSON.stringify(value)}); refusing to silently default. ` +
|
|
26
|
+
`Fix the upstream adapter to emit { side: "long" | "short" } on every event.`);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Validate a stringified numeric field from a stream event. SSOT rule #2: do
|
|
30
|
+
* NOT silently default missing realizedPnl to "0", because we cannot
|
|
31
|
+
* distinguish "trade closed flat" from "adapter forgot the field".
|
|
32
|
+
*/
|
|
33
|
+
function requireNumericString(value, fieldName, eventType, exchange, symbol) {
|
|
34
|
+
if (typeof value === "string" && value.trim() !== "" && Number.isFinite(Number(value)))
|
|
35
|
+
return value;
|
|
36
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
37
|
+
return String(value);
|
|
38
|
+
throw new Error(`position_${eventType} for ${exchange}:${symbol} has missing/invalid ${fieldName} ` +
|
|
39
|
+
`(received ${JSON.stringify(value)}); refusing to silently default. ` +
|
|
40
|
+
`Fix the upstream adapter to emit a numeric ${fieldName}.`);
|
|
41
|
+
}
|
|
16
42
|
/** Append a position record to the log */
|
|
17
43
|
export function logPosition(record) {
|
|
18
44
|
ensureDir();
|
|
@@ -154,7 +180,10 @@ export function attachPositionLogger(onEvent) {
|
|
|
154
180
|
if (event.type === "position_opened") {
|
|
155
181
|
const id = genId();
|
|
156
182
|
const symbol = String(data.symbol ?? "");
|
|
157
|
-
|
|
183
|
+
if (!symbol) {
|
|
184
|
+
throw new Error(`position_opened on ${exchange} missing symbol; refusing to silently default. Raw data: ${JSON.stringify(data)}`);
|
|
185
|
+
}
|
|
186
|
+
const side = requireSide(data.side, "opened", exchange, symbol);
|
|
158
187
|
const key = `${exchange}:${symbol}`;
|
|
159
188
|
openPositions.set(key, { id, openedAt: ts, entryPrice: String(data.entryPrice ?? "") });
|
|
160
189
|
logPosition({
|
|
@@ -172,9 +201,15 @@ export function attachPositionLogger(onEvent) {
|
|
|
172
201
|
}
|
|
173
202
|
else if (event.type === "position_updated") {
|
|
174
203
|
const symbol = String(data.symbol ?? "");
|
|
175
|
-
|
|
204
|
+
if (!symbol) {
|
|
205
|
+
throw new Error(`position_updated on ${exchange} missing symbol; refusing to silently default. Raw data: ${JSON.stringify(data)}`);
|
|
206
|
+
}
|
|
207
|
+
const side = requireSide(data.side, "updated", exchange, symbol);
|
|
176
208
|
const key = `${exchange}:${symbol}`;
|
|
177
209
|
const tracked = openPositions.get(key);
|
|
210
|
+
// tracked?.id ?? genId() is NOT a fallback in the SSOT sense: it covers the
|
|
211
|
+
// legitimate case where the stream delivers an update for a position the
|
|
212
|
+
// logger never saw open (out-of-order delivery, mid-session attach).
|
|
178
213
|
logPosition({
|
|
179
214
|
id: tracked?.id ?? genId(),
|
|
180
215
|
exchange,
|
|
@@ -194,12 +229,20 @@ export function attachPositionLogger(onEvent) {
|
|
|
194
229
|
}
|
|
195
230
|
else if (event.type === "position_closed") {
|
|
196
231
|
const symbol = String(data.symbol ?? "");
|
|
197
|
-
|
|
232
|
+
if (!symbol) {
|
|
233
|
+
throw new Error(`position_closed on ${exchange} missing symbol; refusing to silently default. Raw data: ${JSON.stringify(data)}`);
|
|
234
|
+
}
|
|
235
|
+
const side = requireSide(data.side, "closed", exchange, symbol);
|
|
198
236
|
const key = `${exchange}:${symbol}`;
|
|
199
237
|
const tracked = openPositions.get(key);
|
|
200
238
|
const openedAt = tracked?.openedAt ?? ts;
|
|
201
239
|
const duration = new Date(ts).getTime() - new Date(openedAt).getTime();
|
|
202
|
-
|
|
240
|
+
// SSOT rule #2: do NOT alias unrealizedPnl as realizedPnl. They mean
|
|
241
|
+
// different things: unrealizedPnl is the snapshot before close, and on
|
|
242
|
+
// a real close event the upstream adapter must emit realizedPnl
|
|
243
|
+
// explicitly. Aliasing them would have a flat-close (realizedPnl=0)
|
|
244
|
+
// pretend to be the last unrealized number from the previous tick.
|
|
245
|
+
const realizedPnl = requireNumericString(data.realizedPnl, "realizedPnl", "closed", exchange, symbol);
|
|
203
246
|
logPosition({
|
|
204
247
|
id: tracked?.id ?? genId(),
|
|
205
248
|
exchange,
|
package/dist/settings.d.ts
CHANGED
|
@@ -26,14 +26,76 @@ export interface AlertSettings {
|
|
|
26
26
|
/** Cooldown per symbol in minutes after alert fires (default: 60) */
|
|
27
27
|
cooldownMin: number;
|
|
28
28
|
}
|
|
29
|
+
export interface AgentMeta {
|
|
30
|
+
agentName: string;
|
|
31
|
+
agentWalletName: string;
|
|
32
|
+
/**
|
|
33
|
+
* EVM address of the agent wallet (required for Aster + Hyperliquid).
|
|
34
|
+
* For Pacifica (Phase 2c): kept as a sentinel zero-address since the
|
|
35
|
+
* curve is Solana/Ed25519; the canonical address lives in
|
|
36
|
+
* `agentSolanaAddress`. For Lighter (Phase 2d): populated with the master
|
|
37
|
+
* EVM address (since L1 ChangePubKey is signed by the master EVM key); the
|
|
38
|
+
* canonical agent identity lives in `publicKey + apiKeyIndex`.
|
|
39
|
+
* The `0x${string}` literal is preserved to avoid disrupting Aster/HL strict typing.
|
|
40
|
+
*/
|
|
41
|
+
agentEvmAddress: `0x${string}`;
|
|
42
|
+
/** EVM address of the master/owner wallet — required as `user` field in Aster/HL requests. Populated by `agent approve` (Step 4). */
|
|
43
|
+
userEvmAddress: `0x${string}`;
|
|
44
|
+
/**
|
|
45
|
+
* Solana base58 public key of the agent wallet (Phase 2c — Pacifica only).
|
|
46
|
+
* Optional for Aster/HL since they live on EVM curves.
|
|
47
|
+
*/
|
|
48
|
+
agentSolanaAddress?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Solana base58 public key of the master/owner wallet (Phase 2c — Pacifica only).
|
|
51
|
+
* Optional for Aster/HL.
|
|
52
|
+
*/
|
|
53
|
+
userSolanaAddress?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Lighter slot index (Phase 2d — Lighter only).
|
|
56
|
+
* Range: [4, 254] inclusive. Slots 0-3 are reserved by the Lighter frontend.
|
|
57
|
+
* Selected at approve time as `max(existing slots) + 1`.
|
|
58
|
+
*/
|
|
59
|
+
apiKeyIndex?: number;
|
|
60
|
+
/**
|
|
61
|
+
* Lighter agent secp256k1 public key (hex, no `0x` prefix) (Phase 2d — Lighter only).
|
|
62
|
+
* Canonical identity for the Lighter L2 hot-path. Cross-checked against
|
|
63
|
+
* `GET /api/v1/apikeys?account_index=N` during `wallet agent verify lighter`.
|
|
64
|
+
*/
|
|
65
|
+
publicKey?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Lighter L2 account index (Phase 2d — Lighter only).
|
|
68
|
+
* Resolved at approve time from L1 EVM address via the Lighter REST API
|
|
69
|
+
* and cached so subsequent verify/trade calls don't need to re-query.
|
|
70
|
+
*/
|
|
71
|
+
accountIndex?: number;
|
|
72
|
+
masterWalletName: string;
|
|
73
|
+
owsApiKeyId: string;
|
|
74
|
+
owsPolicyId: string;
|
|
75
|
+
expiresAt: string;
|
|
76
|
+
approvedAt: string;
|
|
77
|
+
permissions: {
|
|
78
|
+
canPerpTrade: boolean;
|
|
79
|
+
canSpotTrade: boolean;
|
|
80
|
+
canWithdraw: boolean;
|
|
81
|
+
};
|
|
82
|
+
asterApprovalNonce: string;
|
|
83
|
+
status?: "active" | "partial";
|
|
84
|
+
}
|
|
85
|
+
export interface AgentsByExchange {
|
|
86
|
+
aster?: Record<string, AgentMeta>;
|
|
87
|
+
hyperliquid?: Record<string, AgentMeta>;
|
|
88
|
+
pacifica?: Record<string, AgentMeta>;
|
|
89
|
+
lighter?: Record<string, AgentMeta>;
|
|
90
|
+
}
|
|
29
91
|
export interface Settings {
|
|
30
92
|
/** Default exchange when -e flag is omitted */
|
|
31
93
|
defaultExchange: string;
|
|
32
94
|
/** Active OWS wallet name (used when no --ows or --wallet flag) */
|
|
33
95
|
owsActiveWallet: string;
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
|
|
96
|
+
/** Per-exchange referral / builder codes (always applied per SSOT Rule #3:
|
|
97
|
+
* no opt-out — Pacifica builder code has always been mandatory; HL/LT
|
|
98
|
+
* aligned 2026-05-01). */
|
|
37
99
|
referralCodes: {
|
|
38
100
|
pacifica: string;
|
|
39
101
|
hyperliquid: string;
|
|
@@ -48,6 +110,8 @@ export interface Settings {
|
|
|
48
110
|
fees: Record<string, ExchangeFees>;
|
|
49
111
|
/** Alert configuration */
|
|
50
112
|
alerts: AlertSettings;
|
|
113
|
+
/** OWS-native agent wallets registered per exchange (Phase 2a: Aster only) */
|
|
114
|
+
agents?: AgentsByExchange;
|
|
51
115
|
}
|
|
52
116
|
export declare function loadSettings(): Settings;
|
|
53
117
|
export declare function saveSettings(settings: Settings): void;
|
package/dist/settings.js
CHANGED
|
@@ -5,7 +5,6 @@ const SETTINGS_FILE = resolve(PERP_DIR, "settings.json");
|
|
|
5
5
|
const DEFAULTS = {
|
|
6
6
|
defaultExchange: "",
|
|
7
7
|
owsActiveWallet: "",
|
|
8
|
-
referrals: false,
|
|
9
8
|
referralCodes: {
|
|
10
9
|
pacifica: "",
|
|
11
10
|
hyperliquid: "HYPERCASH",
|
|
@@ -44,7 +43,6 @@ export function loadSettings() {
|
|
|
44
43
|
return {
|
|
45
44
|
defaultExchange: stored.defaultExchange ?? DEFAULTS.defaultExchange,
|
|
46
45
|
owsActiveWallet: stored.owsActiveWallet ?? DEFAULTS.owsActiveWallet,
|
|
47
|
-
referrals: stored.referrals ?? DEFAULTS.referrals,
|
|
48
46
|
referralCodes: {
|
|
49
47
|
pacifica: stored.referralCodes?.pacifica ?? DEFAULTS.referralCodes.pacifica,
|
|
50
48
|
hyperliquid: stored.referralCodes?.hyperliquid ?? DEFAULTS.referralCodes.hyperliquid,
|
|
@@ -62,6 +60,7 @@ export function loadSettings() {
|
|
|
62
60
|
cooldownMin: stored.alerts?.cooldownMin ?? DEFAULTS.alerts.cooldownMin,
|
|
63
61
|
},
|
|
64
62
|
fees,
|
|
63
|
+
agents: stored.agents && typeof stored.agents === "object" ? stored.agents : undefined,
|
|
65
64
|
};
|
|
66
65
|
}
|
|
67
66
|
catch {
|
package/dist/signer/ows-evm.d.ts
CHANGED
|
@@ -16,3 +16,17 @@ export declare class OwsEvmSigner implements EvmSigner {
|
|
|
16
16
|
}>>, value: Record<string, unknown>): Promise<string>;
|
|
17
17
|
signMessage(message: string | Uint8Array): Promise<string>;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* Normalize OWS signature output to canonical 65-byte hex (0x-prefixed).
|
|
21
|
+
*
|
|
22
|
+
* OWS may return the signature in two shapes depending on version:
|
|
23
|
+
* (A) 65-byte hex with v already embedded — use as-is
|
|
24
|
+
* (B) 64-byte hex (r+s only) + separate recoveryId — append v
|
|
25
|
+
*
|
|
26
|
+
* For shape B, recoveryId may be either canonical (27/28) or raw (0/1).
|
|
27
|
+
* If raw, add 27 to canonicalize.
|
|
28
|
+
*/
|
|
29
|
+
export declare function canonicalizeOwsSignature(result: {
|
|
30
|
+
signature: string;
|
|
31
|
+
recoveryId?: number;
|
|
32
|
+
}): string;
|
package/dist/signer/ows-evm.js
CHANGED
|
@@ -39,11 +39,8 @@ export class OwsEvmSigner {
|
|
|
39
39
|
domain,
|
|
40
40
|
message: value,
|
|
41
41
|
});
|
|
42
|
-
const result = ows.signTypedData(this._walletName, "
|
|
43
|
-
|
|
44
|
-
const sig = result.signature.startsWith("0x") ? result.signature : `0x${result.signature}`;
|
|
45
|
-
const v = result.recoveryId !== undefined ? result.recoveryId + 27 : 27;
|
|
46
|
-
return `${sig}${v.toString(16).padStart(2, "0")}`;
|
|
42
|
+
const result = ows.signTypedData(this._walletName, "ethereum", typedData, this._passphrase);
|
|
43
|
+
return canonicalizeOwsSignature(result);
|
|
47
44
|
}
|
|
48
45
|
async signMessage(message) {
|
|
49
46
|
const ows = loadOws();
|
|
@@ -51,12 +48,34 @@ export class OwsEvmSigner {
|
|
|
51
48
|
? message
|
|
52
49
|
: Buffer.from(message).toString("hex");
|
|
53
50
|
const encoding = typeof message === "string" ? "utf8" : "hex";
|
|
54
|
-
const result = ows.signMessage(this._walletName, "
|
|
55
|
-
|
|
56
|
-
const v = result.recoveryId !== undefined ? result.recoveryId + 27 : 27;
|
|
57
|
-
return `${sig}${v.toString(16).padStart(2, "0")}`;
|
|
51
|
+
const result = ows.signMessage(this._walletName, "ethereum", msgStr, this._passphrase, encoding);
|
|
52
|
+
return canonicalizeOwsSignature(result);
|
|
58
53
|
}
|
|
59
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Normalize OWS signature output to canonical 65-byte hex (0x-prefixed).
|
|
57
|
+
*
|
|
58
|
+
* OWS may return the signature in two shapes depending on version:
|
|
59
|
+
* (A) 65-byte hex with v already embedded — use as-is
|
|
60
|
+
* (B) 64-byte hex (r+s only) + separate recoveryId — append v
|
|
61
|
+
*
|
|
62
|
+
* For shape B, recoveryId may be either canonical (27/28) or raw (0/1).
|
|
63
|
+
* If raw, add 27 to canonicalize.
|
|
64
|
+
*/
|
|
65
|
+
export function canonicalizeOwsSignature(result) {
|
|
66
|
+
const sigHex = result.signature.startsWith("0x") ? result.signature.slice(2) : result.signature;
|
|
67
|
+
if (sigHex.length === 130) {
|
|
68
|
+
// Already 65-byte sig with embedded v — trust OWS
|
|
69
|
+
return `0x${sigHex}`;
|
|
70
|
+
}
|
|
71
|
+
if (sigHex.length !== 128) {
|
|
72
|
+
throw new Error(`Unexpected OWS signature length: ${sigHex.length} hex chars (expected 128 or 130)`);
|
|
73
|
+
}
|
|
74
|
+
// 64-byte r+s — append v from recoveryId
|
|
75
|
+
const rid = result.recoveryId ?? 0;
|
|
76
|
+
const v = rid >= 27 ? rid : rid + 27; // accept canonical or raw recoveryId
|
|
77
|
+
return `0x${sigHex}${v.toString(16).padStart(2, "0")}`;
|
|
78
|
+
}
|
|
60
79
|
function inferEip712DomainType(key) {
|
|
61
80
|
switch (key) {
|
|
62
81
|
case "chainId": return "uint256";
|
package/dist/smart-order.d.ts
CHANGED
|
@@ -16,13 +16,19 @@
|
|
|
16
16
|
* - Saves 5-50+ bps vs raw market orders on thin books
|
|
17
17
|
* - Predictable execution price
|
|
18
18
|
*
|
|
19
|
-
*
|
|
19
|
+
* SSOT rule #2: silent fallback is forbidden. The opt-in `fallback: true` flag
|
|
20
|
+
* is preserved for callers that explicitly want best-effort market substitution
|
|
21
|
+
* after IOC reject, but the DEFAULT is `false` — failure must surface as a
|
|
22
|
+
* thrown error, never a silent market sweep.
|
|
20
23
|
*/
|
|
21
24
|
import type { ExchangeAdapter } from "./exchanges/index.js";
|
|
22
25
|
export interface SmartOrderOpts {
|
|
23
26
|
/** Extra ticks of tolerance beyond best price. Default: 1 */
|
|
24
27
|
tickTolerance?: number;
|
|
25
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Opt-in: fall back to market order if IOC limit fails.
|
|
30
|
+
* SSOT rule #2 default: `false` — failure throws unless caller explicitly opts in.
|
|
31
|
+
*/
|
|
26
32
|
fallback?: boolean;
|
|
27
33
|
/** Reduce only flag for closing positions. Default: false */
|
|
28
34
|
reduceOnly?: boolean;
|