El ciclo de vida de Uniswap V2 consiste en que alguien acuña (mints) tokens LP (suministra liquidez, es decir, tokens al pool) por primera vez, luego un segundo depositante acuña liquidez, ocurren los intercambios (swaps), y finalmente los proveedores de liquidez queman (burn) sus tokens LP para canjear los tokens del pool.
Resulta más fácil estudiar estas funciones a la inversa: quemar, acuñar liquidez y luego acuñar la liquidez inicial.
Así que comencemos con burn.
Uniswap V2 Burn
Antes de que los tokens de liquidez puedan ser quemados, necesita haber liquidez en el pool, así que hagamos esa suposición. Suponemos que hay dos tokens en el sistema: token0 y token1.
A continuación hemos anotado la función burn, explicaremos las partes que no son del todo obvias.

En la línea 140 (caja morada), la liquidez se mide por la cantidad de tokens LP que posee el contrato del pool. Se asume que el quemador (burner) envió tokens LP antes de llamar a burn, pero de manera aconsejable como parte de una sola transacción. (¡Si se envían como dos transacciones, alguien más puede quemar tus tokens LP y retirar tu liquidez!) La cantidad que el usuario envió al contrato será quemada. En general, podemos asumir que el contrato tendrá un balance cero de tokens LP, porque si los tokens LP simplemente permanecen en el contrato del par (pair contract), alguien los quemará y reclamará parte del token0 y token1 gratis. El mecanismo de enviar tokens como parte de la transacción fue introducido en el artículo sobre Uniswap V2 Swap.
Las cajas rojas en las líneas 142 y 154 denotan tarifas (fees), las omitiremos por ahora ya que Uniswap no aplica tarifas a los proveedores de liquidez.
Las cajas naranjas en las líneas 144 a 145 es donde se calculan las cantidades que recuperará el proveedor de LP. Si el suministro total de tokens de liquidez es de 1,000, y queman 100 tokens LP, entonces obtienen el 10% del token0 y token1 que mantiene el pool. Liquidity / totalSupply es su porción quemada del suministro total de tokens LP.
La caja azul en las líneas 147 a 149 es donde los tokens LP se queman realmente y el token0 y token1 se envían al proveedor de liquidez.
La caja amarilla en las líneas 150-151 actualiza las variables de balance para que la llamada a _update en la línea 153(caja verde) pueda actualizar las variables _reserve. Aparte de actualizar el TWAP, la función _update simplemente actualiza las variables _reserve.

Comprobaciones de seguridad
Supongamos que el pool tiene cantidades equivalentes de token0 y token1. Esto significa que el quemador espera recibir ambos tokens en igual cantidad al quemar el token LP. Sin embargo, la proporción del pool de token0 respecto a token1 puede cambiar entre el momento en que se firma la transacción de burn y el momento en que se confirma. Si el quemador tiene lógica posterior (downstream) que depende de recibir una cantidad particular de token0 o token1 (como pagar un flash loan), entonces esa lógica podría romperse si recibe un poco menos de token0 o token1. El contrato de quema debe estar preparado para recibir menos token0 o token1 de lo esperado y revertir si es necesario.
Acuñar liquidez cuando el pool no está vacío
Aquí está la función para acuñar (mint) liquidez. Gran parte de la funcionalidad es similar a burn, por lo que no repetiremos las partes que deberían ser obvias.

Si el pool está vacío, es decir, los tokens de liquidez tienen un suministro total de cero, entonces aún no se ha proporcionado liquidez. Esto se verifica en la línea 119 (La caja amarilla). En esta sección, nos centramos en el caso donde ya se ha proporcionado liquidez (caja amarilla en la línea 123). La liquidez que se acredita al usuario, y que luego se le acuña en la línea 126 (caja verde), es el menor de dos valores.

La proporción que esta línea de código está midiendo es amount0 / _reserve0 - escalada por el totalSupply de tokens LP.
Supongamos que hay 10 token0 y 10 token1. Si el usuario suministró 10 token0 y 0 token1, ¡obtendrá el mínimo de (10/10, 0/10) y recibirá cero tokens de liquidez a cambio! Otro ejemplo: si incrementan el suministro de tokens LP (recuerda, esta proporción se escala por _totalSupply, que es el suministro actual de tokens LP).
El hecho de que el usuario obtenga la peor de las dos proporciones (amount0 / _reserve0 o amount1 / _reserve1) que proporciona, lo incentiva a aumentar el suministro de token0 y token1 sin cambiar la proporción de token0 y token1.
¿Por qué imponer esto? Supongamos que el pool tiene actualmente 100 de token0 y 1 de token1, y el suministro de tokens LP es 1. Supongamos que el valor total, en dólares, de ambos tokens es de $100 cada uno, por lo que el valor total del pool es de $200.
Si tomáramos el máximo de las dos proporciones, alguien podría suministrar un token1 adicional (a un costo de $100) y aumentar el valor del pool a $300. Han aumentado el valor del pool en un 50%. Sin embargo, bajo el cálculo máximo, se les acuñaría 1 token LP, lo que significa que poseerían el 50% del suministro de tokens LP, ya que el suministro circulante total ahora es de 2 tokens LP. Ahora controlan el 50% del pool de $300 (con un valor de $150) depositando solo $100 de valor. Esto es claramente un robo a los demás proveedores de LP.
Comprobación de seguridad de la proporción de suministro
El usuario podría intentar respetar las proporciones de los tokens, pero si otra transacción se ejecuta antes que la suya y cambia el balance de token0 respecto a token1, entonces recibirán menos tokens de liquidez de los que esperaban.
Uniswap no exige cantidades exactas porque, de lo contrario, es probable que la transacción se revierta. Otra transacción ejecutada primero cambiaría el requisito entre el momento en que el minter envió la transacción y el momento en que se incluyó en el bloque.
Comprobación de seguridad de TotalSupply
Al igual que en el caso de burn, el totalSupply de tokens LP podría cambiar en ese momento, por lo que se debe implementar alguna protección contra el deslizamiento (slippage).
El problema del primer minter
Al igual que cualquier pool de LP, Uniswap V2 necesita defensa contra el “ataque de inflación”. Hemos descrito este problema, y la defensa contra el mismo, en nuestro artículo sobre ERC4626, por lo que no lo repetiremos aquí. La defensa de Uniswap V2 consiste en quemar primero los tokens de MINIMUM_LIQUIDITY para asegurar que nadie posea todo el suministro de tokens LP y pueda manipular fácilmente el precio. Nuevamente, consulta el otro artículo si no estás familiarizado con este vector de ataque.

Por qué Uniswap calcula la liquidez como la raíz cuadrada de K
La pregunta más interesante es por qué Uniswap V2 toma la raíz cuadrada del producto de los tokens suministrados para calcular la cantidad de participaciones (shares) LP a acuñar.

Específicamente, liquidity = sqrt(amount0*amount) después de restar la MINIMUM_LIQUIDITY.
Parecería que podríamos acuñar una cantidad arbitraria de tokens para el primer LP: ellos poseen el 100% de las participaciones (menos lo que se quemó), entonces, ¿qué diferencia hace si se escala por 0.01 o 100?
Aquí está la justificación del whitepaper:
Uniswap v2 initially mints shares equal to the geometric mean of the amounts, liquidity = sqrt(xy). This formula ensures that the value of a liquidity pool share at any time is essentially independent of the ratio at which liquidity was initially deposited… The above formula ensures that a liquidity pool share will never be worth less than the geometric mean of the reserves in that pool.
¿Qué significa exactamente eso?
Una de las mejores maneras de tener una intuición sobre algo es introducir valores y ver qué sucede, así que hagámoslo.
Ejemplo: Duplicando la liquidez
Supongamos que no mediéramos la liquidez con la función de raíz cuadrada y comenzamos con 10 de token0 y 10 de token1 en el pool. Más adelante, el pool tiene 20 de token0 y 20 de token1 en el pool.
Intuitivamente, ¿se duplicó o cuadruplicó la liquidez? Porque si no sacamos la raíz cuadrada, la liquidez comenzaría en 100 (10x10) y terminaría en 400 (20x20). Podría decirse que la liquidez no se cuadruplicó. Al principio, el máximo de token0 que podías obtener era (asintóticamente) de 100, pero después del crecimiento de la liquidez, la “profundidad” de la liquidez para ese token se duplicó, no se cuadruplicó.
Pero, ¿cómo importa esto si los futuros proveedores de liquidez no calculan la liquidez usando la raíz cuadrada al acuñar o quemar? Vimos que los nuevos proveedores de liquidez están “forzados” a suministrar activos a la tasa actual, y los quemadores solo pueden canjear a la tasa actual: no hay raíces cuadradas involucradas.
La respuesta está en cómo Uniswap habría cobrado las tarifas de los LP si hubiera decidido hacerlo.
Tarifas
Volviendo a nuestro ejemplo anterior del pool que crece de 100 de token0 y 100 de token1, a 200 de cada uno, la ganancia del proveedor de liquidez es del 100%, por lo que debería pagar una tarifa proporcional a esa cantidad. Si midiéramos el tamaño del pool de 100 a 400, entonces tendrían que pagar tarifas sobre ganancias cuádruples.
Uniswap opta por cobrar tarifas durante la retirada de liquidez porque cobrar una tarifa del protocolo durante el intercambio (swapping) aumentaría el costo de gas de una operación muy común. Uniswap V2 nunca activó realmente la tarifa del protocolo, por lo que esta discusión es un poco teórica.
Publicado originalmente el 30 de octubre de 2023