# Uniswap V2 - Sandwich attack ###### tags: `crypto`, `uniswap2`, `arbitrage` According to the [source](https://medium.com/coinmonks/defi-sandwich-attack-explain-776f6f43b2fd) and [source](https://ethresear.ch/t/improving-front-running-resistance-of-x-y-k-market-makers/1281) the term Sandwich attack describes a practice of taking advantage of automated market makers by frontrunning the swap effectively lowering the asset price before the victim's swap is performed. This only possible in protocols, where price is dynamically adjusted based in response for user interactions. The following is a list of terms used in the current document: **Liquidity pair** (LP) - is a smart contract (a protocol) that allows to exchange some amount of asset X for some amount of asset Y. In scope of the document only Uniswap V2 protocol is taken into consideration. **Swap** - is a procedure of singular exchange. **Reserve** - is an amount of asset X secured in a protocol. Each protocl of Uniswap V2 has two reserves, one for each asset used in exchage. Exchange in scope of Uniswap V2 allowed in both directions. **Amount in** - the amount of tokens spend on exchange. **Amount out** - the amount of tokens received as the result of exchange procedure for **amount in**. <br> ## Definition of exchange According to [source code of Uniswap V2](https://github.com/Uniswap/v2-periphery/blob/master/contracts/libraries/UniswapV2Library.sol#L43-L50), the dependency between an amount $x$ of token bought (by the protocol) and an amount $y$ of tokens sold during a swap is the following: $$y = \frac{997 r_y x}{1000r_x + 997x}$$ Where $r_x$ and $r_y$ are reserves of token $X$ and $Y$ before the exchange. The coefficient `997` shows the protocol fee, which in case of Uniswap V2 is fixed (0.3%). In general, exchange equation is: $$y = \frac{qr_yx}{r_x + qx} \quad q = 1 - fee$$ Where $fee$ is a fee in percents and $q$ is a value introduced for simplicity. The [graph](https://www.desmos.com/calculator/intgs5ozza) of this equation shows that function is a hyperbola asymptotically approaching $r_y$ as $x$ tends to infinity. This dependency is a consequence of the protocol architecture, where an asset price is a product of reserves ratio. In general case, the ratio is the following: $$r_xr_y = k \quad\quad k - const$$ Where $k$ is a constant value, set up by the owner of the protocol during it's initialization. In other words, the reference exchange ration is set acts as an equilibrium point with protocol raising the asset price after it's being sold. <br> Since the reserve ratio is a constant, the following shows the functional dependency between the amount of tokens being received by the protocol and the amount of tokens being released: $$(r_x + qx)(r_y - y) = r_xr_y$$ The amount of tokens in general is a natural number, that so the signs of $+x$ and $-y$ shows the direction of the exchange, meaning that asset `X` was retreived and asset `Y` was released. It is worth mentioning that $q$ multiplier is applied to the amount of tokens received by the protocol, since the fee is held before the amount reaches the reserve. <br> ## Case of multiple interactions Since the Sandwich Attack implies at least three consecutive swaps, let's change the current notation for more clarity. The reserve of $X$ and token $Y$ will write as: $$X_n \quad Y_n$$ Where $n$ is the number of the swaps performed. By $x_n$ and $y_n$ the differences of reserves of token $X$ and $Y$ during the swap $n$ will be ment. Let's form the exchange equation in this terms: $$(X_n + qx_n)(Y_n - y_n) = X_{n+1}Y_{n+1} \\ (X_n - x_n)(Y_n + qy_n) = X_{n+1}Y_{n+1}$$ Where the first one is the exchange in $X \rightarrow Y$ direction, and the second one is in the $X \leftarrow Y$ direction. Let's now build a system of equations for three consecutive swaps, two of which are done in $X \rightarrow Y$ direction and the last one is in opposite. The reserves at each step are: $$X_1=X_0+qx_0 \quad Y_1=Y_0-y_0 \\ X_2=X_1+qx_1 \quad Y_2=Y_1-y_1 \\ X_3=X_2-x_2 \quad Y_3=Y_2+qy_2$$ The exchange equations for each swap are: $$X_0Y_0 = (X_0+qx_0)(Y_0-y_0) \\ X_1Y_1=(X_1+qx_1)(Y_1-y_1) \\ X_2Y_2=(X_2-x_2)(Y_2+qy_2)$$ Let's express the amounts out for each swap as well: $$y_0=Y_0-X_0Y_0/(X_0+qx_0)=qY_0x_0/(X_0+qx_0)\\ y_1=Y_1-X_1Y_1/(X_1+qx_1)=qY_1x_1/(X_1+qx_1)\\ x_2=X_2-X_2Y_2/(Y_2+qy_2)=qX_2y_2/(Y_2+qy_2)$$ <br> <br> ## The attack definition Hereafter the attacker's input in is going to be referred as $x$, and the amount out of the first attacker's swap as $y$. The victim's amount in will be referred as $\chi$ and the amount out as $\xi$ to highlight that those values related to different actors. $$X_1=X_0+qx \quad Y_1=Y_0-y \\ X_2=X_1+q\chi \quad Y_2=Y_1-\xi \\ X_3=X_2-x_2 \quad Y_3=Y_2+qy$$ Based on the definition of the sandwich attack, the margin is the difference between the amount of tokens $X$ spent by attacker for the first swap and the amount of tokens received as the result of the second swap: $$\delta=x'-x$$ Considering the property of the Uniswap V2 protocol $X_nY_n = const$ the system of equations turns into: $$(X_0+qx)(Y_0-y)=X_0Y_0\\ (X_1+q\chi)(Y_1-\xi)=X_0Y_0\\ (X_2-x')(Y_2+qy)=X_0Y_0$$ <br> <br> > ## Input amount dependency from victim's input > > The functional dependency $x(\chi, \xi)$ of attacker's input $x$ from victim's input $\chi$ can be found using the middle equation: > > $$(X_1+q\chi)(Y_1-\xi)=X_0Y_0\\ > X_1Y_1+qY_1\chi-X_1\xi-q\xi\chi=X_0Y_0\quad X_0Y_0=X_1Y_1\\ > \xi(X_1+q\chi)=qY_1\chi\quad\quad Y_1 = X_0Y_0/X_1\\ > \xi(X_1+q\chi)=qX_0Y_0\chi/X_1\\ > X_1(X_1+q\chi)=qX_0Y_0/\xi\\ > (X_0+qx)(X_0+qx+q\chi)=qX_0Y_0/\xi\\ > X_0^2+qX_0x+qX_0x+q^2x^2+qX_0\chi+q^2\chi x=qX_0Y_0/\xi\\ > q^2x^2+(2qX_0+q^2\chi)x+qX_0\chi+X_0^2-qX_0Y_0/\xi=0$$ > > Solutions of the quadratic equation are: > > $$x_{1,2}=\frac{-b\pm\sqrt{b^2-4ac}}{2a}$$ > > Where the coefficients are: > > $$a=q^2\quad b=(2qX_0+q^2\chi)\quad c=X_0^2-qX_0Y_0/\xi$$ > > $$x_{1,2}=\frac{-2qX_0-q^2\chi\pm\sqrt{(2qX_0+q^2\chi)^2-4q^2(X_0^2-qX_0Y_0/\xi)}}{2q^2}$$ > > Considering that $q,X_0,\chi,x > 0$, only one solution is possible: > > $$x(\chi, \xi)=\frac{-2qX_0-q^2\chi+\sqrt{(2qX_0+q^2\chi)^2-4q^2(X_0^2-qX_0Y_0/\xi)}}{2q^2}=\\ > =\frac{-2qX_0-q^2\chi+\sqrt{4q^2X_0^2+q^4\chi^2+4q^3X_0\chi-4q^2X_0^2+4q^3X_0Y_0/\xi}}{2q^2}=\\ > =\frac{-2X_0-q\chi+\sqrt{q^2\chi^2+4qX_0\chi+4qX_0Y_0/\xi}}{2q}$$ > > In case if in result of the victim's swap the amount of received tokens $\xi$ is less then some user pre-defined value $\xi_{min}$, the swap is reverted, that so for the attack to be successful the following inequality should be truthful: > > $$\xi \ge \xi_{min}$$ > > Since the $x(\chi, \xi)$ is inversely proportional to the square root of the $\xi$ value, the constrain for $x$ looks as follows: > > $$x \le x_{max}\quad x \le \frac{-2X_0-q\chi+\sqrt{q^2\chi^2+4qX_0\chi+4qX_0Y_0/\xi_{min}}}{2q}$$ > > <br> > <br> > > ## Margin definition > > The margin of the attack is a function of attacker's input and victim's input, and can be expressed from the exchange equation: > > $$\delta(x)=x'-x$$ > > From the first equation of exchange, the amount out of the attacker's first swap is: > > $$y=qY_0x/(X_0+qx)$$ > > To be able to analyze the margin with respect to the victim's inpit, let's express it as a function of victim's input and attacker's input: > > $\delta(x,\chi)=X_2-X_0Y_0/(Y_2+qy)-x\\ > =X_2-X_0Y_0/(X_0Y_0/X_2+qy)-x\\ > =X_2-X_0Y_0X_2/(X_0Y_0+qX_2y)-x\\ > =X_2-X_0Y_0X_2/(X_0Y_0+\frac{q^2Y_0X_2x}{X_0+qx})-x\\ > =X_2-X_0X_2/(X_0+\frac{q^2X_2x}{X_0+qx})-x\\ > =X_2-X_0X_2(X_0+qx)/(X_0(X_0+qx)+q^2X_2x)-x$ > > Now, considering that: > > $$X_2=X_0+qx+q\chi$$ > > Let's pick new variables to simplify the equation: > > $$z=X_0+qx\qquad\Rightarrow\qquad x=(z-X_0)/q$$ > > $$u=q\chi\qquad\Rightarrow\qquad \chi=u/q$$ > > <br> > > $\delta(z,u)=z+u-X_0(z+u)z/(X_0z+q^2(z+u)(z-X_0)/q)-(z-X_0)/q\\ =z+u-X_0(z+u)z/(X_0z+q(z+u)(z-X_0))-(z-X_0)/q\\ =z+u-(X_0z^2-X_0uz)/(X_0z+qz^2+quz-qX_0z-qX_0u)-(z-X_0)/q\\ =z+u-(X_0z^2-X_0uz)/(qz^2+(X_0+qu-qX_0)z-qX_0u)-(z-X_0)/q$ Now, let's find the maximum of $\delta(z,u)$ on the range of $z \in [0, \infty]$: $$\frac{d\delta(z,u)}{dz}=1-\frac{1}{q}\frac{d\omega(z,u)}{dz}-1/q=0$$ Where: $$\omega(z,u)=(X_0z^2-X_0uz)/(z^2+(X_0/q+u-X_0)z-X_0u)$$ Let's use the rule: $$(f/g)'=(f'g-g'f)/g^2$$ Then: $$1-\frac{1}{q}\frac{f'g-g'f}{g^2}-1/q=0\\ qg^2-f'g+g'f-g^2=0$$ Where: $$v=X_0(q-1)/q$$ $$f(z,u)=X_0z^2-X_0uz\qquad \frac{df(z,u)}{dz}=2X_0z-X_0u$$ $$g(z,u)=z^2+(u+v)z-X_0u\qquad \frac{dg(z,u)}{dz}=2z+(u+v)$$ $g(z,u)^2=z^4+2((u+v)z-X_0u)z^2+((u+v)z-X_0u)^2\\ =z^4+2(u+v)z^3-2X_0uz^2+(u+v)^2z^2-2X_0u(u+v)z+X_0^2u^2\\ =z^4+2uz^3+2vz^3-2X_0uz^2+u^2z^2+v^2z^2+2uvz^2-2X_0u^2z-2X_0uvz+X_0^2u^2\\ =z^4+(2u+2v)z^3+(u^2+v^2+2uv-2X_0u)z^2-(2X_0u^2+2X_0uv)z+(X_0^2u^2)$ $\frac{df(z,u)}{dz}g(z,u)=(2X_0z-X_0u)(z^2+(u+v)z-X_0u)\\ =2X_0z^3+2X_0uz^2+2X_0vz^2-2X_0^2uz-X_0uz^2-X_0u^2z-X_0uvz+X_0^2u^2\\ =(2X_0)z^3+(2X_0u+2X_0v-X_0u)z^2-(2X_0^2u+X_0u^2+X_0uv)z+(X_0^2u^2)$ $\frac{dg(z,u)}{dz}f(z,u)=(X_0z^2-X_0uz)(2z+(u+v))\\ =2X_0z^3-2X_0uz^2+X_0(u+v)z^2-X_0u(u+v)z$ --- $$ g'f-f'g = 2X_0z^3-2X_0uz^2+X_0(u+v)z^2-X_0u(u+v)z - \\((2X_0)z^3+(2X_0u+2X_0v-X_0u)z^2-(2X_0^2u+X_0u^2+X_0uv)z+(X_0^2u^2))\\ g'f-f'g = -X_0(2u+v)z^2+2X_0^2uz+X_0^2u^2\\ qg^2-(f'g-g'f)-g^2 = (q-1)z^4+(2qu+2qv-2u-2v)z^3\\ +((4-2q)X_0u+X_0v+(q-1)(u+v)^2)z^2\\ +((2-2q)X_0uv-2qX_0^2u)z\\ +((q-2)X_0^2u^2) $$ <br> <br> > $$f(z,u)=X_0z^2-X_0uz\qquad g(z,u)=z^2+wz-X_0u$$ > > $df(z,u)/dz=2X_0z-X_0u$ > > $dg(z,u)/dz=2z+w$ > > $g^2(z,u)=(z^2+wz-X_0u)^2=(z^2+wz)^2-2X_0u(z^2+wz)-X_0^2u^2\\ > =z^4+2wz^3+w^2z^2-2X_0uz^2-2X_0uwz-X_0^2u^2\\ > =z^4+2wz^3+(w^2-2X_0u)z^2-2X_0uwz-X_0^2u^2$ > > <br> > > $\frac{df(z,u)}{dz}g(z,u)=(2X_0z-X_0u)(z^2+wz-X_0u)\\ > =2X_0z^3-X_0uz^2+2X_0wz^2-X_0uwz-2X_0^2uz+2X_0^2u^2\\ > =2X_0z^3+(2X_0w-X_0u)z^2-(X_0uw+2X_0^2u)z+2X_0^2u^2$ > > $\frac{dg(z,u)}{dz}f(z,u)=(2z+w)(X_0z^2-X_0uz)\\ > =2X_0z^3+2X_0wz^2-2X_0uz^2-X_0uwz\\ > =2X_0z^3+(2X_0w-2X_0u)z^2-X_0uwz$ > > $g'f-f'g=(2X_0z^3+(2X_0w-2X_0u)z^2-X_0uwz)\\ > \qquad-(2X_0z^3+(2X_0w-X_0u)z^2-(X_0uw+2X_0^2u)z+2X_0^2u^2)\\ > =-X_0uz^2+2X_0^2uz-2X_0^2u^2$ > > $g'f-f'g-b^2=-X_0uz^2+2X_0^2uz-2X_0^2u\\ > \qquad-(z^4+2wz^3+(w^2-2X_0u)z^2-2X_0uwz-X_0^2u^2)\\ > =-z^4-2wz^3-(w^2-X_0u)z^2+(2X_0^2u+2X_0uw)z+(X_0^2u^2-2X_0^2u)$ > > $qg^2-f'g+g'f-g^2=\\ > =q(z^4+2wz^3+(w^2-2X_0u)z^2-2X_0uwz-X_0^2u^2)\\ > \quad-z^4-2wz^3-(w^2-X_0u)z^2+(2X_0^2u+2X_0uw)z+(X_0^2u^2-2X_0^2u)\\ > =qz^4+2qwz^3+(qw^2-2qX_0u)z^2-2qX_0uwz-qX_0^2u^2\\ > \quad-z^4-2wz^3-(w^2-X_0u)z^2+(2X_0^2u+2X_0uw)z+(X_0^2u^2-2X_0^2u)\\ > =(q-1)z^4+2w(q-1)z^3+(qw^2-2qX_0u-w^2+X_0u)z^2\\ > \quad+(2X_0^2u+2X_0uw-2qX_0uw)z+(X_0^2u^2-2X_0^2u-qX_0^2u^2)$ > > $w^2=((1/q-1)X_0+u)^2=\\ > =(1/q-1)^2X_0^2+2(1/q-1)X_0u+u^2\\ > =(1/q^2+1-2/q)X_0^2+2(1/q-1)X_0u+u^2\\ > =X_0^2/q^2-2X_0^2/q+X_0^2+2X_0u/q-2X_0u+u^2$ > > $2w(q-1)=2(X_0/q+u-X_0)(q-1)\\ > =2X_0+2qu-2qX_0-2X_0/q-2u+2X_0\\ > =4X_0-2qX_0-2X_0/q+2qu-2u\\ > =(2-2q)u+(4X_0-2qX_0-2X_0/q)$ > > $qw^2-2qX_0u-w^2+X_0u\\ > =X_0^2/q-2X_0^2+qX_0^2+2X_0u-2qX_0u+qu^2\\ > \quad-X_0^2/q^2-2X_0^2/q+X_0^2+2X_0u/q-2X_0u+u^2\\ > \quad\quad-2qX_0u+X_0u\\ > =(q+1)u^2+(2X_0-2qX_0+2X_0/q-2X_0+2qX_0+X_0)u\\ > \quad+(X_0^2/q-2X_0^2+qX_0^2-X_0^2/q^2-2X_0^2/q+X_0^2)\\ > =(q+1)u^2+(2X_0/q+X_0)u+(qX_0^2-X_0^2/q^2-X_0^2/q-X_0^2)$ <br> <br> ## Algorithm of special case Sandwich attack The following algorithm allows to calculate amounts in and the margin using the target tx and the initial protocol conditions. The pair `WETH` `USDC` will be used as the example: 1. Get victim's transaction info and current protocol reserves: ``` const q = 0.997 function calc_margin(q, X0, Y0, chi, xiMin) { X0 = Number(X0) Y0 = Number(Y0) chi = Number(chi) xiMin = Number(xiMin) const x = ( Math.sqrt(q * chi ** 2 + 4 * q * X0 * Y0 * chi / xiMin) - 2 * X0 - q * chi ) / (2 * q) const y = q * Y0 * x / (X0 + q * x) const X = X0 + q * (x + chi) const margin = X - X0 * Y0 * X / (X0 * Y0 + q * X * y) // [amount_in_weth, amount_in_token, margin] return [BigInt(x), BigInt(y), margin] } ``` This algorithm does not consider the breaking point of margin growth, so applicable only if the target tx's swap amount is relatively small. To prevent potential losses, when target tx amount in that big, so it's passes the point of optimum margin, the general case algorithm should be used. <br> <br>