Books
A book is identified by itstoken_pair:
- Token ids are NEAR Intents multi-token ids (
nep141:<ft contract>ornep245:<contract>:<id>). - Only one direction of a pair exists: if
QTC/USDTexists,USDT/QTCcannot be created. - Each book has its own fee config, minimum order amounts and tick size. Only the contract’s managers create books.
- Orders sit at price levels: asks by price ascending, bids descending; inside a level, by time (
created_ts, the block timestamp in nanoseconds).
Sides
Through
mt_transfer_call the side follows from the token you send. Events use "s" and "b".
An order’s amount / order_balance is in the token it holds: base units for asks, quote units for bids.
Raw prices
Prices are raw: quote units per one base unit, as a decimal string (UD128, up to 38 decimal places).
Back:
human_price = raw_price × 10^decimals(base) / 10^decimals(quote). Use decimal strings or big integers, never
floats, for anything you sign.
Views and events return prices normalized, without trailing zeros: a price placed as "0.0001390" comes back as
"0.000139". Compare prices as numbers, not as strings.
A fill’s quote amount is base × raw_price in integer units, rounded by the contract; fees round up (ceil). Read exact
amounts from the quote view or the trade event instead of recomputing them.
Minimum order amount
Each book hasmin_order_amount: { base, quote } (raw units), shown by
get_active_pairs.
- A new order below the minimum for the token it holds does not rest. From a transfer, it is refunded in the same
transaction (
taker_remainder.refundin the quote,rfin the trade event); in a batch, it panics. - A maker order a trade leaves below the minimum, or unable to buy one base unit, is closed with a refund (
closed_ordersin the quote,cin the trade event).
Tick size
Each book has atick_size (a raw price step, 0 = none). Every new limit price, from a transfer or a batch, must be
an exact multiple of it, or the call panics. Resting orders and market orders are not affected.
Round your prices to the tick away from the market: bids down, asks up.
Fill limit
A taker order fills at mostmax_fills maker orders (default and cap 128, 0 is rejected). Set it in the order msg
and pass the same value to get_quote_pub. Past the limit the call does not fail: the rest is refunded (truncated: true
in the quote). Gas and the 16 KiB log limit can stop a fill earlier, with the same effect.
The NEAR Intents relay gives execute_intents 300 Tgas: orders sent through it should use max_fills ≈ 40. Direct
mt_transfer_call transactions can attach more gas; see gas.
Quote equals execution
get_quote_pub decides everything a trade does: the maker orders it fills and how much, the ones it closes
(closed_orders), whether the taker’s remainder rests (new_order) or is refunded (refund), and every balance it
moves (increase_user_balance). Execution applies the quote as is and checks it. If the book did not change in between
and the receipt has enough gas, the trade matches the quote to the unit.
The view cannot see gas and quotes as if there were enough. With less gas, execution fills a prefix of the quoted fills
and refunds the rest (rf); with too little for one fill it panics (Not enough gas to fill the order) and the transfer
is refunded. Payouts that do not fit in the remaining gas are credited to internal balances instead of paid out (the
trade’s np).
Dead orders
A resting order is dead when:expires_at != 0andexpires_at <= block_timestamp(expired), or- its epoch is below its maker’s current epoch in that book (stale epoch, after
cancel_all/bump_epoch).
- Views hide it.
get_orderbookand the depth views skip it.get_volume/get_active_pairsvolumestill count it (it still holds its balance).is_order_livetells you the state of one hash. - Matching closes it. A trade that meets it does not fill it: it refunds its whole balance to the maker and lists it
in
closed_orders/ the trade’sc. It counts againstmax_fills, gas and the log budget like a closing fill. - Anyone can prune it.
prunecloses listed dead orders; refunds go to the makers’ internal balances. - It still takes its slot in the 500-per-level and 200-per-owner limits, and a batch’s search for the best live price
scans it (at most 128 orders per side). Close your own dead orders in your next batch’s
cancel; see Build a market maker.
Internal balance
The contract keeps a per-account, per-token balance (get_user_balance).
Makers fund many orders from it with one atomic
batch instead of one transfer per
order.
Payout modes
set_payout_mode chooses where a maker’s proceeds go:
With
internal, filled inventory backs the next batch without a deposit round trip. The mode does not change what you
receive as a taker or fee collector. prune refunds always go to the internal balance.
Order hash
An order is identified bysha256(borsh(Order)) with Order = { side, maker, price, token_pair, created_ts }, shown as
64 hex characters. Expiry and epoch are stored separately and are not part of the hash.