Skip to content

Uniswap V2

from uniswappy import *
import numpy as np
import matplotlib.pyplot as plt
import math
user_nm = 'user_intro'
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)
Join().apply(lp, user_nm, eth_amount, dai_amount)
lp.summary()
Exchange ETH-DAI (LP) Reserves: ETH = 1000.0, DAI = 1000000.0 Liquidity: 31622.776601683792

Given CPT formula

xy=L2xy = L^2

with 0.3% swap fee

γ=10.003=9971000\gamma = 1 - 0.003 = \frac{997}{1000} Since L is preserved when swapping, the CPT swap formula with fee is given as

(xΔx)(y+γΔy)=xy\quad (x - \Delta x)(y + \gamma \Delta y) = xy To determine swap amount, isolate Δx\Delta x

Δx=xxyy+γΔy\quad \Delta x = x - \frac{xy}{y + \gamma \Delta y} After performing some additional algebra, we get

Δx=γxΔyy+γΔy\quad \Delta x = \frac{\gamma x\Delta y}{y + \gamma \Delta y}

dy = 1000
gamma = 997/1000
x = lp.get_reserve(eth)
y = lp.get_reserve(dai)
dx = (gamma*x*dy)/(y + gamma*dy)
print(f'We receive {dx:.5f} ETH for {dy} DAI')
We receive 0.99601 ETH for 1000 DAI
out = Swap().apply(lp, dai, user_nm, dy)
lp.summary()
print(f'We receive {out:.5f} ETH for {dy} DAI')
Exchange ETH-DAI (LP) Reserves: ETH = 999.00399301896, DAI = 1001000.0 Liquidity: 31622.776601683792 We receive 0.99601 ETH for 1000 DAI
L = lp.get_liquidity()
x2 = lp.get_reserve(eth)
y2 = lp.get_reserve(dai)
x_arr = np.arange(990, 1010, 0.01)
y_arr = L**2/x_arr
fig, (ax) = plt.subplots(nrows=1, sharex=False, sharey=False, figsize=(10, 5))
ax.plot(x_arr, y_arr, color = 'b',linestyle = 'dashdot', label='initial invest')
ax.plot(x, y, 'ro', color='r')
ax.plot(x2, y2, 'ro', color='g')
ax.hlines(y=y2, xmin=0, xmax=x2, linewidth=1, color='g', linestyle = 'dashed')
ax.vlines(x = x2, ymin=0, ymax=y2, linewidth=1, color='g', linestyle = 'dashed')
ax.hlines(y= y, xmin=0, xmax=x, linewidth=1, color='r', linestyle = 'dashed')
ax.vlines(x = x, ymin=0, ymax=y, linewidth=1, color='r', linestyle = 'dashed')
ax.annotate('post-swap', xy=(x2, y2),xytext=(x2+5, y2+5000), arrowprops=dict(facecolor='green',width=0.5,headwidth=10,headlength=10))
ax.annotate('pre-swap', xy=(x, y),xytext=(x2+7, y2+2000), arrowprops=dict(facecolor='red',width=0.5,headwidth=10,headlength=10))
ax.set_title(f'CPT Price Curve Swap', fontsize=20)
ax.set_ylabel(f'{dai.token_name} Reserve Amt', size=15)
ax.set_xlabel(f'{eth.token_name} Reserve Amt', size=15)
ax.set_xlim((990,1010))
ax.set_ylim((992000,1008000))
(992000.0, 1008000.0)
output
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)
Join().apply(lp, user_nm, eth_amount, dai_amount)
lp.summary()
Exchange ETH-DAI (LP) Reserves: ETH = 1000.0, DAI = 1000000.0 Liquidity: 31622.776601683792
dx = 1
x = lp.get_reserve(eth)
y = lp.get_reserve(dai)
L = lp.get_liquidity()

Given CPT formula

xy=L2xy = L^2

Price is determined as such

P=yx=ΔyΔxP = \frac{y}{x} = \frac{\Delta y}{\Delta x}

P=yx=y2xy=y2L2P = \frac{y}{x} = \frac{y^2}{xy} = \frac{y^2}{L^2}, P=yx=xyx2=L2x2\quad P = \frac{y}{x} = \frac{xy}{x^2} = \frac{L^2}{x^2}

Given P above, calculate Δx\Delta x and Δy\Delta y while maintaining price integrity

P=yL\sqrt{P} = \frac{y}{L}, P=Lx\quad\quad\quad \sqrt{P} = \frac{L}{x}

ΔyΔx=yL\sqrt{\frac{\Delta y}{\Delta x}} = \frac{y}{L}, ΔyΔx=Lx\quad\quad \sqrt{\frac{\Delta y}{\Delta x}} = \frac{L}{x}

Δy2ΔxΔy=yL\sqrt{\frac{\Delta y^2}{\Delta x \Delta y}} = \frac{y}{L}, ΔyΔxΔx2=Lx\quad \sqrt{\frac{\Delta y \Delta x}{\Delta x^2}} = \frac{L}{x}

ΔyΔL=yL\frac{\Delta y}{\Delta L} = \frac{y}{L}, ΔLΔx=Lx\quad\quad\quad \frac{\Delta L}{\Delta x} = \frac{L}{x}

Δy=yΔLL\Delta y = \frac{y \Delta L}{L}, Δx=xΔLL\quad\quad \Delta x = \frac{x \Delta L}{L}

Take RHS of CPT formula and deduct Δx\Delta x and Δy\Delta y from both xx and yy to maintain integrity of the price

(xΔx)(yΔy)=(xxΔLL)(yyΔLL)(x - \Delta x)(y - \Delta y) = (x - \frac{x \Delta L}{L})(y - \frac{y \Delta L}{L}) =xy2xyΔLL+xyΔL2L2\quad\quad\quad\quad\quad\quad\quad\quad = xy - 2xy\frac{\Delta L}{L} + xy\frac{\Delta L^2}{L^2} =(LΔL)2\quad\quad\quad\quad\quad\quad\quad\quad = (L - \Delta L)^2 CPT withdraw formula

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

dL = dx*L/x
dy = y*dL/L
new_x = (x-dx)
new_y = (y-dy)
new_L = L-dL
print(f'The updated reserves are {new_x} ETH and {new_y} DAI, and the updated liquidity is {new_L:8f}')
The updated reserves are 999.0 ETH and 999000.0 DAI, and the updated liquidity is 31591.153825
RemoveLiquidity().apply(lp, eth, user_nm, dx)
lp.summary()
Exchange ETH-DAI (LP) Reserves: ETH = 999.0, DAI = 999000.0 Liquidity: 31591.15382508211
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)
Join().apply(lp, user_nm, eth_amount, dai_amount)
lp.summary()
Exchange ETH-DAI (LP) Reserves: ETH = 1000.0, DAI = 1000000.0 Liquidity: 31622.776601683792
dx = 1
x = lp.get_reserve(eth)
y = lp.get_reserve(dai)
L = lp.get_liquidity()

We know from above to maintain price integrity, double-sided change amounts Δx\Delta x and Δy\Delta y are determined as such

Δy=yΔLL\Delta y = \frac{y \Delta L}{L}, Δx=xΔLL\quad\quad \Delta x = \frac{x \Delta L}{L}

Take RHS of CPT formula and add Δx\Delta x and Δy\Delta y to both xx and yy to maintain integrity of the price

(x+Δx)(y+Δy)=(x+xΔLL)(y+yΔLL)(x + \Delta x)(y + \Delta y) = (x + \frac{x \Delta L}{L})(y + \frac{y \Delta L}{L}) Perform algebra simular to above and we get the CPT deposit formula

(x+Δx)(y+Δy)=(L+ΔL)2(x + \Delta x)(y + \Delta y) = (L + \Delta L)^2

dL = dx*L/x
dy = y*dL/L
new_x = (x+dx)
new_y = (y+dy)
new_L = L+dL
print(f'The updated reserves are {new_x} ETH and {new_y} DAI, and the updated liquidity is {new_L:8f}')
The updated reserves are 1001.0 ETH and 1001000.0 DAI, and the updated liquidity is 31654.399378
AddLiquidity().apply(lp, eth, user_nm, dx)
lp.summary()
Exchange ETH-DAI (LP) Reserves: ETH = 1001.0, DAI = 1001000.0 Liquidity: 31654.399378285478
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)
Join().apply(lp, user_nm, eth_amount, dai_amount)
lp.summary()
Exchange ETH-DAI (LP) Reserves: ETH = 1000.0, DAI = 1000000.0 Liquidity: 31622.776601683792

Given Δx\Delta x and Δy\Delta y for withdraw

Δy=yΔLL\Delta y = \frac{y \Delta L}{L}, Δx=xΔLL\quad\quad \Delta x = \frac{x \Delta L}{L}

Also, given swap equation

Δys=γyΔxx+γΔx\Delta y_{s} = \frac{\gamma y\Delta x}{x + \gamma \Delta x} A single-sided withdraw constitutes of the sum total of a withdraw and a swap, otherwise known as a WithdrawSwap, and is given by

Δyws=Δy+γΔx(yΔy)(xΔx)+γΔx\Delta y_{ws} = \Delta y + \frac{\gamma \Delta x (y - \Delta y)}{(x - \Delta x) + \gamma \Delta x} Plug Δx\Delta x and Δy\Delta y into Δyws\Delta y_{ws} and after performing some algebra we get

ΔL2(xyL2)+ΔL(Δywsx+ΔysswγxxyxyγL)+Δywsx=0\Delta L^2 \left( \frac{xy}{L^2}\right) + \Delta L \left( \frac{-\Delta y_{ws}x + \Delta y_{ssw} \gamma x -xy -xy\gamma}{L} \right) + \Delta y_{ws}x = 0 Given the fact we know our desired withdraw amount, Δyws\Delta y_{ws}, we solve the above quadratic to determine our single-sided settlement amount in terms of ΔL\Delta L; for more detailed information, see this medium article

Perform single-sided withdraw using uniswappy

Section titled “Perform single-sided withdraw using uniswappy”
dy = 1
amount_out = WithdrawSwap().apply(lp, eth, user_nm, dy)
lp.summary()
Exchange ETH-DAI (LP) Reserves: ETH = 999.0, DAI = 1000000.0 Liquidity: 31606.937511796754
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)
Join().apply(lp, user_nm, eth_amount, dai_amount)
lp.summary()
Exchange ETH-DAI (LP) Reserves: ETH = 1000.0, DAI = 1000000.0 Liquidity: 31622.776601683792

A single-sided deposit constitutes of the sum total of a swap followed by a deposit, otherwise known as a SwapDeposit, and is given by

Δxsd=Δxswap+Δxdeposit\Delta x_{sd} = \Delta x_{swap} + \Delta x_{deposit} =αΔxsd+Δys(x+αΔxsd)yΔys\quad\quad = \alpha \Delta x_{sd} + \frac{\Delta y_{s}(x+\alpha\Delta x_{sd})}{y - \Delta y_{s}} Given swap equation

Δys=γxΔyy+γΔy\Delta y_{s} = \frac{\gamma x\Delta y}{y + \gamma \Delta y} Thus, we get this system of equations:

Δys=γxΔyy+γΔy\Delta y_{s} = \frac{\gamma x\Delta y}{y + \gamma \Delta y} Δxsd=αΔxsd+Δys(x+αΔxsd)yΔys\Delta x_{sd} = \alpha\Delta x_{sd} + \frac{\Delta y_{s}(x + \alpha\Delta x_{sd} )}{y - \Delta y_{s}} where γ=9971000\gamma = \frac{997}{1000}

To solve for ratio α\alpha, we plug Δys\Delta y_{s} into Δxsd\Delta x_{sd}, and after some algebra, we get this quadratic

α2997Δxsd21000x+α1997Δxsd1000Δxsd=0\alpha^2 \frac{997 \Delta x_{sd}^2}{1000x} + \alpha\frac{1997\Delta x_{sd}}{1000} - \Delta x_{sd} = 0 For more detailed information, see this medium article

Perform single-sided deposit using uniswappy

Section titled “Perform single-sided deposit using uniswappy”
dy = 1
dep = SwapDeposit().apply(lp, eth, user_nm, dy)
lp.summary()
Exchange ETH-DAI (LP) Reserves: ETH = 1001.0, DAI = 1000000.0 Liquidity: 31638.56029234534