Skip to main content
This guide shows the steps to transfer USDC from Ethereum to HyperCore using the TokenMessengerV2 contract with hook data to call the CctpForwarder contract on HyperEVM. This CCTP flow follows the same pattern as USDC transfers from Ethereum to any other domain, except for the inclusion of hook data to call the CctpForwarder contract on HyperEVM. This guide does not provide full example code, you can find an example of transfers from Ethereum in the CCTP quickstart.
Note: Fast Transfers from Ethereum to HyperEVM incur a variable fee and a small forwarding fee for transfers to HyperCore. Fast Transfer is the default for transfers from Ethereum to HyperEVM.

Steps

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

Step 1. Get CCTP fees from the API

Query the CCTP API for the fees for transferring USDC from Ethereum to HyperCore. This value is passed to the maxFee parameter in the depositForBurnWithHook transaction. The following is an example request to the CCTP using source domain 0 (Ethereum) and destination domain 19 (HyperEVM):
curl --request GET \
  --url 'https://{endpoint}.circle.com/v2/burn/USDC/fees/0/19?forward=true' \
  --header 'Content-Type: application/json'
Response
[
  {
    "finalityThreshold": 1000, // fast transfer
    "minimumFee": 1,
    "forwardFee": {
      "low": 500000, // 0.50 USDC In USDC minor units
      "med": 500000, // Low, med, high will be the same static fee for now, this schema supports future dynamic fees
      "high": 500000
    }
  },
  {
    "finalityThreshold": 2000, // standard transfer
    "minimumFee": 0,
    "forwardFee": {
      "low": 500000, // In USDC minor units
      "med": 500000,
      "high": 500000
    }
  }
]

Step 2. Calculate the USDC amounts minus fees

There is a variable fee to deposit USDC from Ethereum to HyperEVM and a small forwarding fee for the transfer to HyperCore. The CCTP fee is returned by the API in the minimumFee field (1_000 USDC subunits). The forwarding fee is 0.50 USC (0_500_000 subunits). For a 10 USDC transfer from Ethereum to HyperCore, the total fee is 0.5001 USDC.

Step 3. Approve the USDC transfer

To allow the TokenMessengerV2 contract to transfer the USDC on your behalf, you need to approve the transfer. This is done by calling the approve function on the USDC contract. You can see an example of this contract call in the Ethereum CCTP V2 example on GitHub.

Step 4. Sign and broadcast a depositForBurnWithHook transaction on the TokenMessengerV2 contract

Create a depositForBurnWithHook transaction for the TokenMessengerV2 contract with the following parameters:
  • amount: The amount of USDC to transfer
  • destinationDomain: 19 (HyperEVM)
  • mintRecipient: The address of the CctpForwarder contract on HyperEVM
  • destinationCaller: The address of the CctpForwarder contract on HyperEVM
  • maxFee: 0_501_000 (from step 2)
  • minFinalityThreshold: 1000 (Fast Transfer)
  • hookData: The hook data to call the CctpForwarder contract on HyperEVM
The hookData is the data to execute the forwarder to HyperCore. The following is an example of the hook data:
/* Forward Hook Data format:
 * Field                        Bytes      Type       Index
 * magicBytes                   24         bytes24    0     ASCII prefix "cctp-forward", followed by padding
 * version                      4          uint32     24
 * dataLength                   4          uint32     28
 * hyperCoreMintRecipient       20         address    32    EVM address - optional, included if requesting a deposit to HyperCore
 * hyperCoreDestinationDex      4          uint32     52    The destinationDexId on HyperCore (0 for perp and uint32.max for spot)
 */
function encodeForwardHookData(
  hyperCoreMintRecipient,
  hyperCoreDestinationDex = 0,
) {
  // Header: 24 (magic) + 4 (version) + 4 (dataLength) = 32
  const headerLen = 32;
  // Payload when HyperCore deposit: 20 (address) + 4 (destinationDex) = 24
  const payloadLen = hyperCoreMintRecipient ? 24 : 0;
  const totalLen = headerLen + payloadLen;

  const hookDataBuffer = Buffer.alloc(totalLen);

  // magic ("cctp-forward") + version(0) + dataLength(0) as base
  const baseHookData =
    "0x636374702d666f72776172640000000000000000000000000000000000000000";
  hookDataBuffer.write(baseHookData.slice(2), 0, "hex");

  if (hyperCoreMintRecipient) {
    // Write dataLength = 24 (20 bytes address + 4 bytes destinationDex)
    hookDataBuffer.writeUInt32BE(24, 28);

    // Write HyperCore mint recipient at offset 32
    hookDataBuffer.write(hyperCoreMintRecipient.slice(2), 32, 20, "hex");

    // Write hyperCoreDestinationDex (uint32, BE) at offset 52
    const dex = Number(hyperCoreDestinationDex) >>> 0; // clamp to uint32
    hookDataBuffer.writeUInt32BE(dex, 52);
  }

  return hookDataBuffer;
}
You can see an example of this contract call in the Ethereum V2 example on GitHub Once the deposit transaction is confirmed, the USDC is minted on HyperEVM and automatically forwarded to your address on HyperCore. By default (when hyperCoreDestinationDex is 0), deposits credit the perps balance on HyperCore. To deposit to the spot balance, set hyperCoreDestinationDex to 4294967295 (uint32 max value).