Skip to main content

Sub-accounts

info

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.

warning

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_account never fills it, and approve_agent adds 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

GuaranteeMechanism
A sub's loss cannot drain masterSub liquidates against its own balance; master sees only the transfer ledger
A sub's loss cannot drain other subsSame — each sub is a first-class isolation boundary
Master CAN choose to backstop a losing subVoluntarily, via sub_account_transfer deposit
Master CANNOT involuntarily backstopA sub's blowup is the sub's, full stop
Master can liquidate out of a subWithdraw 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 }
}
FieldTypeDescription
namestring ≤ 64 charsBookkeeping label
explicit_indexuint32 | nullSpecific slot to claim; null → next free
shared_stp_groupboolRequired. 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

warning

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

LimitDefaultNotes
Subs per master32V2 may expand
Sub-account name length64 charsUTF-8; no validation beyond length
Concurrent transfers in-flight8 per masterMempool cap
Master can withdraw from subyes, if sub stays SafeOtherwise rejected
Sub can withdraw off-chainnoMust route via master
Sub can have agentsnoapprove_agent writes under the signer, and a sub cannot sign
Sub can be multi-signoV1 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_account takes 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_agent with expires_at_ms in the past.
  • Sub-of-sub. Not supported, and not reachable — a sub cannot sign create_sub_account.

Sequence — full setup

See also

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.