Design
At a high level, the DeepBookV3 design follows the following flow, which revolves around 3 shared objects:
Pool: A shared object that represents one market and is responsible for managing its order book, users, stakes, and so on. See the Pool shared object section to learn more.PoolRegistry: Used only during pool creation, it prevents the creation of duplicate pools and maintains package versioning.BalanceManager: Sources a user's funds when placing orders. You can use a singleBalanceManagerbetween all pools. After each transaction, the pool's vault deducts funds from or adds funds to theBalanceManagerto settle the user's balances. See BalanceManager to learn more.
Pool shared object
All public facing functions take in the Pool shared object as a mutable or immutable reference. Pool consists of 3 distinct components:
DeepBookV3 isolates logic between components, and each component builds on top of the previous one. By maintaining a book, then state, then vault relationship, DeepBookV3 can provide data availability guarantees, improve code readability, and help make maintaining and upgrading the protocol easier.
Book
This component consists of the main Book module along with Fill, OrderInfo, and Order modules. The Book struct maintains 2 BigVector<Order> objects for bids and asks, as well as some metadata. It is responsible for storing, matching, modifying, and removing Orders.
When you place an order, DeepBookV3 first creates an OrderInfo. If applicable, DeepBookV3 first matches it against existing maker orders, accumulating Fills in the process. DeepBookV3 uses any remaining quantity to create an Order object and injects it into the book. By the end of book processing, the OrderInfo object has enough information to update all relevant users and the overall state.
State
State stores Governance, History, and Account. It processes all requests, updating at least one of these stored structs.
Governance
The Governance module stores data related to the pool's trading parameters. These parameters are the taker fee, maker fee, and the stake required. Stake required represents the amount of DEEP tokens that a user must have staked in this specific pool to be eligible for taker and maker incentives.
Every epoch, users with nonzero stake can submit a proposal to change these parameters. The proposed fees must fall within the following bounds.
| min_value (bps) | max_value (bps) | Pool type | Taker or maker |
|---|---|---|---|
| 1 | 10 | Volatile | Taker |
| 0 | 5 | Volatile | Maker |
| 0.1 | 1 | Stable | Taker |
| 0 | 0.5 | Stable | Maker |
| 0 | 0 | Whitelisted | Taker and maker |
Users can also vote on live proposals. When a proposal exceeds the quorum, DeepBookV3 queues the new trade parameters to go live from the following epoch and onwards. Proposals and votes reset every epoch. Users can start submitting and voting on proposals the epoch following their stake. Quorum is equivalent to half of the total voting power. The following formula calculates a user's voting power, where is the voting power, is the amount staked, and is the voting power cutoff. The current value of is 100,000 DEEP.
In plain terms, stake counts one-for-one toward voting power up to the cutoff, and any stake above the cutoff adds only the difference between the square root of S and the square root of V_c, so voting power grows more slowly for large stakes. Written as plain text, the formula is V = min(S, V_c) + max(sqrt(S) - sqrt(V_c), 0).
The following diagram helps visualize the governance lifecycle.
History
The History module stores aggregated volumes, trading parameters, fees collected, and fees to burn for the current epoch and previous epochs. During order processing, the module uses fills to calculate and update the total volume. Additionally, if the maker of the trade has enough stake, the module also updates the total staked volume.
The first operation of every epoch triggers an update, moving the current epoch data into historic data, and resetting the current epoch data.
This module calculates user rebates. During every epoch, a maker is eligible for rebates as long as their DEEP staked is over the stake required and have contributed in maker volume. The following formula, quoted from the Whitepaper: DeepBook Token document, calculates maker fees. You can find details on maker incentives in section 2.2 of the whitepaper.
The computation of incentives – which happens after an epoch ends and is only given to makers who have staked the required number of DEEP tokens in advance – is calculated in Equation (3) for a given maker . Equation (3) introduces several new variables. First, refers to the set of makers who stake a sufficient number of DEEP tokens, and refers to the set of makers who do not fulfill this condition. Second, refers to total fees (collected both from takers and the maker) that a maker’s volume has generated in a given epoch. Third, refers to the total liquidity provided by a maker – and specifically the liquidity traded, not just the liquidity quoted. Finally, the critical point is the “phaseout” point, at which – if total liquidity provided by other makers’ crosses this point – incentives are zero for the maker in that epoch. This point is constant for all makers in a pool and epoch.
(3)
In essence, if the total volume during an epoch is greater than the median volume from the last 28 days, then there are no rebates. The lower the volume compared to the median, the more rebates are available. The maximum amount of rebates for an epoch is equivalent to the total amount of DEEP collected during that epoch. DeepBookV3 burns the remaining DEEP.
Account
Account represents a single user and their relevant data. Everything related to volumes, stake, voted proposal, unclaimed rebates, and balances to be transferred. There is a one to one relationship between a BalanceManager and an Account.
Every epoch, the first action that a user performs updates their account, triggering a calculation of any potential rebates from the previous epoch, as well as resetting their volumes for the current epoch. Any new stakes from the previous epoch become active.
Each account has settled and owed balances. Settled balances are what the pool owes to the user, and owed balances are what the user owes to the pool. For example, when placing an order, the user's owed balances increase, representing the funds that the user has to pay to place that order. Then, if another user takes a maker order, the maker's settled balances increase, representing the funds that the pool owes the maker.
Vault
Every transaction that a user performs on DeepBookV3 resets their settled and owed balances. The vault then processes these balances for the user, deducting or adding to funds to their BalanceManager.
The vault also stores the DeepPrice struct. This object holds up to 100 data points representing the conversion rate between the pool's base or quote asset and DEEP. These data points come from a whitelisted pool, DEEP/USDC or DEEP/SUI. DeepBookV3 uses this conversion rate to determine the quantity of DEEP tokens required to pay for trading fees.
BigVector
BigVector is an arbitrary sized vector-like data structure that uses an onchain B+ Tree to support almost constant time (log base max_fan_out) random access, insertion, and removal.
BigVector supports iteration by exposing access to leaf nodes (slices). You can find the initial slice in almost constant time, and subsequently find the previous or next slice in constant time.
The B+ Tree stores its nodes as individual dynamic fields hanging off the BigVector.
What happens when you place a limit order?
The following diagram of the lifecycle of an order placement action helps visualize the book, then state, then vault flow.
The sections that follow describe each step of this flow in text.
Pool
The Pool module calls place_order_int with the user's input parameters. In this function, 4 things happen in order:
- The function creates an
OrderInfo. - The function calls the
Bookfunctioncreate_order. - The function calls the
Statefunctionprocess_create. - The function calls the
Vaultfunctionsettle_balance_manager.
Book
The order creation within the book involves 3 primary tasks:
- Validate inputs.
- Match against existing orders.
- Inject any remaining quantity into the order book as a limit order.
Validation of inputs ensures that quantity, price, timestamp, and order type are within expected ranges.
To match an OrderInfo against the book, DeepBookV3 iterates the list of Orders in the opposite side of the book. If there is an overlap in price and the existing maker order has not expired, then DeepBookV3 matches their quantities and generates a Fill. DeepBookV3 appends that fill to the OrderInfo fills, to use later in state. DeepBookV3 updates the existing maker order quantities and status during each match, and removes them from the book if they are completely filled or expired.
Finally, if the OrderInfo object has any remaining quantity, DeepBookV3 converts it into a compact Order object and injects it into the order book. Order has the minimum amount of data necessary for matching, while OrderInfo has the maximum amount of data for general processing.
Regardless of direction or order type, DeepBookV3 processes all matching in a single function.
State
The process_create function in State handles the processing of an order creation event within the pool's state: calculating the transaction amounts and fees for the order, and updating the account volumes accordingly.
First, the function processes the list of fills from the OrderInfo object, updating volumes tracked and settling funds for the makers involved. Next, the function retrieves the account's total trading volume and active stake. It calculates the taker's fee based on the user's account stake and volume in DEEP tokens, while it retrieves the maker fee from the governance trade parameters. To receive discounted taker fees, the account must have more than the minimum stake for the pool, and the trading volume in DEEP tokens must exceed the same threshold. If any quantity remains in the OrderInfo object, the function adds it to the account's list of orders as an Order, which already exists in Book.
Finally, the function calculates the partial taker fills and maker order quantities, if there are any, with consideration for the taker and maker fees. It adds these to the previously settled and owed balances from the account. The function updates trade history with the total fees collected from the order and returns 2 tuples to Pool, settled and owed balances, in (base, quote, DEEP) format, ensuring that Vault transfers the correct assets.
Vault
The settle_balance_manager function in Vault is responsible for managing the transfer of any settled and owed amounts for the BalanceManager.
First, the function validates that a trader is authorized to use the BalanceManager.
Then, for each asset type the process compares balances_out against balances_in. If the balances_out total exceeds balances_in, the function splits the difference from the vault's balance and deposits it into the BalanceManager. Conversely, if the balances_in total exceeds balances_out, the function withdraws the difference from the BalanceManager and joins it to the vault's balance.
The function repeats this process for base, quote, and DEEP asset balances, ensuring that it accurately reflects and settles all asset balances between the vault and the BalanceManager.