perp-cli 0.3.9 → 0.3.11
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/dist/exchanges/lighter.js +27 -11
- package/dist/index.js +4 -1
- package/dist/mcp-server.js +4 -1
- package/package.json +1 -1
- package/skills/perp-cli/SKILL.md +67 -14
|
@@ -70,12 +70,16 @@ export class LighterAdapter {
|
|
|
70
70
|
: json.accounts[0].account_index;
|
|
71
71
|
}
|
|
72
72
|
// Auto-generate API key if we have PK but no API key and account exists
|
|
73
|
+
let signerReady = false;
|
|
73
74
|
if (!this._apiKey && this._accountIndex >= 0) {
|
|
74
75
|
try {
|
|
75
76
|
const autoKeyIndex = 2; // default for auto-setup
|
|
76
77
|
const { privateKey: apiKey } = await this.setupApiKey(autoKeyIndex);
|
|
77
78
|
this._apiKey = apiKey;
|
|
78
79
|
this._apiKeyIndex = autoKeyIndex;
|
|
80
|
+
// setupApiKey already configured the static WASM client — reuse it
|
|
81
|
+
this._signer = LighterAdapter._wasmClient;
|
|
82
|
+
signerReady = true;
|
|
79
83
|
// Save to .env for future use
|
|
80
84
|
try {
|
|
81
85
|
const { setEnvVar } = await import("../commands/init.js");
|
|
@@ -91,18 +95,19 @@ export class LighterAdapter {
|
|
|
91
95
|
console.error(`[lighter] API key auto-setup failed: ${msg}. Trading will be read-only. Run 'perp -e lighter manage setup-api-key' to retry.`);
|
|
92
96
|
}
|
|
93
97
|
}
|
|
94
|
-
// Initialize signer for trading if we have an API key
|
|
95
|
-
if (this._apiKey) {
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
await this._signer.initialize();
|
|
99
|
-
await this._signer.createClient({
|
|
98
|
+
// Initialize signer for trading if we have an API key (reuse singleton WASM client)
|
|
99
|
+
if (this._apiKey && !signerReady) {
|
|
100
|
+
const client = await LighterAdapter.getWasmClient();
|
|
101
|
+
await client.createClient({
|
|
100
102
|
url: this._baseUrl,
|
|
101
103
|
privateKey: this._apiKey,
|
|
102
104
|
chainId: this._chainId,
|
|
103
105
|
apiKeyIndex: this._apiKeyIndex,
|
|
104
106
|
accountIndex: this._accountIndex,
|
|
105
107
|
});
|
|
108
|
+
this._signer = client;
|
|
109
|
+
}
|
|
110
|
+
if (this._apiKey) {
|
|
106
111
|
this._readOnly = false;
|
|
107
112
|
}
|
|
108
113
|
// Build symbol → marketIndex map + decimals from orderBookDetails
|
|
@@ -768,11 +773,22 @@ export class LighterAdapter {
|
|
|
768
773
|
static async getWasmClient() {
|
|
769
774
|
if (LighterAdapter._wasmClient)
|
|
770
775
|
return LighterAdapter._wasmClient;
|
|
771
|
-
|
|
772
|
-
const
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
+
// Prevent Go WASM runtime from killing the process on panic
|
|
777
|
+
const origExit = process.exit;
|
|
778
|
+
process.exit = ((code) => {
|
|
779
|
+
process.exit = origExit; // restore immediately
|
|
780
|
+
throw new Error(`Lighter WASM runtime exited with code ${code}`);
|
|
781
|
+
});
|
|
782
|
+
try {
|
|
783
|
+
const { WasmSignerClient } = await import("lighter-ts-sdk");
|
|
784
|
+
const client = new WasmSignerClient({});
|
|
785
|
+
await client.initialize();
|
|
786
|
+
LighterAdapter._wasmClient = client;
|
|
787
|
+
return client;
|
|
788
|
+
}
|
|
789
|
+
finally {
|
|
790
|
+
process.exit = origExit;
|
|
791
|
+
}
|
|
776
792
|
}
|
|
777
793
|
/**
|
|
778
794
|
* Generate a new Lighter API key pair using the WASM signer.
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { config } from "dotenv";
|
|
3
3
|
import { resolve } from "path";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
4
5
|
// Load ~/.perp/.env first (global), then CWD .env (overrides)
|
|
5
6
|
config({ path: resolve(process.env.HOME || "~", ".perp", ".env") });
|
|
6
7
|
config();
|
|
@@ -41,6 +42,8 @@ import { registerInitCommand, EXCHANGE_ENV_MAP, validateKey } from "./commands/i
|
|
|
41
42
|
import { registerEnvCommands } from "./commands/env.js";
|
|
42
43
|
import { loadSettings, saveSettings } from "./settings.js";
|
|
43
44
|
import { setSharedApiNetwork } from "./shared-api.js";
|
|
45
|
+
const _require = createRequire(import.meta.url);
|
|
46
|
+
const _pkg = _require("../package.json");
|
|
44
47
|
const program = new Command();
|
|
45
48
|
// Resolve default exchange from settings (fallback: "pacifica")
|
|
46
49
|
const _settings = loadSettings();
|
|
@@ -48,7 +51,7 @@ const _defaultExchange = _settings.defaultExchange || "pacifica";
|
|
|
48
51
|
program
|
|
49
52
|
.name("perp")
|
|
50
53
|
.description("Multi-DEX Perpetual Futures CLI (Pacifica, Hyperliquid, Lighter)")
|
|
51
|
-
.version(
|
|
54
|
+
.version(_pkg.version)
|
|
52
55
|
.option("-e, --exchange <exchange>", `Exchange: pacifica, hyperliquid, lighter (default: ${_defaultExchange})`, _defaultExchange)
|
|
53
56
|
.option("-n, --network <network>", "Network: mainnet or testnet", "mainnet")
|
|
54
57
|
.option("-k, --private-key <key>", "Private key")
|
package/dist/mcp-server.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Adapters are created lazily from environment variables.
|
|
8
8
|
*/
|
|
9
9
|
import "dotenv/config";
|
|
10
|
+
import { createRequire } from "node:module";
|
|
10
11
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
11
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12
13
|
import { z } from "zod";
|
|
@@ -56,7 +57,9 @@ function err(error, meta) {
|
|
|
56
57
|
return JSON.stringify({ ok: false, error, meta }, null, 2);
|
|
57
58
|
}
|
|
58
59
|
// ── MCP Server ──
|
|
59
|
-
const
|
|
60
|
+
const _require = createRequire(import.meta.url);
|
|
61
|
+
const _pkg = _require("../package.json");
|
|
62
|
+
const server = new McpServer({ name: "perp-cli", version: _pkg.version }, { capabilities: { tools: {}, resources: {} } });
|
|
60
63
|
// ============================================================
|
|
61
64
|
// Market Data tools (read-only, no private key needed)
|
|
62
65
|
// ============================================================
|
package/package.json
CHANGED
package/skills/perp-cli/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ allowed-tools: "Bash(perp:*), Bash(npx perp-cli:*), Bash(npx -y perp-cli:*)"
|
|
|
5
5
|
license: MIT
|
|
6
6
|
metadata:
|
|
7
7
|
author: hypurrquant
|
|
8
|
-
version: "0.3.
|
|
8
|
+
version: "0.3.10"
|
|
9
9
|
mcp-server: perp-cli
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -34,14 +34,6 @@ npm install -g perp-cli
|
|
|
34
34
|
|
|
35
35
|
CRITICAL: Do NOT use `perp init` — it is interactive and will hang.
|
|
36
36
|
|
|
37
|
-
**If user provides a private key:**
|
|
38
|
-
```bash
|
|
39
|
-
perp --json wallet set hl <KEY> # Hyperliquid (aliases: hl, hyperliquid)
|
|
40
|
-
perp --json wallet set pac <KEY> # Pacifica (aliases: pac, pacifica)
|
|
41
|
-
perp --json wallet set lt <KEY> # Lighter (aliases: lt, lighter)
|
|
42
|
-
perp --json wallet set hl <KEY> --default # also set as default exchange
|
|
43
|
-
```
|
|
44
|
-
|
|
45
37
|
**If user needs a new wallet:**
|
|
46
38
|
```bash
|
|
47
39
|
perp --json wallet generate evm # creates EVM wallet for Hyperliquid + Lighter
|
|
@@ -49,6 +41,41 @@ perp --json wallet generate solana # creates Solana wallet for Pacific
|
|
|
49
41
|
# IMPORTANT: Tell user the generated address so they can fund it with USDC!
|
|
50
42
|
```
|
|
51
43
|
|
|
44
|
+
### Hyperliquid setup
|
|
45
|
+
```bash
|
|
46
|
+
perp --json wallet set hl <EVM_PRIVATE_KEY> # register EVM key → ready to trade immediately
|
|
47
|
+
perp --json wallet show # verify
|
|
48
|
+
perp --json -e hl account info # check balance
|
|
49
|
+
```
|
|
50
|
+
No extra steps. Key is saved as `HL_PRIVATE_KEY` in .env.
|
|
51
|
+
|
|
52
|
+
### Pacifica setup
|
|
53
|
+
```bash
|
|
54
|
+
perp --json wallet set pac <SOLANA_PRIVATE_KEY> # register Solana key → ready to trade immediately
|
|
55
|
+
perp --json wallet show # verify
|
|
56
|
+
perp --json -e pac account info # check balance
|
|
57
|
+
```
|
|
58
|
+
No extra steps. Key is saved as `PACIFICA_PRIVATE_KEY` in .env.
|
|
59
|
+
|
|
60
|
+
### Lighter setup (API key auto-generated on registration)
|
|
61
|
+
```bash
|
|
62
|
+
perp --json wallet set lt <EVM_PRIVATE_KEY> # register EVM key
|
|
63
|
+
# → AUTOMATICALLY generates Lighter API key via on-chain tx
|
|
64
|
+
# → Saves to .env: LIGHTER_PRIVATE_KEY, LIGHTER_API_KEY, LIGHTER_ACCOUNT_INDEX, LIGHTER_API_KEY_INDEX
|
|
65
|
+
# → No manual API key creation needed. Do NOT ask the user to visit the Lighter website.
|
|
66
|
+
perp --json wallet show # verify
|
|
67
|
+
perp --json -e lighter account info # check balance
|
|
68
|
+
```
|
|
69
|
+
Same EVM key can be used for both Hyperliquid and Lighter:
|
|
70
|
+
```bash
|
|
71
|
+
perp --json wallet set hl <KEY> # same key
|
|
72
|
+
perp --json wallet set lt <KEY> # same key, different exchange binding
|
|
73
|
+
```
|
|
74
|
+
If API key auto-setup fails (rare, e.g. no ETH for gas on Lighter chain):
|
|
75
|
+
```bash
|
|
76
|
+
perp --json -e lighter manage setup-api-key # manual retry
|
|
77
|
+
```
|
|
78
|
+
|
|
52
79
|
**Verify setup (ALWAYS do this after any wallet command):**
|
|
53
80
|
```bash
|
|
54
81
|
perp --json wallet show
|
|
@@ -75,13 +102,39 @@ Symbols are auto-resolved across exchanges. Use bare symbols (e.g., `BTC`, `SOL`
|
|
|
75
102
|
### Common operations
|
|
76
103
|
```bash
|
|
77
104
|
perp --json wallet show # check configured wallets
|
|
78
|
-
perp --json -e hl account info # balance & margin
|
|
79
|
-
perp --json -e hl account positions # open positions
|
|
80
|
-
perp --json -e hl market list # available markets
|
|
81
|
-
perp --json -e hl market mid BTC # BTC mid price
|
|
82
|
-
perp --json arb scan --min 5 # find funding arb opportunities (>5bps spread)
|
|
83
105
|
perp --json portfolio # unified multi-exchange view
|
|
106
|
+
perp --json arb scan --min 5 # find funding arb opportunities (>5bps spread)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Per-exchange commands (ALL 3 exchanges use the SAME commands)
|
|
110
|
+
Every command below works on ALL exchanges. Just change `-e`:
|
|
111
|
+
```bash
|
|
112
|
+
# Account
|
|
113
|
+
perp --json -e hl account info # Hyperliquid balance & margin
|
|
114
|
+
perp --json -e pac account info # Pacifica balance & margin
|
|
115
|
+
perp --json -e lighter account info # Lighter balance & margin
|
|
116
|
+
perp --json -e <EX> account positions # open positions
|
|
117
|
+
|
|
118
|
+
# Market data
|
|
119
|
+
perp --json -e <EX> market list # available markets
|
|
120
|
+
perp --json -e <EX> market mid <SYM> # mid price
|
|
121
|
+
perp --json -e <EX> market book <SYM> # orderbook depth
|
|
122
|
+
|
|
123
|
+
# Trading (same syntax on ALL exchanges)
|
|
124
|
+
perp --json -e <EX> trade leverage <SYM> <N> --isolated # set leverage
|
|
125
|
+
perp --json -e <EX> trade market <SYM> buy <SIZE> # market buy
|
|
126
|
+
perp --json -e <EX> trade market <SYM> sell <SIZE> # market sell
|
|
127
|
+
perp --json -e <EX> trade close <SYM> # close position
|
|
128
|
+
perp --json -e <EX> trade check <SYM> <SIDE> <SIZE> --leverage <L> # pre-flight
|
|
129
|
+
|
|
130
|
+
# Deposit / Withdraw
|
|
131
|
+
perp --json deposit hyperliquid <AMOUNT> # deposit to HL
|
|
132
|
+
perp --json deposit pacifica <AMOUNT> # deposit to Pacifica
|
|
133
|
+
perp --json deposit lighter info # show Lighter deposit routes
|
|
134
|
+
perp --json deposit lighter cctp arb <AMOUNT> # deposit to Lighter via CCTP
|
|
135
|
+
perp --json withdraw <EX> <AMOUNT> # withdraw from exchange
|
|
84
136
|
```
|
|
137
|
+
**All 3 exchanges are fully operational.** Do NOT say any exchange "requires additional setup" or "is not available" — if `wallet show` shows it configured, it's ready to trade.
|
|
85
138
|
|
|
86
139
|
### Funding arb direction (CRITICAL — do NOT reverse)
|
|
87
140
|
```
|