@zofai/trading-widget
v0.1.1
Published
Embeddable perpetuals trading UI for ZO Finance on Sui. Partners can drop the full widget into their dapp or compose custom layouts from sub-components.
Readme
@zo/trading-widget
Embeddable perpetuals trading UI for ZO Finance on Sui. Partners can drop the full widget into their dapp or compose custom layouts from sub-components.
Features
- Market header – Symbol selector, mark price, funding rate
- Price chart – Pyth-powered OHLC + live updates (lightweight-charts)
- Recent trades – Live trade feed
- Trade panel – Open/close positions (market & limit), ZLP/SLP/USDZ
- Positions / Orders / History – Bottom tabs with countdown to next refresh
- RPC settings – Predefined or custom RPC URL
- Wallet – Sui connect via
@mysten/dapp-kit-react; custom connect button and account sidebar
Peer dependencies
Your app must install:
react&react-dom(≥18)jotai(≥2)@tanstack/react-query(≥5)@mysten/dapp-kit-react(≥1) &@mysten/sui(≥2)zo-sdk(≥0.1)
The widget uses Tailwind-compatible utility classes (e.g. flex, text-white, rounded-lg). Either:
- Use Tailwind CSS or UnoCSS in your app so those classes resolve, or
- Import the bundled CSS once in your app:
import '@zo/trading-widget/style.css'(or@zofai/trading-widget/style.css). This file contains the compiled UnoCSS used by the widget.
Quick start: full widget
- Wrap your app with the required providers (order matters):
import { appStore } from '@zo/trading-widget'
import { Provider as JotaiProvider } from 'jotai'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { DAppKitProvider } from '@mysten/dapp-kit-react'
// Your dapp-kit instance (Sui wallet + network)
import { dAppKit } from './dapp-kit'
const queryClient = new QueryClient({
defaultOptions: {
queries: { staleTime: 60_000, retry: 2 },
},
})
export function Root() {
return (
<JotaiProvider store={appStore}>
<QueryClientProvider client={queryClient}>
<DAppKitProvider dAppKit={dAppKit}>
<App />
</DAppKitProvider>
</QueryClientProvider>
</JotaiProvider>
)
}- Render the widget where you want the trading UI:
import { TradingWidget } from '@zo/trading-widget'
export function App() {
return (
<div className="h-screen flex flex-col">
<header>{/* Your navbar, connect button, etc. */}</header>
<main className="min-h-0 flex-1">
<TradingWidget className="h-full" />
</main>
</div>
)
}TradingWidget props
| Prop | Type | Description |
| ---------- | -------- | ------------------------------------ |
| symbol | string | Initial symbol (default "BTC") |
| className| string | Extra class on the widget container |
Components
All-in-one
TradingWidget– Full layout: header, chart, recent trades, trade panel, bottom tabs (positions/orders/history), dialogs and toasts.
Layout & header
TradingWidgetProvider– Sui + React Query + Jotai setup. Use when building a custom layout so sub-components have the same context.MarketHeader– Symbol dropdown (from ZLP/SLP index tokens), mark price, funding rate.
Market data
PriceChart– Pyth-backed candlestick chart (history + streaming).RecentTrades– Recent trades for the selected symbol.
Trading & account
TradePanel– Long/short, market/limit, leverage, collateral selector; opens positions on ZLP/SLP/USDZ.CustomConnectButton– Connect wallet; when connected opens the account sidebar instead of a dropdown.
Tables (bottom section)
BottomTabs– Tabs: Positions, Orders, History; each shows a circular countdown to next refresh.PositionsList– Open positions with PnL, adjust/close.OrdersList– Open orders with cancel.HistoryList– Trade history.
Settings
RpcSettings– Dropdown: choose predefined RPC or enter custom URL; shows latency. Persists tolocalStorageso the widget’s provider uses the selected RPC.
Custom layout
Use TradingWidgetProvider and the sub-components to build your own layout:
import {
TradingWidgetProvider,
MarketHeader,
PriceChart,
RecentTrades,
TradePanel,
BottomTabs,
CustomConnectButton,
RpcSettings,
} from '@zo/trading-widget'
export function CustomTradePage() {
return (
<TradingWidgetProvider>
<div className="flex flex-col h-full bg-gray-950 text-white">
<header className="flex items-center gap-3 border-b border-gray-800 px-4 py-2">
<MarketHeader />
<div className="flex-1" />
<RpcSettings />
<CustomConnectButton />
</header>
<div className="flex flex-1 overflow-hidden">
<div className="flex-1 min-w-0">
<PriceChart />
</div>
<aside className="w-48 shrink-0">
<RecentTrades />
</aside>
<aside className="w-72 shrink-0">
<TradePanel />
</aside>
</div>
<div className="h-52 shrink-0 border-t border-gray-800">
<BottomTabs />
</div>
</div>
</TradingWidgetProvider>
)
}Ensure your app is wrapped with Jotai (appStore), React Query, and DAppKit as in Quick start.
Hooks & store
For custom UIs that need widget data or actions:
Hooks
useEssential()– wallet, network, consts (zo/sudo/usdz), accountData, refreshAccountuseWallet(),useNetwork()– wallet and current networkusePosition(address, network)– positions list, refresh,dataUpdatedAtuseOrder(address, network)– orders list, refresh,dataUpdatedAtuseHistories(address, network)– trade historyuseFundingRate(symbol, network, lpToken)– funding rateusePositionConfig(network, { symbols })– position config (fees, etc.)useSymbolInfo(network)– symbol info map (ZLP/SLP/USDZ)useRpc()– RPC list, custom URL, latency; used byRpcSettingsuseSponsoredGasAvailability(address, network)– gas sponsorship
Store (Jotai)
appStore– same store instance must be used for the widget and your app (see Quick start).currentSymbolAtom–{ symbolId, unit, icon }; set when user picks a market.tokenPriceAtom–{ tokenPrice: Record<string, number>, isLoading, error }(Pyth oracle prices).
RPC and wallet
- RPC – The widget reads RPC from
localStorage:is-custom-rpc,custom-rpc-url,custom-rpc-index. UseRpcSettingsin your header (or elsewhere) so users can pick a predefined RPC or set a custom URL. After changing RPC, a full page refresh is recommended. - Wallet – Uses Sui dapp-kit. Your app must create a
dAppKit(e.g. withcreateDAppKit) and wrap the tree inDAppKitProvider.CustomConnectButtontriggers the kit’s connect flow; when connected, it opens the widget’s account sidebar.
Example app
The repo includes an example app that integrates the widget:
- Apps/example – Minimal shell: navbar (brand, RPC settings, connect), then full-width
TradingWidget. Seeapps/example/src/App.tsxandapps/example/src/main.tsxfor provider setup anddAppKitregistration.
Run it (from monorepo root):
pnpm install
pnpm --filter example devBuild
From the repo root:
pnpm --filter @zo/trading-widget buildOutput: packages/trading-widget/dist/ (ESM + types). Consume from your app as @zo/trading-widget (workspace or published package).
