# Frequent Batch Auction Dex | FBADex ### CLOB In CLOB price is quantized, for each bucket there are orders (buy or sell) `BuyOrder: (price, amount)` & `SellOrder: (price, amount)` If there is a match, ie BuyOrders and SellOrders with equal price then a trade is executed following first come first server. One can also cancel theie existing orders if only its not filled. This leads to **Sniping**, where a market participant tries to fill the stale order of other market makers before they cancel their order. Hence value can be extracted, risk free, by whoever has the lowest ping to the exchange server. This lead to an arms race in HFT trading. Problem with uniswap like AMMs is also similar, as the design suffer from MEV. Value is extracted by block builders and proposers by re-ordering or introducing new transactions. this value is ultimately paid by the LPs and the users. ## FBA In both, CLOB and Uniswap style markets the problem can be attributed to the need to order transactions. With FBA *(Frequent Batch Auction)* the time is quantised into batches, and all orders inside a batch have same priority. After a batch is finalized a clearing price is calculated and all orders inside the batch is settled at that price and the next batch begins. The batchTime is configurable and typically range between .1s to 5s. [CoW swap](https://docs.cow.fi/cow-protocol/concepts/introduction/batch-auctions) also implements batching of intents where the Eth block time of 12s acts as the batchTime. An order is described using a curve `C(price)`. For instance, for a USDC->BTC pair, at price `p=20000` I want to buy BTC using `C(p) = 100` USDC. Similarly, for sell orders. For simplicity, let restrict $C(p)$ to be linear. So using 2 points we can fully describe an order and a boolean for side (buy / sell) - Order: $(price_L, cost_L, price_H, cost_H)$ where $price_L<price_H$ $$ C(p) = \begin{cases} 0 & p < price_L \\ \frac{(cost_{L}-cost_{H})}{price_{L}-price_{H}}\left(p - price_{L}\ \right)+c_{L} & price_L \leq p \leq price_H \\ 0 & price_H < p \\ \end{cases} $$ | | | | -------- | ------- | | ![BuyOrder](https://hackmd.io/_uploads/H1iX77896.png) | ![DemandSupplyIntersection](https://hackmd.io/_uploads/SJ-pmmI9p.png) | This looks like the demand supply curve. So to find the *clearing price*, we can simply find a solution to the equation, $$\sum_{Buys}C(p) = \sum_{Sells} C(p) $$ > The above equation is not *monotonic* so multiple solutions are possible. Also its discontinuous, hence there can be no solutions at all !!! 1. **Dealing with multiple solution:** If there are multiple solutions it only makes sense for the exchange to choose the one with the highest volume. 1. **Dealing with discontinuity:** The above equation assumes all orders needs be completely filled. Instead we can allow partial execution of orders. $$volume(p) = min(\sum_{Buys}C(p), \sum_{Sells} C(p))$$ | | | | -------- | -------- | | ![Volume](https://hackmd.io/_uploads/HkrFX7Uqp.png) | ![ComplexMarket](https://hackmd.io/_uploads/H1aYQQLcp.png) | The ***clearing price*** ($p_{c}$) should maximise volume. For fairness, all partialy filled orders should be equally filled. At *clearing price* only one side will be partially filled. $$ fillRatio = \frac{Volume(p_{c})}{ max(\sum_{Buys}C(p_{c}), \sum_{Sells} C(p_{c}))}$$ ### Architechture - censorship resistance using transaction receipts - sequencer 1. prove *clearing price* is correct. $volume(p_{c}) \geq volume(p_{c}-1)$ AND $volume(p_{c}) \geq volume(p_{c}+1)$ 1. prove *fill ratio* is correct 1. updates all balances according to the orders that gets executed in the batch 1. prove all transactions are included in the calculation ```typescript ZkProgram({ publicInput: { clearingPrice, fillRatio, BatchNo totalBuy, totalSell, totalBuyMinus1, totalSellMinus1, totalBuyPlus1, totalSellPlus1, }, publicOutput: {orderHash} methods: { base: {...}, addOrderToBatch: { privateInputs: [SelfProof, clearingPrice, fillRatio, pL, cL, pH, cH, batchNo], method(PublicInput, PrivateInputs) { ... // update totalBuy, totalSell ... }, }, finalizeBatch: { privateInputs: [], method(PublicInput, PrivateInputs) { ... // verify clearingPrice & fillRatio was correct using totalBuy, totalSell ... }, } } }); ``` ```sequence Users -> Dex: Order 0 Users -> Dex: Users -> Dex: Users -> Dex: Order N Note over Dex: "Calculate clearingPrice \n of current batch" Note over Dex: "generate proof, Update states" Note over Dex: "start next Batch" Note over Dex: "" Users -> Dex: Dex -> L1: update state root Users -> Dex: Dex -> DA: publish order details Users -> Dex: Users -> Dex: ``` ##### market makers: refers to market participants who provide liquidity for both sides. for example, Sell order at `price+š¯›…` and Buy orders at `price-š¯›…`. The difference`2š¯›…` is often refered to as spread. In marketMaker can choose any strategy they seem fit to set the prices for their orders. Hence unlike passive LPs in uniswapV2 like pools they can react to external price changes and don't suffer as much from arbitrage trades. All trade data will eventually be public. So building a trustless fund which provides liquidity as a market Maker can be possible, allowing anyone who wants to provide passive liquidity to invest in the fund. ### Reference [problem with limit order book markets](https://academic.oup.com/qje/article/130/4/1547/1916146?login=false) [inspiration | Talk by Eric Budish](https://www.youtube.com/watch?v=OwQjTedWSUM&t=3748s)