---
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
---

# 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.
