# Kyberswap Onchain Limit Order [TD] *Stand Alone Version* ## General - This document presents an on-chain limit-order system. - The placing, canceling, settling all orders are entirely on-chain so each one requires gas and on-chain Txns. - Historical activities are all on-chain. - The Limit-order system can be used naturally with any aggregation solution. (It works with the aggregated router of DMM). - Makers can place their orders only in some predefined prices called ticks. - Takers just swap their tokens like using Kyberswap Classic. - This limit-order system can be initialized just like creating a pool in Kyberswap Elastic. Any one can create a pool. Any team can create a limit order system for their token in a permissionless way by implement the Order Manager contract. General flow of limit order: - Makers place their orders in ticks. If the pool not created before then it also create the pool. - Pool will tracking balance by reserve. - If a taker swap using this system and the pool price touches the tick price, the swap will start to fill all liquidity in that tick. - If the swap cross the tick then every limit order in that tick is filled. - If the swap stay at the tick then some limit orders are fully filled, some other limit orders are unfilled and one limit order is partially filled. We tracking it by rule *First come first serve* - If the limit orders are filled, their owners must call the SC to claim their fund. - If the limit orders are unfilled, their owners can call the SC to cancel their order. - Orders which are cancelled will not be burned but also can't use to claim funds. ## Technical Details ### Tick - The price axis is divided in many ticks. Two consecutive ticks are 0.01% different in value. - We can change the difference here by enable it in Factory contract. Each pool limit order will be distinguish by (address, address, tick distance). - Maker can not freely place their limit orders for any price, they must choose a tick price (tick number). - By example, makers can place an order at 1 or 1.0001 but not 1.00005. ### Makers - Maker will place their limit orders on-chain. The placing of order is similar to put liquidity on one direction in the that tick. - Every limit orders at the same price is grouped together. - Makers can keep trace of their order entirely on-chain, which means pool creators can make their own UI. ### Takers - Takers don't fill order by order, they just fully or partially fill all liquidity in one tick. The tick will keep track of the total liquidity at this price. The state of each limit order can be determined using tick's storage and order's storage. - When orders are filled, their own storages do not change, only tick's storage changes. - In the takers' view, this limit order system behaves just like an AMM. They can use an AMM router interface to swap in the limit-order system. - Any aggregation system can naturally use liquidity in limit order system. ## Formula ### Swap #### For buy case - If CurrentTick.Turn mod 2==0 - Move next - If CurrentTick.Turn mod 2==1 - Price=PriceFromTick(CurrentTick) - TmpAmountOut=AmountIn/Price - If (CurrentTick.Liquidity-CurrentTick.FilledLiquidity-CurrentTick.CancelledLiquidity > TmpAmountOut) - AmountOut+=TmpAmountOut - CurrentTick.FilledLiquidity+=AmountOut - Else - AmountOut+=(Liquidity- CancelledLiquidity -FilledLiquidity) - AmountIn-=AmountOut * Price - CurrentTick.Turn+=1 - CurrentTick.Liquidity=0 - CurrentTick.FilledLiquidity=0 - CurrentTick.CancelledLiquidity=0 - Move next #### For sell case - If CurrentTick.Turn mod 2==1 - Move back - If CurrentTick.Turn mod 2==0 - Price=PriceFromTick(CurrentTick) - TmpAmountOut=AmountIn*Price - If (CurrentTick.Liquidity-CurrentTick.FilledLiquidity-CurrentTick.CancelledLiquidity > TmpAmountOut) - AmountOut+=TmpAmountOut - FilledLiquidity+=AmountOut - Else - AmountOut+=(Liquidity- CancelledLiquidity -FilledLiquidity) - AmountIn-=AmountOut /Price - If AmountIn>0 - CurrentTick.Turn+=1 - CurrentTick.Liquidity=0 - CurrentTick.FilledLiquidity=0 - CurrentTick.CancelledLiquidity=0 - Move back ### Create Order #### For buy case - (Tick < CurrentTick)||( (Tick = CurrentTick)&(Turn mod2==0)) - Order.InputAmount=AmountIn - Order.Tick=Tick - Order.BuyOrSell=Buy - Order.LiquidityIndex=Tick.Liquidity - Order.Turn=Tick.Turn (Check if Turn mod2==0) - Tick.Liquidity+=AmountIn - (Tick >CurrentTick)||( (Tick = CurrentTick)&(Turn mod2==1)) - Swap until (CurrentTick>Tick ) or (AmountInLeftOver=0) - If AmountInLeftOver>0 - Order.InputAmount=AmountInLeftOver - Order.Tick=Tick - Order.BuyOrSell=Buy - Order.LiquidityIndex=Tick.Liquidity - Order.Turn=Tick.Turn (Check if Turn mod2==0) - Tick.Liquidity+=AmountInLeftOver #### For sell case - (Tick > CurrentTick)||( (Tick = CurrentTick)&(Turn mod2==1)) - Order.InputAmount=AmountIn - Order.Tick=Tick - Order.BuyOrSell=Sell - Order.LiquidityIndex=Tick.Liquidity - Order.Turn=Tick.Turn (Check if Turn mod2==1) - Tick.Liquidity+=AmountIn - (Tick < CurrentTick)||( (Tick = CurrentTick)&(Turn mod2==0)) - Swap until (CurrentTick<Tick ) or (AmountInLeftOver=0) - If AmountInLeftOver>0 - Order.InputAmount=AmountInLeftOver - Order.Tick=Tick - Order.BuyOrSell=Sell - Order.LiquidityIndex=Tick.Liquidity - Order.Turn=Tick.Turn (Check if Turn mod2==1) - Tick.Liquidity+=AmountInLeftOver ### Cancel #### For buy case - Order.IsCancelled=True - If (Order.Tick.Turn>Order.Turn) || (FilledLiquidity ≥ Order.LiquidityIndex + Order.Amount) - Price=PriceFromTick(Order.tick) - AmountOut2=(Order.Amount-UsedAmount)/Price - UsedAmount=Amount - Else - Price=PriceFromTick(Order.tick) - AmountOut1=Min(Order.Amount-Order.UsedAmount,Liquidity-FilledLiquidity-CancelledLiquidity) - CancelledLiquidity+=AmountOut1 - If Liquidity-FilledLiquidity-CancelledLiquidity == 0 - Order.tick.Turn+=2 - Order.tick.Liquidity=0 - Order.tick.FilledLiquidity=0 - Order.tick.CancelledLiquidity=0 - AmountOut2=(Order.Amount-AmountOut1-UsedAmount)/Price #### For sell case Similar for Sell but AmountOut2=Order.Amount*Price ### Claim #### For buy case - If (Order.Tick.Turn>Order.Turn) || (FilledLiquidity ≥ Order.LiquidityIndex + Order.Amount) - Price=PriceFromTick(Order.tick) - AmountOut=(Order.Amount-UsedAmount)/Price - UsedAmount=Amount - Else - Price=PriceFromTick(Order.tick) - FilledAmount1=Min(Order.Amount , FilledLiquidity-Order.LiquidityIndex) - FilledAmount2=FilledLiquidity+CancelledLiquidity+Order.AmountIn - Liquidity - FilledAmount=Max(0,FilledAmount1-UsedAmount,FilledAmount2-UsedAmount) - AmountOut=FilledAmount/Price - UsedAmount+=FilledAmount #### For sell case Similar for Sell but AmountOut=Order.Amount*Price