useUserBalances
New in v0.5.6 - Real-time balance tracking with WebSocket updates
Return Values
AccountBalance[]
Array of user token balances, automatically updated in real-time. Merged from REST API initial data and WebSocket updates.
boolean
true while fetching initial balances from REST API, false once loadedboolean
true when WebSocket subscription is active, false otherwiseError | null
Error object if something went wrong during fetch or subscription,
null otherwise() => void
Function to clear the current error state
() => Promise<void>
Manually refresh balances from REST API (useful for force refresh after errors or manual updates)
Features
Hybrid Data Loading
- Initial Load: reads every page of balances via REST (
getUserBalances()), which is paginated — a single page would leave assets past the first unreachable. - WebSocket Subscription: subscribes to the
balanceschannel after the initial load. - Race Condition Prevention: the subscription only opens once the REST data is in, so an event cannot be overwritten by the response it raced.
- Subscribe-time Snapshot: the channel’s snapshot carries every balance, and the hook applies it to the list it already has — no second REST read.
Applying the snapshot
The snapshot is the complete balance set, which makes it different from a stream of updates in two ways:- Its totals and
versionare taken verbatim from the same durable spot row as REST. - A held asset the snapshot omits is zeroed rather than left showing a figure that is no longer true. The row itself stays, so a portfolio renders “0 WSEI” instead of losing the line. A held row carrying a real
versionis the exception: a versioned zero is an explicit tombstone, so omission cannot be read as “this went to zero” and the row is retained until a newer one arrives.
Real-time Updates
The hook listens to balance update events triggered by:- Deposits - Tokens deposited to the vault
- Withdrawals - Tokens withdrawn from the vault
- Order Locking - Balance locked when placing orders
- Order Unlocking - Locked balance released when orders are cancelled or expire
- Trades - Balance changes from spot fills and their fees or rebates
- Margin Transfers - The spot leg of collateral moved into or out of a margin account
Every event carries one spot balance row. A versioned event replaces the
whole spot row only when its
version is higher. Equal or lower versions are
idempotent. A collateral transfer that moves the spot wallet row is versioned
like any other spot event. An unversioned event, from a producer that does
not stamp versions yet, is applied fail-open without changing the held spot
version. Margin collateral never arrives on this channel: a margin-routed
deposit, a perpetual fill, a funding settlement, a liquidation and an
auto-deleveraging close send no balance event, so read margin-account state
separately. updatedAt is never used to order rows.Automatic Balance Updates
When a balance update event is received:- If the token already exists in state, the balance is updated with the new values
- If a new token appears, the hook re-reads from REST — the wire payload carries no
assetId,decimalsor wrapped-native flag, so a new asset cannot be built from an event alone - Balance updates include both normalized (human-readable) and raw (wei) values
loading, which describes the initial load. The public refresh() re-reads the full set and applies the same version arbitration: a fetched row supersedes the held one unless the held row carries a newer version, and a held versioned row the fetch omits is retained rather than dropped. So it is a version-aware refresh, not a blind overwrite — an in-flight REST read cannot roll a balance back to a state the stream has already moved past.
Authentication Required
This hook requires an authenticated session. Log in with theuseAuth hook (or sdk.login(...)) before using it.
Basic Usage
With Refresh Button
Filter Non-Zero Balances
Balance Summary with Charts
Real-time Balance Updates
Error Handling with Retry
Complete Dashboard Example
AccountBalance Type Structure
See Also
- useVault - Deposit and withdraw tokens
- useTrade - Place and manage orders that lock/unlock balances
- WebSocket API - Low-level balances WebSocket channel
- TypeScript SDK - Core SDK WebSocket methods
useUserMovements
New in v0.5.4 - Real-time user movement tracking
useUserBalances for the live balance change a fill produces.
In that history, balanceBefore / balanceAfter / lockedBefore / lockedAfter describe a spot balance row. A margin fill leg, a FUNDING row, and a deposit or withdrawal that goes straight into or out of the parent margin account have no spot row and report 0 in all four: that is “no spot snapshot”, not a wallet balance of zero. Read margin account state for collateral rather than these fields.
Parameters
The hook accepts an optional options object.number
default:50
Maximum number of movements to keep in memory
number
Movements to fetch on initial load, 1 to 1000. Defaults to
maxMovements capped at 100. The hook reads one newest-first page and keeps it current from the movements channel; it takes no page, pageToken or orderBy. Walk full history with sdk.profile.getPaginatedUserMovements.LedgerEntryType
Filter the initial REST history by entry type. Changing this value re-fetches history. Live WebSocket events are not filtered by the hook.
TransactionType
Filter the initial REST history by transaction type. Changing this value re-fetches history. Live WebSocket events are not filtered by the hook.
string
Filter the initial REST history by asset UUID. Live WebSocket events are not filtered by the hook.
Return Values
UserMovementEvent[]
Array of movement events, newest first. Automatically deduplicated by movement ID.
boolean
true while fetching initial movements, false once loadedboolean
true after the channel handler is registered, false otherwise. This does not report socket connection or channel delivery state.Error | null
Error object if something went wrong,
null otherwise() => void
Dismisses the current error. It does not retry the request or re-register the handler.
Features
Automatic Deduplication
The hook automatically deduplicates movements by ID. If the same movement is received multiple times (e.g., from WebSocket and initial fetch), only one copy is kept.Hybrid Data Loading
- Initial Load: Fetches recent movements via REST API
- Real-time Updates: Registers a WebSocket channel handler for new movements
- Race Condition Prevention: WebSocket handler registration only starts after REST data is loaded
Memory Management
Movements are automatically limited tomaxMovements entries. Older movements are removed when the limit is exceeded.
Basic Usage
Filter by Transaction Type
Filters are applied server-side on the initial REST fetch. Changing a filter value automatically re-fetches history, but the hook appends all live WebSocket events. Filter the returned array in the client when the live view must remain restricted. REST history values may be uppercase while WebSocket values may be lowercase, so normalize before comparing.Filter by Entry Type and Asset
The REST request usesassetId, but the v1.0.51 REST-to-event adapter does not retain that field. To keep the merged history and live feed restricted to one asset, also compare the token address carried by both sources.
Group by Token
Track Order Lifecycle
Inspect a Movement Balance Snapshot
balanceAfter and lockedAfter describe the balance immediately after that movement; they are not a current-wallet-balance API. Use useUserBalances or sdk.profile.getUserBalances() when you need current balances. A missing snapshot means unavailable data, not zero.
Error Handling
Complete Example with Styling
Movement Event Structure
tokenAddress: Required legacy alias populated fromtoken(or the older wire alias)symbol(optional): Token ticker symbol (e.g., “BTC”, “USDC”)amount: Human-readable decimal string and the simplest exact value to displayamountRaw(optional): Do not assume this value exists or is an integer. Funding history may contain a decimal string; integer raw-unit conversion applies only after validating a token movement’s value.entryTypeandtransactionType: REST history may use uppercase values while WebSocket events may use lowercase values. Normalize casing before comparisons.
See Also
- WebSocket API - Low-level movements WebSocket channel
- TypeScript SDK - Core SDK WebSocket methods
- useProfile - User profile and balance queries
useVault
Vault Operations
(assetId, amount, autoWait?) => Promise<TransactionResult>
Deposit tokens into vault. Use asset UUID from
sdk.profile.getUserBalances().(assetId, amount, autoWait?, source?) => Promise<WithdrawResult>
Withdraw tokens from vault. Use asset UUID from
sdk.profile.getUserBalances(). source is "spot" or "margin"; see sdk.vault.withdraw.(withdrawalIndex, autoWait?) => Promise<WithdrawResult>
Retry the on-chain submission of a withdrawal that never landed. It does not create a new withdrawal; see
sdk.vault.retryWithdrawal.(params?) => Promise<ListPendingWithdrawalsResponse>
List the caller’s withdrawals still awaiting on-chain confirmation, newest first, cursor-paginated with
pageSize and pageToken. Wraps sdk.withdrawals.listPendingWithdrawals.Token Approvals
(assetId, amount, autoWait?) => Promise<TransactionResult>
Approve vault to spend tokens. Use asset UUID from trading pairs.
(assetId) => Promise<bigint>
Check current token allowance by asset UUID
(assetId, amount) => Promise<boolean>
Check if approval is needed for an asset UUID
Validation Requirements
All vault operations include built-in validation to prevent common errors: Asset ID must be a non-empty string, and amount must be greater than 0. Validation Checks:
Example with error handling:

