Trading on the exchange
Why this matters
A business can swap one asset for another — USDT for TRX, say, or across chains — without sending its funds to an exchange that holds them. Both sides move in one step or neither does, the trade settles on Varnir's ledger with no chain gas, and no trading fee is charged today. That is the convenience of a centralised exchange without handing over your keys.
How it works
This is an exchange that settles only with your signature. You trade balances you already
hold on Varnir's L2, an off-ledger matcher pairs orders, and every settlement
is one atomic Varnir.Swap transaction signed by the people trading — never
by Varnir. This page walks through using it; the SDK calls underneath are in
Swaps and gas-free transfers.
The scanner's exchange is at scanner.varnir.site/exchange. The mobile wallet has Make, Take, and Cancel on its Trade tab too; Market orders are scanner-only for now — see "On mobile" below.
What you're actually trading
Every asset you hold on Varnir is a pooled L2 balance, not a coin sitting in one wallet. The exchange lets you trade that balance for someone else's — cross-chain or same-chain, it makes no difference — without either of you handing your keys or funds to a third party. Settlement moves both legs in one transaction or neither. Nothing holds funds in between: the matcher holds the terms of resting orders, never the funds. See Swaps and gas-free transfers for the mechanism.
Make, Take, Cancel, Market
Four actions cover everything:
- Make — post a resting order: what you give, what you want back, and when it expires. This is a limit order — the give/want ratio is your price, and you never settle for worse than it (sometimes better; see below). Signing costs no gas and moves nothing yet; it publishes a signed offer to the order book.
- Take — settle against someone else's resting order, in full or in part.
- Market — skip resting on the book and fill now against the best crossing order, within a slippage tolerance you set.
- Cancel — revoke one of your own resting orders before it's taken or expires.
Naming a price: limit orders and crossing the spread
When you Make an order, "you give" and "you want" together name a price: so much of one asset for so much of the other. The exchange settles your order at that rate or better, never worse.
Two resting orders, or a resting order and an incoming Take, don't need to name the same rate to settle against each other. They pair whenever their prices cross — one side's bid meets or beats the other's ask — and they settle at the resting order's price. If your order was already resting when a better-priced one arrived to take it, you get exactly the price you named. If you're the one arriving and your price crosses by a margin, you keep the difference as price improvement. Stock and crypto exchanges work the same way; it's what makes the book a market rather than a bulletin board of exact-match prices.
Matching is event-driven: when a crossing order arrives, the off-ledger matcher pairs it and submits the settlement at once. A crossing trade typically completes in a fraction of a second; it doesn't wait for a periodic sweep.
Filling now: market orders
A Market order never rests on the book. It fills immediately against the best-priced order that crosses it, immediate-or-cancel (IOC): it settles on the spot against existing liquidity or fails outright. Instead of an exact price you name a maximum slippage, a percentage below the best crossing order's own rate, and the exchange won't settle below that floor. If nothing on the book crosses you, the order is refused, not left waiting.
In today's version a market order fills against at most one resting order. If that order is smaller than what you asked to trade, the rest goes unfilled; it isn't swept across several makers for you. Placing the order again picks up the current book, so finishing a larger trade means repeating the action.
How Take and Market both settle — and why they're different paths
Every resting order in the public book (GET /orders, or getOrderBook() in
the SDK) is a signed artifact, and the book now carries the maker's
signature with it. Varnir.Swap, not the gateway serving the book, is the
sole authority on whether that signature is valid, so publishing it opens no
new trust boundary. What it does open is a direct fill.
So the exchange has two settlement paths, both live today:
- Take (mirror-and-match). Take on a book row posts its exact mirror — same network, same token, same raw amount, give and want swapped — as a resting order of your own. The matcher pairs the two and settles them in one atomic transaction. From your side: click Take, wait a moment, balances update. This is still how the scanner and mobile Take buttons work. It needs no signature up front, because it settles through the same crossing-spread matcher as any two resting orders.
- Market (direct fill). A Market order takes the signature straight off a book row and settles against it in one transaction. No resting order of yours is created. This is the path that needed the maker's signature in the book, which is why it's new.
In short: Take posts the mirror and lets the matcher pair it — the right tool when you've picked a specific row. Market skips the book and fills at the best price now — the right tool when you want the trade done at whatever the market offers.
Balances, reservations, and why you can't double-spend
Nothing above holds funds in escrow. This is what keeps an order book safe anyway, without anyone holding the funds in between.
You cannot double-spend or lose funds. Every settlement — a swap, a fill, a match — reads each side's balance fresh at commit and moves both legs in one atomic transaction. If either side is short, the whole transaction reverts: nothing half-settles, and the counterparty's funds are never touched. The ledger will not let the same balance be spent twice.
Phantom orders. A resting order commits you to give an amount when it's filled, but it doesn't lock those funds — the order is a signed offer, not an escrow. Post an order, then spend the committed balance elsewhere (a withdrawal, another trade), and your order is now unfillable: the next taker's attempt is rejected ("balance too low") and reverts, harming no one but leaving a dead order on the book. The gateway detects these — along with cancelled and already-filled orders — and sweeps them out of the book on its own.
Reserved vs available balance. Because a resting order commits funds without locking them, the SDK tells your total balance apart from what's actually free to spend:
const [bal] = await client.getBalances();
// bal.total — your full L2 balance for this asset
// bal.reserved — committed to your own open resting orders
// bal.available — total − reserved, what you can actually spend now
send, transferOnLedger, and createOrder check available, so you don't
strand one of your own orders by spending what it needs. That guard is a
convenience, not the safety mechanism. It's advisory and best-effort: if it
can't read your open orders it lets the operation through rather than blocking
you. The real guarantee is the contract's balance-at-commit check above, which
protects the funds either way.
Cancelling is immediate on the ledger. cancelOrder writes the cancellation
on-ledger straight away — from that moment the order can never be filled. The
public order book is a separate, cached view that catches up on its next sweep (a
few seconds), so a just-cancelled order may briefly still show there even though
it's already dead. The order is gone; the display is a step behind.
On the scanner
Open /exchange as your web wallet
identity (create or import one on /wallet
first if you haven't). The page shows:
- Order book — every resting order, grouped by market (give asset → want asset). Rows that are yours are marked Yours; every other row has a Take button.
- A ticket — the Make/Take/Market form. A Limit / Market toggle picks the mode when you're not mid-Take. A Limit ticket has an optional Price field (derives "You want" from "You give" at that rate) and an expiry (1, 6, or 24 hours); a Market ticket has a Max slippage percentage instead. Click Take on a book row and the ticket switches to Take mode, pre-filled with the mirrored counterpart for you to review before signing.
- Your L2 balances and your resting orders, so you can see what you have to trade and cancel anything you no longer want resting.
Either leg can be any registered token, not just a native asset: pick Sepolia USDT or Tron USDT from the token dropdown the same way you'd pick ETH or TRX. The browser has the full token registry.
To Make a limit order: with the ticket on Limit, fill in what you give, either a price or "you want" directly, and an expiry, then click Sign & post order. The order is signed in your browser with your wallet's identity key and appears on the book immediately.
To place a Market order: switch the ticket to Market, fill in what you give, set your max slippage (a percentage below the best crossing order's own rate; the default is 0.5%), and click Sign & fill at market. It settles immediately against the best crossing order in the book. No resting order is created; if nothing crosses, the page says there's no liquidity and leaves nothing pending.
To Take an order: click Take on a book row. The ticket fills with the mirrored terms. Leave the amounts alone to take it in full, or enter a smaller "You give" for a partial fill ("You want" rescales at the same rate; the remainder stays resting for the next taker). Review and click Sign & post counterpart. The page watches the book; when the taken row disappears (or shrinks, for a partial fill) it shows Settled and refreshes your balances.
To Cancel an order: find it under Your resting orders and click Cancel. This writes an on-ledger cancel marker signed by you — authoritative even if the matcher's own copy of the order is stale. A cancelled order can never be taken.
On mobile (the Trade tab)
The wallet-mobile app's Trade tab has Make, Take, and Cancel, signed on-device with your wallet's own key:
- A New order card to Make: pick the network and token you're giving and the network and token you want, an amount (or a Price to derive "you want" from "you give", the same limit-order pricing as the scanner), and an expiry, then Review order → Post order.
- Your resting orders, each with a Cancel button.
- The live order book of everyone else's resting orders, each with a Take button.
Mobile now supports token legs. Until recently an order made on mobile could only trade one chain's native coin for another's: posting a signed order means scaling a human amount by the token's decimals, and the on-device signing helper didn't have the on-ledger token registry it needed to do that safely. Now it does. Each network picker on the New order card carries a token dropdown (any registered token, or the native asset), the same as the scanner.
Market orders on mobile are a follow-up. The Trade tab has no Market
ticket yet; that's a separate increment on top of the SDK's marketOrder,
tracked for a later release. Make (limit) and Take both work on mobile
today. Only "fill now at the best available price" is scanner-only for the
moment.
Signing on your phone from the scanner
If you've paired your phone with the scanner (the wallet dock's QR pairing), the exchange page offers a Sign on phone toggle. Turn it on and Make, Take, and Cancel go through the pairing channel instead of your browser: the phone shows what you're approving, you confirm on the device, and it signs and submits with the key it holds, which never leaves it. Only the result comes back over the wire: an order hash for Make and Take (the resting order was posted off-ledger; nothing has settled yet when you see the hash), or a ledger transaction id for Cancel, which is an on-ledger operation.
Phone-signed Make uses the same on-device signing helper as the mobile app's Trade tab, so it has the same token-leg support: the phone resolves a token's decimals from its own registry before signing, and refuses a token it doesn't recognize rather than risk a bad scale factor. Take copies the book row's raw legs exactly, so it's token-safe regardless. Market orders aren't offered over the pairing channel yet; Make, Take, and Cancel are.
Signing with the browser extension
If the Varnir browser extension is installed and connected to the scanner, the exchange page sends Make, Take and Cancel to the extension instead of signing in the page. Each one opens the extension's own approval window with a plain summary, and the extension signs and submits. As with the phone, market orders aren't offered this way: the ticket switches to a limit order.
Current limits
- Market orders fill at most one resting order per click. If the best crossing order can't absorb your whole request, the rest goes unfilled — reported back, not silently dropped — rather than swept across several makers. Place the order again to continue against the refreshed book.
- Mobile doesn't have a Market ticket yet. Make and Take both work on mobile with full token support today; "fill now at the best price" is scanner-only until that follow-up ships.
- No exchange fee today. See Exchange pricing for what a future fee could look like — nothing is charged now.
- Treasury-protected identities can't yet approve a trade with a second key. An order-level approval flow mirroring AI agent payments' propose/verify model is planned, not available today. Until it lands, such an identity is refused a fill or a match rather than allowed to trade on one key.
Next
- Swaps and gas-free transfers — the SDK calls
(
createOrder,fillOrder,marketOrder,postOrder,getOrderBook,cancelOrder) behind everything on this page. - Exchange pricing — why nothing is charged yet, and what could change.