Sub-accounts
Preview. The user-visible API is stable; the address-derivation scheme is finalised before mainnet.
TL;DR
A sub-account is a derived address under a master. It holds its own balance and its own risk, and it moves funds in and out only through the master. Up to 32 subs per master.
A sub-account cannot sign today, so it cannot trade today.
A sub address is a hash of the master address and the index. No private key exists for it. An action reaches an account in one of two ways — the account's own key signs it, or an approved agent of the account signs it — and a sub can use neither:
- It has no key, so it cannot sign for itself.
- Its approved-agent set is always empty.
create_sub_accountnever fills it, andapprove_agentadds an agent to the signer's account. Only the sub could approve an agent of the sub, and the sub cannot sign.
So a sub is a fund-segregation bucket the master funds and defunds. It cannot place orders, hold positions it opened itself, or enrol in portfolio margin. Plan for one master account per trading strategy until sub-account signing ships.
Mental model
Each sub is a first-class account in the state machine — own balance, own liquidation threshold. The master-of-sub relationship is recorded in a side map. "First-class" describes the ledger, not the signing surface: no sub can sign, so no sub can act. See the TL;DR warning.
Hard cap: 32 subs per master. Hitting the cap returns
PRECONDITION_FAILED on create_sub_account.
Transfers
Only between master and sub:
External withdrawals (off-chain, to a third address) must come from the master. Sub-accounts cannot withdraw directly off-chain.
Address derivation
Each sub-account index n maps deterministically to an address derived from the master's 20-byte address:
sub_addr_n = first_20_bytes( keccak256( master_addr || uint64_be(n) ) )
Anyone can compute a sub's address without on-chain state. The derivation is consensus-fixed at V1 launch; treat returned addresses as authoritative until then.
Fund-segregation guarantees
| Guarantee | Mechanism |
|---|---|
| A sub's loss cannot drain master | Sub liquidates against its own balance; master sees only the transfer ledger |
| A sub's loss cannot drain other subs | Same — each sub is a first-class isolation boundary |
| Master CAN choose to backstop a losing sub | Voluntarily, via sub_account_transfer deposit |
| Master CANNOT involuntarily backstop | A sub's blowup is the sub's, full stop |
| Master can liquidate out of a sub | Withdraw via sub_account_transfer (only if the sub stays in the Safe tier after the transfer) |
Creating
{
"type": "create_sub_account",
"params": { "name": "scalping-desk", "explicit_index": null, "shared_stp_group": false }
}
| Field | Type | Description |
|---|---|---|
name | string ≤ 64 chars | Bookkeeping label |
explicit_index | uint32 | null | Specific slot to claim; null → next free |
shared_stp_group | bool | Required. There is no default — a body without this field fails admission with a missing-field error. true puts the sub in the master's self-trade-prevention group, so the book refuses a match between master and sub. false leaves the sub out of the group, so the two CAN match each other. |
Response:
{
"accepted": true,
"data": {
"sub_index": 0,
"sub_address": "0x<derived>",
"name": "scalping-desk"
}
}
Indices are monotonic — once allocated, they never get reused, even after the sub is emptied and abandoned. Use explicit_index carefully.
Funding
{
"type": "sub_account_transfer",
"params": { "sub_index": 0, "deposit": true, "amount": "1000000000" }
}
amount in USDC base units (6 decimals). deposit: true is master → sub; false is sub → master.
For spot assets use sub_account_spot_transfer (adds an asset field).
Transfer must leave the sub in Safe tier — a withdrawal that would push the sub into T0+ is rejected with MARGIN_INSUFFICIENT. Add margin first, then withdraw the excess.
Trading from a sub
A sub cannot trade today. It holds no key, so it cannot sign an order. See the TL;DR warning.
An agent does not open a path either, and the attempt fails silently.
approve_agent writes the agent under
the recovered signer's account. Its body carries agent, name and
expires_at_ms — there is no owner field and no delegation field. So a master
that signs approve_agent "for" a sub approves an agent on the master. The
action is accepted, the sub's agent set stays empty, and you get no error to
read.
The remap that lets a master act on a sub covers three actions only:
create_sub_account, sub_account_transfer and sub_account_spot_transfer.
Every other action lands on the signer's own account. So a master can move funds
in and out of a sub, and nothing else.
There is no workaround. Run one master account per trading strategy until sub-account signing ships.
Liquidation isolation
A sub's tiered liquidation is computed against its own account value and maintenance margin. A blowup in sub_0 does not put sub_1 or the master at risk.
You can also set a sub's margin mode to StrictIso per-asset so that asset's positions don't contribute to cross-asset PM even if the master is PM-enrolled.
Per-sub PM enrollment
Not available. user_portfolio_margin
enrols the signing account. Its body carries only enroll — there is no
target field — and a sub cannot sign. So a sub cannot enrol in
portfolio margin, and a master cannot enrol one on its
behalf.
The master enrols itself:
{ "type": "user_portfolio_margin", "params": { "enroll": true } }
To run one strategy on portfolio margin and another on classical margin today, use two master accounts.
Querying
curl -X POST https://api.testnet.mtf.exchange/info \
-d '{"type":"account_state","address":"0x<master>","detail":"overview"}'
Returns the sub list. Each row carries exactly three keys: index, address
and equity. equity is one aggregate number — there is no label field and no
clearinghouse state on the row. To read a sub's positions, query
clearinghouse_state with the sub's
address.
Each sub can be read as a first-class account via account_state, open_orders, user_fills and the rest, by passing its address as address. Reads work; writes do not (see the TL;DR warning).
Limits
| Limit | Default | Notes |
|---|---|---|
| Subs per master | 32 | V2 may expand |
| Sub-account name length | 64 chars | UTF-8; no validation beyond length |
| Concurrent transfers in-flight | 8 per master | Mempool cap |
| Master can withdraw from sub | yes, if sub stays Safe | Otherwise rejected |
| Sub can withdraw off-chain | no | Must route via master |
| Sub can have agents | no | approve_agent writes under the signer, and a sub cannot sign |
| Sub can be multi-sig | no | V1 only the master can be multi-sig |
Use-case patterns
Strategy separation
Each strategy has its own agent key, its own liquidation envelope, its own PnL reporting.
Risk firewalling
main book gains: full upside; sub_0 blowup is capped to its deposit.
A/B portfolios
Quarterly comparison of NAV per sub determines which gets more allocation.
Edge cases
Show edge cases
create_sub_accounttakes effect at the next block, like all state changes. A sub cannot approve an agent or trade, so there is no agent-traffic race to plan for.- Master tries to transfer from sub during sub's T1 liquidation. Rejected; sub's collateral is being used to defend. Transfer is allowed once sub re-enters Safe.
- Master deletes / abandons a sub. Not in V1. Subs stick around forever in the index. Empty subs have zero state cost; not worth worrying about.
- Sub's agent key compromised. Revoke via the master (master is sub's master, holds delegation authority). Use the same
approve_agentwithexpires_at_msin the past. - Sub-of-sub. Not supported, and not reachable — a sub cannot sign
create_sub_account.
Sequence — full setup
See also
- Agent wallets — per-sub hot keys
- Portfolio margin — interaction with cross-asset PM
- Margin modes — Cross / Isolated / Strict-Iso per sub
POST /info account_statewithdetail: "overview"— MTF-native query; the sub-account list is one facet of it
FAQ
Show FAQ
Q: Are sub-account fees aggregated with master for tier purposes? A: Yes. The 30-day volume tier rolls up across master + all subs. Trading inside subs counts for the master's tier discount.
Q: Can a sub receive funds from another account directly (not via master)?
A: Yes — the general account-to-account transfer action (send_asset) can target a sub's address just like any account. The funds aren't restricted to flow through master after that point; they're just funds in the sub's balance.
Q: Do subs share a nonce space with master? A: No. Each sub has its own nonce sequence. Master's nonces are master's; sub_0's are sub_0's; etc.
Q: Can I convert a sub-account into a master / detach it? A: Not in V1. A sub is permanently a sub. To "detach," create a fresh account at a different address and transfer.