noble-exchange 0.0.0

Exchange Noble implements in-block order-matching algorithm


Exchange Noble implements in-block order-matching algorithm


Trades coming through exchange pallet are matched in a block which leads to lower slippage per trade. If we sum all AMM transactions of one pair in one block, we need to only trade resulting sum through the AMM module. The current spot price of the pair is used. Other transactions can be traded directly from account to account. Fee will still be sent to the pool as Liquidity provisioning reward. Completely matched transactions will have 0 slippage (excluding fee). This pallet is pool design agnostic. If the AMM pallet implements required API, it can be connected.

Implementation details

Dispatchable functions

  • buy - Register buy intention - sell - Register sell intention

Handling and storing intention

Registering intention means storing the intention's info in substrate storage. All intentions within the current block are resolved prior to block finalization, therefore none is actually committed to the storage.

Resolving Intention

Intentions are resolved in on_finalize. Resolving an intention means trying to match one or more intentions following the order matching algorithm. If one or more such intentions are matched - amounts can be traded directly between the corresponding accounts and resulting difference is then traded through AMM module.

Order-matching algorithm

The algorithm works as follows: Intentions are stored in two groups for each asset pair. For example , for asset_a and asset_b, there would be: - (asset_a, asset_b) - includes all intentions where asset_a is being sold - (asset_b, asset_a) - includes all intentions where asset_b is being sold During block finalization, these paired groups are processed, intentions matched and resolved in following steps: 1. Intentions in each group are sorted by sold amount 2. For each intention from the first group - Intention_A ( note: possible improvements can be done here as it always takes first group regardless of number of intentions, amounts etc...) - Find and match as many as intentions from the second group such that Intention_A.amount >= Sum(Intention_B.amount) 3. As a result of 2, there is one intention Intention_A on one side and list of matched intentions Intention_B on the other side. 4. For each matched Intention_B - there might be 3 possible scenarios:

  • Intention_A.amount left == Intention_B.amount - Direct trade between intention A and B accounts - Intention_A amount left > Intention_B.amount - B amount is traded directly between intentions A,B accounts - Intention_A.amount = Intention_A.amount - Intention_B.amount
  • Intention_A.amount left < Intention_B.amount - note: should not happen in the current implement, however such case is still handled as follows: - Intention_A amount is traded directly between intention_b and intention_a accounts - Intention_B.amount - Intention_B.amount - difference is traded through AMM.
  1. After all matched intentions are resolved, if there is anything left for intention A - it is traded through AMM. 6. If there are any intentions left in the second group( have not been matched ) - all are traded through AMM.

Fees are paid to the pool account for each direct trade - 0.2% of amount - by each intention's account involved in the direct trade.