Indexing Problem

[29]:
from IPython.display import Image
from uniswappy import *

user_nm = 'user_test'
eth_amount = 1000
dai_amount = 1000000

dai = ERC20("DAI", "0x111")
eth = ERC20("ETH", "0x09")
exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = dai, symbol="LP", address="0x011")

factory = UniswapFactory("ETH pool factory", "0x2")
lp = factory.deploy(exchg_data)
lp.add_liquidity(user_nm, eth_amount, dai_amount, eth_amount, dai_amount)
lp.summary()
Exchange ETH-DAI (LP)
Reserves: ETH = 1000.0, DAI = 1000000.0
Liquidity: 31622.776601683792

Problem Defined

  • We have some liquidity token (dL), and want to know home much x or y its worth

  • Let’s start with the Naive approach

\(x = \frac{L^2}{y}\)

\(\frac{dx}{dL} = \frac{2L}{y}\)

Substitute (\(y = \frac{L^2}{x}\)) into above

\(\frac{dx}{dL} = \frac{2x}{L}\)

Hence $:nbsphinx-math:`Delta `x $ approximates to:

\(\Delta x \sim \frac{2x \Delta L }{L}\)

Likewise \(\Delta L\) approximates to:

\(\Delta L \sim \frac{L \Delta x }{2x}\)

Logically, this works ok for small values of \(\Delta x\) and \(\Delta L\), so let’s assume \(\Delta L\) is 1% of total supply

[30]:
lp_position = 0.01*lp.get_liquidity()
naive_approximation = 2*lp.get_reserve(eth)*lp_position/(lp.total_supply)

print(f'{lp_position:.5f} LP token is worth {naive_approximation:.5f} ETH tokens using the Naive \napproach with 1% of LP')
316.22777 LP token is worth 0.00000 ETH tokens using the Naive
approach with 1% of LP

However, not for large values; let’s assume \(\Delta L\) is 100% of total supply

[31]:
lp_position = lp.get_liquidity()
naive_approximation = 2*lp.get_reserve(eth)*lp_position/(lp.total_supply)

print(f'{lp_position:.5f} LP token is worth {naive_approximation:.5f} ETH tokens using the Naive approach with 100% of LP')
31622.77660 LP token is worth 0.00000 ETH tokens using the Naive approach with 100% of LP

2000 ETH is completely off, as there are only 1000 ETH in the pool!

[32]:
Image("./indexed_tkn.png", width = 300, height = 300)
[32]:
../../_images/uniswapv2_tutorials_indexing_problem_7_0.png

Given the definition of constant product trading (CPT) as:

\((x-\Delta x)(y - \gamma\Delta y) = L^2\)

where * \(x\) -> reserve0 (r0) * \(y\) -> reserve1 (r1) * \(\Delta x\) -> swap x (a0) * \(\Delta y\) -> swap y (a1) * \(L\) -> total supply * \(\gamma\) -> fee \(\left(ie, \frac{997}{1000} \right)\)

We define the indexing problem via the following linear system of equations:

(Eq. 1) \(\Delta x = \frac{\Delta L x}{L}\)

(Eq. 2) \(\Delta y = \frac{\Delta L y}{L}\)

(Eq. 3) \(\Delta y_{(i)} = \Delta y + \frac{\gamma \Delta x(y-\Delta y)}{(x - \Delta x) + \gamma \Delta x}\)

where

  • \(\Delta y_{(i)}\) -> indexed token

  • \(\Delta L\) -> liquidity deposit

[33]:
def calc_tkn_settlement(lp, token_in, dL):

    if(token_in.token_name == lp.token1):
        x = lp.reserve0
        y = lp.reserve1
    else:
        x = lp.reserve1
        y = lp.reserve0

    L = lp.total_supply
    a0 = dL*x/L
    a1 = dL*y/L
    gamma = 997/1000

    dy1 = a1
    dy2 = gamma*a0*(y - a1)/(x - a0 + gamma*a0)
    itkn_amt = dy1 + dy2

    return itkn_amt if itkn_amt > 0 else 0
[34]:
delta_L = 1
delta_eth = calc_tkn_settlement(lp, eth, delta_L)
delta_dai = calc_tkn_settlement(lp, dai, delta_L)
print(f'1 LP token is worth {delta_eth:.5f} {eth.token_name}')
print(f'1 LP token is worth {delta_dai:.5f} {dai.token_name}')
1 LP token is worth 0.06315 ETH
1 LP token is worth 63.15068 DAI

Uniswap Settlement Problem

We have x or y and want to know how much LP token it is worth

[35]:
Image("./settlement_lp_tkn.png", width = 300, height = 300)
[35]:
../../_images/uniswapv2_tutorials_indexing_problem_12_0.png

Let’s now address the problem; using the system of equations outlined in the indexing problem, Eq. 3 can be rearranged as: > \((\Delta y_{(i)}x) - (\Delta y_{(i)}\Delta x) + (\gamma \Delta y_{(i)} \Delta x) - (\Delta y x) + (\Delta y\Delta x) - (\gamma y\Delta x) = 0\)

Plug Eq. 1 and Eq. 2 into above, and we get: > \((\Delta y_{(i)} x) - (\frac{\Delta y_{(i)} \Delta L x}{L}) + (\frac{\Delta y_{(i)} \gamma \Delta L x}{L}) - (\frac{\Delta L xy}{L}) + (\frac{\Delta L^2 xy}{L^2}) - (\frac{\Delta L \gamma x y}{L}) = 0\)

The above equation gets reduced to the following quadratic: > \(\Delta L^2 \left( \frac{xy}{L^2} \right) - \Delta L \left(\frac{1000 \Delta y_{(i)} x - 997\Delta y_{(i)} x + 1000xy + 997 xy}{1000L} \right) + \Delta y_{(i)} x = 0\)

Now, solve for \(\Delta L\) using calc_lp_settlement

[36]:
import math

def calc_lp_settlement(lp, token_in, itkn_amt):

    if(token_in.token_name == lp.token1):
        x = lp.reserve0
        y = lp.reserve1
    else:
        x = lp.reserve1
        y = lp.reserve0

    L = lp.total_supply
    gamma = 997

    a1 = x*y/L
    a2 = L
    a = a1/a2
    b = (1000*itkn_amt*x - itkn_amt*gamma*x + 1000*x*y + x*y*gamma)/(1000*L);
    c = itkn_amt*x;

    dL = (b*a2 - a2*math.sqrt(b*b - 4*a1*c/a2)) / (2*a1);
    return dL
[37]:
print(f'{delta_eth:.5f} {eth.token_name} token is worth {calc_lp_settlement(lp, eth, delta_eth):.5f} LP tokens')
print(f'{delta_dai:.5f} {dai.token_name} token is worth {calc_lp_settlement(lp, dai, delta_dai):.5f} LP tokens')
0.06315 ETH token is worth 0.00000 LP tokens
63.15068 DAI token is worth 0.00000 LP tokens

Using UniswapPy

  • Use LPQuote and set quote_opposing = False

[38]:
delta_eth = LPQuote(quote_opposing = False).get_amount_from_lp(lp, eth, 1)
delta_dai = LPQuote(quote_opposing = False).get_amount_from_lp(lp, dai, 1)
print(f'1 LP token is worth {delta_eth:.5f} {eth.token_name}')
print(f'1 LP token is worth {delta_dai:.5f} {dai.token_name}')
1 LP token is worth 0.06315 ETH
1 LP token is worth 63.14969 DAI
[39]:
delta_eth_lp = LPQuote(quote_opposing = False).get_lp_from_amount(lp, eth, delta_eth)
delta_dai_lp = LPQuote(quote_opposing = False).get_lp_from_amount(lp, dai, delta_dai)
print(f'{delta_eth:.5f} {eth.token_name} token is worth {delta_eth_lp:.5f} LP tokens')
print(f'{delta_dai:.5f} {dai.token_name} token is worth {delta_dai_lp:.5f} LP tokens')
0.06315 ETH token is worth 1.00000 LP tokens
63.14969 DAI token is worth 1.00000 LP tokens

As we can see this quoting mechanisim is validated as we get back to the original 1 LP token for both assets

Naive Approach

Finally, let’s see how Indexed approach sizes up against the Naive approach

[40]:
lp_position = 0.01*lp.get_liquidity()
naive_approximation = 2*lp.get_reserve(eth)*lp_position/(lp.total_supply)
indexed_approach = LPQuote(quote_opposing = False).get_amount_from_lp(lp, eth, lp_position)

print(f'{lp_position:.2f} LP token is worth {naive_approximation:.2f} ETH tokens using the Naive approach with 1% of LP')
print(f'{lp_position:.2f} LP token is worth {indexed_approach:.2f} ETH tokens using the Indexed approach with 1% of LP')
316.23 LP token is worth 0.00 ETH tokens using the Naive approach with 1% of LP
316.23 LP token is worth 19.87 ETH tokens using the Indexed approach with 1% of LP

Indexed Approach

We can see that the Naive approximation is pretty close to our Indexed solution (with 1% LP); let’s now try 100%

[41]:
lp_position = lp.get_liquidity()
naive_approximation = 2*lp.get_reserve(eth)*lp_position/(lp.total_supply)
indexed_approach = LPQuote(quote_opposing = False).get_amount_from_lp(lp, eth, lp_position)

print(f'{lp_position:.2f} LP token is worth {naive_approximation:.2f} ETH tokens using the Naive approach with 100% of LP')
print(f'{lp_position:.2f} LP token is worth {indexed_approach:.2f} ETH tokens using the Indexed approach with 100% of LP')
31622.78 LP token is worth 0.00 ETH tokens using the Naive approach with 100% of LP
31622.78 LP token is worth 1000.00 ETH tokens using the Indexed approach with 100% of LP

Final Check

Excellent, we see that with our Indexed solution all 1000 ETH are accounted for using the indexed approach

[42]:
dai = ERC20("DAI", "0x111")
eth = ERC20("ETH", "0x09")
exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = dai, symbol="LP", address="0x011")

factory = UniswapFactory("ETH pool factory", "0x2")
lp = factory.deploy(exchg_data)
lp.add_liquidity(user_nm, eth_amount, dai_amount, eth_amount, dai_amount)
lp.summary()
Exchange ETH-DAI (LP)
Reserves: ETH = 1000.0, DAI = 1000000.0
Liquidity: 31622.776601683792

[43]:
delta_dai_lp = LPQuote(quote_opposing = False).get_lp_from_amount(lp, dai, 1)
delta_dai_lp
[43]:
0.0158351449592624