The examples on this page use Hyperliquid (
provider: 'hyperliquid'). Withdrawal mechanics (supported assets, destination chains, and processing times) vary by provider.Overview
PerpsClient.withdraw() is a single-call helper that builds the withdrawal payload, authorizes it through the registered provider plugin, and submits the signed action. It dispatches through the same create → authorize → execute pipeline documented in Actions, but consumers do not have to compose the steps manually.
The examples on this page use a PerpsClient with the provider plugin registered and, for Hyperliquid, the user’s wallet bound:
Ondo withdraws USDC to the connected wallet address only. The destination must be in the Ondo address book, so call
getWithdrawFlow() first. See Ondo Withdrawals.Hyperliquid: Withdrawal processing typically takes 3–4 minutes. The bridge transfer from Hyperliquid L1 to Arbitrum is asynchronous.
Checking the Withdrawal Flow
CallgetWithdrawFlow() to see if a venue accepts a withdrawal now. It returns undefined when the provider declares no withdrawal flow.
WithdrawFlow:
Running the setup actions
Eachsetup entry is an ActionType. Run each one in order with perps.execute, then read the flow again. executeProviderSetupAction() rejects them, because they are not in the provider’s setup list.
siweLogin and addWithdrawalAddress. See Ondo Withdrawals.
Discovering Withdrawable Balances
CallgetWithdrawableBalances() before rendering a withdrawal picker. Providers that support the capability return one row per withdrawable (asset, category) pair; providers without the optional read return undefined, which means the form remains amount-only.
Hyperliquid, Lighter, and Ondo all implement this read. Each provider’s own page describes its categories: Hyperliquid, Lighter, and Ondo.
WithdrawableBalance contains:
The SDK joins provider rows with
/assets, drops unknown assets, and filters amounts below each asset’s minWithdrawalAmount. Never merge balances across categories. The amount remains a human-readable decimal string — the provider signer applies the asset precision.
What a row lets you submit depends on the provider:
A
WithdrawableBalance row is assignable to WithdrawalAssetRef, so you can pass the row’s categoryId and asset as source. The backend drops unknown withdrawal params without an error, so a misspelled field is never reported.
A provider plugin implements the optional
getWithdrawableBalances read by returning ProviderWithdrawableBalance[] — the pre-join shape, keyed by the provider-native assetId, not the resolved Asset. It carries categoryId, available, max, and the optional withdrawalFee and isFeeDeducted. Only relevant when authoring a provider plugin; consumers use WithdrawableBalance as above.Throws
getWithdrawableBalances() throws PerpsError with one code for the account’s access state. See Account access.
SetupRequired— the venue needs a credential (a Lighter auth token or an Ondo session) and none is stored.Unauthorized— the venue rejects the credential.AccountNotFound— the wallet has no venue account.
AccountNotFound. An account with nothing to withdraw returns an empty list.
Choosing a Withdrawal Type
CallgetWithdrawalTypes() to read how the venue can settle a withdrawal from each holding. It returns undefined when the provider plugin declares no such read. Only Lighter implements it.
WithdrawalSourceTypes holds a source (WithdrawalAssetRef) and a list of WithdrawalTypeOption entries:
The method throws
PerpsError when the provider plugin is not registered or when the plugin read fails.
Using PerpsClient (recommended)
PerpsClient.withdraw
Build, sign with the provider-declared signer, and submit a withdrawal in a single call.WithdrawParams
WithdrawalParams:
For a Lighter spot or non-quote asset, pass
source from a getWithdrawableBalances() row. For a Lighter fast withdrawal, pass withdrawalOptions from getWithdrawalTypes(). See Lighter Withdrawals.ExecuteActionResponse — { results: ActionResult[] }. The array contains a single result for the WITHDRAWAL action:
Using Service Functions (advanced)
For complete control over the create/authorize/execute steps — for example, to surface the typed-data payload in a confirmation dialog before requesting the signature — call the lower-levelcreateAction / executeAction service functions directly. See Actions for the full create → authorize → execute pattern.
A Hyperliquid withdrawal step is user-signed EIP-712. The wallet must be on the chain named in typedData.domain.chainId; PerpsClient.withdraw() switches it for you through the switchChain hook when one is set. Prefer withdraw() unless you need the payload before it is signed.