github.com/gravity-devs/liquidity@v1.5.3/x/liquidity/spec/03_state_transitions.md (about)

     1  <!-- order: 3 -->
     2  
     3   # State Transitions
     4  
     5  These messages (Msg) in the liquidity module trigger state transitions.
     6  
     7  ## Coin Escrow for Liquidity Module Messages
     8  
     9  Transaction confirmation causes state transition on the [Bank](https://docs.cosmos.network/master/modules/bank/) module. Some messages on the liquidity module require coin escrow before confirmation.
    10  
    11  The coin escrow processes for each message type are:
    12  
    13  ### MsgDepositWithinBatch
    14  
    15  To deposit coins into an existing `Pool`, the depositor must escrow `DepositCoins` into `LiquidityModuleEscrowAccount`.
    16  
    17  ### MsgWithdrawWithinBatch
    18  
    19  To withdraw coins from a `Pool`, the withdrawer must escrow `PoolCoin` into `LiquidityModuleEscrowAccount`.
    20  
    21  ### MsgSwapWithinBatch
    22  
    23  To request a coin swap, the swap requestor must escrow `OfferCoin` into `LiquidityModuleEscrowAccount`.
    24  
    25  ## LiquidityPoolBatch Execution
    26  
    27  Batch execution causes state transitions on the `Bank` module. The following categories describe state transition executed by each process in the `PoolBatch` execution.
    28  
    29  ### Coin Swap
    30  
    31  After a successful coin swap, coins accumulated in `LiquidityModuleEscrowAccount` for coin swaps are sent to other swap requestors(self-swap) or to the `Pool`(pool-swap). Fees are also sent to the liquidity `Pool`.
    32  
    33  ### LiquidityPool Deposit
    34  
    35  After a successful deposit transaction, escrowed coins are sent to the `ReserveAccount` of the targeted `Pool` and new pool coins are minted and sent to the depositor.
    36  
    37  ### LiquidityPool Withdrawal
    38  
    39  After a successful withdraw transaction, escrowed pool coins are burned and a corresponding amount of reserve coins are sent to the withdrawer from the liquidity `Pool`.
    40  
    41  ## Pseudo Algorithm for LiquidityPoolBatch Execution
    42  
    43  If you are curious, you can see a Python simulation script on the B-Harvest [GitHub repo](https://github.com/b-harvest/Liquidity-Module-For-the-Hub/blob/master/pseudo-batch-execution-logic/batch.py).
    44  
    45  ## Swap Price Calculation
    46  
    47  Swap execution applies a universal swap ratio for all swap requests.
    48  
    49  Swap price calculations are used for these cases.
    50  
    51  **Find price direction**
    52  
    53  Variables:
    54  
    55  - `X`: Reserve of X coin
    56  - `Y`: Reserve of Y coin before this batch execution
    57  - `PoolPrice` = `X`/`Y`
    58  - `XOverLastPrice`: amount of orders that swap X for Y with order price higher than the last `PoolPrice`
    59  - `XAtLastPrice`: amount of orders that swap X for Y with order price equal to the last `PoolPrice`
    60  - `YUnderLastPrice`: amount of orders that swap Y for X with order price lower than last `PoolPrice`
    61  - `YAtLastPrice`: amount of orders that swap Y for X with order price equal to the last `PoolPrice`
    62  
    63  - **Increase**: swap price is increased from the last `PoolPrice`
    64  
    65    - `XOverLastPrice` > (`YUnderLastPrice`+`YAtLastPrice`)*`PoolPrice`
    66  
    67  - **Decrease**: swap price is decreased from the last `PoolPrice`
    68  
    69    - `YUnderLastPrice` > (`XOverLastPrice`+`XAtLastPrice`)/`PoolPrice`
    70  
    71  - **Stay**: swap price is not changed from the last `PoolPrice` when the increase and decrease inequalities do not hold
    72  
    73  ### Stay case
    74  
    75  Variables:
    76  
    77  - `swapPrice` = last `PoolPrice`
    78  - `EX`: All executable orders that swap X for Y with order price equal to or greater than last `PoolPrice`
    79  - `EY`: All executable orders that swap Y for X with order price equal or lower than last `PoolPrice`
    80  
    81  - **ExactMatch**: If `EX` == `EY`*`swapPrice`
    82  
    83    - Amount of X coins matched from swap orders = `EX`
    84    - Amount of Y coins matched from swap orders = `EY`
    85  
    86  - **FractionalMatch**
    87  
    88    - If `EX` > `EY`*`swapPrice`: Residual X order amount remains
    89  
    90      - Amount of X coins matched from swap orders = `EY`*`swapPrice`
    91      - Amount of Y coins matched from swap orders = `EY`
    92  
    93    - If `EY` > `EX`/`swapPrice`: Residual Y order amount remains
    94  
    95      - Amount of X coins matched from swap orders = `EX`
    96      - Amount of Y coins matched from swap orders = `EX`/`swapPrice`
    97  
    98  ### Increase case
    99  
   100  Iteration: iterate `orderPrice(i)` of all swap orders from low to high.
   101  
   102  Variables:
   103  
   104  - `EX(i)`: Sum of all order amount of swap orders that swap X for Y with order price equal or higher than this `orderPrice(i)`
   105  - `EY(i)`: Sum of all order amounts of swap orders that swap Y for X with order price equal or lower than this `orderPrice(i)`
   106  
   107  - ExactMatch: SwapPrice is found between two orderPrices
   108  
   109    - `swapPrice(i)` = (`X` + 2_`EX(i)`)/(`Y` + 2_`EY(i-1)`)
   110  
   111      - condition1) `orderPrice(i-1)` < `swapPrice(i)` < `orderPrice(i)`
   112  
   113    - `PoolY(i)` = (`swapPrice(i)`_`Y` - `X`) / (2_`swapPrice(i)`)
   114  
   115      - condition2) `PoolY(i)` >= 0
   116  
   117    - If both above conditions are met, `swapPrice` is the swap price for this iteration
   118  
   119      - Amount of X coins matched = `EX(i)`
   120  
   121    - If one of these conditions doesn't hold, go to FractionalMatch
   122  
   123  - FractionalMatch: SwapPrice is found at an orderPrice
   124  
   125    - `swapPrice(i)` = `orderPrice(i)`
   126    - `PoolY(i)` = (`swapPrice(i)`_`Y` - `X`) / (2_`swapPrice(i)`)
   127    - Amount of X coins matched:
   128  
   129      - `EX(i)` ← min[ `EX(i)`, (`EY(i)`+`PoolY(i)`)*`swapPrice(i)` ]
   130  
   131  - Find optimized swapPrice:
   132  
   133    - Find `swapPrice(k)` that has the largest amount of X coins matched
   134  
   135      - this is our optimized swap price
   136      - corresponding swap result variables
   137  
   138        - `swapPrice(k)`, `EX(k)`, `EY(k)`, `PoolY(k)`
   139  
   140  ### Decrease case
   141  
   142  Iteration: iterate `orderPrice(i)` of all swap orders from high to low.
   143  
   144  Variables:
   145  
   146  - `EX(i)`: Sum of all order amount of swap orders that swap X for Y with order price equal or higher than this `orderPrice(i)`
   147  - `EY(i)`: Sum of all order amount of swap orders that swap Y for X with order price equal or lower than this `orderPrice(i)`
   148  
   149  - ExactMatch: SwapPrice is found between two orderPrices
   150  
   151  - `swapPrice(i)` = (`X` + 2_`EX(i)`)/(`Y` + 2_`EY(i-1)`)
   152  
   153    - condition1) `orderPrice(i)` < `swapPrice(i)` < `orderPrice(i-1)`
   154  
   155  - `PoolX(i)` = (`X` - `swapPrice(i)`*`Y`)/2
   156  
   157    - condition2) `PoolX(i)` >= 0
   158  
   159  - If both above conditions are met, `swapPrice` is the swap price for this iteration
   160  
   161    - Amount of Y coins matched = `EY(i)`
   162  
   163  - If one of these conditions doesn't hold, go to FractionalMatch
   164  
   165  - FractionalMatch: SwapPrice is found at an orderPrice
   166  
   167  - `swapPrice(i)` = `orderPrice(i)`
   168  
   169  - `PoolX(i)` = (`X` - `swapPrice(i)`*`Y`)/2
   170  
   171  - Amount of Y coins matched:
   172  
   173    - `EY(i)` ← min[ `EY(i)`, (`EX(i)`+`PoolX(i)`)/`swapPrice(i)` ]
   174  
   175  - Find optimized swapPrice
   176  
   177    - Find `swapPrice(k)` that has the largest amount of Y coins matched
   178  
   179      - this is our optimized swap price
   180      - corresponding swap result variables
   181  
   182        - `swapPrice(k)`, `EX(k)`, `EY(k)`, `PoolX(k)`
   183  
   184  ### Calculate matching result
   185  
   186  - for swap orders from X to Y
   187  
   188    - Iteration: iterate `orderPrice(i)` of swap orders from X to Y (high to low)
   189  
   190      - sort by order price (high to low), sum all order amount with each `orderPrice(i)`
   191      - if `EX(i)` ≤ `EX(k)`
   192  
   193        - `fractionalRatio` = 1
   194  
   195      - if `EX(i)` > `EX(k)`
   196  
   197        - `fractionalRatio(i)` = (`EX(k)` - `EX(i-1)`) / (`EX(i)` - `EX(i-1)`)
   198        - break the iteration
   199  
   200      - matching amount for swap orders with this `orderPrice(i)`:
   201  
   202        - `matchingAmt` = `offerAmt` * `fractionalRatio(i)`
   203  
   204  - for swap orders from Y to X
   205  
   206    - Iteration: iterate `orderPrice(i)` of swap orders from Y to X (low to high)
   207  
   208      - sort by order price (low to high), sum all order amount with each `orderPrice(i)`
   209      - if `EY(i)` ≤ `EY(k)`
   210  
   211        - `fractionalRatio` = 1
   212  
   213      - if `EY(i)` > `EY(k)`
   214  
   215        - `fractionalRatio(i)` = (`EY(k)` - `EY(i-1)`) / (`EY(i)` - `EY(i-1)`)
   216        - break the iteration
   217  
   218      - matching amount for swap orders with this `orderPrice(i)`:
   219  
   220        - `matchingAmt` = `offerAmt` * `fractionalRatio(i)`
   221  
   222  ### Swap Fee Payment
   223  
   224  Rather than taking fee solely from `OfferCoin`, liquidity module is designed to take fees half from `OfferCoin`, and the other half from `ExchangedCoin`. This smooths out an impact of the fee payment process.
   225  - **OfferCoin Fee Reservation ( fee before batch process, in OfferCoin )**
   226      - when user orders 100 Xcoin, the swap message demands
   227          - `OfferCoin`(in Xcoin) : 100
   228          - `ReservedOfferCoinFeeAmount`(in Xcoin) = `OfferCoin`*(`SwapFeeRate`/2)
   229      - user needs to have at least 100+100*(`SwapFeeRate`/2) amount of Xcoin to successfully commit this swap message
   230          - the message fails when user's balance is below this amount
   231  - **Actual Fee Payment**
   232      - if 10 Xcoin is executed
   233          - **OfferCoin Fee Payment from Reserved OfferCoin Fee**
   234              - `OfferCoinFeeAmount`(in Xcoin) = (10/100)*`ReservedOfferCoinFeeAmount`
   235              - `ReservedOfferCoinFeeAmount` is reduced from this fee payment
   236          - **ExchangedCoin Fee Payment ( fee after batch process, in ExchangedCoin )**
   237              - `ExchangedCoinFeeAmount`(in Ycoin) = `OfferCoinFeeAmount` / `SwapPrice`
   238                  - this is exactly equal value compared to advance fee payment assuming the current SwapPrice, to minimize the pool price impact from fee payment process
   239  
   240  - Swap fees are proportional to the coins received from matched swap orders.
   241  - Swap fees are sent to the liquidity pool.
   242  - The decimal points of the swap fees are rounded up.
   243  
   244  ## Cancel unexecuted swap orders with expired CancelHeight
   245  
   246  After execution of `PoolBatch`, all remaining swap orders with `CancelHeight` equal to or higher than current height are cancelled.
   247  
   248  ## Refund escrowed coins
   249  
   250  Refunds are issued for escrowed coins for cancelled swap order and failed create pool, deposit, and withdraw messages.