Skip to main content
The CoreDepositWallet contract on HyperEVM allows you to deposit USDC from HyperEVM to HyperCore. This topic describes the contract interface and the available deposit functions.
To move USDC from HyperEVM to HyperCore, always call one of the CoreDepositWallet deposit functions (deposit, depositFor, or depositWithAuth). Only USDC is supported.Sending USDC or any tokens directly to the CoreDepositWallet contract address doesn’t trigger a deposit on HyperCore. The funds are permanently stuck.

Deposit functions

The CoreDepositWallet provides three entry points for depositing USDC from HyperEVM into HyperCore. All deposits credit a user’s balance on HyperCore, on either the perps or spot DEX.

deposit function

The deposit function transfers USDC from the caller’s address and credits the same address on HyperCore, after the caller has approved the CoreDepositWallet to spend their tokens. Signature:
deposit(uint256 amount, uint32 destinationDex);
Parameters:
ParameterValue
amountThe USDC amount being deposited from HyperEVM to HyperCore
destinationDexThe HyperCore destination dex index. Accepted values are:
- 0 → default perps DEX
- type(uint32).max → spot DEX
Token pull: Uses transferFrom(msg.sender, address(this), amount) → requires prior ERC-20 approve from the msg.sender to the core deposit wallet. Who is credited: The msg.sender of the transaction on HyperEVM is credited on HyperCore. Examples: ERC-20 Approval:
# approve the CoreDepositWallet to spend 100 USDC from the sender
cast send <USDC_ADDRESS> "approve(address,uint256)" <CORE_DEPOSIT_WALLET_ADDRESS> 100000000 \
  --private-key $PRIVATE_KEY \
  --rpc-url $RPC_URL
Depositing to the perps DEX:
# Deposit 100 USDC to the perps DEX (destinationDex = 0)
cast send <CORE_DEPOSIT_WALLET_ADDRESS> "deposit(uint256,uint32)" 100000000 0 \
  --private-key $PRIVATE_KEY \
  --rpc-url $RPC_URL
Depositing to the spot DEX:
# Deposit 100 USDC to the spot DEX (destinationDex = uint32.max)
cast send <CORE_DEPOSIT_WALLET_ADDRESS> "deposit(uint256,uint32)" 100000000 4294967295 \
  --private-key $PRIVATE_KEY \
  --rpc-url $RPC_URL
Note: If the destination DEX value is not supported (spot or perps), the deposit is credited to the sender’s spot balance.

depositFor function

The depositFor function transfers USDC from the caller but credits a specified recipient address on HyperCore. This allows deposits on behalf of another user. Signature:
depositFor(address recipient, uint256 amount, uint32 destinationId);
Parameters:
ParameterValue
recipientThe recipient address on HyperCore
amountThe USDC amount being deposited from HyperEVM to HyperCore
destinationIdThe HyperCore destination dex index. Accepted values are:
- 0 → default perps DEX
- type(uint32).max → spot DEX
Token pull: Uses transferFrom(msg.sender, address(this), amount) → requires prior ERC-20 approve from the msg.sender to the core deposit wallet. Who is credited: The recipient address passed to the function is credited on HyperCore. Examples: ERC-20 Approval:
# approve the CoreDepositWallet to spend 100 USDC from the sender
cast send <USDC_ADDRESS> "approve(address,uint256)" <CORE_DEPOSIT_WALLET_ADDRESS> 100000000 \
  --private-key $PRIVATE_KEY \
  --rpc-url $RPC_URL
Depositing to the perps DEX:
# Deposit 100 USDC to the perps DEX (destinationDex = 0)
cast send <CORE_DEPOSIT_WALLET_ADDRESS> "depositFor(address,uint256,uint32)" <RECIPIENT_ADDRESS> 100000000 0 \
  --private-key $PRIVATE_KEY \
  --rpc-url $RPC_URL
Depositing to the spot DEX:
# Deposit 100 USDC to the spot DEX (destinationDex = uint32.max)
cast send <CORE_DEPOSIT_WALLET_ADDRESS> "depositFor(address,uint256,uint32)" <RECIPIENT_ADDRESS> 100000000 4294967295 \
  --private-key $PRIVATE_KEY \
  --rpc-url $RPC_URL
Note: If the destination DEX value is not supported (spot or perps), the deposit is credited to the recipient’s spot balance.

depositWithAuth function

The depositWithAuth function allows depositing USDC using a pre-signed ERC-3009 authorization. This enables a deposit where the token transfer is authorized offchain and executed onchain without requiring a prior approve call. Signature:
depositWithAuth(uint256 amount, uint256 authValidAfter, uint256 authValidBefore, bytes32 authNonce, uint8 v, bytes32 r, bytes32 s, uint32 destinationDex);
Parameters:
  • amount: The USDC amount being deposited from HyperEVM to HyperCore
  • authValidAfter, authValidBefore, authNonce, v, r, s: EIP-3009-style authorization fields for receiveWithAuthorization
  • destinationDex: The HyperCore destination dex index. Accepted values are:
    • 0 → default perps DEX
    • type(uint32).max → spot DEX
Token pull: Calls token.receiveWithAuthorization(...), no prior approve needed. Who is credited: The msg.sender which has to match the from address from the receiveWithAuthorization is credited on HyperCore. receiveWithAuthorization details:
  • ERC: ERC-3009
  • Function Signature: ReceiveWithAuthorization
  • Parameters:
ParameterValue
fromThe payer’s address (authorizer) has to match the msg.sender of the depositWithAuth function
toThe CoreDepositWallet address (payee)
valueThe auth amount
validAfterThe time after which this is valid (Unix time)
validBeforeThe time before which this is valid (Unix time)
nonceUnique nonce
vv of the signature
rr of the signature
ss of the signature
Example: The example below illustrates how to generate an ERC-3009 authorization:
#!/usr/bin/env node

const ethers = require("ethers");
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const wallet = new ethers.Wallet(PRIVATE_KEY);
const provider = new ethers.JsonRpcProvider(
  process.env.RPC_URL || "https://rpc.hyperliquid-testnet.xyz/evm",
);

const usdcAddress = "<USDC_CONTRACT_ADDRESS>";
const coreDepositWallet = "<CORE_DEPOSIT_WALLET_ADDRESS>";

const EIP712_PREFIX = "0x1901";

const amount = ethers.parseUnits("100", 6); // 100 USDC
const nonce = ethers.hexlify(ethers.randomBytes(32));
const validAfter = 0;
const validBefore = Math.floor(Date.now() / 1000) + 3600; // valid for 1 hour

// Minimal ABI for DOMAIN_SEPARATOR
const USDC_ABI = [
  {
    inputs: [],
    name: "DOMAIN_SEPARATOR",
    outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }],
    stateMutability: "view",
    type: "function",
  },
];

async function getDomainSeparator(usdc) {
  try {
    return await usdc.DOMAIN_SEPARATOR();
  } catch {
    const domain = {
      name: "USD Coin",
      version: "2",
      chainId: await provider.getNetwork().then((n) => n.chainId),
      verifyingContract: await usdc.getAddress(),
    };
    return ethers.TypedDataEncoder.hashDomain(domain);
  }
}

async function main() {
  const usdc = new ethers.Contract(usdcAddress, USDC_ABI, provider);
  const domainSeparator = await getDomainSeparator(usdc);

  const structHash = ethers.keccak256(
    ethers.AbiCoder.defaultAbiCoder().encode(
      [
        "bytes32",
        "address",
        "address",
        "uint256",
        "uint256",
        "uint256",
        "bytes32",
      ],
      [
        ethers.keccak256(
          ethers.toUtf8Bytes(
            "ReceiveWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)",
          ),
        ),
        wallet.address,
        coreDepositWallet,
        amount,
        validAfter,
        validBefore,
        nonce,
      ],
    ),
  );

  const digest = ethers.keccak256(
    ethers.concat([EIP712_PREFIX, domainSeparator, structHash]),
  );
  const signer = new ethers.SigningKey(PRIVATE_KEY);
  const sig = signer.sign(digest);

  console.log("Authorization parameters:");
  console.log({
    amount: amount.toString(),
    validAfter,
    validBefore,
    nonce,
    v: sig.v,
    r: sig.r,
    s: sig.s,
  });
}

main().catch(console.error);
The example below illustrates how to call the depositWithAuth function with the authorization data:
cast send <CORE_DEPOSIT_WALLET_ADDRESS> \
  "depositWithAuth(uint256,uint256,uint256,bytes32,uint8,bytes32,bytes32,uint32)" \
  <AMOUNT> 0 1735660000 0x<NONCE> <V> 0x<R> 0x<S> <DEST_DEX_ID> \
  --private-key $PRIVATE_KEY \
  --rpc-url $RPC_URL
Note: If the destination DEX value is not supported (spot or perp), the deposit is credited to the authorizer's spot balance.