Overview

Desk is an over-the-counter desk for BNB Smart Chain. It lets a holder sell a whole bag, or a buyer pick one up, without routing the size through a PancakeSwap pool.

The problem

Liquidity on most BEP-20 coins sits in one or two pools. A pool prices every trade on a curve: the bigger the trade relative to the pool, the worse the price, and the further the chart moves. Selling $100,000 into a pool that holds $1,000,000 on each side costs the seller about 9.3 % of the bag and drops the chart about 17 %. Everyone watching sees the candle.

The usual answer is to split the sale over days, or to find a buyer in a group chat and trust them to send first. The first leaks value and time. The second is how people get robbed.

What the desk does

  • Asks. A holder lists an amount of a coin for a total price in BNB. The tokens stay in the holder's wallet; the desk only holds an approval.
  • Bids. A buyer offers BNB for an amount of a coin. The BNB is escrowed in the contract so the bid is real.
  • Private offers. Either kind can name one taker. Only that wallet can fill it. The maker sends the link.
  • One transaction. When an offer is taken, the contract moves the tokens and the BNB in the same transaction. If any part fails, nothing moves.

There is no backend, no account, no order matching server. The book is the contract's storage; this site reads it from a public BNB Smart Chain node and writes through your own wallet.

What it is not

  • Not a market maker. Nobody quotes you a price; another person has to want the other side.
  • Not a router. The desk never touches PancakeSwap, so it can't give you a better pool price either.
  • Not custody. Asks hold nothing. Bids hold only the BNB a buyer chose to escrow, and the buyer can take it back at any time.

Status

The contract source is complete and is the same design that already runs as an OTC desk on another EVM chain, ported to BNB. The BNB Smart Chain deployment address is published on the token page, in config.js and on X at launch. Until then the desk page reads an empty book.

How it works

Three calls carry the whole desk: post, take, cancel. Here is what each one moves.

SELLERholds 4.2M TOKENapprove(desk) DESK CONTRACTask #A124.2M for 18 BNBholds: nothing BUYERtakeAsk(12, 4.2M)value: 18 BNB tokens tokens → ← 18 BNB 17.946 BNB ONE TRANSACTION · SELLER TOKENS → BUYER · BUYER BNB → SELLER (MINUS 0.30 %) · OR NOTHING MOVES
FIG. 1 · An ask being taken. The desk never holds the tokens; it pulls them from the seller and pushes them to the buyer inside the same call.

An ask, step by step

  1. The seller approves the desk for the amount (one ERC-20 approve).
  2. The seller calls postAsk(token, amount, priceWei, taker, expiry, partialOk). The contract checks the balance and the approval, then writes the ask to storage and emits AskPosted.
  3. A buyer calls takeAsk(id, amount) with BNB attached. The contract computes the cost pro rata, pulls the tokens from the seller to the buyer, sends the BNB to the seller minus the fee, and refunds any extra BNB.
  4. Partial fills repeat step 3 until nothing is left. The last fill pays exactly what remains, so rounding never leaves dust.

A bid, step by step

  1. The buyer calls postBid(token, amount, taker, expiry, partialOk) with the BNB as msg.value. The BNB stays in the contract.
  2. A holder approves the desk and calls takeBid(id, amount). The contract pulls the tokens to the buyer and pays the holder from the escrow, minus the fee.
  3. The buyer can cancel at any time and gets back the BNB still escrowed. After expiry anyone can close the bid; the refund still goes to the buyer.

Private offers

Set taker to a wallet address and only that wallet can fill. The site gives every offer a link (offer.html#ask/12); send it to your counterparty. Anyone can read a private offer, only the named wallet can take it.

What the contract checks

  • Every token move is measured before and after. A token that takes a tax on transfer, or that rebases down, is rejected with TokenTaxed instead of short-changing one side.
  • An ask is filled straight from the seller's wallet, so if the seller sold the tokens elsewhere or revoked the approval, the fill reverts and the buyer's BNB never leaves.
  • Expiry is between now and 30 days. Self-trades revert. All state changes sit behind a reentrancy lock.

Quickstart

From the desk page in under a minute, or straight against the contract with Foundry's cast.

From the site

  1. Open the offers page and connect a wallet on BNB Smart Chain (chain id 56). The site asks to switch if you are elsewhere.
  2. Pick the coin on the left, or paste its address in the search box.
  3. In the right panel choose Sell a bag or Buy a bag, type the amount, press a price button (−10 %, −5 %, Pool, +5 %) or type a total in BNB.
  4. Choose how long it stays open, whether partial fills are fine, and optionally one private taker.
  5. Confirm in the wallet. An ask asks for an approval first, then the post. A bid sends the BNB with the post.

From the command line

Replace $DESK with the published address and $TOKEN with the coin.

export RPC=https://bsc-dataseed.bnbchain.org
# 1. approve the desk for 4,200,000 tokens (18 decimals)
cast send $TOKEN "approve(address,uint256)" $DESK 4200000ether --rpc-url $RPC --account me
# 2. ask 18 BNB for all of it, open to anyone, 7 days, partial fills ok
cast send $DESK "postAsk(address,uint256,uint256,address,uint64,bool)" \
  $TOKEN 4200000ether 18ether 0x0000000000000000000000000000000000000000 \
  $(( $(date +%s) + 604800 )) true --rpc-url $RPC --account me
# 3. read it back
cast call $DESK "getAsk(uint256)((address,uint64,bool,bool,address,address,uint256,uint256,uint256,uint256))" 0 --rpc-url $RPC
# 4. a buyer takes half: cost is quoted by the contract
cast call $DESK "quoteFill(uint8,uint256,uint256)(uint256)" 0 0 2100000ether --rpc-url $RPC
cast send $DESK "takeAsk(uint256,uint256)" 0 2100000ether --value 9ether --rpc-url $RPC --account buyer

Every offer has a stable address on the site: offer.html#ask/<id> or offer.html#bid/<id>. The page reads the offer straight from the contract, so the link shows the live state: open, filled, cancelled or expired.

Concepts

The words used on the desk, the way the desk uses them.

TermMeaning
BagA size of one token that changes hands whole, in one transaction.
AskAn offer to sell an amount for a total in BNB. Nothing is held; the seller's approval lets the desk move the tokens at fill time.
BidAn offer to buy an amount for a total in BNB. The BNB is escrowed in the contract.
MakerThe wallet that posted the offer.
TakerThe wallet that fills it. If the maker names one, only that wallet can fill.
WeightThe token amount still open on an offer.
vs poolThe offer's price per token against the pool price right now. 0% = the pool price, −5% = 5% under it. Shown on every offer so you can judge it at a glance.
Pool impactWhat selling into the pool costs: the slippage paid and the chart move it causes.
Partial fillTaking part of an offer. The maker decides whether it is allowed.
ExpiryWhen the offer stops being fillable. Between now and 30 days.
SerialThe offer id, shown as No. 000012. Asks and bids count separately.
Fee passHolding at least the set amount of $TOKEN makes a fill fee-free, for either side.

Pricing and pool impact

Every pool number on the site uses the constant-product model that PancakeSwap v2 pools follow. Here is the math, and where it stops being exact.

The model

A pool holds R worth of the coin and R worth of the quote (BNB or a stable) at the mid price, so the reported liquidity is L = 2R. Selling a bag worth D at mid:

proceeds    = D · R / (R + D) · (1 − 0.0025)     # 0.25 % LP fee
price after = price before · (R / (R + D))²
lost        = D − proceeds

The desk fee on an OTC fill of the same bag is D · 0.003, and the chart does not move.

A $2,000,000 pool

One side holds $1,000,000. Selling into it:

BagChart movePool paysLostLost %Desk fee
$10,000−1.97 %$9,876$1241.24 %$30
$50,000−9.30 %$47,500$2,5005.00 %$150
$100,000−17.36 %$90,682$9,3189.32 %$300
$250,000−36.00 %$199,500$50,50020.20 %$750
$500,000−55.56 %$332,500$167,50033.50 %$1,500

Where the estimate is off

  • v3 pools. Concentrated liquidity sits in ranges. Near the price a v3 pool can be deeper than the formula says; past the edge of the range it can be much thinner.
  • Several pools. Aggregators split a big sale across pools, which softens the hit. The site uses the deepest pool only.
  • Arbitrage. After a dump, bots buy back part of the move. The chart move shown is the instant one.
  • Reported liquidity. The numbers are DexScreener's view of the pool at the time you look.

Reading "vs pool"

"vs pool" compares an offer to the pool's mid price, which is a price you can't actually get at size. An ask at −5% can still be a good deal for the buyer: buying the same size in the pool would push the price up, often by more than 5 %. The desk shows both numbers so you don't have to guess.

Fees and $TOKEN

One fee, on fills only, taken in BNB.

ActionFeePaid by
Post an ask or a bidnone (gas only)—
Cancelnone (gas only)—
Take an ask0.30 % of the BNBSeller (comes off what the seller receives)
Take a bid0.30 % of the BNBSeller (comes off the payout)
  • The fee rate is feeBps, set to 30 at deploy. The owner can change it but the code caps it at MAX_FEE_BPS = 50 (0.50 %).
  • A fee change applies to fills after the change. It never touches an offer's price.
  • Fee pass. If either side of a fill holds at least passMin of passToken, the fee is zero. At launch passToken is $TOKEN. See the token page.
  • Fees are pushed to feeTo with a gas cap. If that push fails, the fee is kept in feesOwed and anyone can call flushFees(). A broken fee wallet can never block a trade.

Contract

The desk contract, Solidity 0.8.26, no proxy, no external dependencies.

ItemValue
NetworkBNB Smart Chain, chain id 56
Addresspublished at deploy
Native assetBNB (bids escrow BNB, asks are paid in BNB)
Fee30 bps, cap 50 bps
Offer lifeup to 30 days

Write functions

FunctionWhat it does
postAsk(token, amount, priceWei, taker, expiry, partialOk)Lists amount for priceWei BNB in total. Needs balance and approval. Returns the id.
takeAsk(id, amount) payableBuys amount. Cost rounds up, extra BNB is refunded.
cancelAsk(id)Maker closes the ask.
postBid(token, amount, taker, expiry, partialOk) payableEscrows msg.value for amount. Returns the id.
takeBid(id, amount)Sells amount into the bid. Payout rounds down.
cancelBid(id)Maker anytime, anyone after expiry. Refund goes to the maker.
openAuction, commit, reveal, settle, withdrawSealed-bid auctions (commit-reveal). In the contract, not on this site yet; callable from BscScan.
flushFees()Sends fees whose push failed to feeTo. Anyone.

Read functions

FunctionReturns
getAsk(id), getBid(id)The order: maker, expiry, partialOk, cancelled, token, taker, amount, remaining, price, remainingPrice.
nextAskId(), nextBidId()How many of each have been posted.
quoteFill(kind, id, amount)BNB for a fill of amount (kind 0 = ask, 1 = bid).
quoteFee(payer, counterparty, gross)The fee for a fill between two wallets, zero with the pass.
feeBps, feeTo, passToken, passMin, ownerSettings.

Events

AskPosted(id, maker, token, taker, amount, priceWei, expiry, partialOk)
BidPosted(id, maker, token, taker, amount, priceWei, expiry, partialOk)
AskTaken(id, maker, taker, token, amount, ethGross, fee)
BidTaken(id, maker, taker, token, amount, ethGross, fee)
Cancelled(kind, id, by)
FeeSet(feeBps) · FeeToSet(feeTo) · PassSet(token, minBalance) · FeesFlushed(to, amount)

Errors

ErrorMeans
NoBalance / NoAllowanceThe seller lacks the tokens or the approval.
Expired / ClosedThe offer is past expiry, filled or cancelled.
NotTakerPrivate offer for another wallet.
ExceedsRemaining / PartialNotAllowedToo much, or a partial fill on an all-or-nothing offer.
InsufficientValueNot enough BNB attached to takeAsk.
TokenTaxedThe token moved less than asked (transfer tax or rebase).
SelfTradeMaker and taker are the same wallet.
BadExpiry / BadAmount / BadPriceInputs out of range.

Examples

Worked numbers, using the contract's own rounding.

A partial ask

Ask No. 000012: 4,200,000 TOKEN for 18 BNB, partial fills allowed.

FillAmountBuyer paysFee 0.30 %Seller getsLeft
11,000,0004.285714285714285715 BNB0.012857 BNB4.272857 BNB3,200,000 · 13.714285714285714285 BNB
22,000,0008.571428571428571429 BNB0.025714 BNB8.545714 BNB1,200,000 · 5.142857142857142856 BNB
31,200,0005.142857142857142856 BNB0.015429 BNB5.127428 BNB0 · 0

Fills 1 and 2 round the cost up to the last wei; fill 3 takes the remaining price exactly, so the total paid is 18 BNB to the wei.

A private bid

A buyer wants a holder's 2.5 % of supply without moving the chart. They post a bid for 25,000,000 TOKEN, escrow 40 BNB, set taker to the holder, 3 days, all or nothing, and send the link. The holder opens it, approves, and calls takeBid(7, 25000000e18): the holder receives 39.88 BNB, the buyer receives the tokens, the fee wallet 0.12 BNB. If the holder never answers, the buyer cancels and gets 40 BNB back.

A taxed token

A coin with a 5 % transfer tax is listed. At fill time the desk measures the buyer's balance: it grew by 95 % of the amount, not 100 %. The whole fill reverts with TokenTaxed; the buyer keeps the BNB, the seller keeps the tokens.

Risks

Read this before you trade. It is short on purpose.

Smart contract risk. The contract has not had a paid third-party audit. The design has run on mainnet on another chain, and every rule in these docs is in the source, but a bug could still cost funds.

Who you are trusting

  • The contract code, for settlement and escrow. There is no admin path to user funds, no pause, no upgrade.
  • The owner, only for the fee (capped at 0.50 %), the fee wallet and the fee pass.
  • This website, for showing you the right numbers. It builds the transaction your wallet signs: check the contract address and the values in your wallet before you confirm. You can always use the contract from BscScan or cast instead.
  • DexScreener, for pool prices and liquidity shown next to offers. Those numbers are for reference; they never enter a transaction.

What can go wrong

  • Wrong coin. Anyone can post an offer on any token, including a fake with a copied name and logo. Always check the token address, not the ticker.
  • Price. The desk does not judge whether a price is fair. A maker can ask far above the pool. Check "vs pool" on the offer.
  • Honeypots. A token can block transfers or sales after you buy it. OTC does not protect you from the token itself.
  • Approvals. An ask leaves an approval in place. Cancel the ask and revoke the approval if you change your mind; the desk can only use it inside a fill you agreed to, but an approval left open is still an open door if the contract ever had a bug.
  • Stale offers. An ask can fail at fill time if the seller moved the tokens. You lose only gas.

FAQ

Why not just sell in the pool?

For small sizes, do. The pool is fast and always there. The desk is for sizes where the pool's curve costs you real money, or where the chart move matters to you or the community.

Does the desk hold my tokens?

For an ask, no. The tokens stay in your wallet until the second a buyer pays. For a bid, the desk holds the buyer's BNB until it is filled, cancelled or expired.

Can someone fill my ask without paying?

No. takeAsk reverts unless the BNB attached covers the cost, and the tokens move in the same call.

Which coins work?

Any standard BEP-20 on BNB Smart Chain. Tokens that tax transfers or rebase down are rejected at fill time.

What does the buyer see on the chart?

Nothing. The trade never touches a pool, so no candle. The transfer is public on BscScan like any transfer.

Can I change the price of an offer?

Cancel it and post a new one. Prices are fixed once posted so a taker always gets what they saw.

Is there a minimum size?

No, but gas makes tiny offers pointless.

Where are the sealed auctions?

In the contract. This edition of the site shows asks and bids; auctions can be used directly from BscScan with the functions listed in Contract.

Changelog

What changed, newest first.

Edition 1 · November 2026

  • The desk contract on BNB Smart Chain: asks, bids, private offers, sealed auctions, fee pass.
  • Site: live BNB Chain markets, the book read from contract storage, offers posted from a swap-style window with the pool comparison, shareable offer pages, token pages, activity from events.
  • Pool impact on PancakeSwap pools through GeckoTerminal and DexScreener.

Next

  • Sealed auctions on the site.
  • An independent review of the contract, published in full.