Skip to main content

Overview

This guide shows how to use Magic’s Embedded Wallet to trade perpetual futures on Hyperliquid. The @nktkas/hyperliquid SDK accepts any viem-compatible account, so your app creates a custom account that delegates signTypedData to the Magic wallet — no private key management needed.

Prerequisites

Before starting, ensure you have:
  1. A Magic Publishable API Key from your Magic Dashboard
  2. USDC on Arbitrum One and ETH for gas (to activate the wallet on Hyperliquid mainnet — required even for testnet)

How It Works

  1. User authenticates with Magic
  2. A viem wallet client wraps Magic’s RPC provider
  3. Your app deposits at least $5 USDC from Arbitrum to activate the wallet on Hyperliquid
  4. For testnet: claim 1,000 mock USDC via the faucet API
  5. A custom account delegates signTypedData to the Magic wallet
  6. The @nktkas/hyperliquid ExchangeClient uses this account for order signing
  7. Orders, cancellations, and leverage updates are signed and submitted to Hyperliquid
Hyperliquid uses EIP-712 typed data signatures for all exchange actions. The @nktkas/hyperliquid SDK handles nonces and signature construction automatically — your Magic account only needs to implement signTypedData.

Setting Up the Wallet Client

Install dependencies and initialize Magic with viem.
TypeScript

Creating a Custom Account

The Hyperliquid SDK expects a wallet with a signTypedData method. Create a custom account adapter that delegates signing to Magic’s wallet.
TypeScript

Setting Up Hyperliquid Clients

Initialize the SDK with the Magic-backed account.
TypeScript

Depositing USDC

Hyperliquid runs on its own L1 chain — you can’t trade directly from an Arbitrum wallet. To fund your Hyperliquid account, send USDC to the bridge contract on Arbitrum. This is a standard ERC20 transfer — your Hyperliquid account is credited within ~1 minute.
TypeScript
The minimum deposit is 5 USDC. Deposits below this amount are not credited and cannot be recovered.

Testnet Faucet

Once a wallet has been activated with a mainnet deposit of at least $5 USDC, you can claim 1,000 mock USDC on Hyperliquid testnet. This is a one-time claim per address.
TypeScript
After claiming, switch to testnet clients for development and testing.

Withdrawing USDC

To withdraw USDC from Hyperliquid back to Arbitrum, use the SDK’s withdraw3 method. The withdrawal is signed on Hyperliquid and processed by validators — no Arbitrum transaction is needed from the user.
TypeScript

Reading Market Data

Use the InfoClient to fetch prices, order books, and account state. These calls are read-only and don’t require signing.
TypeScript

Placing Orders

The ExchangeClient handles nonce generation and EIP-712 signing automatically.

Limit Order

Place a Good-Til-Canceled limit order at a specific price.
TypeScript

Market Order

Hyperliquid doesn’t have a native market order type. Use an Immediate-or-Cancel (IOC) limit order with a slippage price.
TypeScript
For market buys, set the slippage price above the current mid. For market sells, set it below. The unfilled portion of an IOC order is automatically canceled.

Canceling Orders

TypeScript

Updating Leverage

TypeScript

Switching to Production

To move from testnet to mainnet, remove the isTestnet flag from the transport. The deposit and withdrawal code already uses mainnet addresses.
TypeScript
Asset indices can change between testnet and mainnet. In production, use info.meta() to look up the correct index for each asset dynamically rather than hardcoding values.

Key Dependencies


Troubleshooting

Symptoms: getAddresses() returns an empty array or errors.Solutions:
  • Ensure the user is logged in before creating the wallet client
  • Verify your Magic Publishable API Key is correct
  • Check that magic.rpcProvider is passed to custom() transport
Symptoms: Hyperliquid rejects the order with a signature error.Solutions:
  • Verify the custom account’s signTypedData correctly delegates to the wallet client
  • Ensure the account address matches the address that deposited USDC on Hyperliquid
  • Check that the wallet client chain is set to arbitrum
Symptoms: Order rejected due to insufficient margin or balance.Solutions:
  • Deposit USDC to Hyperliquid using the bridge contract (see Depositing USDC above)
  • Check available margin with info.clearinghouseState({ user: address })
  • Ensure at least 5 USDC was deposited (minimum)
  • Reduce order size or increase leverage
Symptoms: Order rejected because the asset index is invalid.Solutions:
  • Use info.meta() to look up the correct asset index for each coin
  • Asset indices may differ between testnet and mainnet
  • Common indices: 0 = BTC, 4 = ETH (but always verify with meta())

Resources

Magic Embedded Wallets

Learn about Magic’s Embedded Wallet product

Hyperliquid Documentation

Official Hyperliquid protocol documentation

@nktkas/hyperliquid SDK

TypeScript SDK with full API coverage

Hyperliquid Testnet

Testnet UI for deposits and testing