Spot trading
Live. Plain spot trading is shipped — a token-for-token order book, separate from perps, with no leverage and no positions. (Leveraged spot is the separate, planned spot-margin track.)
Non-leveraged spot is the one Sharia-compliant product on MetaFlux — see Sharia compliance. Leveraged spot margin is not.
TL;DR
Spot is a token-for-token central limit order book: you swap one token for another at a price you choose. It is entirely separate from perps — separate books, separate balances, no leverage and no positions. You trade only what you own. A resting spot order locks the funds it would owe on fill into a reserved balance (escrow); those funds are paid to the counterparty on fill, or refunded to you on cancel.
A spot order is just another /exchange action —
spot_order to place,
spot_cancel to cancel. Both are
sender-authorized by default (omit owner and the recovered signer is the
trader); both also take an optional owner so an approved
agent wallet can trade for the account it is
approved for.
The three orders the node runs FOR you — TWAP, the scale ladder and the chase — also accept a spot pair id. See The three on a spot pair.
What a spot pair is
A spot pair trades a base token against a quote token (e.g. B/Q). The
order side picks the direction:
side | You give | You receive | Escrow locked while resting |
|---|---|---|---|
bid (buy) | quote | base | quote — notional at your limit price |
ask (sell) | base | quote | base — the base you are offering |
The order field is the spot pair id (pair), which is distinct from a perp
market id and from a token id. Pairs are deployed under
MIP-1 (spot token standard + market deploy); each carries its
own base/quote tokens, size decimals, optional minimum notional, and fee
overrides.
Reserved-balance escrow
This is the core of how spot stays solvent without leverage. When a gtc / alo
order (or the un-crossed residual of one) rests on the book, the protocol
moves the funds it would owe on a full fill out of your spendable balance into a
reserved balance:
- A resting bid reserves quote equal to its notional at the limit price
(
size × limit_px). - A resting ask reserves the base it offers.
Reserved funds are not spendable. They are:
- paid to the counterparty when the order fills,
- refunded to your spendable balance on cancel, on self-trade-prevention, or if the market is deactivated.
Per-token balances are conserved exactly across every rest, fill, cancel, and STP event — spendable plus reserved is invariant per token per account (it is fuzz-verified across randomized rest/cross/cancel streams).
Affordability clamping
You can never rest or fill more than you can fund. At admission the order size is clamped to what your balance covers:
- a priced bid (
limit_px > 0) is clamped byquote_balance ÷ limit_px, - a market bid (
limit_px = 0) is clamped by walking the resting asks level by level against your quote balance — there is no single price to divide by, - an ask, priced or market, is clamped by the base you actually own.
The market-bid walk counts only asks the engine will actually fill. It skips your own asks and every ask in your self-trade-prevention group — a shared sub-account, or the other side of a Metaliquidity vault/operator pair. The engine refuses to fill those, so counting them would price your budget against liquidity you cannot buy, and the order would then walk deeper than the budget allows.
An order that is entirely unaffordable is refused with
insufficient spot balance — nothing fills, nothing rests, no order id is burned.
The refusal is about money, not liquidity: a funded order that finds no
counterparty still answers filled with total_sz: "0". One exception stays an
accepted no-op: a market buy that holds quote, when the pair carries no ask the
engine would fill for you — every ask is your own or a group peer. You have the
money, so this is not a balance error. That no-op burns no order id and emits no
STP cancellations, so the peers' orders stay on the book and their escrow stays
reserved. An ask the engine WOULD fill, that your quote cannot buy one lot of, is
a refusal, not a no-op. A partially-affordable order trades/rests the
affordable portion. Because the clamp runs before matching, every resulting
fill and every escrow reservation is funded; there is no post-match fill drop.
The refusal ships with the next node release after 0.9.7. Until then, a live node
accepts an entirely unaffordable order as a no-op and answers filled with
total_sz: "0".
Matching, fills, and fees
Spot matching is the same price-time CLOB the rest of MetaFlux uses. A fill swaps base for quote at the maker's resting price.
Today both sides pay their fee in the QUOTE token of the pair. The fee leaves the payer's spendable quote balance, never the base balance. Fees accrue to a dedicated spot fee account, separate from the perp fee pool.
| Side | Fee taken from | Rate |
|---|---|---|
| Taker | your spendable quote balance | pair taker_fee_bps, else the global spot default |
| Maker | your spendable quote balance | pair maker_fee_bps, else the global spot default |
A buy is credited the base token minus its fee, taker and maker alike,
and a sell pays from the USDC it receives. So the fill sz stays gross while
the balance credit is net — read the balance, never the sum of fill sizes.
Buy admission reserves no quote fee headroom. The full rule, the in-kind referrer
share and the sub-lot dust are in
fees.
Spot fees are per-pair: a pair may set its own taker_fee_bps /
maker_fee_bps, and when unset the global spot default applies. Spot uses a flat
per-pair rate — the perp volume / maker-rebate / staking tiers do not apply to
spot. Query the live values in the /info fee_schedule
response; see fees for the settlement model.
Time-in-force
Spot orders carry the same TIF set as perps, with one spot-specific rule:
tif | Behavior on spot |
|---|---|
gtc | Crosses what it can; any residual rests (escrow-backed) until filled or cancelled |
alo | Add-liquidity-only; a crossing alo is rejected (never takes). A non-crossing alo rests |
ioc | Crosses what it can immediately; the residual is discarded — never rests, never escrows |
aon is rejected (no core equivalent). Self-trade prevention uses the same
stp_mode set as perps (cancel_oldest / cancel_newest /
cancel_both); reject is not supported.
A market order must be ioc. Send limit_px = 0 to place a market order —
it crosses the book at whatever price is available, bounded by your balance (a
buy walks the asks up to what your quote funds; a sell is bounded by the base you
own). A market order carries no resting price, so it must use tif: "ioc";
gtc or alo with limit_px = 0 is rejected. A priced order (limit_px > 0)
may use any tif.
Lifecycle — cancel refunds escrow
spot_cancel retires one of your
resting orders by oid on a pair and refunds the escrow it locked back to your
spendable balance.
- Owner-only. Only the order's owner may cancel it; a third party is rejected
(
not the order owner). - Typed miss. An unknown or already-gone
oidreturnsorder not found(harmless). - Always available. Cancels are not gated by the spot halt — even when new orders are disabled, you can always exit a resting order and reclaim its escrow.
Limits and governance
- Resting-order cap. Each account may rest up to 1000 orders per spot
pair; a new resting order past the cap is rejected (
spot resting-order cap reached — cancel some orders first). Recognized market-maker accounts are exempt.iocorders never rest, so they are never subject to the cap. - Minimum notional. A pair may set a minimum notional; an order below it is rejected.
- Spot halt (governance). Spot trading can be globally enabled or disabled by
governance. When disabled, new orders are rejected (
spot trading disabled), but cancels still work so resting escrow is never trapped.
Reading spot state
Spot balances and open spot orders are queryable via
POST /info. A spot_order returns a synchronous
per-order status once it commits — the real assigned oid with a resting or
filled entry (or error), or pending if no commit lands within the
order-wait window — the same status union as the perp
submit_order.
Relationship to spot-margin and Earn
Plain spot is the baseline: trade only what you own, no leverage, no liquidation. Two planned overlays build on it:
- Spot margin (planned) — borrow quote against collateral to buy spot with leverage, with a maintenance margin and a liquidation price.
- Earn (planned) — a USDC lending pool that funds spot-margin borrows and earns the borrow interest as yield.
Both are opt-in overlays; plain spot is unaffected by them.
See also
spot_order/spot_cancel— the wire actions and field tables- Order types — TIF and STP semantics shared with perps
- Fees — the spot fee schedule and quote-side charging
- Spot margin — the planned leveraged spot track
- MIP-1 — spot token standard and market deploy
FAQ
Show FAQ
Q: Do I need collateral or margin to trade spot? A: No. Spot is balance-only — you trade what you own. There is no margin, no leverage, and no liquidation. (Leverage is the separate, planned spot-margin track.)
Q: What happens to my funds when my order is resting? A: They are held in a reserved balance (escrow) — not spendable, but yours. They pay the counterparty on fill, or come back to your spendable balance on cancel.
Q: Why did my large buy only partially fill / rest?
A: Affordability clamping. The order size is reduced to what your quote balance
funds at the limit price. An entirely unaffordable order is refused
(insufficient spot balance). Not live yet: a live node accepts it as a no-op.
Q: Can I place a spot market order?
A: Yes — send limit_px = 0 with tif: "ioc". gtc / alo require a positive
limit_px.
Q: Are spot fills and perp fills on the same book? A: No. Spot has its own books, balances, and fee account, entirely separate from perps.