---
# System prepended metadata

title: Liquidity Pool Subsystem

---

# Liquidity Pool Subsystem

## Notations

| Name | Description | Symbol |
|----|----|----|
| Time | Timesteps | $t$ |
| Period | Time period | $T$ |
| Liquidity Pools | Number of liquidity pools |  ${n_{LP}}$ |
| Liquidity Pool Identifier | Reference to  a particular liquidity pool | $i, j, k$ |
| Rowan | Number of Rowan tokens in liquidity pool | $\mathbf{S_L}$ |
| M-Tokens | Number of M-tokens in liquidity pool | $\mathbf{M_L}$ |
| Swap Fee | Fees for swapping in a liquidity pool | $f_{swap}$ |
| Swap Volume | Volume of swaps in a liquidity pool | $v_{swap}$ |
| Rowan Price | Price of Rowan in a liquidity pool | $P_S$ |
| M-Token Price | Price of M-token in a liquidity pool | $P_M$ |
| Liquidity Provider | Reference to a liquidity provider | $\pi$ |
| Liquidity Provider System | Reference to the liquidity provider subsystem | $\Pi$ |
| Liquidity Provider Reward | Reward earned by a liquidity provider | $\mathbf{r_{\pi}}$ |
| Liquidity Provider System Reward | Reward earned by the liquidity provider system | $\mathbf{R_{\Pi}}$ |
| Liquidity Provider's Cost of Operation | Operational cost incurred by a liquidity provider | $C_{\Pi}$ |
| Liquidity Provider System ROI | Return on investment of the liquidity provider system | $\Omega_{\Pi}$ |
| Awarded Subsidies | Proto rewards- tokens awarded to LPs and Validators | | $\mathbf{S_P}$ |
| Observed Ratio | Ratio of supply tokens in Liquidity Pool to the total supply | $\rho_l$ |
| Target Ratio | Target ratio of supply tokens in Liquidity Pool to the total supply | $\gamma_l$ |
| Swap fee parameter | Control parameter on the liquidity subsystem's swap fee | $\lambda_l$ |

## Roles

A liquidity pool consists of two primary actors:
- **Liquidity Providers** who provide Rowan or N-tokens for a given duration of time to earn rewards.
- **Swappers** who participate in the liquidity pool to swap Rowan for N-tokens or vice versa.

## Actions

![](https://i.imgur.com/AYTYVwc.png)

### Add and remove liquidity
The Rowan price $P_S$ is defined as the units of Rowan $\mathbf{S}$ that can be bought per unit of M-token $\mathbf{M}$. $$P_S = \frac{\mathbf{S_L}}{\mathbf{M_L}}$$

Adding liquidity can be modeled as adding (m, s) such that $$ P^{+}_S = P_S $$ $$ P^{+}_S = \frac{\mathbf{S_L}+s}{\mathbf{M_L}+m} = \frac{\mathbf{S_L}}{\mathbf{M_L}} = P_S$$ where 
- $P_S$ is the Rowan price at the current state,
- $P^+_S$ is the Rowan price at the next state, 
- $s > 0$ is the amount of Rowan added through the action; $\mathbf{s} = \mathbf{\Delta S}$
- $m > 0$ is the amount of M-tokens required to make the action; $\mathbf{m} = \mathbf{\Delta M}$

Removing liquidity can be modeled as removing (m, s) such that $$ P^{+}_S = \frac{\mathbf{S_L}+s}{\mathbf{M_L}+m} = \frac{\mathbf{S_L}}{\mathbf{M_L}} = P_S$$ where 
- $P_S$ is the Rowan price at the current state,
- $P^+_S$ is the Rowan price at the next state, 
- $s<0$ is some fraction of S; the amount of Rowan removed through the action; $\mathbf{s} = \mathbf{\Delta S}$
- $m<0$ is some fraction of M; the amount of M-tokens removed through the action $\mathbf{m} = \mathbf{\Delta M}$

### Swapping
A swap is defined as an exchange of M-tokens for Rowan or vice versa, while preserving the Continuous Liquidity Provider (CLP) formula. 

#### Parameterized Swap Fees 
Consider a prior state (M, S). A swapper swaps $\mathbf m = \Delta \mathbf{M}$ to obtain $s = f(m; M, S)$ computed using the parametrized swap fee function.

We need to design a parametrized swap fee policy in order to modulate the fee according to the dynamic rebalancing policy. We choose a parameter $\lambda_l$ such that 
- at $\lambda_l = 0$, the swapper incurs no fee to swap akin to the Constant Marker Maker Model (idealized Uniswap)
- at $0< \lambda_l \leq 1$, the swapper incurs a combination slip-based fee to swap
- at $\lambda_l > 1$, the swapper incurs a magnifed slip-based fee

In the Constant Market Maker Model, the next state after a swap is $$\mathbf {S_{L,cmm}^+} = \mathbf {S_L} - \frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}}$$

In the Continuous Liquidity Pool Model, the next state after a swap is $$\mathbf {S_{L,clp}^+} = \mathbf {S_L} - \frac{\mathbf{m}\mathbf{S_L}\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})^2}$$

In the case of the Constant Product Market Maker, the amount of tokens returned to the swapper who provided $\mathbf m$ is $\frac{\mathbf{m}\mathbf{S_L}}{(\mathbf{m}+\mathbf{M_L})}$, whereas in the case of the slip based fee it is $\frac{\mathbf{m}\mathbf{S_L}\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})^2}$.

Given that we want a parametrization that allows for both of these rules to be realized, we can express the Parametrized Continuous Liquidity Provider Model as follows:

$$\mathbf {S_{L,param}^+} = \mathbf {S_L} - \frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}} + \lambda_l \left( \frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}} - \frac{\mathbf{m}\mathbf{S_L}\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})^2} \right)$$

Note that 
- if ${\lambda_l} = 0$ then we recover the Constant Product Market Maker $\mathbf {S_{L,cmm}}$ equation 
- if ${\lambda_l} = 1$ the we recover the Continuous Liquidity Provider $\mathbf {S_{L,clp}}$ equation.

Furthermore, this is analytically equivalent to:

$$\mathbf {S_{L,param}^+} = \mathbf {S_L} - (1-\lambda_l) \frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}} - \lambda_l\frac{\mathbf{m}\mathbf{S_L}\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})^2}$$

That means the the quantity of tokens recieved by the swapper is: 
$$\mathbf {S_L}-\mathbf {S_{L,param}^+}=(1-\lambda_l) \frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}} + \lambda_l\frac{\mathbf{m}\mathbf{S_L}\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})^2}$$

Furthermore, we can interpret the Constant Product Market Maker rule as being "without fees" (the slippage is not a fee). Thus, any fee rule such as the Continuous Liquidity Provider rule can be interpreted relative to what the swapper would have recieved under the Constant Product Market Maker, giving the difference which is the "fee".

In this framing, the fee for the Continuous Liquidity Provider rule is
$$(\mathbf {S_{L,cmm}^+}-\mathbf {S_L})-(\mathbf {S_{L,clp}^+}-\mathbf {S_L})=\mathbf {S_{L,cmm}^+}-\mathbf {S_{L,clp}^+}\\=\frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}} - \frac{\mathbf{m}\mathbf{S_L}\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})^2}\\=\frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}}\left(1 - \frac{\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})} \right) >0$$

The $\lambda_l$ term needs to parameterize the fee directly such that
- when $\lambda_l = 0$ we have no fee 
- when $\lambda_l = 1$ we have the slip based fee
- when $\lambda_l >1$ we have maginified (or suppresed) version of the slip-based fee.

$$(\mathbf {S_{L,cmm}^+}-\mathbf {S_L})-(\mathbf {S_{L,param}^+}-\mathbf {S_L})=\mathbf {S_{L,cmm}^+}-\mathbf {S_{L,param}^+}\\=\lambda_l\left(\frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}} - \frac{\mathbf{m}\mathbf{S_L}\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})^2}\right)\\=\lambda_l\frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}}\left(1 - \frac{\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})} \right) >0$$

for any parameter $\lambda_l>0$ where $m, M_L, S_L >0$.

This gives the **Parametrized Swap Fee** for this Liquidity Provider system

$$ 
y= f_{swap}(x, \mathbf X,  \mathbf Y) = \lambda_l\frac{\mathbf x \mathbf{Y}}{\mathbf x+\mathbf{X}}\left(1 - \frac{\mathbf{X}}{(\mathbf{x}+\mathbf{X})} \right)
$$

$$f_{swap}(m, \mathbf M, \mathbf S) = \lambda_l\frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}}\left(1 - \frac{\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})} \right) $$

#### Cases
**No fees at $\lambda_l = 0$** 
$$f_{swap, \lambda_l=0} =  0$$ 

**Combination Slip-Based Fee at $0< \lambda \leq 1$**
$$f_{swap, 0< \lambda_l \leq 1} =  \lambda_l\frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}}\left(1 - \frac{\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})} \right)$$ 

**Magnified Slip-Based Fee at $\lambda_l > 1$**
$$f_{swap, \lambda_l > 1} =  \lambda_l\frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}}\left(1 - \frac{\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})} \right)$$

> **NOTE**
> Although this framework allows for $\lambda > 0$, the Sifchain system will only operate under $\lambda \in [0,1]$ as the rebalancing policy imposes this domain constraint on the control parameter $\lambda$ across all subsystems. 


The Rebalancing Policy for Sifchain thus must provide instructions as to whether fees should rise or fall by providing an increase or decrease in $\lambda$ of the form $\lambda^+ = \lambda +\Delta \lambda$ where $\Delta \lambda$ is determined as a function of the overall system state including token supply, tokens staked in the validator subsystem and locked across the liquidity pools. See [Sifchain Overview](https://hackmd.io/@shrutiappiah/By450P3ID).


Plugging in the slip-based fee $f_{swap} = \lambda\frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}}\left(1 - \frac{\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})} \right)$, the resulting Rowan obtained by the swapper is

$$\mathbf {S_L}-\mathbf {S_{L,param}^+}=(1-\lambda_l) \frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}} + \lambda_l\frac{\mathbf{m}\mathbf{S_L}\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})^2}$$


![](https://i.imgur.com/A5yYQTR.jpg)


We can define an invariant $I$ in this subsystem to represent the conservation of the $\mathbf{M_L},\mathbf{S_L}$ relationship. $$I = f(f_{swap}, \mathbf{S_L}, \mathbf{M_L})$$


### Create and destroy pool
A user can list a new pool with their choice of M-token and its ratio with Rowan. To create a pool, the user must provide the initial liquidity in its specified Rowan:M-token ratio.

Under reasonable grounds, a pool can be removed or destroyed from Sifchain. See [Sifchain Liquidity System PRD](https://drive.google.com/file/d/1P9Co01zrTFz-x9ardaoYF7xfVskN21XR/view?ts=5f7c6d55).

## State variables
**Definition 1: Rowan in Liquidity Provider Subsystem $\mathbf{S_L}$**
The amount of Rowan in locked up as liquidity in all the liquidity pools of the Liquidity Provider Subsystem in the current state.

**Definition 2: Rowan in Validator Subsystem $\mathbf{S_V}$**
The amount of Rowan currently staked by all validators in the Validator Subsystem in the current state.

**Definition 3: Rowan in Circulating Supply $\mathbf{S_C}$**
Circulating supply. This contains all the Rowan circulating in the system, including the stock availed through the accumulation of swap fees. 

**Definition 4: Liquidity Provider Rewards $\mathbf{R_\pi}$**
Rewards earned by the liquidity provider are a function of the swap fees and the dynamic rebalacing parameter.


## Metrics

**Definition 5: M-token Supply**
The amount of M-tokens in the liquidity pool in the current state.

**Definition 6: Swap Fees**
Fees incurred by swapper while making a Rowan/M-token swap. Sifchain implements a *paramterized slip-based fee* for swaps, computed using the Continuous Liquidity Provider (CLP) model. The parameter $\lambda$ The swap fee is a function of the swap volume and the demand for a pool's liquidity. $$f_{swap} =  \lambda_l\frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}}\left(1 - \frac{\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})} \right)$$ 

**Definition 7: Liquidity Provider System Revenue**
We can define the revenue per period of the liquidity provider subsystem as a function of the swap fee policy and the volume of swaps that occur in that period. $$R_{\Pi, T} = \sum{{f_{swap}*v_{swap, T}}}$$

**Definition 8: Liquidity Provider System ROI**
We can define the ROI per period of the liquidity provider subsystem as a function of the revenue generated in that period and the cost of providing liquidity. $$\Omega_{\Pi, T} = \frac{R_{\Pi, T} - C_{\Pi, T}}{C_{\Pi, T}}$$

## Assumptions
- Assume no destruction of liquidity pool 
- Assume paramterized fee applied to swaps


-----------------------------------

## Implementation Support: Liquidity Provider Subsystem 

**TODO**
1. Update swap fees to parametrized CLP model
2. Update next state (output) after swap to reflect parametrized CLP model
3. Ensure LP rewards are computed based on updated swap fee formula
4. Check how asymmetric liquidity adds & removes are handled - are adds symmetrical to removes? Are they both handled using composed symmetric liquidity add/remove and a swap?

### Swap Fee Parameterization

The goal of this section is to characterize the parametrized swap fee that allows for a control policy to be implemented upon on it. Importantly, this characterization must be specified in a way to co-exist with the validator subsystem. 

| Name | Domain |  Symbol |  Notes |
|----|----|----|----|----|
| Goal Bonded |  $D = (0,1)$ | $\gamma_l$ |Desired Ratio of Liquidity Provider Subsystem Tokens | 
| Bonded Ratio |  $D = (0,1)$ | $\rho_l$ |Actual Ratio of Bonded Tokens in the Liquidity Provider Subsystem|

**Keeper**
| Name | Domain |  Symbol |  Notes |
|----|----|----|----|----|
| Liquidity Provider Control Parameter |  $D = [0,1]$ | $\lambda_L$ |Liquidity Provider Component of $\overrightarrow{\lambda}$ |

> **NOTE**
> Liquidity Provider Control Parameter is updated via the control module. The update to the Liquidity Provider Control Parameter should come through a hook from the control module. Liquidity Provider must be updated and thus needs either a parameter update method OR Liquidity Provider Control Parameter may be defined as a state of this module and would have a state transition function defined. Updated through a keeper in the swap fee module.

Control parameter, $\overrightarrow{\lambda}$ is defined as the set of components:
$$\overrightarrow{\lambda} = \{\lambda_v, \lambda_l,...,\lambda_c,\lambda_t\}$$
where $\lambda_l$ will provide an update (exert influence) to the goal bonded ratio, $\gamma_l^+$.  $\gamma_l^+$ is one of a set defined of ratios of total supply, where:
$$\overrightarrow{\gamma} = \{\gamma_v, \gamma_l,...,\gamma_c,\gamma_t\}$$

It is expected that only the validator and liquidity pool component of these parameters would be employed. However, this framework allows for the ability to control other subsets of supply tokens if they are not purely dependent upon $\mathbf{S_V}$ and $\mathbf{S_L}$.

The liquidity provider control parameter is applied to control the swap fees $f_{swap}$ as shown below
$$f_{swap} =  \lambda_l\frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}}\left(1 - \frac{\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})} \right)$$ 


#### 1. Update Swap Fee

``` go 
// calculateFee the fee of the swap
func calcLiquidityFee(X, x, Y cosmos.Uint) cosmos.Uint {
	// ( x^2 *  Y ) / ( x + X )^2
	numerator := x.Mul(x).Mul(Y)
	denominator := x.Add(X).Mul(x.Add(X))
	if denominator.IsZero() {
		return cosmos.ZeroUint()
	}
	return numerator.Quo(denominator)
}

```
Updated parametrized swap fee:

$$f_{swap}(\mathbf m, \mathbf M, \mathbf S) = \lambda_l\frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}}\left(1 - \frac{\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})} \right) $$

Introduce a parameter ```params.Liquidity_Provider_Control_Parameter``` $\lambda_l$ and make the following substitutions: <br/>
- $x \rightarrow \mathbf m$
- $X \rightarrow \mathbf {M_L}$
- $Y \rightarrow \mathbf {S_L}$

#### 2. Update output/next state
``` go
// calculate the number of assets sent to the address (includes liquidity fee)
func calcAssetEmission(X, x, Y cosmos.Uint) cosmos.Uint {
	// ( x * X * Y ) / ( x + X )^2
	numerator := x.Mul(X).Mul(Y)
	denominator := x.Add(X).Mul(x.Add(X))
	if denominator.IsZero() {
		return cosmos.ZeroUint()
	}
	return numerator.Quo(denominator)
}
```

Updated output to swapper:
$$\mathbf {S_L}-\mathbf {S_{L,param}^+}=(1-\lambda_l) \frac{\mathbf m \mathbf{S_L}}{\mathbf m+\mathbf{M_L}} + \lambda_l\frac{\mathbf{m}\mathbf{S_L}\mathbf{M_L}}{(\mathbf{m}+\mathbf{M_L})^2}$$

Introduce a parameter ```params.Liquidity_Provider_Control_Parameter``` $\lambda_l$ and make the following substitutions: <br/>
- $x \rightarrow \mathbf m$
- $X \rightarrow \mathbf {M_L}$
- $Y \rightarrow \mathbf {S_L}$

#### Update tradeSlip metric
``` go
// calcTradeSlip - calculate the trade slip, expressed in basis points (10000)
func calcTradeSlip(Xi, xi cosmos.Uint) cosmos.Uint {
	// Cast to DECs
	xD := cosmos.NewDecFromBigInt(xi.BigInt())
	XD := cosmos.NewDecFromBigInt(Xi.BigInt())
	dec2 := cosmos.NewDec(2)
	dec10k := cosmos.NewDec(10000)

	// x * (2*X + x) / (X * X)
	numD := xD.Mul((dec2.Mul(XD)).Add(xD))
	denD := XD.Mul(XD)

	if denD.IsZero() {
		return cosmos.ZeroUint()
	}
	tradeSlipD := numD.Quo(denD) // Division with DECs

	tradeSlip := tradeSlipD.Mul(dec10k)                             // Adds 5 0's
	tradeSlipUint := cosmos.NewUint(uint64(tradeSlip.RoundInt64())) // Casts back to Uint as Basis Points
	return tradeSlipUint
}

```

>**NOTE**
tradeSlip computation needs to be updated in alignment with the parametrized CLP model. 

>**TODO**
> find derivation for trade slip


#### Update slipAdjustment
``` go // r = rune staked;
// a = asset staked
// R = rune Balance (before)
// A = asset Balance (before)
// P = existing Pool Units
// slipAdjustment = (1 - ABS((R a - r A)/((2 r + R) (a + A))))
// units = ((P (a R + A r))/(2 A R))*slidAdjustment
func calculatePoolUnitsV14(oldPoolUnits, poolRune, poolAsset, stakeRune, stakeAsset cosmos.Uint) (cosmos.Uint, cosmos.Uint, error) {
	if stakeRune.Add(poolRune).IsZero() {
		return cosmos.ZeroUint(), cosmos.ZeroUint(), errors.New("total RUNE in the pool is zero")
	}
	if stakeAsset.Add(poolAsset).IsZero() {
		return cosmos.ZeroUint(), cosmos.ZeroUint(), errors.New("total asset in the pool is zero")
	}
	if poolRune.IsZero() || poolAsset.IsZero() {
		return stakeRune, stakeRune, nil
	}
	P := cosmos.NewDecFromBigInt(oldPoolUnits.BigInt())
	R := cosmos.NewDecFromBigInt(poolRune.BigInt())
	A := cosmos.NewDecFromBigInt(poolAsset.BigInt())
	r := cosmos.NewDecFromBigInt(stakeRune.BigInt())
	a := cosmos.NewDecFromBigInt(stakeAsset.BigInt())

	// (2 r + R) (a + A)
	slipAdjDenominator := (r.MulInt64(2).Add(R)).Mul(a.Add(A))
	// ABS((R a - r A)/((2 r + R) (a + A)))
	var slipAdjustment cosmos.Dec
	if R.Mul(a).GT(r.Mul(A)) {
		slipAdjustment = R.Mul(a).Sub(r.Mul(A)).Quo(slipAdjDenominator)
	} else {
		slipAdjustment = r.Mul(A).Sub(R.Mul(a)).Quo(slipAdjDenominator)
	}
	// (1 - ABS((R a - r A)/((2 r + R) (a + A))))
	slipAdjustment = cosmos.NewDec(1).Sub(slipAdjustment)

	// ((P (a R + A r))
	numerator := P.Mul(a.Mul(R).Add(A.Mul(r)))
	// 2AR
	denominator := cosmos.NewDec(2).Mul(A).Mul(R)
	stakeUnits := numerator.Quo(denominator).Mul(slipAdjustment)
	newPoolUnit := P.Add(stakeUnits)

	return cosmos.NewUintFromBigInt(newPoolUnit.TruncateInt().BigInt()), cosmos.NewUintFromBigInt(stakeUnits.TruncateInt().BigInt()), nil
}
```

> **NOTE**
> If slipAdjustment depends on slip fee, it needs to be modified. The modification depends on the result obtained from deriving slipAdjustment again by substiuting the CLP slip fee with the new parametrized CLP slip fee.

> **TODO**
> source derivation for slipAdjustment





----------------------












--------------------------------
# NOTES

# Sifchain System Income

## Mechanisms

### Staking Mechanism
Validators stake Rowan $$R_V =$$

### Liquidity Mechanism

#### Providing liquidity
Liquidity providers contribute to the liquidity pool. Earn rewards based on their contributions. $$R_{LP} =$$

#### Swapping
Swappers make Rowan-$X$ swaps, $X$ being a 3rd party token such as ETH, ATOM, DAI or any compatible token. Swaps move supply from the external world into the Sifchain system. Swappers incur a fee for swapping tokens. $$f =$$

The liquidity providing mechanism and the swapping mechanism are coupled through the liquidity pool. 

**Impermanent loss**

Impermanent loss occurs when the price of a token locked up in a liquidity pool becomes lower than its external price. 

Swapping protocols utilize an automated market maker to maintain the ratio of tokens locked up in a liquidity pool. 

Consider a liquidity pool with Rowan and ETH at a 50:50 ratio. The external price of ETH (that in Binance or Coinbase) rises or falls due to exogenous processes. The case where the price of ETH rises presents an arbitrage opportunity. Arbitrageurs are able to make a profit off of buying cheaper ETH from the liquidity pool and selling it in the open market, up until the price of ETH in the liquidity pool equalizes to the external ETH price.

Upon sufficently depleting the liquidity pool of ETH until its price equalizes, the arbitrageur would have extracted the amount of value that accounts for the price difference from the liquidity pool.  

The liquidity provider - whose ETH tokens are locked up in this liquidity pool - thus undergoes an impermanent loss of the same value. The loss is considered impermanent since it has not been realized yet. The loss is currently only on paper and becomes permanent when the liquidity provider withdraws their liquidity from the pool.

## Dynamic Rebalancing Policy

This policy ensures that the revenue earned by participants in the validator system and the liquidity system are balanced and equivalent. This is to prevent validators from jumping over to the liquidity system so as to earn higher rewards, setting off a positive feedback loop that brings in even more validators into the liquidity system, eventually driving the validator system empty. And vice versa on from the liquidity system to the validator system. 

# Liquidity Pool Subsystem

## Notations

| Name | Description | Symbol |
|----|----|----|
| Time | Timesteps | $t$ |
| Period | Time period | $T$ |
| Liquidity Pools | Number of liquidity pools |  | ${c_{LP}}$ |
| Liquidity Pool Identifier | Reference to  a particular liquidity pool | $i, j, k$ |
| Rowan | Number of Rowan tokens in liquidity pool | $S$ |
| N-Tokens | Number of N-tokens in liquidity pool | $N$ |
| Swap Fee | Fees for swapping in a liquidity pool | $f_{swap}$ |
| Swap Volume | Volume of swaps in a liquidity pool | $v_{swap}$ |
| Rowan Price | Price of Rowan in a liquidity pool | $P_S$ |
| N-Token Price | Price of N-token in a liquidity pool | $P_N$ |
| Liquidity Provider | Reference to a liquidity provider | $\Pi$ |
| Liquidity Provider Reward | Reward earned by a liquidity provider | $r_{\pi}$ |
| Liquidity Provider ROI | Return on investment to a liquidity provider | $R_{\pi}$ |
| Liquidity Provider System Reward | Reward earned by the liquidity provider system | $R_{\Pi}$ |
| Liquidity Provider's Cost of Operation | Operational cost incurred by a liquidity provider | $C_{\Pi}$ |
| Liquidity Provider System ROI | Return on investment of the liquidity provider system |$\Omega_{\Pi}$ |

## Roles

A liquidity pool consists of two primary actors:
- **Liquidity Providers** who provide Rowan or N-tokens for a given duration of time to earn rewards.
- **Swappers** who participate in the liquidity pool to swap Rowan for N-tokens or vice versa.

## Actions

### Add and remove liquidity
The Rowan price is $P_S$ is defined as the units of Rowan $S$ that can be bought per unit of N-token $N$. $$P_S = \frac{S}{N}$$

Adding liquidity can be modeled as adding (n, s) such that $$ P^{+}_S = P_S $$ $$ P^{+}_S = \frac{S+s}{N+n} = \frac{S}{N} = P_S$$ where 
- $P_S$ is the Rowan price at the current state,
- $P^+_S$ is the Rowan price at the next state, 
- $s$ is the amount of Rowan added through the action 
- $n$ is the amount of N-tokens required to make the action. 

Removing liquidity can be modeled as removing (n, s) such that $$ P^{+}_S = \frac{S+s}{N+n} = \frac{S}{N} = P_S$$ where 
- $P_S$ is the Rowan price at the current state,
- $P^+_S$ is the Rowan price at the next state, 
- $s<0$ is some fraction of S; the amount of Rowan removed through the action
- $n<0$ is some fraction of N; the amount of N-tokens removed through the action

### Swapping
A swap is defined as an exchange of N-tokens for an Rowan or vice versa, while preserving the Continuous Liquidity Provider (CLP) formula. 

Consider a prior state (N, S). A swapper deposits $n = \Delta N$ to obtain $s = f(n; N, S)$ computed using the CLP model. Plugging in the slip-based fee $f_{swap} = \frac{n^2 S}{(n+N)^2}$, the resulting Rowan obtained is $$s = \frac{nSN}{(n+N)^2}$$


![](https://i.imgur.com/GXnYfiR.jpg)

We can define an invariant $I$ in this subsystem to represent the conservation of the $N,S$ relationship. $$I = f(f_{swap}, S, N)$$



### Create and destroy pool
A user can list a new pool with thier choice of N-token and its ratio with Rowan. To create a pool, the user must provide the initial liquidity in its specified Rowan:N-token ratio.

Under reasonable grounds, a pool can be removed or destroyed from Sifchain. See [Sifchain Liquidity System PRD](https://drive.google.com/file/d/1P9Co01zrTFz-x9ardaoYF7xfVskN21XR/view?ts=5f7c6d55).

## State Variables
**Definition 1: Rowan Supply**
The amount of Rowan in the liquidity pool in the current state.

**Definition 2: N-token Supply**
The amount of N-tokens in the liquidity pool in the current state.

**Definition 3: Liquidity Provider Rewards**
Rewards earned by the liquidity provider are a function of the swap fees and the dynamic rebalacing parameter

**Definition 4: Swap Fees**
Fees incurred by swapper while making a Rowan/Ntoken swap. Sifchain implements a *slip-based fee* for swaps, computed using the Continuous Liquidity Provider (CLP) model. The swap fee is a function of the swap volume and the demand for a pool's liquidity. $$f_{swap} = \frac{n^2 S}{(n+N)^2}$$

**Definition 5: Liquidity Provider System Revenue**
We can define the revenue per period of the liquidity provider subsystem as a function of the swap fee policy and the volume of swaps that occur in that period. $$R_{\Pi, T} = f_{swap}*v_{swap, T}$$

**Definition 6: Liquidity Provider System ROI**
We can define the ROI per period of the liquidity provider subsystem as a function of the revenue generated in that period and the cost of providing liquidity. $$\Omega_{\Pi, T} = \frac{R_{\Pi, T}}{C_{\Pi, T}}$$

## Assumptions
- Assume no destruction of liquidity pool 

#### Compute CLP output
https://docs.thorchain.org/how-it-works/continuous-liquidity-pools

From: https://github.com/thorchain/THORChain/blob/master/x/clp/keeper.go

``` go 
//Run Formula for CLP command
func RunCLPFormula(a float64, b float64, c float64, d float64) int64 {
	//y = a * ((1 + (b/c))^d - 1)
	y := a * (math.Pow(float64(1+(b/c)), d) - 1)
	return int64(math.Round(y))
}
```
#### Calculate Price based on CLP rule

https://docs.thorchain.org/how-it-works/prices

From: https://github.com/thorchain/THORChain/blob/master/x/clp/keeper.go

``` go
//CalculateCLPPrice get price
func CalculateCLPPrice(clp *types.CLP, clpCoins sdk.Coins, coinsPaid int64, baseCoinTicker string) float64 {
	c := float64(clpCoins.AmountOf(baseCoinTicker).Int64())
	a := float64(clp.CurrentSupply)
	d := float64(clp.ReserveRatio) / float64(100)
	b := float64(coinsPaid)
	y := a * (math.Pow(float64(1+(b/c)), d) - 1)
	return 1.0 / y
}
```

