Koine docs

Trading

How a buy or sell runs from tap to fill, what it costs, how SOL gets in and out, and what can pause trading. The bot and the web terminal use the same trading code, so everything here applies to both.

How a buy runs #

  1. You pick a token and an amount.
  2. Koine's own checks. A buy stops if the coin wasn't launched on Koine ("Koine only trades coins launched on Koine."), if Koine can't reach the launchpad's list of coins to check, if buying is halted for everyone, your account is not active, you haven't chosen an untie delay or accepted changed terms, the amount isn't above zero, a withdrawal of everything is waiting, or the wallet can't cover the buy. Koine sets no size limit of its own.
  3. The balance check. The wallet needs the amount, plus Koine's fee, the tip, 0.0021 SOL for network and priority fees and a temporary wrapped-SOL account (returned), 0.0005 SOL left behind so the position can later be sold, and 0.0021 SOL rent if you have no token account for that token yet. SOL set aside for a waiting withdrawal doesn't count. If you're short, the message says how much you can buy.
  4. Your knots. Any knot you tied can hold the buy.
  5. Quote and signature. Jupiter builds the route. Koine checks Jupiter's answer against the order before anything is signed: the program, the wallet as the authority, the input and output mints, that the output goes to the wallet's own token account, the input amount, the minimum output, and every extra instruction around the swap. Koine adds its fee and the tip to the same transaction. Privy signs it only if every instruction passes the wallet's swap policy. With swap co-signing on, the withdrawal approver must co-sign it too (see Security).
  6. You confirm. Every knot is checked again inside a per-trader lock, so a knot tied since the quote, or a buy that landed since, can still hold it. Nothing is spent if it does.
  7. It's sent. The signed transaction goes to Helius Sender and to Koine's RPC (Helius unless TRADE_RPC_URL is set) at once, with MEV Protect on, and is re-sent every 2 seconds until it confirms or can no longer land, for up to 90 seconds. The same signed bytes are re-sent, never re-signed, so one press can't land twice.
  8. The fill is recorded from what changed on chain. A position's cost is the SOL that left the wallet, less rent for new accounts.

Source: trade/server/trading.ts (quoteBuy, recheckBuy), trade/server/presale.ts (notKoine), trade/server/rules.ts (checkBuy), trade/server/web.ts (/web/quote, /web/send), trade/server/bot.ts (DELAY_FREE_COMMANDS), trade/server/build.ts (checkRoute, compose), trade/server/orders.ts (prepare, execute, heldAtPress, record), trade/server/send.ts

How long a quote lasts #

A signed quote is kept in the service's memory for 10 minutes. If it was signed against a recent blockhash more than 45 seconds earlier, or its nonce lane was used since, Koine rebuilds and re-signs it when you confirm, with the same amount and slippage. The price can differ from the quote you saw. Your slippage still sets the minimum.

Quotes are pre-signed on a durable nonce when the wallet has a free nonce lane. Lanes are created once a wallet receives a deposit of at least 0.01 SOL or passes a buy's balance check, if Koine's operations wallet (TRADE_OPS_KEYPAIR) is set. It pays their rent. Without a lane, a recent blockhash is used.

The web terminal replaces a quote on screen every 20 seconds, and a quote older than that can't be sent from the page.

The confirm button carries the quote's id, so double taps collapse to one order. Each trader can ask for at most 60 buy quotes a minute.

Source: trade/server/orders.ts (DRAFT_TTL_MS, BLOCKHASH_FRESH_MS, stale), trade/server/nonce.ts, trade/server/deposits.ts, trade/server/config.ts (laneMinDepositLamports), trade/server/trading.ts (tooFast), app/web/src/terminal/components/terminal/useTrade.ts

If Koine can't tell how a send ended #

After a crash or a timeout, a recovery job runs at startup and every minute. It reads each open order older than 30 seconds from chain, records what landed and tells you. A nonce transaction that hasn't landed after 10 minutes gets its nonce advanced, so it can never land later. That costs one network fee.

While a trade of a token is unresolved, the web terminal won't quote another trade of that token that could double it.

Source: trade/server/orders.ts (settleOrders, settleOne, retire), trade/server/server.ts, trade/server/web.ts (/web/quote)

How a sell runs #

No knot ever holds a sell. A sell stops only if sells are halted for everyone or you hold none of the token.

Before a sell, Koine reads the wallet's real token balance. If the wallet holds less than Koine's record (for example after a key export), the position shrinks to match, and the sell is sized from that.

In the bot you sell 25, 50 or 100%. Opening a position in the bot signs those three sells ahead of time, on the position's nonce lane when there is one, so only one of them can land. Tapping one drops the other two. On the web you can sell any percentage, to two decimals.

Source: trade/server/trading.ts (quoteSell, presignSells), trade/server/held.ts (syncHeld)

If a trade doesn't land #

What you see What happened
The price moved past your slippage before it landed. Only the network fee was spent. The chain refused a fill below your minimum
Not enough balance when it landed. Only the network fee was spent. The wallet had less SOL by then
Failed on chain. Only the network fee was spent. Another on-chain failure
It expired without landing. Nothing was spent. It didn't land before its blockhash or nonce expired
Every route refused the transaction. Nothing was spent. No sender accepted it
Couldn't confirm the result. Check your wallet on Solscan before trying again. It may have gone out; the recovery job will settle it
No route for this token right now Jupiter has no route, often because the token is too new or has no liquidity
Jupiter's answer didn't match the order, so it wasn't signed. Nothing was spent. Koine's route check refused Jupiter's answer

Source: trade/server/orders.ts (describeChainError, EXPIRED, UNSURE), trade/server/build.ts (BadRoute), trade/server/bot.ts (explain)

Slippage #

Slippage is how far the price may move before a trade gives up. You set buy and sell slippage separately. New traders start at 10% for buys and 15% for sells. The service also caps the slippage an order uses at 50% (TRADE_MAX_SLIPPAGE_BPS).

Where Options
Bot 5%, 10%, 15%, 25%, 50%
Web 5%, 10%, 15%, 25%, 50%

Settings are not knots: they change at once. Your minimum output is written into the swap instruction, so the chain refuses a fill below it. Slippage protects a single swap, not a position.

Source: trade/server/users.ts (DEFAULT_BUY_SLIPPAGE_BPS), trade/server/config.ts (hardMaxSlippageBps), trade/server/bot.ts (SLIPPAGES), app/web/src/terminal/components/terminal/SwapCard.tsx (SLIPPAGES)

Fees #

Cost Amount Goes to
Koine's fee 1% (FEE_BPS, default 100) of the SOL spent on a buy, or of the minimum SOL out on a sell. 0.9% if you joined through a referral link Koine's fee wallet, as a separate transfer in the same transaction
Tip 0.00001 SOL on โšก Fast, 0.001 SOL on ๐Ÿš€ Turbo A Helius Sender tip account
Network and priority fees Set by the network. Priority fees are capped at 2% of the order's value, or 0.0001 SOL if that's more Solana
Rent About 0.002 SOL per new token account The token account. Koine closes empty token accounts later and the rent comes back (see below)

Each quote shows Koine's fee and the tip. Presale deposits, withdrawals, claims and refunds pay no Koine fee.

Speed. โšก Fast uses only Sender's staked route, plus the RPC. ๐Ÿš€ Turbo uses all of Sender's routes and a higher priority fee estimate. Exits pick their own speed (see Exits).

Source: trade/server/config.ts (feeBps, TIP_LAMPORTS, priorityCapBps, priorityFloorLamports), trade/server/orders.ts (prepare), trade/server/build.ts (priorityCap), trade/server/referrals.ts (feeBpsFor), trade/server/presale.ts

Rent coming back #

A swap can open token accounts, each holding about 0.002 SOL of rent. About 20 seconds after an order lands, and for every wallet at startup, Koine closes the wallet's empty token accounts back to the wallet in a separate transaction. Wrapped SOL is left alone. It waits while you have an open quote. Its priority fee is at most 1/20 of the rent that comes back. You get a "โ™ป๏ธ Rent back" message. Nothing is closed while sells are halted.

Source: trade/server/refunds.ts

Deposits #

  • Send SOL to your wallet's address.
  • The service watches each wallet live over a WebSocket and sweeps every wallet every 10 minutes for anything a dropped connection missed.
  • A deposit is a confirmed plain SOL transfer into the wallet from another address. Each is recorded once and announced in Telegram or your web inbox, except a referral payout, which gets its own message. SOL that arrives inside a more complex transaction still counts in your balance, but you may get no message.
  • Tokens sent in arrive but aren't tracked, so Koine can't sell or withdraw them.

Source: trade/server/deposits.ts

Withdrawals #

  • SOL only, to one saved address. It can't be your Koine wallet itself. Your first address applies at once, unless the approver's reply names a later time. A change waits your untie delay, or the approver's time if that's later, and you can stop it until then. Telegram accounts save the address in the bot. Accounts with a sign-in wallet change it on the web with a fresh signature.
  • Delay. A withdrawal waits your untie delay, then goes out on its own. You can cancel until then. With no delay it goes at once. Koine adds no delay of its own, but if the approver's reply names a later time, it waits for that.
  • Which address. It goes to the address saved when it sends.
  • Set aside. A waiting withdrawal's SOL can't be spent on buys. A waiting withdrawal of everything holds all buys.
  • Amount. If the wallet holds less by then, what's there is sent, less the 0.000005 SOL network fee, and the message says so. "Everything" sends the balance less that fee.
  • Two keys. A withdrawal is signed by the wallet's 2-of-2 owner: the trading service's key and the withdrawal approver's key. The approver is told about each withdrawal when you ask for it. The owner policy allows SOL only to the saved address.
  • Retries. A send that expires unconfirmed, or that the approver or the network doesn't answer, is tried up to 3 times in all. An approver refusal or a failure on chain ends it. One left mid-send is settled from chain after 3 minutes.
  • Receipt. You get the amount and a Solscan link when it lands.

No knot ever holds a withdrawal. A withdrawals halt pauses sending.

Source: trade/server/withdraw.ts, trade/server/approver.ts, trade/server/policy.ts (ownerRules), trade/server/bot.ts (confirmWithdrawScreen)

Key export #

Exporting gives you the wallet's private key, so you no longer need Koine to reach the funds. Getting it out needs Koine's servers.

From the bot:

  1. Tap ๐Ÿ’ผ Wallet โ†’ ๐Ÿ”‘ Export key โ†’ ๐Ÿ”‘ Request export. It waits your untie delay, if you set one, and you can cancel until then.
  2. When it unlocks, the bot sends a one-time link to koine.markets/export. It works once, for 30 minutes. An unused link lapses with a message.
  3. The page makes a one-time HPKE key pair in your browser and sends only the public key, with the link's token. The token sits after # in the link, so loading the page doesn't send it anywhere; the page posts it once, then removes it from the address bar.
  4. The service opens an export window in the wallet's owner policy, from 60 seconds before to 600 seconds after the page's request, asks Privy to export, and closes the window right after (if closing fails, it lapses at the end). Both policy changes and the export carry the approver's co-signature.
  5. The key arrives encrypted to your browser's key, and the page opens it. It never passes through Telegram or Koine's servers in readable form: the site's server only passes the ciphertext from the trading service to the page.

From the web (website accounts): signing in again starts the export, it waits your untie delay, and signing in again once more reveals it in your browser within 24 hours of unlocking. See Accounts and sign-in.

After an export, whoever holds the key controls the wallet outside Koine, where knots, delays and signing rules can't reach.

Source: trade/server/export.ts, trade/server/server.ts (/internal/export), trade/server/privy.ts (exportWallet), app/server/terminal.ts (exportReveal), app/web/src/terminal/components/terminal/PlainPages.tsx (KeyExportPage), app/web/src/terminal/lib/keyExport.ts

If Koine shuts down #

This is a policy commitment. No code enforces it.

  • Koine posts notice on X (@koinemarkets) at least 30 days before shutting down.
  • New trading stops.
  • Withdrawals and key export stay open until the shutdown date.

The kill switch #

โ›” Stop all buying is a knot. Tie it with /stop, the โ›” Stop buying button on Home, or Stop buying on the web. Tying is instant and holds every buy. A limit buy or a buy at open that comes due while it's tied is refused and doesn't come back. Sells, exits and withdrawals still work. Untying follows the usual rule.

In the bot, /stop also offers ๐Ÿ”ด Sell everything now when you hold something. On the web, Sell everything asks first, then sells each position.

Source: trade/server/bot.ts (stopBuying, sellEverything), trade/server/web.ts (/web/stop, /web/sell-all), trade/server/knots.ts, trade/server/limits.ts (fire), trade/server/presale.ts (fireOpenBuy)

Admin halts #

During an incident, Koine's admins can pause trading for everyone with /halt. There is one switch each for buys, sells, withdrawals and keys, and all sets all four. /halt with nothing after it halts buys.

Halt Effect Message
Buys New buy quotes and presale deposits and claims are refused. Limit buys and buys at open wait, and can fire after it lifts "Koine has paused buying for everyone right now. Sells still work." If sells are halted too: "Koine has paused all trading for everyone right now, sells included."
Sells New sell quotes are refused, exits wait, presale withdrawals and refunds are refused, and rent refunds stop "Koine has paused all trading during an incident, sells included. Updates are on X: @koinemarkets."
Withdrawals Requests are recorded, and nothing is sent until it lifts "recorded, not sent", with a cancel button
Keys Key export links and reveals wait, address changes are refused, and a change that came due waits "Koine has paused key export during an incident."

A halt is checked when a quote is made, so a quote signed just before it can still be confirmed. Exits keep tracking highs during a sells halt and can fire after it lifts.

Source: trade/server/bot.ts (haltCommand), trade/server/rules.ts, trade/server/trading.ts, trade/server/exits.ts, trade/server/limits.ts, trade/server/presale.ts, trade/server/withdraw.ts, trade/server/export.ts, trade/server/refunds.ts