Liquidity - How It Works


Each pool has the following variables:

  • totalCapitalSupplyPerCycle: this represents how much BRZ the Pool has and can use in the next cycle. It is not counting the BRZ that LPs added in requests which were not finalized yet as well as capital that is currently in use by Loans and not repayed yet. If a loan is being late repayed (after the cycle it has been created) it is not added to this variable. We will cover late repayments in a section further down this page.
  • totalLPTokenSupplyPerCycle: this represents the total amount of shared that have been minted. It is not counting the BRZ that LPs added in requests which were not finalized yet.

The Ratio of Shares to BRZ and BRZ to Shares is calculated with those variables and can be easily requested by calling the following functions:

  • getShares: this function takes the amount of BRZ you want to convert to shares. And gives back the amount of shares you would get given the amount.
  • getBRZForShares: this function takes the amount of shares you want to convert to BRZ and gives back the amount of BRZ the shares represent.

Requests & Shares

The ratio of the shares of a request are determined in the cycle they start to be active (in technical terms: requested cycle + 1).

At the time of a withdraw-request shares will be stored in the pool contract. When requesting a deposit, BRZ is being sent to the pool contract but not yet added to the working/assignable capital of the pool.

Shares are only minted/burnt at rollover. The same goes for adding the requested BRZ to add to working capital. The reason for this is that we don't want to change the ratio of the shares by accounting one side, as we can't determine the future share ratio yet. Only after the cycle ended and the rollover has taken place we can now determine both sides and mint/burn at the correct ratio and add the capital.



Simple Direct Deposit Example

We are going to go through an example to explain how this works:

  • Let's say the system just initialised and we are on cycle 1
  • There's a liquidity provider, 0xabc, which executes a direct deposit of 1000BRZ: the pool has now 1000BRZ
  • There are 50M xKona tokens in circulation and 50% are staked
  • There's one Oracle which a ratio of his assigned to standby capital of 50%
  • The cost of capital should be 5% = 25BRZ

Calculation in detail

  • As no additional risk is seen in the system risk calculated:
    max(100% - stakedPercentage - standbyRatio, 0)²/2= riskAPR
  • To get the total apr:
  • We move into the "cycle" status. A loan of 500BRZ is created, with an interest rate of 10%
  • (cycle status) The borrow repays the loan entirely: 550BRZ, as he agreed offchain with the oracle
    • 525BRZ goes to the Pool and 25BRZ is distributed to the Oracle and Stakers
  • (Join/Leave status) We move to the Join/Leave status. Now if 0xabc withdraws, he gets 1025BRZ

Deposit Example With Late Claiming

Let's do a new example:

  • The system just initialised, we are on cycle 1 and the pool has 1000BRZ from provider 0xxyz

  • (cycle status) Another liquidity provider, 0xabc, sends a request to deposit 1000BRZ. Because the cycle is already started, he cannot do a direct deposit

  • For simplicity reasons, cycle 1 goes on with no loans

  • The system moves to cycle 2, but before, all pending requests are processed (the platform automatically calls the necessary functions in the smart contracts to do this)

    • 0xabc's funds are added to the pool and now count as active shares
    • The pool has now 2000BRZ
  • In cycle 2 a loan is created, creating 25BRZ in revenue for the Pool

  • We move to cycle 3. Still, 0xabc didn't call the smart contract function to finalize his request, which is a necessary step

  • This is what the pool contract now holds for the user

    • withdrawBalancePerCycle(requestedCycle, pool, user) = 1000BRZ
    • virtual shares that were minted for him on rollover 1000Shares (assuming it's a fresh Pool)

    What is the Rollover

    On the start of each cycle we rollover the queues, processing any pending requests, to ensure the shares are either removed or withdrawn the next cycle.

    This is done automatically when moving forward in the cycle state. The KonaPools contract calls the poolQueues contract, which then deposits or withdraws the requested amount for each request.

    • This is how we can use the public functions in the contracts to get the amount it's worth now:
      • call getShares(1000BRZ, requestedCycle)
      • with those shares call getBRZAmount(shares, currentCycle)
        • now you will see he already earned 25BRZ and holds 1025BRZ worth of shares
  • If 0xabc now wishes to finalize his deposit.

    • This can be in any status as soon as the requested cycle passed.

Function for finalizing

function finalizeDepositQueue(address pool, uint requestedCycle, uint amount) external;
  • If 0xabc would now withdraw his shares, he would get the revenue generated in cycle 2, even though he claimed his shares in cycle 3. (withdrawQueue or direct withdraw in JoinLeave)
    • in addition his historic LP holdings are be adjusted for him, to make him eligible to claim late repayments, in case the borrowers don't repay in the designated cycle.
  • 0xabcs virtual holdings are 1025BRZ.

Withdraw Example

Let's say we have a liquidity provider with the wallet 0xabc

  • The system is on cycle 2 and the pool has 2000BRZ
  • 0xabc has half of the shares of the pool and wants to withdraw by sending a withdraw request to withdraw all his shares
  • The cycle 2 has a loan which generated 50BRZ in revenue for the Pool
  • The system moves to cycle 3 and processes all requests
    • The wallets 0xabcs funds are now removed from the pool and are now stored as inactive BRZ
  • 0xabc is now able to withdraw his BRZ at any point without being exposed to any risks nor benefits.
  • 0xabcs BRZ he can now withdraw are 1025BRZ.

Late Repayment Management

By depositing directly in the Join Leave status - the cycle will be pushed into relevantChanges and the LPTokens of that cycle for the user will be updated

By Queueing the withdraw, the next cycles historic LP balance will be adjusted and the relevantChanges will be set for the next cycle

By queueing to deposit, no LP changes will be set yet as we don't know the exact amount of shares for the queued BRZ yet.
On finalizing the queue, we insert it into the correct spot in the relevantChanges and change the LP share balance for requestedCycle+1

This ensures that on late repayment the users can claim their share on cycles their share worth was impacted.

//call this to check if there are funds recovered in the cycle
function lateRecovered(uint cycle) external returns(uint);

//call this to claim the recovered funds proportionally
function claimLateRepayment(uint cycle) external;