Skip to main content

TLDR

Overview

Hyperliquid operates two interconnected layers:
  • HyperCore — the high-performance L1 for trading (perps and spot)
  • HyperEVM — the EVM-compatible layer for smart contracts
Moving USDC between these layers requires understanding the bridging mechanism, system addresses, and token linking. This guide provides complete code examples for both directions.
Connect to a reliable Hyperliquid RPC endpoint to follow along with the examples.

System addresses

Every token on Hyperliquid has a designated system address that serves as the bridge between HyperCore and HyperEVM. The format is:
HYPE uses a special system address (0x2222222222222222222222222222222222222222) and is received as the native gas token on HyperEVM, not as an ERC20.

Contract addresses

Mainnet

Testnet

Important distinction between the two USDC-related contracts:
  • Native USDC — Circle’s standard ERC20 USDC token. Use this for DeFi apps, DEXs, and as the source for bridging.
  • CoreDepositWallet — Circle’s bridge contract (shown in spotMeta as evmContract.address). Call deposit() on this contract to bridge USDC to HyperCore.
The CoreDepositWallet is NOT a standard ERC20—do not call transfer() on it directly.
You can retrieve the correct linked USDC contract address programmatically using the spotMeta API endpoint. The contract address is returned in the evmContract.address field.

Endpoint requirements

Different bridging operations require different endpoints:
Exchange actions like spotSend are only available on Hyperliquid’s public RPC (https://api.hyperliquid.xyz for mainnet). Chainstack endpoints support Info API queries and EVM JSON-RPC but not exchange actions. See Hyperliquid methods for complete endpoint capabilities.

Prerequisites

1

Install dependencies

Install the required Python packages:
2

Set up configuration

Create a config.json file with your credentials:
3

Verify token linking

USDC must be linked between HyperCore and HyperEVM. On mainnet, USDC is already linked. On testnet, check token linking status before bridging.

HyperCore to HyperEVM

Transfer USDC from your HyperCore spot account to your HyperEVM wallet using the spotSend action directed at the system address.
Exchange actions like spotSend require the Hyperliquid public RPC endpoint (https://api.hyperliquid.xyz for mainnet). Chainstack endpoints support Info API and EVM JSON-RPC but not exchange actions. See Hyperliquid methods for endpoint capabilities.

Using the Python SDK

How it works

  1. You send a spotSend action with the system address (0x2000000000000000000000000000000000000000) as the destination
  2. Hyperliquid detects this as a bridge request and triggers a system transaction
  3. The system transaction calls transfer(sender_address, amount) on the linked ERC20 contract
  4. USDC appears in your HyperEVM wallet (the sender’s address)
The bridge is nearly instant—funds typically appear within 2 seconds. The HyperCore → HyperEVM transfer costs approximately 200K gas at the base gas price.

HyperEVM to HyperCore

Transfer USDC from HyperEVM back to HyperCore for trading using the CoreDepositWallet contract.
The linked USDC contract shown in spotMeta is a CoreDepositWallet contract developed by Circle—not a standard ERC20. To bridge USDC from HyperEVM to HyperCore, you must use the deposit() function on this contract after approving the native USDC token.

Understanding the two USDC contracts

Bridging from HyperEVM to HyperCore involves two contracts: The CoreDepositWallet address is the evmContract.address returned by the spotMeta API endpoint.

Using the CoreDepositWallet

The deposit() function signature:
Parameters:
  • amount — amount in 6 decimals (native USDC decimals)
  • destinationDex — destination on HyperCore:
    • 0 = perps balance
    • 4294967295 (type(uint32).max) = spot balance
The CoreDepositWallet source code is available at circlefin/hyperevm-circle-contracts.

How it works

  1. Approve the native USDC contract to allow CoreDepositWallet to spend your tokens
  2. Call deposit() on the CoreDepositWallet with:
    • Amount in 6 decimals
    • Destination dex (0 for perps, 4294967295 for spot)
  3. The CoreDepositWallet transfers USDC from your wallet and credits your HyperCore account
For new HyperCore accounts, a small account creation fee may be deducted from your first deposit.

Using CoreWriter for spot/perps transfers

Once USDC is on HyperCore (via the direct transfer method above), you can use the CoreWriter system contract to transfer between spot and perps accounts:
The CoreWriter contract (0x3333333333333333333333333333333333333333) is an event emitter only. It does not revert if the corresponding HyperCore action fails—the EVM transaction will succeed even if the HyperCore action silently fails. Always verify balances after transfers.
For simple spot/perps transfers, you can also use the Python SDK’s usd_class_transfer() method which handles the encoding automatically. The CoreWriter approach is useful when building smart contracts that need to interact with HyperCore—see Write to HyperCore from a contract with CoreWriter for the full contract pattern, the complete action table, and the prerequisites that keep actions from being silently dropped.

Token linking

For custom tokens (not USDC), you must link the HyperEVM ERC20 contract to the HyperCore spot token before bridging works.

Check if a token is linked

You can use Chainstack’s Info HTTP API endpoint for this:
The spotMeta response includes the evmContract field for linked tokens. For USDC, you’ll see the contract address and evm_extra_wei_decimals (typically -2, meaning 6 decimals on EVM vs 8 on HyperCore).

Linking process (for token deployers)

Token linking is a two-step process:
1

Request EVM contract

Send a RequestEvmContract action specifying the ERC20 contract address and decimal difference.
2

Finalize linking

Send a FinalizeEvmContract action with nonce verification or storage slot validation.
Only the spot token deployer can link a token. USDC is already linked on mainnet.

Testnet considerations

Testnet bridging has specific restrictions that differ from mainnet.

Net-transfer restriction

On testnet, the net transfer from HyperCore to HyperEVM is capped. If you try to bridge more USDC to HyperEVM than you’ve previously bridged to HyperCore, the transaction will fail silently. Workaround:
  1. First bridge USDC from an external chain (like Arbitrum Sepolia) to HyperCore
  2. Then you can bridge that amount to HyperEVM

New account fees

New HyperCore accounts incur a 1 USDC fee on first deposit:
  • Minimum first deposit: >1 USDC + any forwarding fees
  • Deposits ≤1 USDC to new accounts fail silently
  • Multiple deposits to new accounts in the same block each incur the fee

Common issues

”Cannot self-transfer” error

Cause: You tried to send tokens to your own address using spot_transfer(). Solution: For bridging, send to the system address (0x2000000000000000000000000000000000000000), not to your own address. Self-transfers to the same user are not allowed.

”Token not linked” error

Cause: The token hasn’t been linked between HyperCore and HyperEVM. Solution: For USDC, this shouldn’t happen on mainnet. For custom tokens, the token deployer must complete the linking process.

balanceOf() reverts on CoreDepositWallet

Cause: The CoreDepositWallet contract (from spotMeta) is not a standard ERC20—it’s a bridge contract that doesn’t support balanceOf() or other ERC20 read functions. Solution: This is expected behavior. To check your USDC balance on HyperEVM, call balanceOf() on the Native USDC contract (0xb88339CB7199b77E23DB6E890353E22632Ba630f on mainnet).

”Caller is not the system address” error

Cause: You tried to call transfer() directly on the CoreDepositWallet contract. This contract has access control and does not support standard ERC20 transfers. Solution: Use the deposit(amount, destinationDex) function on the CoreDepositWallet instead:
  1. First approve your native USDC to the CoreDepositWallet
  2. Call deposit(amount, 4294967295) for spot balance or deposit(amount, 0) for perps
See the HyperEVM to HyperCore section for complete code examples.

Silent failure on testnet

Cause: Net-transfer restriction or insufficient amount for new account. Solution:
  • Ensure you’ve deposited to HyperCore before trying to bridge to HyperEVM
  • For new accounts, deposit >1 USDC

Transaction succeeds but balance unchanged

Cause: Transfer to unlinked token system address or incorrect destination. Solution: Verify the system address matches the token you’re bridging.

”No HYPE for gas” on HyperEVM

Cause: HyperEVM uses HYPE as the native gas token, and your wallet has no HYPE. Solution: Bridge some HYPE from HyperCore to HyperEVM first. HYPE uses the special system address 0x2222222222222222222222222222222222222222.

Gas costs

Best practices

DO
  • Use the Python SDK spot_transfer() for HyperCore → HyperEVM bridging
  • Use the CoreDepositWallet.deposit() function for HyperEVM → HyperCore bridging
  • Approve native USDC to the CoreDepositWallet before calling deposit
  • Verify token linking status before bridging custom tokens
  • Test with small amounts first
  • Check balances on both sides after bridging
DON’T
  • Call transfer() on the CoreDepositWallet contract (will fail with “Caller is not the system address”)
  • Confuse native USDC with the CoreDepositWallet address
  • Bridge amounts ≤1 USDC to new HyperCore accounts
  • Assume testnet behaves identically to mainnet
  • Bridge unlinked tokens (they’ll be lost)
Last modified on June 25, 2026