orchestration/SKILL.md
How an AI agent plans, builds, and deploys a complete Hyperliquid application. The three-phase build system for HyperEVM dApps and HyperCore integrations. Use when building any full application on Hyperliquid.
npx skillsauth add cloudzombie/liquidskills orchestrationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
"I'll just deploy to mainnet immediately." Never skip testnet. HyperEVM testnet (chain ID 998) and HyperCore testnet API are available. Test there first. Mainnet mistakes cost real HYPE and USDC.
"I'll handle HyperCore and HyperEVM separately." Plan both layers from the start. If your app uses HyperEVM contracts AND HyperCore API, coordinate them from day one. Late integration always reveals architectural problems.
"Secrets in env are fine." AI agents are the #1 source of leaked credentials. Before committing anything, verify no private keys or API credentials are in the codebase.
| Phase | Environment | What Happens | |-------|-------------|-------------| | Phase 1 | Local + testnet | Contracts on testnet, HyperCore testnet API. Iterate fast. | | Phase 2 | Mainnet contracts + local UI | Deploy to mainnet. Test with real state. Polish UI. | | Phase 3 | Production | Deploy frontend. Final QA. Monitor. |
# Fork HyperEVM mainnet for local testing
anvil --fork-url https://rpc.hyperliquid.xyz/evm --chain-id 999
# Or work against testnet directly
# Chain ID: 998, RPC: https://rpc.hyperliquid-testnet.xyz/evm
Contract development flow:
src/ (Foundry) or contracts/ (Hardhat)security/SKILL.md)# Deploy to HyperEVM testnet
forge create src/MyVault.sol:MyVault \
--rpc-url https://rpc.hyperliquid-testnet.xyz/evm \
--private-key $PRIVATE_KEY \
--broadcast
# Run tests
forge test -vvv
forge test --fuzz-runs 1000
Test against the testnet API, never mainnet:
# .env
HYPERLIQUID_API_URL=https://api.hyperliquid-testnet.xyz
PRIVATE_KEY=0x... # Testnet wallet key
# config.py
import os
from hyperliquid.info import Info
from hyperliquid.exchange import Exchange
from hyperliquid.utils import constants
from eth_account import Account
def get_clients():
wallet = Account.from_key(os.environ['PRIVATE_KEY'])
api_url = os.environ.get('HYPERLIQUID_API_URL', constants.MAINNET_API_URL)
return Info(api_url), Exchange(wallet, api_url)
// TypeScript: environment-based config
const isTestnet = process.env.HYPERLIQUID_TESTNET === 'true';
const client = new HyperliquidClient({ testnet: isTestnet });
Validate Phase 1:
// For development, point at testnet
const CHAIN_CONFIG = process.env.NODE_ENV === 'development'
? {
chainId: 998,
rpcUrl: 'https://rpc.hyperliquid-testnet.xyz/evm',
}
: {
chainId: 999,
rpcUrl: 'https://rpc.hyperliquid.xyz/evm',
};
Use ONE loading state per button. Each button has its own isLoading / isPending state. Never share.
Four-state flow (MANDATORY for token interactions):
const needsApproval = !allowance || allowance < amount;
const wrongNetwork = chain?.id !== 999; // HyperEVM mainnet
const notConnected = !address;
{notConnected ? (
<ConnectButton />
) : wrongNetwork ? (
<button onClick={() => switchChain({ id: 999 })} disabled={isSwitching}>
{isSwitching ? "Switching..." : "Switch to HyperEVM"}
</button>
) : needsApproval ? (
<button onClick={handleApprove} disabled={isApproving}>
{isApproving ? "Approving..." : "Approve"}
</button>
) : (
<button onClick={handleDeposit} disabled={isDepositing}>
{isDepositing ? "Depositing..." : "Deposit"}
</button>
)}
Before touching Phase 2 (real mainnet), read this carefully.
This applies to ALL credentials:
# .gitignore MUST include:
.env
.env.*
*.key
*.pem
secrets/
__pycache__/
Pre-commit check:
# Check for private keys
grep -rn "0x[a-fA-F0-9]\{64\}" src/ contracts/ --include="*.ts" --include="*.py" --include="*.sol"
# If this matches ANYTHING in source files, STOP. Use environment variables.
# Check for hardcoded RPC keys
grep -rn "alchemyapi.io\|infura.io" src/ contracts/
# Deploy to HyperEVM mainnet
forge create src/MyVault.sol:MyVault \
--rpc-url https://rpc.hyperliquid.xyz/evm \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
--verifier blockscout \
--verifier-url https://explorer.hyperliquid.xyz/api
# Record the deployed address in your config
export CONTRACT_ADDRESS=0x...
Post-deployment checklist:
# Switch from testnet to mainnet
import os
# ONLY change the API URL — everything else is the same
API_URL = os.environ.get('HYPERLIQUID_API_URL',
'https://api.hyperliquid.xyz') # Default to mainnet
# Verify you're on the right network before first trade
info = Info(API_URL)
meta = info.meta()
print(f"Connected to: {API_URL}")
print(f"Universe has {len(meta['universe'])} perp markets")
Start with tiny amounts. First real mainnet test: the smallest allowed order. Verify everything before scaling.
// Update for production
const wagmiConfig = createConfig({
chains: [hyperliquid], // Chain ID 999
transports: {
[hyperliquid.id]: http(process.env.NEXT_PUBLIC_HL_RPC_URL || 'https://rpc.hyperliquid.xyz/evm'),
},
});
Design rule: Make the UI actually good. No placeholder styling, no LLM-default purple gradients.
Vercel (recommended for Hyperliquid dApps):
cd packages/nextjs
vercel --prod
IPFS (decentralized alternative):
yarn build
# Upload to IPFS — any IPFS pinning service works
# Set next.config trailingSlash: true for IPFS routing
Before going live, fetch qa/SKILL.md and give it to a separate reviewer agent.
Key HyperEVM-specific QA items:
// Watch for contract events in real-time
const unwatch = publicClient.watchContractEvent({
address: contractAddress,
abi: vaultAbi,
eventName: 'Deposit',
onLogs: (logs) => {
for (const log of logs) {
console.log(`Deposit: ${log.args.amount} from ${log.args.user}`);
}
},
});
import asyncio
import websockets
import json
# WebSocket for real-time updates
async def monitor_fills(address):
async with websockets.connect('wss://api.hyperliquid.xyz/ws') as ws:
# Subscribe to user fills
await ws.send(json.dumps({
"method": "subscribe",
"subscription": {"type": "userFills", "user": address}
}))
async for message in ws:
data = json.loads(message)
if data.get('channel') == 'userFills':
for fill in data['data']:
print(f"Fill: {fill['coin']} {fill['side']} {fill['sz']} @ {fill['px']}")
my-project/
├── src/ # Solidity contracts
├── script/ # Deploy scripts
├── test/ # Foundry tests
├── lib/ # Dependencies (OpenZeppelin, etc.)
├── foundry.toml # Chain configs
├── frontend/
│ ├── app/ # Pages
│ ├── components/ # React components
│ ├── lib/
│ │ ├── chains.ts # HyperEVM chain definitions
│ │ ├── wagmi.ts # wagmi config
│ │ └── hypercore.ts # HyperCore API helpers
│ └── .env.local # NEVER COMMIT THIS
└── .gitignore # Includes .env*
development
Why build on Hyperliquid. HyperBFT consensus, native orderbook, speed, AI agent angle, honest tradeoffs. Use when someone asks "should I build on Hyperliquid?", "why not Ethereum?", or when an agent needs to understand what makes Hyperliquid unique.
development
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.
tools
Development tools for Hyperliquid — Foundry, Hardhat, viem, wagmi for HyperEVM; Python SDK and TypeScript SDK for HyperCore API. What works, what to use, how to set up.
testing
Smart contract testing for HyperEVM with Foundry/Hardhat — unit tests, fuzz testing, testnet fork testing. What to test, what not to test, and what LLMs get wrong on Hyperliquid.