showing how this formula comes from
- https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol#L43
- https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2LiquidityMathLibrary.sol#L17
ua: reserveA ub: reserveB
sa: truePriceTokenA sb: truePriceTokenB
x: amountIn y: amountOut
>>> from sympy import *
>>> ua, ub, sa, sb, x, y, r_in, r_out, d = symbols('ua ub sa sb x y in, out, d')
>>> init_printing(use_unicode=True)
>>> k_before_swap = ua * ub
>>> k_after_swap = (ua+x)*(ub-y)
>>> solve(Eq(k_before_swap, k_after_swap), y)
⎡ ub⋅x ⎤
⎢──────⎥
⎣ua + x⎦
>>> ((ub*x)/(ua+x)).subs({x: 0.997*x})
0.997⋅ub⋅x
────────────
ua + 0.997⋅x
>>> true_price = sa/sb
>>> price_after_arbitrage = (ua + x) / (ub - (x*ub)/(ua+x))
>>> price_after_arbitrage
ua + x
─────────────
ub⋅x
- ────── + ub
ua + x
>>> solve(Eq(true_price, price_after_arbitrage),x)
⎡ _____________ _____________⎤
⎢ ╲╱ sa⋅sb⋅ua⋅ub ╲╱ sa⋅sb⋅ua⋅ub ⎥
⎢-ua - ───────────────, -ua + ───────────────⎥
⎣ sb sb ⎦
>>> # (bonus) slightly different version of above, with fee and assume price in s is not "true price"
>>> get_amount_in = (1000 * r_in * y)/(997*(r_out - y))
>>> get_amount_out = (997 * r_out * x)/(1000 * r_in + 997 * x)
>>> profit = get_amount_out.subs({x: d, r_in: ua, r_out: ub}) - get_amount_in.subs({y: d, r_in: sb, r_out: sa})
>>> solve(Eq(diff(profit, d), 0), d)[1]
_____________ _____________
-1000⋅sa⋅sb⋅ua - 997⋅sa⋅ua⋅ub + 997⋅sa⋅╲╱ sa⋅sb⋅ua⋅ub + 1000⋅ua⋅╲╱ sa⋅sb⋅ua⋅ub
────────────────────────────────────────────────────────────────────────────────
997⋅sa⋅sb - 997⋅ua⋅ub