Indexing Problem
To download notebook to this tutorial, see here
from uniswappy import *
user_nm = 'user_test'eth_amount = 1000dai_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()Problem Defined
Section titled “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
Substitute () into above
Hence approximates to:
Likewise approximates to:
Logically, this works ok for small values of and , so let’s assume is 1% of total supply
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')However, not for large values; let’s assume is 100% of total supply
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')2000 ETH is completely off, as there are only 1000 ETH in the pool!
Uniswap Indexing Problem
Section titled “Uniswap Indexing Problem”We have a certain amount of LP token and want to know how much its worth in x or y
Given the definition of constant product trading (CPT) as:
where
- -> reserve0 (r0)
- -> reserve1 (r1)
- -> swap x (a0)
- -> swap y (a1)
- -> total supply
- -> fee
We define the indexing problem via the following linear system of equations:
(Eq. 1)
(Eq. 2)
(Eq. 3)
where
- -> indexed token
- -> liquidity deposit
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 0delta_L = 1delta_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}')Uniswap Settlement Problem
Section titled “Uniswap Settlement Problem”We have x or y and want to know how much LP token it is worth
Let’s now address the problem; using the system of equations outlined in the indexing problem, Eq. 3 can be rearranged as:
Plug Eq. 1 and Eq. 2 into above, and we get:
The above equation gets reduced to the following quadratic:
Now, solve for using calc_lp_settlement
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 dLprint(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')Using UniswapPy
Section titled “Using UniswapPy”- Use LPQuote and set quote_opposing = False
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}')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')As we can see this quoting mechanisim is validated as we get back to the original 1 LP token for both assets
Naive Approach
Section titled “Naive Approach”Finally, let’s see how Indexed approach sizes up against the Naive approach
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')Indexed Approach
Section titled “Indexed Approach”We can see that the Naive approximation is pretty close to our Indexed solution (with 1% LP); let’s now try 100%
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')Final Check
Section titled “Final Check”Excellent, we see that with our Indexed solution all 1000 ETH are accounted for using the indexed approach
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()delta_dai_lp = LPQuote(quote_opposing = False).get_lp_from_amount(lp, dai, 1)delta_dai_lp