Problem Statement
Users who trade on Hyperliquid frequently manage multiple sub-accounts to isolate risk, run separate strategies, or split capital across different trading contexts. HyperTerminal currently has no concept of sub-accounts — every user sees and trades from only their master wallet. This means power users must switch to Hyperliquid's own interface to create, manage, or transfer funds between accounts, and cannot trade from a sub-account context in HyperTerminal at all.
Solution
Add full sub-account management to HyperTerminal. Users will be able to view all their sub-accounts alongside their master account, create new sub-accounts, rename them, switch the active trading context to any sub-account, and transfer USDC or spot tokens between the master and any sub-account. When a sub-account is active, the entire trading interface reflects that account's balances, positions, and orders, with a clear visual indicator that trading is happening on behalf of the sub-account.
User Stories
- As a trader, I want to see a list of all my sub-accounts alongside my master account (with Perps equity and Spot equity for each), so that I have a clear picture of how my capital is distributed.
- As a trader, I want to create a new sub-account by entering a name (1–16 characters), so that I can isolate a new trading strategy without spinning up a new wallet.
- As a trader, I want to see the address of each sub-account with a one-click copy button, so that I can reference sub-account addresses quickly.
- As a trader, I want to rename a sub-account inline (pencil icon in the account list), so that I can keep my accounts labelled clearly without navigating to a separate settings page.
- As a trader, I want to transfer USDC from my master perp account to a sub-account, so that I can fund the sub-account for trading.
- As a trader, I want to transfer USDC from a sub-account back to my master account, so that I can consolidate profits or close the sub-account's position capital.
- As a trader, I want to transfer spot tokens from my master spot account to a sub-account, so that I can fund spot trading on that sub-account.
- As a trader, I want to transfer spot tokens from a sub-account back to my master spot account, so that I can retrieve spot assets from a sub-account.
- As a trader, I want a transfer modal that shows the available balance for both the source and destination accounts, so that I can enter the correct amount without doing mental arithmetic.
- As a trader, I want to switch the active trading account to a sub-account from the user menu in the header, so that I can quickly jump to any account without going to a management page.
- As a trader, I want to switch the active trading account from the sub-account management view by clicking a "Trade" action on any account row, so that I can start trading on that account immediately.
- As a trader, I want a persistent banner in the trading terminal when a sub-account is active (e.g. "Trading on behalf of sub-account: Tareeq"), so that I always know which account I am trading from.
- As a trader, I want account balances, positions, open orders, and trade history to all reflect the currently active account, so that the entire terminal is scoped to the account I have selected.
- As a trader, I want deposit and external withdrawal actions to be disabled when a sub-account is active, so that I am not confused about which operations are possible on a sub-account.
- As a trader, I want the user menu trigger label to update to show the sub-account name when a sub-account is active, so that I always know which account I am in at a glance.
- As a trader, I want to switch back to the master account from the user menu, so that I can return to master account trading without reloading the page.
- As a trader, I want the active account to reset to master whenever I disconnect and reconnect my wallet, so that I never accidentally trade from a stale sub-account context.
- As a trader on mobile, I want to switch between master and sub-accounts from the mobile header menu, so that sub-account switching is not desktop-only.
- As a trader on mobile, I want to access the sub-account management view (list, create, rename, transfer) from mobile, so that I can manage my accounts from any device.
- As a trader, I want inline feedback (loading state, success, error) when creating a sub-account, so that I know whether the operation succeeded before trying to trade.
- As a trader, I want inline feedback when renaming a sub-account, so that I know the new name has been saved on-chain.
- As a trader, I want inline feedback when submitting a transfer, so that I can see the result of the transfer before initiating another one.
- As a trader, I want the sub-account list to refresh automatically after I create a new sub-account or rename one, so that the UI is always in sync with on-chain state.
- As a trader, I want account equity values in the sub-account list to update in real time from WebSocket subscriptions, so that I see live balances without manual refreshes.
Implementation Decisions
API Capabilities Confirmed
The @nktkas/hyperliquid SDK exposes everything required:
- Create:
exchange.createSubAccount({ name }) — name is 1–16 characters, returns new sub-account address
- Rename:
exchange.subAccountModify({ subAccountUser, name }) — updates name on-chain
- List:
info.subAccounts({ user }) — returns array of { name, subAccountUser, master, clearinghouseState, spotState } or null
- Perp transfer:
exchange.subAccountTransfer({ subAccountUser, isDeposit, usd }) — isDeposit: true = master→sub, false = sub→master; usd is the dollar amount multiplied by 1e6 as an integer
- Spot transfer:
exchange.subAccountSpotTransfer({ subAccountUser, isDeposit, token, amount }) — same direction semantics, token is the token identifier string
- Trading on behalf of sub-account: All exchange actions (order, cancel, updateLeverage, etc.) accept an optional
vaultAddress field; passing the sub-account address there routes execution to that account
There is no delete sub-account endpoint in the SDK or Hyperliquid API.
Active Account State
- A Zustand store (already partially implemented) tracks the selected sub-account address (
null = master). This store is session-only and does not persist across page reloads.
- A
useActiveAddress() hook composes the wallet address and selected sub-account address into a single value consumed by all data-fetching hooks.
- All subscription hooks (clearinghouse state, spot state, positions, active asset data, fee rates) must use
useActiveAddress() rather than reading directly from wagmi's useConnection().
- All exchange mutation hooks (order, leverage, cancel, etc.) must pass
vaultAddress when a sub-account is active.
isConnected continues to come from wagmi — it is wallet-level, not account-level.
Sub-Account Management UI
- A dedicated Sub-Accounts view (either a modal sheet accessible from the user menu, or a settings-style full-width panel). The exact surface is left to implementation — a modal/drawer is preferred on mobile; a full page or modal works on desktop. The content is the same: master account row + sub-account rows, each with Name, Address+copy, Perps Equity, Spot Equity, and Actions (Trade / Transfer / Rename).
- Create Sub-Account button opens a small dialog with a name input field (1–16 char validation, live character count). On submit it calls
createSubAccount, shows loading, then refreshes the list on success.
- Rename is triggered by a pencil icon on the sub-account name cell. It switches the cell to an inline text input pre-filled with the current name. Saving calls
subAccountModify.
- Transfer opens a modal. The modal lets the user pick direction (Master → Sub or Sub → Master), select the asset type (Perps USDC or Spot token), enter an amount, and see available balances on both sides. Submitting calls
subAccountTransfer or subAccountSpotTransfer depending on asset type.
- Trade action on any row in the management view sets that account as active and navigates/closes back to the trading terminal.
Trading Terminal Changes
- When a sub-account is active, a persistent banner appears at the top of the trading interface: "Trading on behalf of sub-account: [name]". A button in the banner allows switching back to master.
- Deposit and external withdrawal buttons are disabled (with a tooltip explaining they are not available for sub-accounts).
- The account panel shows balances from the active account.
- The user menu trigger shows the sub-account name instead of the master address when a sub-account is active.
Mobile
- The mobile header's user menu gains the same account list as desktop (master + sub-accounts).
- The sub-account management view must be accessible from mobile (likely a full-screen drawer or bottom sheet).
Data Freshness
- The sub-account list (
info.subAccounts) is a one-time query (not a WebSocket subscription). It should be refetched after any create or rename operation.
- Account equity within the management list comes from the snapshot returned by
info.subAccounts (which includes clearinghouseState and spotState per sub-account). Real-time subscriptions for individual sub-account balances are out of scope for the management view; live data is only needed in the trading terminal for the active account.
Modules to Build or Modify
- Active account store — session-only Zustand store for selected sub-account address (already started)
useActiveAddress hook — single source of truth for the address used by all data-fetching hooks
useSubAccounts hook — wraps info.subAccounts, returns list + refetch trigger
- Sub-account management view — list UI with create, rename, transfer, and trade actions
- Create sub-account dialog — name input + submit with validation feedback
- Transfer modal — direction picker, asset picker, amount input, balance display
- Rename inline edit — pencil icon → inline text field on sub-account row
- Sub-account active banner — persistent context indicator in the trading terminal when a sub-account is selected
- User menu — updated to list accounts and show active account name (already partially started)
- Exchange hooks — all
useExchange-based mutations must pass vaultAddress when a sub-account is active
- Subscription hooks — all hooks reading user data must use
useActiveAddress()
- Disabled actions — deposit and external withdrawal disabled when sub-account active
Testing Decisions
Good tests for this feature verify external behavior (what the user sees and what the API receives), not internal implementation details like store structure or hook composition.
What makes a good test here:
- Render a component with a mocked wallet connected and sub-accounts in the response; assert the rendered list matches.
- Simulate selecting a sub-account and assert that subsequent data hooks use the sub-account address (not the master wallet address).
- Simulate submitting a transfer form and assert the correct exchange method was called with the correct parameters and direction.
- Simulate creating a sub-account and assert the sub-account list refetches after success.
Modules worth testing:
- The transfer modal — validate amount parsing, direction toggling, and correct API method selection (perp vs spot)
- The create sub-account dialog — validate name constraints (1–16 chars) and error state on API failure
useActiveAddress — verify it returns the sub-account address when one is selected, and the master address when none is
Prior art: Look at how existing modal components (deposit modal, wallet modal) structure their submit/loading/error states as a pattern for the create and transfer dialogs.
Out of Scope
- Delete sub-account — Hyperliquid does not expose a delete endpoint; this is a protocol-level limitation.
- Depositing from L1 (bridge/on-ramp) into a sub-account — Hyperliquid only supports L1 deposits to the master account. Transfers from master to sub-account cover the internal funding use case.
- Real-time balance subscriptions in the management list — equity values in the sub-account list come from the snapshot returned by the API query. Subscribing to live balance streams for all sub-accounts simultaneously is not needed for the management view.
- Sub-account creation limits — Hyperliquid enforces a maximum number of sub-accounts per master. HyperTerminal will surface the API error if the limit is hit but will not enforce it client-side.
- Agent wallet configuration per sub-account — agent wallets (used for gasless signing in the existing flow) are separate from sub-account management and are not in scope here.
- Cross-sub-account transfers — the API only supports master↔sub transfers, not sub↔sub directly.
Further Notes
- Sub-account names on Hyperliquid are 1–16 characters, enforced by the API with a valibot schema. The UI should enforce this with live validation to avoid unnecessary failed requests.
- The
vaultAddress mechanism used for trading on behalf of a sub-account is the same one used for vaults; the implementation should verify that existing vault-related code paths do not conflict.
- The
subAccountTransfer amount field (usd) is an integer representing the dollar value × 1,000,000. The UI should accept a decimal USD string and convert on submit.
- Hyperliquid allows the master wallet to sign all sub-account operations — no separate private key or agent registration is needed for read or write operations from the master.
Problem Statement
Users who trade on Hyperliquid frequently manage multiple sub-accounts to isolate risk, run separate strategies, or split capital across different trading contexts. HyperTerminal currently has no concept of sub-accounts — every user sees and trades from only their master wallet. This means power users must switch to Hyperliquid's own interface to create, manage, or transfer funds between accounts, and cannot trade from a sub-account context in HyperTerminal at all.
Solution
Add full sub-account management to HyperTerminal. Users will be able to view all their sub-accounts alongside their master account, create new sub-accounts, rename them, switch the active trading context to any sub-account, and transfer USDC or spot tokens between the master and any sub-account. When a sub-account is active, the entire trading interface reflects that account's balances, positions, and orders, with a clear visual indicator that trading is happening on behalf of the sub-account.
User Stories
Implementation Decisions
API Capabilities Confirmed
The
@nktkas/hyperliquidSDK exposes everything required:exchange.createSubAccount({ name })— name is 1–16 characters, returns new sub-account addressexchange.subAccountModify({ subAccountUser, name })— updates name on-chaininfo.subAccounts({ user })— returns array of{ name, subAccountUser, master, clearinghouseState, spotState }or nullexchange.subAccountTransfer({ subAccountUser, isDeposit, usd })—isDeposit: true= master→sub,false= sub→master;usdis the dollar amount multiplied by 1e6 as an integerexchange.subAccountSpotTransfer({ subAccountUser, isDeposit, token, amount })— same direction semantics, token is the token identifier stringvaultAddressfield; passing the sub-account address there routes execution to that accountThere is no delete sub-account endpoint in the SDK or Hyperliquid API.
Active Account State
null= master). This store is session-only and does not persist across page reloads.useActiveAddress()hook composes the wallet address and selected sub-account address into a single value consumed by all data-fetching hooks.useActiveAddress()rather than reading directly from wagmi'suseConnection().vaultAddresswhen a sub-account is active.isConnectedcontinues to come from wagmi — it is wallet-level, not account-level.Sub-Account Management UI
createSubAccount, shows loading, then refreshes the list on success.subAccountModify.subAccountTransferorsubAccountSpotTransferdepending on asset type.Trading Terminal Changes
Mobile
Data Freshness
info.subAccounts) is a one-time query (not a WebSocket subscription). It should be refetched after any create or rename operation.info.subAccounts(which includesclearinghouseStateandspotStateper sub-account). Real-time subscriptions for individual sub-account balances are out of scope for the management view; live data is only needed in the trading terminal for the active account.Modules to Build or Modify
useActiveAddresshook — single source of truth for the address used by all data-fetching hooksuseSubAccountshook — wrapsinfo.subAccounts, returns list + refetch triggeruseExchange-based mutations must passvaultAddresswhen a sub-account is activeuseActiveAddress()Testing Decisions
Good tests for this feature verify external behavior (what the user sees and what the API receives), not internal implementation details like store structure or hook composition.
What makes a good test here:
Modules worth testing:
useActiveAddress— verify it returns the sub-account address when one is selected, and the master address when none isPrior art: Look at how existing modal components (deposit modal, wallet modal) structure their submit/loading/error states as a pattern for the create and transfer dialogs.
Out of Scope
Further Notes
vaultAddressmechanism used for trading on behalf of a sub-account is the same one used for vaults; the implementation should verify that existing vault-related code paths do not conflict.subAccountTransferamount field (usd) is an integer representing the dollar value × 1,000,000. The UI should accept a decimal USD string and convert on submit.