jaspervault_cli 1.0.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 +138 -0
- package/config/chains.json +104 -0
- package/dist/bin/jv.d.ts +2 -0
- package/dist/bin/jv.js +29 -0
- package/dist/bin/jv.js.map +1 -0
- package/dist/src/client.d.ts +18 -0
- package/dist/src/client.js +128 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/commands/connect.d.ts +22 -0
- package/dist/src/commands/connect.js +128 -0
- package/dist/src/commands/connect.js.map +1 -0
- package/dist/src/commands/deposit.d.ts +59 -0
- package/dist/src/commands/deposit.js +261 -0
- package/dist/src/commands/deposit.js.map +1 -0
- package/dist/src/commands/init.d.ts +4 -0
- package/dist/src/commands/init.js +97 -0
- package/dist/src/commands/init.js.map +1 -0
- package/dist/src/commands/job.d.ts +2 -0
- package/dist/src/commands/job.js +20 -0
- package/dist/src/commands/job.js.map +1 -0
- package/dist/src/commands/limit-order.d.ts +2 -0
- package/dist/src/commands/limit-order.js +51 -0
- package/dist/src/commands/limit-order.js.map +1 -0
- package/dist/src/commands/order.d.ts +2 -0
- package/dist/src/commands/order.js +110 -0
- package/dist/src/commands/order.js.map +1 -0
- package/dist/src/commands/orders.d.ts +2 -0
- package/dist/src/commands/orders.js +72 -0
- package/dist/src/commands/orders.js.map +1 -0
- package/dist/src/commands/sl.d.ts +2 -0
- package/dist/src/commands/sl.js +67 -0
- package/dist/src/commands/sl.js.map +1 -0
- package/dist/src/commands/tp.d.ts +2 -0
- package/dist/src/commands/tp.js +67 -0
- package/dist/src/commands/tp.js.map +1 -0
- package/dist/src/commands/vault.d.ts +24 -0
- package/dist/src/commands/vault.js +249 -0
- package/dist/src/commands/vault.js.map +1 -0
- package/dist/src/services/chain-config.d.ts +57 -0
- package/dist/src/services/chain-config.js +96 -0
- package/dist/src/services/chain-config.js.map +1 -0
- package/dist/src/services/key-manager.d.ts +23 -0
- package/dist/src/services/key-manager.js +79 -0
- package/dist/src/services/key-manager.js.map +1 -0
- package/dist/src/services/order-signer.d.ts +24 -0
- package/dist/src/services/order-signer.js +162 -0
- package/dist/src/services/order-signer.js.map +1 -0
- package/dist/src/services/price-service.d.ts +14 -0
- package/dist/src/services/price-service.js +47 -0
- package/dist/src/services/price-service.js.map +1 -0
- package/dist/src/services/subgraph-client.d.ts +53 -0
- package/dist/src/services/subgraph-client.js +120 -0
- package/dist/src/services/subgraph-client.js.map +1 -0
- package/dist/src/services/vault-profile.d.ts +15 -0
- package/dist/src/services/vault-profile.js +56 -0
- package/dist/src/services/vault-profile.js.map +1 -0
- package/dist/src/templates/skill-body.d.ts +11 -0
- package/dist/src/templates/skill-body.js +233 -0
- package/dist/src/templates/skill-body.js.map +1 -0
- package/dist/src/types.d.ts +212 -0
- package/dist/src/types.js +3 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/config.d.ts +7 -0
- package/dist/src/utils/config.js +14 -0
- package/dist/src/utils/config.js.map +1 -0
- package/dist/src/utils/endpoints.d.ts +8 -0
- package/dist/src/utils/endpoints.js +13 -0
- package/dist/src/utils/endpoints.js.map +1 -0
- package/dist/src/utils/output.d.ts +14 -0
- package/dist/src/utils/output.js +50 -0
- package/dist/src/utils/output.js.map +1 -0
- package/package.json +50 -0
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# JasperVault CLI (`jv`)
|
|
2
|
+
|
|
3
|
+
Trade perpetuals on JasperVault through AI conversation. Install this CLI and connect your AI assistant (OpenClaw, Cursor, Claude Code) — then just talk to place orders, set take-profits, and manage positions without touching the command line.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Quick Start (OpenClaw)
|
|
8
|
+
|
|
9
|
+
### 1. Install the CLI
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g jaspervault_cli
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Verify:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
jv --version
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 2. Install JasperVault Skill to OpenClaw
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
jv init --ai openclaw
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
This installs the trading skill to `~/.openclaw/skills/jasper-vault-cli/SKILL.md`. OpenClaw will now know how to trade on your behalf.
|
|
28
|
+
|
|
29
|
+
> If the skill already exists, add `--force` to overwrite:
|
|
30
|
+
> ```bash
|
|
31
|
+
> jv init --ai openclaw --force
|
|
32
|
+
> ```
|
|
33
|
+
|
|
34
|
+
### 3. Initialize Your Wallet (One-Time Setup)
|
|
35
|
+
|
|
36
|
+
In OpenClaw, say:
|
|
37
|
+
|
|
38
|
+
> **"I want to start trading"**
|
|
39
|
+
|
|
40
|
+
OpenClaw will call `jv vault init-wc`, which displays a QR code. Scan it with your mobile wallet (MetaMask Mobile, Rabby, etc.) and confirm the delegation signature on your phone. Done — no private key export required.
|
|
41
|
+
|
|
42
|
+
Or run it manually in the terminal:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
jv vault init-wc --network jaspervault --pretty
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 4. Start Trading
|
|
49
|
+
|
|
50
|
+
Just talk to OpenClaw. Examples:
|
|
51
|
+
|
|
52
|
+
- "Go long JBTC with 100 JUSDC, 50x leverage"
|
|
53
|
+
- "Set take-profit for order 99 at 105000"
|
|
54
|
+
- "Show my current positions"
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Install for Other AI Platforms
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
jv init --ai cursor # Cursor (current project)
|
|
62
|
+
jv init --ai cursor --global # Cursor (user-level)
|
|
63
|
+
jv init --ai claude # Claude Code (current project)
|
|
64
|
+
jv init --ai claude --global # Claude Code (user-level)
|
|
65
|
+
jv init --ai all # All platforms at once
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Options:
|
|
69
|
+
- `--global` — Install to user home instead of current project (cursor/claude only)
|
|
70
|
+
- `--force` — Overwrite existing skill file without prompting
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
All configuration is done via environment variables. For most users, **no configuration is needed** — the CLI connects to the JasperVault test environment by default.
|
|
77
|
+
|
|
78
|
+
| Variable | Required | Description | Default |
|
|
79
|
+
|----------|----------|-------------|---------|
|
|
80
|
+
| `JV_API_URL` | No | Trading API base URL | `https://trading-api-test.jaspervault.pro` |
|
|
81
|
+
| `JV_API_KEY` | No | Bearer token for API authentication | — |
|
|
82
|
+
| `JV_TIMEOUT` | No | Request timeout in ms | `30000` |
|
|
83
|
+
| `JV_DELEGATION_KEY` | No | Delegation wallet private key override; auto-generated on first `vault init` | from `~/.jaspervault/keys.json` |
|
|
84
|
+
| `JV_BASE_RPC_URL` | No | Base chain RPC URL override (for deposit) | built-in |
|
|
85
|
+
| `JV_JASPERVAULT_RPC_URL` | No | JasperVault chain RPC URL override | built-in |
|
|
86
|
+
| `JV_SUBGRAPH_URL` | No | Subgraph endpoint override | built-in per network |
|
|
87
|
+
| `WC_PROJECT_ID` | No | WalletConnect Cloud project ID (get one at [cloud.reown.com](https://cloud.reown.com)) | — |
|
|
88
|
+
| `PRIVATE_KEY` | No* | EOA wallet private key; only needed for traditional `vault init` and `deposit` | — |
|
|
89
|
+
|
|
90
|
+
\* Not required when using the WalletConnect flow (`vault init-wc`, `deposit info`).
|
|
91
|
+
|
|
92
|
+
### Connecting to a Different Environment
|
|
93
|
+
|
|
94
|
+
Add to `~/.zshrc` or `~/.bashrc`:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
export JV_API_URL=https://your-api-endpoint.example.com
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Then restart your terminal or run `source ~/.zshrc`.
|
|
101
|
+
|
|
102
|
+
### How Credentials Are Stored
|
|
103
|
+
|
|
104
|
+
After the first successful `jv vault init` or `jv vault init-wc`, the delegation wallet is saved to `~/.jaspervault/keys.json` and your vault profile to `~/.jaspervault/profile.json`. The CLI reads these automatically — no manual configuration needed for subsequent operations.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Funding Your Account (Optional)
|
|
109
|
+
|
|
110
|
+
To deposit tokens from Base to JasperVault, tell OpenClaw:
|
|
111
|
+
|
|
112
|
+
> **"Deposit 100 JUSDC into my vault"**
|
|
113
|
+
|
|
114
|
+
OpenClaw will fetch the transaction data and send it to your phone via WalletConnect for approval.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Full Command Reference
|
|
119
|
+
|
|
120
|
+
For a complete list of available commands and trading examples, see the documentation:
|
|
121
|
+
|
|
122
|
+
- [User Guide](docs/USER_GUIDE.md) — Full CLI reference including all commands and options
|
|
123
|
+
- [OpenClaw Setup Guide](docs/OPENCLAW_GUIDE.md) — Detailed walkthrough for OpenClaw users
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Development
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
cd cli
|
|
131
|
+
npm install
|
|
132
|
+
npm run build
|
|
133
|
+
npm link # makes `jv` available globally from local source
|
|
134
|
+
|
|
135
|
+
npm run typecheck # TypeScript type checking
|
|
136
|
+
npm test # Run tests
|
|
137
|
+
npm run dev -- orders list --pretty # Run via tsx without building
|
|
138
|
+
```
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"networks": {
|
|
3
|
+
"base_uat": {
|
|
4
|
+
"name": "Base UAT",
|
|
5
|
+
"chainId": 8453,
|
|
6
|
+
"rpcUrl": "https://base-mainnet.g.alchemy.com/v2/igHoSYAWMvPX86unqNbyZ",
|
|
7
|
+
"contracts": {
|
|
8
|
+
"diamond": "0xB571399F2824424D4c15496406Ea7ACBc1a276AB",
|
|
9
|
+
"vaultFactory": "0x54d365E5E31472108e6AE5bdF89d85912d1A428E",
|
|
10
|
+
"perpsOptionModuleHandle": "0x2BB0319B622058F8090b6742705Eb80F8dcC3cdc",
|
|
11
|
+
"optionModuleV2": "0x4De345778a85Cf12aF49c423c75Fe02C5799d425"
|
|
12
|
+
},
|
|
13
|
+
"tokens": {
|
|
14
|
+
"JBTC": { "address": "0xf3cEe52BDa02DaE997D00A0Bf8d221C4f129ebaF", "decimals": 8 },
|
|
15
|
+
"CBBTC": { "address": "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf", "decimals": 8 },
|
|
16
|
+
"JUSDC": { "address": "0x6e236176D1B473Bdb770CDDF4d257B877F2DA9db", "decimals": 6 },
|
|
17
|
+
"USDC": { "address": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "decimals": 6 }
|
|
18
|
+
},
|
|
19
|
+
"marginAsset": { "symbol": "JUSDC", "address": "0x6e236176D1B473Bdb770CDDF4d257B877F2DA9db", "decimals": 6 },
|
|
20
|
+
"writers": {
|
|
21
|
+
"JBTC": { "long": "0x2D0640Bc9624fd3B66D07FE54C223F138B0391Aa", "short": "0x71c44CF5Ca04b1a2a1A5bA93081DA89183AAc0b6" },
|
|
22
|
+
"CBBTC": { "long": "0x97cDCF310653a2Cbefee479adE77AD8D3De99dF1", "short": "0x71c44CF5Ca04b1a2a1A5bA93081DA89183AAc0b6" }
|
|
23
|
+
},
|
|
24
|
+
"defaultLeverage": 50,
|
|
25
|
+
"quoteCenterUrl": "https://quotecenterv2-uat-gcx2x.ondigitalocean.app",
|
|
26
|
+
"subgraphUrl": "https://subgraph.satsuma-prod.com/0981c2ab3685/garys-team/jaspervault-v2-base-uat/api"
|
|
27
|
+
},
|
|
28
|
+
"jaspervault": {
|
|
29
|
+
"name": "JasperVault",
|
|
30
|
+
"chainId": 55531,
|
|
31
|
+
"rpcUrl": "https://enterprise.onerpc.com/apikey/42b59vURnC9pSN2XWPunWiYWTeUOU6Mh/jasper_mainnet",
|
|
32
|
+
"contracts": {
|
|
33
|
+
"diamond": "0xAfD11c2d9350B2080eD601Ba64ea9f1F532A093c",
|
|
34
|
+
"vaultFactory": "0x54d365E5E31472108e6AE5bdF89d85912d1A428E",
|
|
35
|
+
"perpsOptionModuleHandle": "0xcbCCf074E030CDfd907375B00449B4f10d7d475f",
|
|
36
|
+
"optionModuleV2": "0x0f487603edE93a5329023512B7dcdA632eD70Ed5"
|
|
37
|
+
},
|
|
38
|
+
"tokens": {
|
|
39
|
+
"JBTC": { "address": "0xCb9d5Ae34cc0476BD8Cb22Aa9C21545be4e38bf2", "decimals": 8 },
|
|
40
|
+
"JUSDC": { "address": "0x567717052247C5Fa302fb2E8DF681A07D63E9faF", "decimals": 6 },
|
|
41
|
+
"CBBTC": { "address": "0x821DF7b83c9FCba013B37490CFC4B5a0bDe36220", "decimals": 8 }
|
|
42
|
+
},
|
|
43
|
+
"marginAsset": { "symbol": "JUSDC", "address": "0x567717052247C5Fa302fb2E8DF681A07D63E9faF", "decimals": 6 },
|
|
44
|
+
"writers": {
|
|
45
|
+
"JBTC": { "long": "0xfe7fe5D5de9a8B0BcF39D8676d0C92065a3ca20f", "short": "0x7c7900E40652A9C2225cf6d1E96c38606407e5B0" }
|
|
46
|
+
},
|
|
47
|
+
"defaultLeverage": 50,
|
|
48
|
+
"quoteCenterUrl": "https://uat-jasperquotecenterv2.fly.dev",
|
|
49
|
+
"subgraphUrl": "https://subgraph.satsuma-prod.com/0981c2ab3685/garys-team/jaspervault-v2-base-uat/api"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"warpRoutes": {
|
|
53
|
+
"jbtc": {
|
|
54
|
+
"symbol": "jBTC",
|
|
55
|
+
"decimals": 8,
|
|
56
|
+
"base": {
|
|
57
|
+
"underlyingToken": "0xf3cEe52BDa02DaE997D00A0Bf8d221C4f129ebaF",
|
|
58
|
+
"warpRouter": "0xf29d79382d5d092193F0746671397410490e51fF"
|
|
59
|
+
},
|
|
60
|
+
"jaspervault": {
|
|
61
|
+
"domain": 55531,
|
|
62
|
+
"warpRouter": "0xCb9d5Ae34cc0476BD8Cb22Aa9C21545be4e38bf2"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"jusdc": {
|
|
66
|
+
"symbol": "jUSDC",
|
|
67
|
+
"decimals": 6,
|
|
68
|
+
"base": {
|
|
69
|
+
"underlyingToken": "0x6e236176D1B473Bdb770CDDF4d257B877F2DA9db",
|
|
70
|
+
"warpRouter": "0x7C475c87b8AA7609073e1be3d3CEB62BbbD5276a"
|
|
71
|
+
},
|
|
72
|
+
"jaspervault": {
|
|
73
|
+
"domain": 55531,
|
|
74
|
+
"warpRouter": "0x567717052247C5Fa302fb2E8DF681A07D63E9faF"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"cbbtc": {
|
|
78
|
+
"symbol": "cBBTC",
|
|
79
|
+
"decimals": 8,
|
|
80
|
+
"base": {
|
|
81
|
+
"underlyingToken": "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
|
|
82
|
+
"warpRouter": "0xf08d7Be10E69BD5B7FfCb65612720a747C9B8Bed"
|
|
83
|
+
},
|
|
84
|
+
"jaspervault": {
|
|
85
|
+
"domain": 55531,
|
|
86
|
+
"warpRouter": "0x821DF7b83c9FCba013B37490CFC4B5a0bDe36220"
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
"usdc": {
|
|
90
|
+
"symbol": "USDC",
|
|
91
|
+
"decimals": 6,
|
|
92
|
+
"base": {
|
|
93
|
+
"underlyingToken": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
94
|
+
"warpRouter": "0xDe0f17681123CbE998E7896B74a197937123b3D9"
|
|
95
|
+
},
|
|
96
|
+
"jaspervault": {
|
|
97
|
+
"domain": 55531,
|
|
98
|
+
"warpRouter": "0x23559FcF18896ed3280c4d7106ca74fFda14bd79"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
"defaultBaseRpc": "https://base-mainnet.g.alchemy.com/v2/igHoSYAWMvPX86unqNbyZ",
|
|
103
|
+
"defaultJaspervaultRpc": "https://enterprise.onerpc.com/apikey/42b59vURnC9pSN2XWPunWiYWTeUOU6Mh/jasper_mainnet"
|
|
104
|
+
}
|
package/dist/bin/jv.d.ts
ADDED
package/dist/bin/jv.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { registerOrderCommand } from '../src/commands/order.js';
|
|
4
|
+
import { registerJobCommand } from '../src/commands/job.js';
|
|
5
|
+
import { registerLimitOrderCommand } from '../src/commands/limit-order.js';
|
|
6
|
+
import { registerOrdersCommand } from '../src/commands/orders.js';
|
|
7
|
+
import { registerTpCommand } from '../src/commands/tp.js';
|
|
8
|
+
import { registerSlCommand } from '../src/commands/sl.js';
|
|
9
|
+
import { registerVaultCommand } from '../src/commands/vault.js';
|
|
10
|
+
import { registerDepositCommand } from '../src/commands/deposit.js';
|
|
11
|
+
import { registerInitCommand } from '../src/commands/init.js';
|
|
12
|
+
import { registerConnectCommand } from '../src/commands/connect.js';
|
|
13
|
+
const program = new Command();
|
|
14
|
+
program
|
|
15
|
+
.name('jv')
|
|
16
|
+
.description('JasperVault CLI — interact with the JasperVault Manager API')
|
|
17
|
+
.version('1.0.0');
|
|
18
|
+
registerOrderCommand(program);
|
|
19
|
+
registerTpCommand(program);
|
|
20
|
+
registerSlCommand(program);
|
|
21
|
+
registerJobCommand(program);
|
|
22
|
+
registerLimitOrderCommand(program);
|
|
23
|
+
registerOrdersCommand(program);
|
|
24
|
+
registerVaultCommand(program);
|
|
25
|
+
registerDepositCommand(program);
|
|
26
|
+
registerInitCommand(program);
|
|
27
|
+
registerConnectCommand(program);
|
|
28
|
+
program.parse();
|
|
29
|
+
//# sourceMappingURL=jv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jv.js","sourceRoot":"","sources":["../../bin/jv.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAEpE,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,IAAI,CAAC;KACV,WAAW,CAAC,6DAA6D,CAAC;KAC1E,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC3B,iBAAiB,CAAC,OAAO,CAAC,CAAC;AAC3B,kBAAkB,CAAC,OAAO,CAAC,CAAC;AAC5B,yBAAyB,CAAC,OAAO,CAAC,CAAC;AACnC,qBAAqB,CAAC,OAAO,CAAC,CAAC;AAC/B,oBAAoB,CAAC,OAAO,CAAC,CAAC;AAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAChC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AAC7B,sBAAsB,CAAC,OAAO,CAAC,CAAC;AAEhC,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type CliConfig } from './utils/config.js';
|
|
2
|
+
import type { ApiResponse, SSEWatchResult } from './types.js';
|
|
3
|
+
export declare class ApiClient {
|
|
4
|
+
private baseUrl;
|
|
5
|
+
private timeout;
|
|
6
|
+
private headers;
|
|
7
|
+
constructor(config: CliConfig);
|
|
8
|
+
get<T>(path: string, query?: Record<string, string | undefined>): Promise<ApiResponse<T>>;
|
|
9
|
+
post<T>(path: string, body?: unknown): Promise<ApiResponse<T>>;
|
|
10
|
+
delete<T>(path: string): Promise<ApiResponse<T>>;
|
|
11
|
+
/**
|
|
12
|
+
* Query job result via blocking POST to /order/perpsSSE.
|
|
13
|
+
* Resolves when the server returns the final job result.
|
|
14
|
+
*/
|
|
15
|
+
watchJobStream(jobId: string, timeoutSeconds?: number): Promise<SSEWatchResult>;
|
|
16
|
+
private buildUrl;
|
|
17
|
+
private request;
|
|
18
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { ENDPOINTS } from './utils/endpoints.js';
|
|
2
|
+
import { EXIT_CODES, printError } from './utils/output.js';
|
|
3
|
+
export class ApiClient {
|
|
4
|
+
baseUrl;
|
|
5
|
+
timeout;
|
|
6
|
+
headers;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
this.baseUrl = config.apiUrl;
|
|
9
|
+
this.timeout = config.timeout;
|
|
10
|
+
this.headers = { 'Content-Type': 'application/json' };
|
|
11
|
+
if (config.apiKey) {
|
|
12
|
+
this.headers['Authorization'] = `Bearer ${config.apiKey}`;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async get(path, query) {
|
|
16
|
+
const url = this.buildUrl(path, query);
|
|
17
|
+
return this.request(url, { method: 'GET' });
|
|
18
|
+
}
|
|
19
|
+
async post(path, body) {
|
|
20
|
+
const url = this.buildUrl(path);
|
|
21
|
+
return this.request(url, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
async delete(path) {
|
|
27
|
+
const url = this.buildUrl(path);
|
|
28
|
+
return this.request(url, { method: 'DELETE' });
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Query job result via blocking POST to /order/perpsSSE.
|
|
32
|
+
* Resolves when the server returns the final job result.
|
|
33
|
+
*/
|
|
34
|
+
async watchJobStream(jobId, timeoutSeconds = 60) {
|
|
35
|
+
const overrideTimeout = timeoutSeconds * 1000;
|
|
36
|
+
const controller = new AbortController();
|
|
37
|
+
const timer = setTimeout(() => controller.abort(), overrideTimeout);
|
|
38
|
+
try {
|
|
39
|
+
const url = this.buildUrl(ENDPOINTS.ORDER_SSE);
|
|
40
|
+
const response = await fetch(url, {
|
|
41
|
+
method: 'POST',
|
|
42
|
+
headers: this.headers,
|
|
43
|
+
body: JSON.stringify({ jobID: jobId }),
|
|
44
|
+
signal: controller.signal,
|
|
45
|
+
});
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
if (response.status === 404) {
|
|
48
|
+
return { jobId, status: 'not_found', error: 'Job not found on server' };
|
|
49
|
+
}
|
|
50
|
+
return { jobId, status: 'failed', error: `HTTP ${response.status}` };
|
|
51
|
+
}
|
|
52
|
+
const body = await response.json();
|
|
53
|
+
const data = (body.data ?? body);
|
|
54
|
+
return {
|
|
55
|
+
jobId,
|
|
56
|
+
status: 'completed',
|
|
57
|
+
transactionHash: (data.transactionHash ?? data.txHash),
|
|
58
|
+
gasUsed: data.gasUsed,
|
|
59
|
+
executionTimeMs: data.executionTimeMs,
|
|
60
|
+
operation: data.operation,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
if (err instanceof DOMException && err.name === 'AbortError') {
|
|
65
|
+
return { jobId, status: 'timeout', error: `Client timeout after ${timeoutSeconds} seconds` };
|
|
66
|
+
}
|
|
67
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
68
|
+
return { jobId, status: 'failed', error: msg };
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
clearTimeout(timer);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
buildUrl(path, query) {
|
|
75
|
+
const url = new URL(path, this.baseUrl);
|
|
76
|
+
if (query) {
|
|
77
|
+
for (const [key, value] of Object.entries(query)) {
|
|
78
|
+
if (value !== undefined) {
|
|
79
|
+
url.searchParams.set(key, value);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return url.toString();
|
|
84
|
+
}
|
|
85
|
+
async request(url, init) {
|
|
86
|
+
const controller = new AbortController();
|
|
87
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
88
|
+
try {
|
|
89
|
+
const response = await fetch(url, {
|
|
90
|
+
...init,
|
|
91
|
+
headers: this.headers,
|
|
92
|
+
signal: controller.signal,
|
|
93
|
+
});
|
|
94
|
+
const body = await response.json();
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
const errMsg = body?.data?.errorMessage
|
|
97
|
+
?? body?.msg
|
|
98
|
+
?? `HTTP ${response.status}`;
|
|
99
|
+
printError(String(errMsg));
|
|
100
|
+
process.exit(EXIT_CODES.HTTP_ERROR);
|
|
101
|
+
}
|
|
102
|
+
if (body.code !== 0) {
|
|
103
|
+
const errMsg = body?.data?.errorMessage
|
|
104
|
+
?? body?.msg
|
|
105
|
+
?? 'Unknown business error';
|
|
106
|
+
printError(String(errMsg));
|
|
107
|
+
process.exit(EXIT_CODES.BUSINESS_ERROR);
|
|
108
|
+
}
|
|
109
|
+
return body;
|
|
110
|
+
}
|
|
111
|
+
catch (err) {
|
|
112
|
+
if (err instanceof DOMException && err.name === 'AbortError') {
|
|
113
|
+
printError(`Request timed out after ${this.timeout}ms`);
|
|
114
|
+
}
|
|
115
|
+
else if (err instanceof TypeError) {
|
|
116
|
+
printError(`Network error: ${err.message}`);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
printError(`Unexpected error: ${err}`);
|
|
120
|
+
}
|
|
121
|
+
process.exit(EXIT_CODES.HTTP_ERROR);
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
clearTimeout(timer);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { SignClient } from '@walletconnect/sign-client';
|
|
3
|
+
export interface InitWcResult {
|
|
4
|
+
client: InstanceType<typeof SignClient>;
|
|
5
|
+
session: {
|
|
6
|
+
topic: string;
|
|
7
|
+
pairingTopic: string;
|
|
8
|
+
namespaces: Record<string, {
|
|
9
|
+
accounts: string[];
|
|
10
|
+
}>;
|
|
11
|
+
};
|
|
12
|
+
walletAddress: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Initialize WalletConnect SignClient, connect, show QR, wait for approval.
|
|
16
|
+
* Returns client + session + walletAddress for further requests (e.g. eth_signTypedData_v4).
|
|
17
|
+
*/
|
|
18
|
+
export declare function initWcAndConnect(opts: {
|
|
19
|
+
timeoutS: number;
|
|
20
|
+
onAwaiting?: (uri: string, qrCodePath: string, pretty?: boolean) => void;
|
|
21
|
+
}): Promise<InitWcResult>;
|
|
22
|
+
export declare function registerConnectCommand(program: Command): void;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import * as fs from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { SignClient } from '@walletconnect/sign-client';
|
|
4
|
+
import QRCode from 'qrcode';
|
|
5
|
+
import { printJson, exitWithError, EXIT_CODES } from '../utils/output.js';
|
|
6
|
+
const DEFAULT_TIMEOUT_S = 120;
|
|
7
|
+
// Embedded project ID — users can override with WC_PROJECT_ID env var
|
|
8
|
+
const DEFAULT_WC_PROJECT_ID = 'f47863c3ad29e5bae9cee8013ec05982';
|
|
9
|
+
const WC_METADATA = {
|
|
10
|
+
name: 'JasperVault CLI',
|
|
11
|
+
description: 'JasperVault perpetual trading CLI',
|
|
12
|
+
url: 'https://jaspervault.io',
|
|
13
|
+
icons: [],
|
|
14
|
+
};
|
|
15
|
+
function getJvDir() {
|
|
16
|
+
return join(process.env.HOME || process.env.USERPROFILE || '', '.jaspervault');
|
|
17
|
+
}
|
|
18
|
+
function getQrCodePath() {
|
|
19
|
+
return join(getJvDir(), 'wc-qrcode.png');
|
|
20
|
+
}
|
|
21
|
+
function getSessionFile() {
|
|
22
|
+
return join(getJvDir(), '.wc-session.json');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Initialize WalletConnect SignClient, connect, show QR, wait for approval.
|
|
26
|
+
* Returns client + session + walletAddress for further requests (e.g. eth_signTypedData_v4).
|
|
27
|
+
*/
|
|
28
|
+
export async function initWcAndConnect(opts) {
|
|
29
|
+
const projectId = process.env.WC_PROJECT_ID || DEFAULT_WC_PROJECT_ID;
|
|
30
|
+
let client;
|
|
31
|
+
try {
|
|
32
|
+
client = await SignClient.init({
|
|
33
|
+
projectId,
|
|
34
|
+
metadata: WC_METADATA,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
exitWithError(`Failed to initialize WalletConnect: ${err.message}`, EXIT_CODES.HTTP_ERROR);
|
|
39
|
+
}
|
|
40
|
+
const { uri, approval } = await client.connect({
|
|
41
|
+
optionalNamespaces: {
|
|
42
|
+
eip155: {
|
|
43
|
+
chains: ['eip155:8453', 'eip155:55531'],
|
|
44
|
+
methods: ['eth_signTypedData_v4', 'eth_sendTransaction'],
|
|
45
|
+
events: ['accountsChanged', 'chainChanged'],
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
if (!uri) {
|
|
50
|
+
exitWithError('WalletConnect did not return a pairing URI', EXIT_CODES.HTTP_ERROR);
|
|
51
|
+
}
|
|
52
|
+
await fs.mkdir(getJvDir(), { recursive: true });
|
|
53
|
+
const qrPath = getQrCodePath();
|
|
54
|
+
await QRCode.toFile(qrPath, uri, { width: 400, errorCorrectionLevel: 'M' });
|
|
55
|
+
opts.onAwaiting?.(uri, qrPath);
|
|
56
|
+
const timeoutMs = opts.timeoutS * 1000;
|
|
57
|
+
let session;
|
|
58
|
+
try {
|
|
59
|
+
session = await Promise.race([
|
|
60
|
+
approval(),
|
|
61
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeoutMs)),
|
|
62
|
+
]);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
const msg = err.message;
|
|
66
|
+
if (msg === 'timeout') {
|
|
67
|
+
throw new Error(`Connection timed out after ${opts.timeoutS}s`);
|
|
68
|
+
}
|
|
69
|
+
throw new Error(`Connection rejected or failed: ${msg}`);
|
|
70
|
+
}
|
|
71
|
+
const accounts = Object.values(session.namespaces).flatMap((ns) => ns.accounts);
|
|
72
|
+
const firstAccount = accounts[0];
|
|
73
|
+
if (!firstAccount) {
|
|
74
|
+
exitWithError('No accounts returned from wallet', EXIT_CODES.BUSINESS_ERROR);
|
|
75
|
+
}
|
|
76
|
+
const parts = firstAccount.split(':');
|
|
77
|
+
const walletAddress = parts[2];
|
|
78
|
+
return { client, session, walletAddress };
|
|
79
|
+
}
|
|
80
|
+
export function registerConnectCommand(program) {
|
|
81
|
+
program
|
|
82
|
+
.command('connect')
|
|
83
|
+
.description('Connect to a wallet via WalletConnect — outputs URI and QR code image for wallet pairing')
|
|
84
|
+
.option('--timeout <seconds>', 'Connection timeout in seconds', String(DEFAULT_TIMEOUT_S))
|
|
85
|
+
.option('--pretty', 'Pretty-print JSON output')
|
|
86
|
+
.action(async (opts) => {
|
|
87
|
+
const timeoutS = parseInt(opts.timeout, 10) || DEFAULT_TIMEOUT_S;
|
|
88
|
+
let result;
|
|
89
|
+
try {
|
|
90
|
+
result = await initWcAndConnect({
|
|
91
|
+
timeoutS,
|
|
92
|
+
onAwaiting: (uri, qrCodePath) => {
|
|
93
|
+
printJson({
|
|
94
|
+
status: 'awaiting_connection',
|
|
95
|
+
uri,
|
|
96
|
+
qrCodePath,
|
|
97
|
+
message: 'Scan QR code or paste URI in wallet to connect',
|
|
98
|
+
}, opts.pretty);
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
printJson({ status: 'error', success: false, message: err.message }, opts.pretty);
|
|
104
|
+
process.exit(EXIT_CODES.BUSINESS_ERROR);
|
|
105
|
+
}
|
|
106
|
+
const { client: _client, session, walletAddress } = result;
|
|
107
|
+
const chainId = parseInt(Object.values(session.namespaces)[0].accounts[0].split(':')[1], 10);
|
|
108
|
+
const sessionInfo = {
|
|
109
|
+
walletAddress,
|
|
110
|
+
chainId,
|
|
111
|
+
sessionTopic: session.topic,
|
|
112
|
+
pairingTopic: session.pairingTopic,
|
|
113
|
+
};
|
|
114
|
+
await fs.writeFile(getSessionFile(), JSON.stringify(sessionInfo, null, 2), {
|
|
115
|
+
mode: 0o600,
|
|
116
|
+
});
|
|
117
|
+
printJson({
|
|
118
|
+
status: 'connected',
|
|
119
|
+
success: true,
|
|
120
|
+
walletAddress,
|
|
121
|
+
chainId,
|
|
122
|
+
sessionTopic: session.topic,
|
|
123
|
+
message: 'Wallet connected successfully',
|
|
124
|
+
}, opts.pretty);
|
|
125
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=connect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../../../src/commands/connect.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { ethers } from 'ethers';
|
|
3
|
+
import type { WarpTokenConfig } from '../services/chain-config.js';
|
|
4
|
+
export interface UnsignedTx {
|
|
5
|
+
to: string;
|
|
6
|
+
data: string;
|
|
7
|
+
value: string;
|
|
8
|
+
chainId: string;
|
|
9
|
+
}
|
|
10
|
+
export interface DepositTxInfo {
|
|
11
|
+
recipient: string;
|
|
12
|
+
token: string;
|
|
13
|
+
amount: string;
|
|
14
|
+
amountWei: string;
|
|
15
|
+
transactions: Array<{
|
|
16
|
+
step: number;
|
|
17
|
+
description: string;
|
|
18
|
+
required: boolean;
|
|
19
|
+
tx: UnsignedTx;
|
|
20
|
+
}>;
|
|
21
|
+
polling?: {
|
|
22
|
+
description: string;
|
|
23
|
+
command: string;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Compute vault address from vault factory (read-only).
|
|
28
|
+
*/
|
|
29
|
+
export declare function computeVaultAddress(provider: ethers.Provider, vaultFactoryAddress: string, ownerAddress: string, vaultIndex: number): Promise<string>;
|
|
30
|
+
/**
|
|
31
|
+
* Build approve tx calldata for ERC20.
|
|
32
|
+
*/
|
|
33
|
+
export declare function buildApproveCalldata(spender: string, amountWei: bigint): string;
|
|
34
|
+
/**
|
|
35
|
+
* Build transferRemote tx calldata for Hyperlane Warp.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildTransferRemoteCalldata(destinationDomain: number, recipient: string, amountWei: bigint): string;
|
|
38
|
+
/**
|
|
39
|
+
* Build unsigned transaction objects for deposit (approve + transferRemote).
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildDepositTransactions(warpConfig: WarpTokenConfig, recipient: string, amountWei: bigint, needsApprove: boolean): DepositTxInfo['transactions'];
|
|
42
|
+
/**
|
|
43
|
+
* Check balances and allowance for deposit (read-only).
|
|
44
|
+
*/
|
|
45
|
+
export declare function checkDepositBalances(baseProvider: ethers.Provider, walletAddress: string, warpConfig: WarpTokenConfig, amountWei: bigint): Promise<{
|
|
46
|
+
underlyingBalance: bigint;
|
|
47
|
+
warpBalance: bigint;
|
|
48
|
+
allowance: bigint;
|
|
49
|
+
hasEnough: boolean;
|
|
50
|
+
needsApprove: boolean;
|
|
51
|
+
}>;
|
|
52
|
+
/**
|
|
53
|
+
* Poll for token arrival on JasperVault chain.
|
|
54
|
+
*/
|
|
55
|
+
export declare function pollForDepositArrival(jaspervaultProvider: ethers.Provider, destWarpRouterAddress: string, recipient: string, initialBalance: bigint, timeoutMs?: number): Promise<{
|
|
56
|
+
arrived: boolean;
|
|
57
|
+
arrivalTimeMs?: number;
|
|
58
|
+
}>;
|
|
59
|
+
export declare function registerDepositCommand(program: Command): void;
|