For the complete documentation index, see llms.txt. This page is also available as Markdown.

HyperCore signing & broadcasting

Selling from HyperCore means signing a Hyperliquid EIP-712 action and submitting it yourself — the payload, the signing rules, and the traps.

SwapKit supports HyperCore (Hyperliquid's exchange chain, HYPE) as a swap source and destination. Selling from HyperCore is the one flow where your wallet signs EIP-712 typed data and submits it to Hyperliquid itself, instead of building and broadcasting an ordinary chain transaction. HyperCore has no plain transfer primitive — value moves by signing a Hyperliquid action — so a deposit address alone is not actionable.

Depositing into HyperCore is unaffected: X → HYPE.USDC is a normal transaction on the sell chain, with the HyperCore account as the destination. Only the sell direction produces typed data.

Chain & asset identifiers

HyperCore is chain HYPE. HyperEVM is a separate chain (HYPEREVM) and is not interchangeable with it.

Identifier
Notes

HYPE.USDC-USDC:0x6d1e7cde53ba9467b783cb7c530ce054

The tradable HyperCore asset, at eight decimals. The address part is HyperCore's HIP-1 token id — the id the chain itself uses for balances, transfers and explorer output. Not an EVM contract address. The same id appears bare in the signed action's token field.

Amounts are human-readable decimal strings everywhere, including inside the signed action ("8", not base units).

What /v3/swap returns

Discriminate on meta.txType === "EIP_712_HYPE_SEND_ASSET". The tx object carries everything needed: the typed data to sign, the action to submit, and where to submit it.

{
  "txHint": "simpleTransfer",
  "targetAddress": "0x4d434471b3337062c6cb74eaf8d5595dbbba6839",
  "swapId": "496b0ea3-4ff4-45ae-a222-75a0b4a3d2f7",
  "meta": { "txType": "EIP_712_HYPE_SEND_ASSET" },
  "fees": [
    {
      "type": "inbound",              // Hyperliquid account-activation fee — see below
      "amount": "1",
      "asset": "HYPE.USDC-USDC:0x6d1e7cde53ba9467b783cb7c530ce054",
      "chain": "HYPE",
      "protocol": "FLASHNET"
    }
  ],
  "tx": {
    "typedData": {
      "domain": {
        "name": "HyperliquidSignTransaction",
        "version": "1",
        "chainId": 42161,
        "verifyingContract": "0x0000000000000000000000000000000000000000"
      },
      "primaryType": "HyperliquidTransaction:SendAsset",
      "types": {
        "HyperliquidTransaction:SendAsset": [
          { "name": "hyperliquidChain", "type": "string" },
          { "name": "destination",      "type": "string" },
          { "name": "sourceDex",        "type": "string" },
          { "name": "destinationDex",   "type": "string" },
          { "name": "token",            "type": "string" },
          { "name": "amount",           "type": "string" },
          { "name": "fromSubAccount",   "type": "string" },
          { "name": "nonce",            "type": "uint64" }
        ]
      },
      "message": {
        "hyperliquidChain": "Mainnet",
        "destination": "0x4d434471b3337062c6cb74eaf8d5595dbbba6839",
        "sourceDex": "spot",
        "destinationDex": "",
        "token": "USDC:0x6d1e7cde53ba9467b783cb7c530ce054",
        "amount": "8",
        "fromSubAccount": "",
        "nonce": 1786652874878
      }
    },
    "action": {
      "type": "sendAsset",
      "hyperliquidChain": "Mainnet",
      "signatureChainId": "0xa4b1",
      "destination": "0x4d434471b3337062c6cb74eaf8d5595dbbba6839",
      "sourceDex": "spot",
      "destinationDex": "",
      "token": "USDC:0x6d1e7cde53ba9467b783cb7c530ce054",
      "amount": "8",
      "fromSubAccount": "",
      "nonce": 1786652874878
    },
    "submitTo": "https://api.hyperliquid.xyz/exchange"
  }
}

action and typedData.message describe the same transfer. signatureChainId and type belong to the action envelope only — they are not part of the signed struct, which is exactly the eight fields listed in types.

Signing

Sign tx.typedData with standard eth_signTypedData_v4. primaryType is given explicitly and types contains exactly that one struct — no EIP712Domain entry, so add one yourself if your signer requires it.

The domain chainId is 42161 (Arbitrum) and verifyingContract is the zero address. That is Hyperliquid's action-signing domain, not a contract call — nothing here touches Arbitrum, and everything stays on HyperCore. Don't "correct" it to 999 or 1337. action.signatureChainId: "0xa4b1" is the same 42161, hex-encoded, which is what Hyperliquid expects in the envelope.

Broadcasting

POST to tx.submitTo, passing action through unchanged and reusing its nonce:

A success looks like {"status":"ok","response":{"type":"default"}}.

Why sendAsset, and what the dex fields mean

sourceDex and destinationDex name the HyperCore sub-account each side of the transfer touches: "" is the default perps account, "spot" is the spot account.

  • destinationDex is always "". Flashnet's hypercore:USDC route quotes default-perps USDC and cannot credit a spot deposit — a deposit sent with "spot" arrives but is not claimable by the route.

  • sourceDex is resolved for you. SwapKit reads the sender's live perps and spot balances and picks whichever can fund the transfer, preferring perps.

Account-activation fee

Hyperliquid charges the sender a one-time 1 USDC fee when the destination account does not yet exist, on top of amount. Providers mint a fresh deposit address per swap, so in practice this applies to most HyperCore payins.

It is quoted as an inbound fee on the route (see fees above). The signed amount is unaffected — the user needs amount + fee available in the funding sub-account. When the balance falls short, the route carries an insufficientBalance warning and remains build-able, so present it before the user signs:

Verifying before you sign

Because the signature covers typedData.message while the funds move on action, a wallet should confirm the two agree before signing — every one of the eight signed fields, plus action.destination against the route's targetAddress. A disagreement means signing one transfer and submitting another.

Tracking the payin

A sendAsset appears in Hyperliquid's ledger (userNonFundingLedgerUpdates) as delta.type: "send"not spotTransfer or internalTransfer. Filtering for the older types will never match, and the transfer will look like it never happened:

Swap progress is tracked normally through /track, keyed on the deposit address.

Don't confuse it with the Mayan HyperCore withdraw

Mayan's HyperCore route signs a different action (HyperliquidTransaction:SendToEvmWithData) under meta.txType = EIP_712_HYPE_WITHDRAW, in a {domain, types, value} shape — note value, not message, and no primaryType. That one bridges off HyperCore and is relayed by Mayan; this one stays on HyperCore and you submit it. The shapes are deliberately different so the two cannot be crossed — always branch on meta.txType.

Last updated