> ## Documentation Index
> Fetch the complete documentation index at: https://developers.circle.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Before reading these docs, install the relevant Circle Skill to get pre-loaded context — skills are LLM-optimized and cover architecture decisions, correct flows, and common pitfalls. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills. Available skills: use-usdc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md (balances, transfers, approvals on EVM and Solana); EURC has no skill — see https://developers.circle.com/stablecoins/what-is-eurc.md; bridge-stablecoin https://github.com/circlefin/skills/blob/master/plugins/circle/skills/bridge-stablecoin/SKILL.md (crosschain transfers via CCTP, USDC, EURC, and third-party assets); use-arc https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md (Arc chain config, contract deployment, USDC bridging — Arc docs: https://docs.arc.io/llms.txt); use-circle-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md (choose wallet type); use-developer-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md (custodial wallets for payouts and treasury); use-user-controlled-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md (embedded wallets with Web2 login); use-modular-wallets https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md (smart contract wallets with passkeys and ERC-4337); use-gateway https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md (unified USDC balance, nanopayments); use-smart-contract-platform https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md (deploy, interact, monitor contracts). Pair any skill with the Circle MCP server for live SDK signatures, contract addresses, and chain IDs: {"mcpServers":{"circle":{"url":"https://api.circle.com/v1/codegen/mcp"}}}.
> Read the product overview first. Each product has an overview explaining when and why to use it. Read it before quickstarts.
> Pick the right wallet type. Developer-controlled (you hold keys), user-controlled (end user holds keys via PIN/social login), or modular (smart contract wallets with passkeys). See https://developers.circle.com/wallets.md.
> Use CCTP V2 for crosschain transfers. CCTP natively transfers USDC and EURC via burn-and-mint, and supports permissionless wrapping of third-party assets via lock-and-mint. V1 is legacy; always use V2 unless V1 is specified or the chain requires it (Noble, Sui, and Aptos still require V1). Migration guide: https://developers.circle.com/cctp/migration-from-v1-to-v2.md.
> Use Bridge Kit for frontend bridging. Wraps CCTP with a simpler SDK for user-facing apps. Use CCTP directly for backend transfers.
> Gas Station vs Paymaster. Gas Station sponsors gas for Circle Wallet transactions. Paymaster lets users pay gas in USDC. Different use cases — read both overviews.
> Gateway Nanopayments for sub-cent payments. Gasless USDC micropayments down to $0.000001 via x402 and batched settlement. For pay-per-request APIs, AI agent payments, streaming.
> Look up USDC addresses per chain. Never hardcode — use https://developers.circle.com/stablecoins/usdc-contract-addresses.md.
> Prefer SDKs over raw API calls. Node.js and Python SDKs handle auth, retries, and errors.
> API key required. Bearer token in Authorization header. Testnet and mainnet use separate keys and may use different base URLs depending on the product.
> Set up webhooks when available. Most operations are async. Webhooks deliver transaction confirmations and state changes.
> When calling list endpoints, paginate using pageSize and pageAfter until no nextPageAfter cursor is returned—stopping at the first page silently misses records.
> Building an AI agent? Start with the Agent Stack—Circle CLI, agent wallets, and nanopayments built for autonomous use cases: https://developers.circle.com/agent-stack.md.

# Transfer USDC from HyperEVM to HyperCore

This guide shows how to transfer USDC from HyperEVM to HyperCore using the
`CoreDepositWallet` contract.

<Tip>
  **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](/cctp/references/coredepositwallet-contract-interface) for detailed
  information.
</Tip>

## Prerequisites

Before you begin, ensure that you've:

* Installed [Node.js v22.6+](https://nodejs.org/)

* Prepared an EVM testnet wallet with the private key available

* Funded your wallet with HyperEVM testnet USDC from the
  [Circle Faucet](https://faucet.circle.com)

* Created a new Node project and installed dependencies:

  ```bash theme={null}
  npm install viem
  npm install -D typescript @types/node
  ```

* Created a `.env` file with required environment variable:

  ```text theme={null}
  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:

```ts TypeScript theme={null}
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:

```ts TypeScript theme={null}
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.

```ts script.ts expandable theme={null}
/**
 * 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:

```bash theme={null}
node --env-file=.env script.ts
```
