Docs / bridging

Bridging

Moving USDC and other tokens between HyperEVM and HyperCore — including the unified-account edge case.

Hyperliquid runs two surfaces: HyperEVM (chain id 999) for ERC-20 balances and contract calls, and HyperCore (L1) where orderbook trading happens. Outcome markets live on HyperCore, but your USDC most likely starts on HyperEVM.

Hedgepit handles the bridge for you, but it helps to know what's actually happening on each path.

Deposit (HyperEVM → HyperCore)#

There are two flavours depending on the token:

  • USDC → calls CoreDepositWallet.deposit(amount, dest=0) after a standard ERC-20 approve. Lands in the perps (or unified) balance.
  • Any other spot token → direct ERC-20 transfer(systemAddress, amount) where systemAddress = 0x20…<tokenIndex>. Lands in the spot balance. No approval needed.

Withdraw (HyperCore → HyperEVM)#

Withdrawal is more nuanced — Hyperliquid has two account modes and they take different paths.

Standard (non-unified) account#

  1. usdClassTransfer perps → spot, if you're withdrawing more USDC than already sits in spot.
  2. spotSend to the token's system address.

Unified / portfolio-margin account#

Unified accounts reject usdClassTransfer and spotSend to system address with "Action disabled when unified account is active". Use sendAsset instead:

{
  sourceDex: "spot",
  destinationDex: "spot",
  destination: tokenSystemAddress(idx),
  token: "Name:0x<tokenId>",
  fromSubAccount: "",
}

Decimal truncation#

Both paths require the amount truncated to evmDecimals = weiDecimals + evm_extra_wei_decimals. For most stables that's 8 + (-2) = 6. Pass weiDecimals and the bridge rejects with "Invalid number of decimals".

Token format#

spotSend and sendAsset want the colon-prefixed form: "USDH:0x<tokenId>". Bare names ("USDH") return "Unknown token".