Use this skill to create a HyperLiquid perpetuals and spot wallet for your agent. Trade perps, manage spot balances, transfer USDC between sub-accounts, get...
---
name: Vincent - HyperLiquid for agents
description: Use this skill to create a HyperLiquid perpetuals and spot wallet for your agent. Trade perps, manage spot balances, transfer USDC between sub-accounts, get prices, place orders — all without exposing private keys.
homepage: https://heyvincent.ai
source: https://github.com/HeyVincent-ai/Vincent
metadata:
clawdbot:
homepage: https://heyvincent.ai
requires:
config:
- ${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/credentials/agentwallet
- ./agentwallet
---
# Vincent - HyperLiquid for agents
Use this skill to create a HyperLiquid perpetuals and spot wallet for your agent. Trade perps, check spot balances, and transfer USDC between perps and spot sub-accounts. The generated EOA **is** the HyperLiquid account — fund it directly via the HL bridge and start trading immediately with no Safe deployment or collateral approval steps.
**The agent never sees the private key.** All operations are executed server-side. The agent receives a scoped API key that can only perform actions permitted by the wallet owner's policies.
All commands use the `@vincentai/cli` package. API keys are stored and resolved automatically.
## Security Model
**No environment variables are required.** The agent creates its own HyperLiquid wallet at runtime by calling the Vincent API, which returns a scoped API key. There is no pre-existing credential to configure.
**The generated EOA is a standalone HyperLiquid account.** Unlike Polymarket (which deploys a Gnosis Safe), the EOA private key IS the HyperLiquid account. Deposits go directly to this address via the HyperLiquid bridge from Arbitrum, or via `usdSend` from another HL account.
**The agent's API key is not a private key.** It is a scoped Bearer token enforced server-side. The Vincent server evaluates all policies before executing any trade. If a trade violates a policy, the server rejects it. If a trade requires human approval, the server holds it and notifies the wallet owner via Telegram.
**All API calls go exclusively to `heyvincent.ai`** over HTTPS/TLS. The service calls `api.hyperliquid.xyz` server-side on the agent's behalf.
**Key lifecycle:**
- **Creation**: Agent runs `secret create` — Vincent generates the EOA, stores the key, returns `keyId`, `walletAddress`, and `claimUrl`.
- **Claim**: Human operator uses the claim URL to take ownership and configure policies at `https://heyvincent.ai`.
- **Revocation**: Wallet owner revokes the agent's API key from the frontend at any time.
- **Re-linking**: Agent exchanges a one-time re-link token (generated by the owner) for a new key via `secret relink`.
## Quick Start
### 1. Check for Existing Keys
Before creating a new wallet, check if one already exists:
```bash
npx @vincentai/cli@latest secret list --type HYPERLIQUID_WALLET
```
If a key is returned, use its `id` as `--key-id` for all subsequent commands. If not, create one.
### 2. Create a HyperLiquid Wallet
```bash
npx @vincentai/cli@latest secret create --type HYPERLIQUID_WALLET --memo "My HL perp wallet"
```
Returns:
- `keyId` — use for all future commands
- `walletAddress` — the EOA address (this IS the HyperLiquid account)
- `claimUrl` — share with the user to take ownership
After creating, tell the user:
> "Here is your wallet claim URL: `<claimUrl>`. Use this to claim ownership, set spending policies, and monitor your agent's wallet activity at https://heyvincent.ai."
**Important:** The wallet is empty at creation. The user must deposit USDC before trading.
### 3. Get Balance
```bash
npx @vincentai/cli@latest hyperliquid balance --key-id <KEY_ID>
```
Returns:
- `walletAddress` — the EOA address
- `accountValue` — total perps account value in USD (cross-margin)
- `withdrawable` — USDC available to withdraw from the perps account
- `positions` — array of open perpetual positions
- `spotBalances` — array of spot token balances (each with `coin`, `token`, `hold`, `total`)
### 4. Transfer Between Perps and Spot
HyperLiquid has separate perps and spot sub-accounts. USDC must be in the correct sub-account before trading. Use `internal-transfer` to move USDC between them.
```bash
# Move 100 USDC from spot → perps (needed before perp trading)
npx @vincentai/cli@latest hyperliquid internal-transfer --key-id <KEY_ID> --amount 100 --to-perp true
# Move 50 USDC from perps → spot (needed before spot trading)
npx @vincentai/cli@latest hyperliquid internal-transfer --key-id <KEY_ID> --amount 50 --to-perp false
```
Parameters:
- `--amount`: USDC amount to transfer (string, numeric)
- `--to-perp`: `true` = spot→perps, `false` = perps→spot
**Response codes:**
- `200` — `status: "executed"` — transfer completed
- `202` — `status: "pending_approval"` (human approval required by policy)
- `403` — `status: "denied"` (rejected by policy)
### 5. Withdraw USDC to External Address
Send USDC from this HyperLiquid wallet to another HyperLiquid address via `usdSend`. This is an on-chain HL→HL transfer (instant, no gas).
```bash
# Withdraw 100 USDC to another HL address
npx @vincentai/cli@latest hyperliquid withdraw --key-id <KEY_ID> \
--destination 0x1234567890abcdef1234567890abcdef12345678 --amount 100
```
Parameters:
- `--destination`: Target 0x address (must be a valid 40-hex-char Ethereum address)
- `--amount`: USDC amount to send (string, numeric)
**Response codes:**
- `200` — `status: "executed"` — withdrawal completed
- `202` — `status: "pending_approval"` (human approval required by policy)
- `403` — `status: "denied"` (rejected by policy)
### 6. Fund the Wallet
Deposit USDC to the EOA address via:
- **HyperLiquid bridge** from Arbitrum: visit `https://app.hyperliquid.xyz/portfolio` and bridge USDC to the EOA address
- **HL→HL transfer** (`usdSend`) from another HL account — instant
Minimum for a BTC perp trade: **$2 USDC** (covers $10 notional at 20x default leverage + taker fees).
### 7. Browse Markets
```bash
npx @vincentai/cli@latest hyperliquid markets --key-id <KEY_ID>
```
Returns a JSON object mapping coin names to mid prices (e.g. `{"BTC": "105234.5", "ETH": "3412.0", ...}`).
### 8. Get Order Book
```bash
npx @vincentai/cli@latest hyperliquid orderbook --key-id <KEY_ID> --coin BTC
```
Returns `levels` — a two-element array `[bids, asks]`. Each entry is `[price, size, numOrders]`. Use `levels[1][0][0]` for best ask, `levels[0][0][0]` for best bid.
### 9. Place a Trade
```bash
# Market buy (IoC — fills immediately or cancels)
npx @vincentai/cli@latest hyperliquid trade --key-id <KEY_ID> \
--coin BTC --is-buy true --sz 0.0001 \
--limit-px 106000 --order-type market
# Market sell to close (reduceOnly)
npx @vincentai/cli@latest hyperliquid trade --key-id <KEY_ID> \
--coin BTC --is-buy false --sz 0.0001 \
--limit-px 104000 --order-type market --reduce-only
# GTC limit buy
npx @vincentai/cli@latest hyperliquid trade --key-id <KEY_ID> \
--coin BTC --is-buy true --sz 0.0001 \
--limit-px 100000 --order-type limit
```
Parameters:
- `--coin`: Asset name (e.g. `BTC`, `ETH`, `SOL`)
- `--is-buy`: `true` for long, `false` for short/close
- `--sz`: Size in base currency (e.g. `0.0001` BTC)
- `--limit-px`: Price. For market orders, set slightly above ask (buy) or below bid (sell) to ensure fill. Recommended: `askPx * 1.005` for buys, `bidPx * 0.995` for sells.
- `--order-type`: `market` (IoC) or `limit` (GTC)
- `--reduce-only`: Pass when closing a position to prevent accidentally opening a new one in the opposite direction
**Minimum notional:** $10 (e.g. 0.0001 BTC at $100k/BTC). Default leverage is 20x cross-margin.
**Response codes:**
- `200` — `status: "executed"` with `orderId` (numeric) and `fillDetails`
- `202` — `status: "pending_approval"` (human approval required by policy)
- `403` — `status: "denied"` (rejected by policy)
### 10. View Open Orders
```bash
# All open orders
npx @vincentai/cli@latest hyperliquid open-orders --key-id <KEY_ID>
# Filter by coin
npx @vincentai/cli@latest hyperliquid open-orders --key-id <KEY_ID> --coin BTC
```
### 11. View Trade History
```bash
# All fills
npx @vincentai/cli@latest hyperliquid trades --key-id <KEY_ID>
# Filter by coin
npx @vincentai/cli@latest hyperliquid trades --key-id <KEY_ID> --coin ETH
```
### 12. Cancel Orders
```bash
# Cancel a specific order (requires coin and numeric order ID)
npx @vincentai/cli@latest hyperliquid cancel-order --key-id <KEY_ID> --coin BTC --oid <ORDER_ID>
# Cancel all open orders
npx @vincentai/cli@latest hyperliquid cancel-all --key-id <KEY_ID>
# Cancel all orders for a specific coin
npx @vincentai/cli@latest hyperliquid cancel-all --key-id <KEY_ID> --coin ETH
```
## Trading Engine: Stop-Loss, Take-Profit & Trailing Stop
The **Trading Engine** fully supports HyperLiquid. You can set automated stop-loss, take-profit, and trailing stop rules on any HL position. Rules execute automatically when price conditions are met — no LLM involved.
For HyperLiquid rules, use `--venue hyperliquid` and set `--market-id` / `--token-id` to the coin name (e.g. `BTC`, `ETH`, `SOL`). The `--trigger-price` is an absolute USD price (not 0–1 like Polymarket).
### Stop-Loss
```bash
npx @vincentai/cli@latest trading-engine create-rule --key-id <KEY_ID> \
--venue hyperliquid --market-id BTC --token-id BTC \
--rule-type STOP_LOSS --trigger-price 95000
```
Sells the position if BTC drops to $95,000.
### Take-Profit
```bash
npx @vincentai/cli@latest trading-engine create-rule --key-id <KEY_ID> \
--venue hyperliquid --market-id ETH --token-id ETH \
--rule-type TAKE_PROFIT --trigger-price 4500
```
Sells the position if ETH rises to $4,500.
### Trailing Stop
```bash
npx @vincentai/cli@latest trading-engine create-rule --key-id <KEY_ID> \
--venue hyperliquid --market-id SOL --token-id SOL \
--rule-type TRAILING_STOP --trigger-price 170 --trailing-percent 5
```
Stop price ratchets up as SOL rises. Sells if SOL drops 5% from its peak.
### Manage Rules
```bash
# List all rules
npx @vincentai/cli@latest trading-engine list-rules --key-id <KEY_ID>
# Update trigger price
npx @vincentai/cli@latest trading-engine update-rule --key-id <KEY_ID> --rule-id <RULE_ID> --trigger-price 98000
# Cancel a rule
npx @vincentai/cli@latest trading-engine delete-rule --key-id <KEY_ID> --rule-id <RULE_ID>
# View rule events
npx @vincentai/cli@latest trading-engine events --key-id <KEY_ID>
```
For full strategy docs (LLM-powered strategies, signal pipeline, drivers), see the **Trading Engine** skill.
## Policies (Server-Side Enforcement)
The wallet owner controls what the agent can do by setting policies at `https://heyvincent.ai`. All policies are enforced server-side before any trade executes.
| Policy | What it does |
| --------------------------- | ---------------------------------------------------------------- |
| **Spending limit (per tx)** | Max USD notional per trade |
| **Spending limit (daily)** | Max USD notional per rolling 24 hours |
| **Spending limit (weekly)** | Max USD notional per rolling 7 days |
| **Require approval** | Every trade needs human approval via Telegram |
| **Approval threshold** | Trades above a USD amount need human approval via Telegram |
If a trade is blocked, the API returns `status: "denied"` with the reason. If approval is needed, `status: "pending_approval"` is returned and the wallet owner receives a Telegram notification.
## Re-linking
If the agent loses its API key:
1. User generates a re-link token from `https://heyvincent.ai`
2. User gives the token to the agent
3. Agent runs:
```bash
npx @vincentai/cli@latest secret relink --token <TOKEN_FROM_USER>
```
Re-link tokens are one-time use and expire after 10 minutes.
## Workflow Example
```bash
# 1. Create wallet
npx @vincentai/cli@latest secret create --type HYPERLIQUID_WALLET --memo "HL wallet"
# → returns keyId, walletAddress, claimUrl
# 2. Tell user: "Fund <walletAddress> on HyperLiquid with USDC, then I can trade."
# 3. Check balance after funding (returns both perps and spot balances)
npx @vincentai/cli@latest hyperliquid balance --key-id <KEY_ID>
# → accountValue shows perps balance, spotBalances shows spot holdings
# 4. Transfer USDC between sub-accounts if needed
# Move 100 USDC from spot → perps before perp trading:
npx @vincentai/cli@latest hyperliquid internal-transfer --key-id <KEY_ID> --amount 100 --to-perp true
# Move 50 USDC from perps → spot before spot trading:
npx @vincentai/cli@latest hyperliquid internal-transfer --key-id <KEY_ID> --amount 50 --to-perp false
# 5. Withdraw USDC to another HL address
npx @vincentai/cli@latest hyperliquid withdraw --key-id <KEY_ID> \
--destination 0xRecipientAddress --amount 50
# 6. Get BTC mid price
npx @vincentai/cli@latest hyperliquid markets --key-id <KEY_ID>
# 7. Get order book to find best ask
npx @vincentai/cli@latest hyperliquid orderbook --key-id <KEY_ID> --coin BTC
# → levels[1][0][0] is best ask, e.g. "105200.0"
# 8. Open long — 0.5% above ask to ensure IoC fill
npx @vincentai/cli@latest hyperliquid trade --key-id <KEY_ID> \
--coin BTC --is-buy true --sz 0.0001 --limit-px 105726 --order-type market
# 9. Check fills
npx @vincentai/cli@latest hyperliquid trades --key-id <KEY_ID> --coin BTC
# 10. Close long — 0.5% below bid
npx @vincentai/cli@latest hyperliquid orderbook --key-id <KEY_ID> --coin BTC
npx @vincentai/cli@latest hyperliquid trade --key-id <KEY_ID> \
--coin BTC --is-buy false --sz 0.0001 --limit-px 104674 --order-type market --reduce-only
```
## Output Format
All CLI commands return JSON to stdout.
**balance:**
```json
{
"walletAddress": "0x...",
"accountValue": "105.23",
"withdrawable": "95.00",
"positions": [
{
"position": {
"coin": "BTC",
"szi": "0.0001",
"entryPx": "105200.0",
"positionValue": "10.52",
"unrealizedPnl": "0.05",
"liquidationPx": null,
"leverage": { "type": "cross", "value": 20 }
},
"type": "oneWay"
}
],
"spotBalances": [
{
"coin": "USDC",
"token": 0,
"hold": "0.0",
"total": "50.0"
}
]
}
```
**markets:**
```json
{
"BTC": "105234.5",
"ETH": "3412.0",
"SOL": "185.3"
}
```
**orderbook:**
```json
{
"coin": "BTC",
"levels": [
[["105200.0", "0.5", 3], ["105100.0", "1.2", 5]],
[["105300.0", "0.3", 2], ["105400.0", "0.8", 4]]
]
}
```
`levels[0]` = bids (descending), `levels[1]` = asks (ascending). Each entry is `[price, size, numOrders]`. Best bid: `levels[0][0][0]`, best ask: `levels[1][0][0]`.
**trade (executed):**
```json
{
"orderId": 12345678,
"status": "executed",
"transactionLogId": "clx...",
"walletAddress": "0x...",
"fillDetails": {
"totalSz": "0.0001",
"avgPx": "105250.0"
}
}
```
**trade (pending approval):**
```json
{
"status": "pending_approval",
"transactionLogId": "clx...",
"walletAddress": "0x...",
"reason": "Exceeds approval threshold"
}
```
**trade (denied):**
```json
{
"status": "denied",
"transactionLogId": "clx...",
"walletAddress": "0x...",
"reason": "Exceeds daily spending limit"
}
```
**withdraw (executed):**
```json
{
"status": "executed",
"transactionLogId": "clx..."
}
```
**withdraw (pending approval):**
```json
{
"status": "pending_approval",
"transactionLogId": "clx...",
"reason": "Exceeds approval threshold"
}
```
**withdraw (denied):**
```json
{
"status": "denied",
"transactionLogId": "clx...",
"reason": "Exceeds daily spending limit"
}
```
**internal-transfer (executed):**
```json
{
"status": "executed",
"transactionLogId": "clx..."
}
```
**internal-transfer (pending approval):**
```json
{
"status": "pending_approval",
"transactionLogId": "clx...",
"reason": "Exceeds approval threshold"
}
```
**internal-transfer (denied):**
```json
{
"status": "denied",
"transactionLogId": "clx...",
"reason": "Exceeds daily spending limit"
}
```
**open-orders:**
```json
{
"walletAddress": "0x...",
"openOrders": [
{
"coin": "BTC",
"side": "B",
"limitPx": "100000.0",
"sz": "0.0001",
"oid": 12345678,
"timestamp": 1700000000000,
"origSz": "0.0001"
}
]
}
```
`side`: `"B"` = buy/long, `"A"` = ask/sell.
**trades (fills):**
```json
{
"walletAddress": "0x...",
"fills": [
{
"coin": "BTC",
"px": "105200.0",
"sz": "0.0001",
"side": "B",
"time": 1700000000000,
"dir": "Open Long",
"closedPnl": "0",
"fee": "0.0105",
"oid": 12345678
}
]
}
```
**cancel-order / cancel-all:**
```json
{}
```
Empty object on success. Any non-zero exit code indicates failure.
## Error Handling
| Error | Cause | Resolution |
|-------|-------|------------|
| `401 Unauthorized` | Invalid or missing API key | Check key-id is correct; re-link if needed |
| `status: "denied"` | Trade blocked by server-side policy | User must adjust policies at heyvincent.ai |
| `status: "pending_approval"` | Trade exceeds approval threshold | Do not retry — wallet owner receives Telegram notification to approve/deny |
| `400 Bad Request` | Invalid parameters (e.g. non-numeric oid, bad coin) | Fix the parameter values |
| `429 Rate Limited` | Too many requests | Wait and retry with backoff |
| `500 TRADE_FAILED` | HyperLiquid rejected the order (e.g. insufficient margin, bad price) | Check account balance and order parameters |
| `Key not found` | API key was revoked or never created | Re-link with a new token from the wallet owner |
## Important Notes
- **No gas required.** HyperLiquid L1 is gasless — all perp trades settle natively.
- **Perps and spot sub-accounts.** The generated EOA has both a perps sub-account (cross-margin) and a spot sub-account. Use `internal-transfer` to move USDC between them. Deposits via the HL bridge land in the perps account by default.
- **Never try to access raw secret values.** The private key stays server-side.
- Always share the claim URL with the user after creating a wallet.
- For market orders, always set `limitPx` slightly outside the best price (`* 1.005` for buys, `* 0.995` for sells) to guarantee IoC fill at the current market price.
- If a trade returns `status: "pending_approval"`, do not retry — wait for the wallet owner to respond via Telegram.
don't have the plugin yet? install it then click "run inline in claude" again.