Skip to main content
This guide shows how to transfer USDC from HyperEVM to HyperCore using the CoreDepositWallet contract.
Tip: The CoreDepositWallet contract provides deposit, depositFor, and depositWithAuth methods. This guide uses deposit. All methods accept a destinationDex parameter (0 for perps, 4294967295 for spot). See the CoreDepositWallet contract interface for detailed information.

Prerequisites

Before you begin, ensure that you’ve:
  • Installed Node.js v22+
  • Prepared an EVM testnet wallet with the private key available
  • Funded your wallet with HyperEVM testnet USDC from the Circle Faucet
  • Created a new Node project and installed dependencies:
    npm install viem
    npm install -D tsx typescript @types/node
    
  • Created a .env file with required environment variable:
    PRIVATE_KEY=0x...
    

Steps

Use the following steps to transfer USDC from HyperEVM to HyperCore.

Step 1. Approve the CoreDepositWallet to spend USDC

Approve the CoreDepositWallet contract to transfer USDC on your behalf:
TypeScript
const hash = await walletClient.writeContract({
  address: USDC_ADDRESS,
  abi: USDC_ABI,
  functionName: "approve",
  args: [CORE_DEPOSIT_WALLET, amount],
});

await publicClient.waitForTransactionReceipt({ hash });

Step 2. Call the deposit function

Call the deposit function with your desired amount and destination:
TypeScript
const hash = await walletClient.writeContract({
  address: CORE_DEPOSIT_WALLET,
  abi: CORE_DEPOSIT_WALLET_ABI,
  functionName: "deposit",
  args: [amount, destinationDex], // 0 = perps, 4294967295 = spot
});

const receipt = await publicClient.waitForTransactionReceipt({ hash });
The deposit function transfers USDC from your account to the CoreDepositWallet and credits your HyperCore balance.

Full example code

The following is a complete example of how to transfer USDC from HyperEVM to HyperCore.
script.ts
/**
 * Script: Call CoreDepositWallet.deposit on HyperEVM
 * - Approves USDC spending
 * - Calls deposit(amount, destinationDex)
 */

import {
  createWalletClient,
  createPublicClient,
  http,
  parseUnits,
  formatUnits,
  type Address,
  type Hex,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { hyperliquidEvmTestnet } from "viem/chains";

// -------- Configuration --------
const config = {
  privateKey: (process.env.PRIVATE_KEY || "0x") as Hex,

  // Contract addresses (HyperEVM Testnet)
  coreDepositWallet: "0x0B80659a4076E9E93C7DbE0f10675A16a3e5C206" as Address,
  usdcToken: "0x2B3370eE501B4a559b57D449569354196457D8Ab" as Address,

  // Transfer parameters
  amount: "2", // USDC amount to deposit

  // HyperCore destination (0 = perps, 4294967295 = spot)
  destinationDex: 0,
};

// -------- Main Function --------
async function main() {
  // Validate private key
  if (!config.privateKey || config.privateKey === "0x") {
    throw new Error("Set PRIVATE_KEY");
  }

  // Setup account and clients
  const account = privateKeyToAccount(config.privateKey);
  const publicClient = createPublicClient({
    chain: hyperliquidEvmTestnet,
    transport: http(),
  });
  const walletClient = createWalletClient({
    chain: hyperliquidEvmTestnet,
    transport: http(),
    account,
  });

  const amount = parseUnits(config.amount, 6);

  console.log("User:", account.address);
  console.log("CoreDepositWallet:", config.coreDepositWallet);
  console.log("USDC:", config.usdcToken);
  console.log("Amount (USDC):", config.amount);
  console.log(
    "Destination DEX:",
    config.destinationDex === 0 ? "perps" : "spot",
  );

  // Check USDC balance
  const balance = await publicClient.readContract({
    address: config.usdcToken,
    abi: [
      {
        name: "balanceOf",
        type: "function",
        stateMutability: "view",
        inputs: [{ name: "account", type: "address" }],
        outputs: [{ name: "", type: "uint256" }],
      },
    ],
    functionName: "balanceOf",
    args: [account.address],
  });

  if (balance < amount) {
    throw new Error(
      `Insufficient USDC: have ${formatUnits(balance, 6)}, need ${config.amount}`,
    );
  }

  // Check current allowance
  const currentAllowance = await publicClient.readContract({
    address: config.usdcToken,
    abi: [
      {
        name: "allowance",
        type: "function",
        stateMutability: "view",
        inputs: [
          { name: "owner", type: "address" },
          { name: "spender", type: "address" },
        ],
        outputs: [{ name: "", type: "uint256" }],
      },
    ],
    functionName: "allowance",
    args: [account.address, config.coreDepositWallet],
  });

  // Step 1: Approve if needed
  if (currentAllowance < amount) {
    console.log("\nApproving USDC spending...");
    const hash = await walletClient.writeContract({
      address: config.usdcToken,
      abi: [
        {
          name: "approve",
          type: "function",
          stateMutability: "nonpayable",
          inputs: [
            { name: "spender", type: "address" },
            { name: "amount", type: "uint256" },
          ],
          outputs: [{ name: "", type: "bool" }],
        },
      ],
      functionName: "approve",
      args: [config.coreDepositWallet, amount],
    });

    console.log("Approve tx hash:", hash);
    await publicClient.waitForTransactionReceipt({ hash });
    console.log("Approval confirmed");
  } else {
    console.log("\nSufficient allowance already exists");
  }

  // Step 2: Deposit
  console.log("\nDepositing USDC to HyperCore...");
  const hash = await walletClient.writeContract({
    address: config.coreDepositWallet,
    abi: [
      {
        name: "deposit",
        type: "function",
        stateMutability: "nonpayable",
        inputs: [
          { name: "amount", type: "uint256" },
          { name: "destinationDex", type: "uint32" },
        ],
        outputs: [],
      },
    ],
    functionName: "deposit",
    args: [amount, config.destinationDex],
  });

  console.log("Deposit tx hash:", hash);

  // Wait for transaction receipt
  const receipt = await publicClient.waitForTransactionReceipt({ hash });

  console.log("Status:", receipt.status === "success" ? "SUCCESS" : "FAILED");
  console.log(
    "Block:",
    receipt.blockNumber,
    "\nGas Used:",
    receipt.gasUsed.toString(),
  );
}

// Run
main().catch((error) => {
  console.error("Error:", error.message);
  process.exit(1);
});
Run the script:
npx tsx script.ts