Skip to main content
Network calls fail and pages reload. The SDK is built so neither one trades twice or loses a trade.

Sign, persist, send

openPosition and cashOut run in one call. To survive a reload mid-trade, split them into three steps: sign, save the signed record, then send it.

signEntry({ quote, core, cash })

Asks the wallet for every signature the entry needs, at once. It plans the funding from cash (a spendableCash() read) or, without it, from current balances: free vault cash first, then the wallet, then a bridge of core to the wallet. 0.05 USDC (bridgeGasBuffer) stays behind.
  • core is the HyperCore spot USDC you offer. Leave it out to fund from the wallet alone. core: null means your HyperCore read failed.
  • Pass cash to plan before the wallet prompt. Without it, the wallet is asked for TakerAccept while the balances load, so a plan that fails throws after the prompt.
  • Throws EntryError BALANCE_UNKNOWN when the vault balance is not current.

signCashout({ quote })

Has the owner sign a cash-out quote’s SellBack or CashoutTransfer.

sendAcceptance(signed, { onRecord })

Sends either kind of record under its acceptance ID, and checks the answer echoes the record’s IDs. An entry’s bridge is sent only after the accept answers ACCEPTED with its fund_by still ahead. Any other answer discards it.

recoverAcceptance(signed, { wait, onRecord })

Reads and fences the acceptance. It signs nothing. It sends a never-sent bridge only if the acceptance is ACCEPTED before its fund_by, and resends a sent one that got no answer, with the same bytes, in that same window. It waits out PENDING_CONFIRM unless you pass wait: false.

Entry records and the bridge

An entry record carries version: 2 and a bridgeState: SENT, LANDED, PROCESSED, REFUSED or DISCARDED. onRecord is awaited with the record before the bridge is first sent and again on each new state. Persist it over the stored one. sendAcceptance refuses a record from SDK 0.63 or older; recoverAcceptance only reads it. The result never waits for Hyperliquid:
  • bridging is set when this call sent the bridge. It resolves to Hyperliquid’s answer, or unknown when none came before fund_by.
  • bridged is { amount, landed } (amount in atomic USDC) once a bridge was sent, and never for one Hyperliquid refused. landed: "yes" means Hyperliquid answered ok: unless the operation COMMITTED, that cash is now in the wallet on HyperEVM, not on HyperCore. "unknown" means read the balances rather than assume where it is.
See If an entry fails after its bridge for what to show the user.

Retries

Each command is built once with its Idempotency-Key. After a network failure or a BACKOFF error, the SDK resends it byte for byte, up to five sends. Change that with retry: { attempts }, or turn it off with retry: false.

Errors

unwrap and every flow throw ApiError for a venue error, with code, retry, status, requestId, fieldViolations and retryAfterMs, plus resend on a flow command answered BACKOFF. Its retry says what to do next: NetworkError means the outcome is unknown: the command may have reached the venue. When it carries resend, call it, never a new command, so it cannot run twice.
Every code is on Errors.

normalizeError(error)

Turns any SDK failure into one shape for your UI: { code, message, retryable, retry, requestId, status, mayStillRun, resend, cause }. mayStillRun is true when the command may have reached the venue.

Flow errors