Withdraw-Swap
To download notebook to this tutorial, see here
import osimport math as mthimport numpy as npfrom termcolor import coloredfrom uniswappy import *user_nm = 'user0'eth_amount = 1000tkn_amount = 100000Problem Defined
Section titled “Problem Defined”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:
where
- -> indexed token
- -> liquidity deposit
tkn = ERC20("TKN", "0x111")eth = ERC20("ETH", "0x09")exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = tkn, symbol="LP", address="0x011")
factory = UniswapFactory("ETH pool factory", "0x2")lp = factory.deploy(exchg_data)lp.add_liquidity(user_nm, eth_amount+100, tkn_amount, eth_amount+100, tkn_amount)
print('***\nInitial LP\n***')lp.summary()
amt_out = 100token_out = ethtrading_token = tknuser_nm1 = 'user0'#rate = 0
# Step 1: withdrawalp_out = 0.5removeLiq = RemoveLiquidity()res = removeLiq.apply(lp, token_out, user_nm1, p_out*amt_out)
print('***\nLP post step 1\n***')lp.summary()
# Step 2: swapout = Swap().apply(lp, trading_token, user_nm1, res[trading_token.token_name])
print('***\nLP post step 2\n***')lp.summary()
withdrawn = res[eth.token_name] + out
print('Total withdrawn is {:.6f} + {:.6f} = {:.6f} ETH'.format(p_out*amt_out, out, withdrawn))print('Of the requested {} ETH, a total of {:.6f} ETH has been withdrawn when using a 50/50 split'.format(amt_out, withdrawn))Solve Problem
Section titled “Solve 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
def calc_lp_settlement(lp, token_in, itkn_amt):
if(token_in.token_name == lp.token1): x = UniV3Helper().gwei2dec(lp.reserve0) y = UniV3Helper().gwei2dec(lp.reserve1) else: x = UniV3Helper().gwei2dec(lp.reserve1) y = UniV3Helper().gwei2dec(lp.reserve0)
L = UniV3Helper().gwei2dec(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*mth.sqrt(b*b - 4*a1*c/a2)) / (2*a1); return dLeth = ERC20("ETH", "0x09")tkn = ERC20("TKN", "0x111")exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = tkn, symbol="LP", address="0x011")
factory = UniswapFactory("ETH pool factory", "0x2")lp = factory.deploy(exchg_data)lp.add_liquidity(user_nm, eth_amount+100, tkn_amount, eth_amount+100, tkn_amount)lp.summary()
eth_amt = 100dL = calc_lp_settlement(lp, eth, eth_amt)
print('A request of {} ETH requires a settlement of {:.6f} LP token'.format(eth_amt, dL))y = UniV3Helper().gwei2dec(lp.reserve0)x = UniV3Helper().gwei2dec(lp.reserve1)L = UniV3Helper().gwei2dec(lp.total_supply)gamma = 997
(dL**2)*x*y/(L*L) - dL*((1000*eth_amt*x - eth_amt*gamma*x + 1000*x*y + x*y*gamma)/(1000*L)) + eth_amt*xToken Distribution
Section titled “Token Distribution”Using , we can determine the splitting distribution for withdrawal. Reconsidering Eq. 3, we redefine and by portion , thus:
Therefore, using Eq. 2 we calculate our distribution as:
Hence, using the above equation and from our solver, we can calculate the withdraw distribution via calc_portion
def calc_withdraw_portion(lp, token_in, amt):
if(token_in.token_name == lp.token1): x = UniV3Helper().gwei2dec(lp.reserve0) y = UniV3Helper().gwei2dec(lp.reserve1) else: x = UniV3Helper().gwei2dec(lp.reserve1) y = UniV3Helper().gwei2dec(lp.reserve0)
L = UniV3Helper().gwei2dec(lp.total_supply) gamma = 997/1000
dL = calc_lp_settlement(lp, token_in, amt) dx = dL*x/L dy = dL*y/L aswap = (gamma*dx)*(y-dy)/(x-dx+gamma*dx)
return dy/amtalpha = calc_withdraw_portion(lp, eth, eth_amt)print('The correct portion (for step 1) is {:.6f}'.format(alpha))WithdrawSwap Steps
Section titled “WithdrawSwap Steps”Finally, lets run through the steps to a WithdrawSwap and compare above
tkn = ERC20("TKN", "0x111")eth = ERC20("ETH", "0x09")exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = tkn, symbol="LP", address="0x011")
factory = UniswapFactory("ETH pool factory", "0x2")lp = factory.deploy(exchg_data)lp.add_liquidity(user_nm, eth_amount+100, tkn_amount, eth_amount+100, tkn_amount)
print('***\nInitial LP\n***')lp.summary()
amt_out = 100token_out = ethuser_nm = 'user0'
# Step 1: withdrawalp_out = calc_withdraw_portion(lp, token_out, amt_out)removeLiq = RemoveLiquidity()res = removeLiq.apply(lp, token_out, user_nm, p_out*amt_out)
print('***\nLP post step 1\n***')lp.summary()
# Step 2: swapout = Swap().apply(lp, trading_token, user_nm, res[trading_token.token_name])
print('***\nLP post step 2\n***')lp.summary()
withdrawn = res[eth.token_name] + out
print('Total withdrawn is {:.6f} + {:.6f} = {:.6f} \ETH'.format(p_out*amt_out, out, withdrawn))print('Of the requested {} ETH, a total of {:.6f} ETH \has been withdrawn'.format(amt_out, withdrawn))Final Solution
Section titled “Final Solution”Finally, let’s check when our solution is integrated into WithdrawSwap
tkn = ERC20("TKN", "0x111")eth = ERC20("ETH", "0x09")exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = tkn, symbol="LP", address="0x011")
factory = UniswapFactory("ETH pool factory", "0x2")lp = factory.deploy(exchg_data)lp.add_liquidity(user_nm, eth_amount+100, tkn_amount, eth_amount+100, tkn_amount)lp.summary()
amt_out = 100out = WithdrawSwap().apply(lp, eth, user_nm, 100)lp.summary()
print('Total withdrawn is {:.6f} ETH, as per request'.format(out))