Es muy educativo reconstruir Uniswap V2 desde cero usando Solidity moderno (o Huff si realmente quieres hacerlo en modo difícil). Aquí tienes algunos consejos y sugerencias para hacerlo.
- Usa una versión actualizada de Solidity. Ten en cuenta que esto conllevará cambios sintácticos.
- Reemplaza los números de punto fijo (fixed point numbers) por tipos de datos personalizados.
- Usa el ERC20 de Solady para el ERC20 y así ahorrar gas.
- No uses la protección actual contra reentradas (reentrancy) de Uniswap V2, ya no es eficiente en gas; usa la de OpenZeppelin o alguna otra alternativa.
- Ten cuidado de añadir unchecked en el oráculo de precios, ya que espera que ocurra un desbordamiento (overflow).
- No uses
safeMathcon Solidity 0.8.0 o superior. - Si no estás implementando el router por separado, las comprobaciones de seguridad para el deslizamiento (slippage) deben integrarse en el contrato. Las EOAs no pueden enviar tokens como parte de la transacción.
- Asegúrate de poner el bloqueo de reentrada en los lugares correctos. ¿Es Uniswap V2 vulnerable a la reentrada de solo lectura (read-only reentrancy)? ¿Por qué o por qué no?
- El contrato factory se puede simplificar sin usar assembly debido a las actualizaciones de Solidity.
- Ten cuidado con los tokens que cobran comisiones por transferencia (fee-on-transfer) o los tokens de reajuste (re-basing).
- La función de raíz cuadrada se puede realizar de manera más eficiente con la biblioteca Solady, pero asegúrate de estar redondeando en la dirección correcta.
- Uniswap codifica rígidamente (hardcodes) la comisión con números mágicos (magic numbers); esta no es una forma ideal de escribir código.
- No olvides seguir la guía de estilo profesional de Solidity (la cual Uniswap V2 no sigue).
- La forma en que el contrato factory rastrea los pares no es eficiente en gas, intenta mejorarla.
- Algunas variables de storage en la implementación original podrían definirse como
immutable(las variablesimmutableno estaban disponibles en el momento en que se lanzó Uniswap V2). - Los errores personalizados (custom errors) resultarán en un costo de despliegue más barato que las declaraciones
require(por lo general). - Al quemar el suministro inicial, asegúrate de que el
totalSupplyno baje a cero. De lo contrario, la defensa contra el ataque de primer depósito no funcionará. Algunas implementaciones de burn reducen el suministro total en lugar de bloquear los fondos como pretende Uniswap. - Ten cuidado de ejecutar
burn,mintyupdatesobre las reservas en el orden correcto al calcular las participaciones (shares). - El
_safeTransferde Uniswap V2 es vulnerable al ataque de expansión de memoria (muy poco probable, pero aun así debe prevenirse). Dado que solo se leerá un bool, es mejor usarreturndatacopypara una sola palabra (word). Intenta evitar el hábito de leer por completo el return data de otros contratos. - Una buena prueba invariante es que la liquidez nunca debería disminuir si no se llama a
burn. - No uses las variables de balance o el balance del pool como un oráculo, ya que son vulnerables a ataques de préstamos relámpago (flash loans).
- Recuerda siempre redondear a favor del pool al hacer intercambios (trades) o al hacer mint o burn de participaciones (shares).
- No olvides escribir pruebas unitarias.
- Lee nuestro libro sobre optimización de gas en Solidity para inspirarte sobre cómo mejorar el rendimiento (después de terminar tu segundo o tercer borrador del clon de Uniswap y haber escrito las pruebas). Si quieres hacer esto en modo difícil, hay varias oportunidades para mejorar el gas usando assembly sin sacrificios sustanciales en la legibilidad.
- Prueba Damn Vulnerable Defi Puppet V2. Debería resultarte fácil de resolver llegados a este punto.
Aprende más con RareSkills
Este material es parte de nuestro Bootcamp de Solidity avanzado. Por favor, consulta el programa para aprender más.
Publicado originalmente el 1 de noviembre de 2023