# Orderbook #### The structure of the Pair smart contract: ```rust pub struct Pair { pub factory_id: ActorId, pub base_token: FTokenId, pub quote_token: FTokenId, pub order_book: OrderBook, pub order_id: OrderId, pub balances: HashMap<ActorId, Vec<(FTokenId, Amount)>>, pub user_to_order_ids: HashMap<ActorId, HashSet<OrderId>>, pub withdrawal_amount: HashMap<ActorId, Vec<(FTokenId, Amount)>>, pub msg_manager: MsgManager, } ``` - `factory_id`: Address of the factory contract. - `base token`: The address of the token being traded. - `quote token`: The token used to price trades. - `order_book`: The order book for buying (bids) or selling (asks) the base token (This structure will be described in more detail below). - `order_id`: The number of the last order. - `balances`: User balances that change when an order is created. For example, if a user creates an order to buy the base token, they must deposit the quote token, and this deposit is reflected in this field. - `withdrawal_amount`: The amount of tokens available for withdrawal by the user. For example, if a user places an order to buy the base token, and the order is fully or partially executed, it is reflected in this field. - `msg_manager`: Used for tracking messages between contracts, specifically between the pair contract and token contracts. #### The structure of the order book is as follows: ```rust pub struct OrderBook { pub asks: IndexMap<(ActorId, OrderId), Order>, pub bids: IndexMap<(ActorId, OrderId), Order>, } ``` - `asks`: Orders offering to sell the `base_token` for `quote_token`. These orders are arranged in descending order of price. - `bids`: Orders to buy the `base_token` for `quote_token`. These orders are arranged in ascending order of price. :::info `IndexMap` is used here because it preserves the order of inserted elements, effectively implementing an ordered list. In the worst case, the complexity for insertion and deletion operations is `O(1)`, just like in `HashMap`. However, unlike `HashMap`, `IndexMap` provides methods to sort elements based on keys and values. Sorting in the worst case has a complexity of `O(n log(n))`. Here, it is necessary to assess the costs of operations with IndexMap and conduct research on optimization. ::: #### Order Structure: ```rust pub struct Order { pub amount: u128, pub price: u128, pub created_at: u64, } ``` - `amount`: the quantity of base_token - `price`: the price at which traders want to buy or sell base_token - `created_at`: the order creation time :::info What could be added here: - Order storage time: either by default or by allowing the trader to specify the duration for which the order will be stored. Storing the order would require a deposit in VARA tokens from the user. - How to delete orders after the storage time has expired (possibly using delayed messages). ::: #### Order types currently supported in the order book. - `LMK (Limit Order)`: A buy or sell order where a trader specify the price at which he is willing to buy or sell an asset. It allows him to set a specific price and wait for the market to reach that price before executing the trade. - `FOK (Fill or Kill Order)`: An order that must be executed immediately and in its entirety, or it will be canceled without being placed in the order book. It can create multiple trades if matched against multiple existing orders. - `FAK(Fill and Kill Order)`: Used for bulk orders, it allows a trader to place a buy or sell order at his preferred price (limit price). Any unfilled portion of the order is canceled after execution. - `MKT (Market order)`: An order to buy or sell a digital asset immediately at the current market price. It guarantees execution but does not guarantee a specific price. #### Order creation and matching engine operation. To create an order, a trader must send the following message to the pair contract: ```rust CreateOrder { order_side: OrderSide, // Buy or Sell order_type: OrderType, // LMK, MKT, FAK, or FOK amount: Amount, price: u128, } ``` 1. The first part of executing an order involves depositing the respective tokens into the pair contract: - If a trader wants to buy base tokens at the specified price, they must deposit quote tokens in the corresponding amount. - If a trader wants to sell base tokens, they must deposit the specified quantity of tokens. :::info What can be done to avoid unnecessary messages: For FOK order types, which must either be fully executed or rolled back, it's possible to first check if the order will be executed before transferring tokens to avoid unnecessary token transfers back and forth. ::: 2. After a successful deposit, the Matching Engine begins to process the new order: - If the order is to buy tokens, it iterates through the sell orders. - If the order is to sell tokens, it iterates through the buy orders. - If there is a price match, a trade is executed, and a structure called `MatchedOrder` is created, containing information about the order participating in the trade. ```rust pub struct MatchedOrder { // Order number pub order_id: OrderId, // Change in the quantity of base tokens // (should be accounted for either in the user's balance // or the quantity of tokens available for withdrawal) pub base_token_change: u128, // Change in the quantity of quote tokens // (should be accounted for either in the user's balance // or the quantity of tokens available for withdrawal) pub quote_token_change: u128, // Trader's address pub trader: ActorId, // Whether the order has been completed entirely or not pub order_completed: bool, } ``` - If the new order is not completed entirely, the iteration continues until either the order is completed or all existing orders are exhausted. The result of the Matching Engine's work is a vector of `MatchedOrder` and the modified structure of new order. 3. If an order was completely executed, no information about it is retained in the order book. If an order was partially executed or not executed, a decision is made based on the order type: - For `LMK` orders, the changes are saved in the state, and the remainder of the order is also saved. - For `MKT` orders or `FAK` orders, the changes are saved in the state, but the remainder of the order is not saved. - For `FOK` orders, the remainder of the order is not saved, and any state changes made are completely rolled back. 4. If an order is fully or partially executed (and also if the order is partially executed and of type `LMK`, `FAK`, or `MKT`), then based on the trades, the balances and withdrawable funds of the traders are modified. 5. An event is sent out about the occurred trade and the orders involved in it (if there was a trade). ![](https://hackmd.io/_uploads/Hy_EBTqlp.png)