# Wallets

> Wallets on Hyperliquid — MetaMask + chain ID 999 setup, HyperCore API wallets, agent wallet patterns, EIP-712 signing for exchange actions. Essential for any agent that needs to interact with Hyperliquid.

- Skill: `dvcrn/wallets` (Agent Skill)
- Install (CLI): `npx skillmds@latest add dvcrn/wallets`
- Raw SKILL.md: https://api.skillmd.com/api/skills/dvcrn/wallets/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: dvcrn (https://skillmd.com/u/dvcrn)
- Updated: 2026-09-08
- Page: https://skillmd.com/skills/dvcrn/wallets

---


# Wallets on Hyperliquid

## What You Probably Got Wrong

**"I can use my Ethereum wallet directly."** For HyperEVM: yes, same wallet, add the chain. For HyperCore: the API uses EIP-712 typed data signatures — you need to understand the signing scheme, not just connect MetaMask.

**"Private key = full access."** For automated agents, use the API wallet pattern — approve a subaccount agent key with limited permissions. The agent key can trade but can't withdraw beyond the approved limit. Main wallet stays cold.

**"Any nonce works."** HyperCore nonces are NOT sequential. They use a rolling-set scheme — you can use any nonce that's greater than the lowest in your recent 20 nonces. This is fundamentally different from Ethereum. Getting this wrong means rejected orders.

---

## HyperEVM: Adding to MetaMask

Add HyperEVM to any EVM-compatible wallet:

| Parameter | Mainnet | Testnet |
|-----------|---------|---------|
| **Chain ID** | 999 | 998 |
| **RPC URL** | https://rpc.hyperliquid.xyz/evm | https://rpc.hyperliquid-testnet.xyz/evm |
| **Chain Name** | HyperEVM | HyperEVM Testnet |
| **Currency Symbol** | HYPE | HYPE |
| **Block Explorer** | https://explorer.hyperliquid.xyz | https://explorer-testnet.hyperliquid.xyz |

```typescript
// Programmatically add to MetaMask
await window.ethereum.request({
  method: 'wallet_addEthereumChain',
  params: [{
    chainId: '0x3E7',  // 999 in hex
    chainName: 'HyperEVM',
    nativeCurrency: { name: 'HYPE', symbol: 'HYPE', decimals: 18 },
    rpcUrls: ['https://rpc.hyperliquid.xyz/evm'],
    blockExplorerUrls: ['https://explorer.hyperliquid.xyz'],
  }],
});
```

**Same address as Ethereum.** Your Ethereum address works on HyperEVM. Same private key, same address, different chain.

---

## HyperCore: How Signing Works

HyperCore uses **EIP-712 typed data** signatures for all exchange actions. This is NOT a standard EVM transaction — it's a signed message that the HyperCore API validates.

### The Signing Flow

```
1. Build the action payload (order, cancel, transfer, etc.)
2. Hash it with EIP-712 (domain + struct hash)
3. Sign with your private key (standard eth_signTypedData_v4)
4. POST to /exchange with { action, nonce, signature, vaultAddress? }
```

### Domain Separator for HyperCore

```typescript
const domain = {
  name: 'Exchange',
  version: '1',
  chainId: 1337,           // HyperCore always uses chainId 1337 for signing
  verifyingContract: '0x0000000000000000000000000000000000000000',
};
```

**Critical:** The chainId for EIP-712 signing in HyperCore is ALWAYS 1337 — regardless of whether you're on mainnet or testnet. This is NOT the HyperEVM chain ID (999/998).

---

## API Wallet Pattern (For Agents)

**Never use your main wallet private key in an automated bot.** Use the API wallet pattern:

### Step 1: Create an Agent Wallet

Generate a new private key. This is your agent key — it will have limited permissions.

```python
from eth_account import Account

# Generate a new random private key for the agent
agent_key = Account.create()
print(f"Agent address: {agent_key.address}")
print(f"Agent key: {agent_key.key.hex()}")
```

### Step 2: Approve the Agent Wallet

The main wallet approves the agent key via the API:

```python
from hyperliquid.exchange import Exchange
from hyperliquid.utils import constants

# Using the main wallet
exchange = Exchange(main_wallet, constants.MAINNET_API_URL)

# Approve agent key to trade on behalf of main wallet
result = exchange.approve_agent(
    agent_address=agent_key.address,
    agent_name="MyTradingBot"
)
```

### Step 3: Agent Uses Its Own Key

The agent wallet submits orders independently, signing with its own key:

```python
# Agent trades using its own key, but against main wallet's account
agent_exchange = Exchange(
    agent_key,
    constants.MAINNET_API_URL,
    account_address=main_wallet.address  # Trading on behalf of main wallet
)

# Place order
order_result = agent_exchange.order(
    "ETH",
    is_buy=True,
    sz=0.1,
    limit_px=2000.0,
    order_type={"limit": {"tif": "Gtc"}}
)
```

**Benefits:**
- Agent key can be compromised without losing your main wallet funds
- Set withdrawal limits: agent can't drain beyond a threshold
- Revoke agent access anytime from main wallet
- Different agents for different strategies

---

## Nonce Management on HyperCore

HyperCore nonces are NOT sequential like Ethereum. They use a **rolling-set scheme**.

**How it works:**
- Each signer has a set of "recent nonces" (the 20 highest nonces seen)
- Any new nonce must be greater than the LOWEST nonce in the set
- Once the set has 20 entries, the lowest is evicted as new ones are added
- This allows batching and out-of-order submission within a window

**Practical implications:**

```python
# ✅ CORRECT: Use timestamp-based nonces (milliseconds since epoch)
import time
nonce = int(time.time() * 1000)  # milliseconds — always increasing

# ✅ CORRECT: The SDK handles nonces automatically
# hyperliquid-python-sdk manages nonce generation internally

# ❌ WRONG: Don't manually track sequential nonces
nonce = last_nonce + 1  # This breaks with concurrent requests
```

**The recommended approach:** Use the official SDK — it handles nonce generation (typically millisecond timestamps) correctly.

---

## 🚨 NEVER COMMIT SECRETS TO GIT

This applies to Hyperliquid exactly as it does to Ethereum. Bots scrape GitHub in real-time.

**Things that must NEVER be committed:**
- Main wallet private keys
- Agent wallet private keys
- API credentials

```bash
# .gitignore MUST include:
.env
.env.*
*.key
*.pem
secrets/
```

```python
# ✅ Load from environment
import os
from eth_account import Account

private_key = os.environ['HYPERLIQUID_PRIVATE_KEY']
wallet = Account.from_key(private_key)

# ❌ NEVER hardcode
private_key = "0xdeadbeef..."  # DON'T DO THIS
```

**If you leaked a key:**
1. Assume it's compromised immediately
2. Move all funds to a new wallet NOW
3. Revoke agent approvals from the compromised wallet
4. Rotate to new keys
5. Clean git history (but the key is already burned)

---

## CRITICAL Guardrails for AI Agents

1. **NEVER use main wallet for automated trading.** Use agent wallet pattern.
2. **NEVER store private keys in chat logs, code, or version control.**
3. **NEVER move funds without human confirmation** for amounts above threshold.
4. **Always verify the action before signing.** Check the order params, size, price.
5. **Use a dedicated wallet with limited funds** for agent operations.
6. **Set withdrawal limits** on agent wallets via the API.
7. **Log all transactions** (never log keys).
8. **Test on testnet first.** Use api.hyperliquid-testnet.xyz.
9. **Implement position size limits.** Require human approval above threshold.
10. **Monitor for anomalies.** Alert if agent places orders outside expected parameters.

---

## Multisig for HyperEVM

For HyperEVM contracts holding significant value, use a multisig:

- Safe (Gnosis Safe) works on HyperEVM — it's EVM-compatible
- For contract ownership, use a multisig not a single EOA
- HyperCore doesn't have native multisig but you can control HyperCore accounts from a HyperEVM multisig via custom contract logic

---

## Wallet Libraries

**TypeScript/JavaScript:**
```typescript
import { createWalletClient, http, privateKeyToAccount } from 'viem';
import { hyperliquid } from './chains';

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const client = createWalletClient({
  account,
  chain: hyperliquid,
  transport: http('https://rpc.hyperliquid.xyz/evm'),
});
```

**Python:**
```python
from eth_account import Account
from hyperliquid.exchange import Exchange
from hyperliquid.utils import constants

wallet = Account.from_key(os.environ['PRIVATE_KEY'])
exchange = Exchange(wallet, constants.MAINNET_API_URL)
info = exchange.info  # Read-only info client
```

