Swap-Deposit
To download notebook to this tutorial, see here
import osimport mathimport numpy as npfrom termcolor import coloredfrom uniswappy import *user_nm = 'user0'eth_amount = 1000usdc_amount = 1000000Problem Defined
Section titled “Problem Defined”- A
SwapDepositis where a certain amount of a specific token is deposited into the LP under one operation - Includes two steps:
- (step 1) perform approx. 50% swap for opposing token
- (step 2) using amt from step 1, perform 1:1 deposit
- A portion of the incoming funds are swapped to achieve equal portions of both assets
- These portions are then deposited into the LP
- To ensure all the funds are deposited, we must determine the portion () of that must first get swapped
Follows this system of equations:
where
- -> amt token in
- -> amt opposing token out after swap
- -> portion of swapped in
- x -> reserve0
- y -> reserve1
Let’s highlight why the above considerations are important …
eth = ERC20("ETH", "0x09")usdc = ERC20("USDC", "0x111")exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = usdc, symbol="LP", address="0x011")
factory = UniswapFactory("ETH pool factory", "0x2")lp = factory.deploy(exchg_data)lp.add_liquidity(user_nm, eth_amount, usdc_amount, eth_amount, usdc_amount)
print('***\nInitial LP\n***')lp.summary()
s_in = 100alpha = 0.5s_out = Swap().apply(lp, eth, user_nm, alpha*s_in)
print('***\nLP post step 1\n***')lp.summary()
balance0 = alpha*s_inbalance1 = lp.quote(balance0, lp.reserve0, lp.reserve1)lp.add_liquidity(user_nm, balance0, balance1, balance0, balance1)
print('***\nLP post step 2\n***')lp.summary()
print('Given {} initial ETH:'.format(s_in))print(' (step 1) {} ETH must first get swapped for {} '.format(alpha*s_in, s_out))print(' (step 2) The received TKN gets deposited along with the remaining {} ETH'.format(balance0))
print('\nTotal deposited is {:.6f} + {:.6f} = {:.6f} ETH:'.format(alpha*s_in, balance0, alpha*s_in + balance0))print('However, we have {} unaccounted USDC which need to be considered when using a 50/50 split'.format(colored(str(usdc_amount-lp.get_reserve(usdc)), 'red', attrs=['bold'])))Solve Problem
Section titled “Solve Problem”Let’s now address this problem …
usdc = ERC20("TKN", "0x111")eth = ERC20("ETH", "0x09")exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = usdc, symbol="LP", address="0x011")
factory = UniswapFactory("ETH pool factory", "0x2")lp = factory.deploy(exchg_data)lp.add_liquidity(user_nm, eth_amount, usdc_amount, eth_amount, usdc_amount)
s_in = 100alpha = 0.5y = lp.get_reserve(usdc)x = lp.get_reserve(eth)Plug above into equation (1), and see how many TKN we get when 50% of ETH is swapped in for step (1)
s_out = (997*alpha*s_in*y)/(1000*x + 997*alpha*s_in)print('For {} ETH, we get {:.2f} TKN with a 50% portion'.format(s_in, s_out))Now, lets check how many ETH gets SwapDeposited in when 50% of ETH is swapped in for step (1)
a1_out = alpha*s_in + s_out*(x + alpha*s_in)/(y - s_out)print('Instead of {} ETH, we get {:.2f} ETH under a 50% portion'.format(s_in, a1_out))We can see that there is an imbalance in the system under a 50% distribution for step (1);
- we need to solve the system above for to get the proper distribution
- plug (1) into (2) and we get:
reduces to:
Now, solve for, and we can calculate the correct distribution using calc_deposit_dist
def calc_deposit_portion(lp, token_in, dx):
tokens = lp.factory.token_from_exchange[lp.name] if(token_in.token_name == lp.token0): tkn_supply = lp.get_reserve(tokens[lp.token0]) else: tkn_supply = lp.get_reserve(tokens[lp.token1])
a = 997*(dx**2)/(1000*tkn_supply) b = dx*(1997/1000) c = -dx
alpha = -(b - np.sqrt(b*b - 4*a*c)) / (2*a) return alphaalpha = calc_deposit_portion(lp, eth, s_in)print('The correct swap distrbution (for step 1) is {}'.format(alpha))Now, check against our reduced quadratic, and we should expect to get 0
997*(alpha**2)*(s_in**2)/(1000*x) + alpha*s_in*(1997/1000) - s_inFinal Steps
Section titled “Final Steps”Finally, lets run through the steps to a SwapDeposit and compare above
usdc = ERC20("USDC", "0x111")eth = ERC20("ETH", "0x09")exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = usdc, symbol="LP", address="0x011")
factory = UniswapFactory("ETH pool factory", "0x2")lp = factory.deploy(exchg_data)lp.add_liquidity(user_nm, eth_amount, usdc_amount, eth_amount, usdc_amount)
print('***\nInitial LP\n***')lp.summary()
s_in = 100alpha = calc_deposit_portion(lp, eth, s_in)s_out = Swap().apply(lp, eth, user_nm, alpha*s_in)
print('***\nLP post step 1\n***')lp.summary()
balance1 = s_outbalance0 = s_in-alpha*s_inlp.add_liquidity(user_nm, balance0, balance1, balance0, balance1)
print('***\nLP post step 2\n***')lp.summary()
print('Given {} initial ETH:'.format(s_in))print(' (step 1) {} ETH must first get swapped for {} USDC'.format(alpha*s_in, s_out))print(' (step 2) The received USDC gets deposited along with the remaining {} ETH'.format(balance0))
print('\nTotal deposited is {:.6f} + {:.6f} = {:.6f} ETH:'.format(alpha*s_in, balance0, alpha*s_in + balance0))Final Check
Section titled “Final Check”Finally, let’s check when our solution is integrated into SwapDeposit
usdc = ERC20("USDC", "0x111")eth = ERC20("ETH", "0x09")exchg_data = UniswapExchangeData(tkn0 = eth, tkn1 = usdc, symbol="LP", address="0x011")
factory = UniswapFactory("ETH pool factory", "0x2")lp = factory.deploy(exchg_data)lp.add_liquidity(user_nm, eth_amount, usdc_amount, eth_amount, usdc_amount)lp.summary()
s_in = 100dep = SwapDeposit().apply(lp, eth, user_nm, s_in)lp.summary()