El 23 de noviembre de 2023, se produjo una serie de ataques dirigidos a KyberSwap. Estos ataques resultaron en una pérdida total de más de 48 millones de dólares. El problema fundamental se originó en una dirección de redondeo incorrecta durante el proceso de reinversión de KyberSwap. Esto llevó posteriormente a cálculos incorrectos de ticks y, en última instancia, a un doble conteo de liquidez.
Hemos publicado un informe exhaustivo, "Yet Another Tragedy of Precision Loss: An In-Depth Analysis of the KyberSwap Incident", que profundiza en los detalles del evento. Para una comprensión más profunda, se le anima a consultar el análisis completo. A continuación, ofrecemos una introducción sucinta a este incidente, destacándolo como uno de los diez principales incidentes de seguridad de 2023.
Antecedentes
KyberSwap es una plataforma descentralizada de creador de mercado automatizado (CLAMM). Para satisfacer la demanda del mercado de liquidez concentrada, KyberSwap Elastic se lanza basándose en Uniswap V3, con varias mejoras que incluyen la curva de reinversión para permitir la capitalización automática de los rendimientos de provisión de liquidez.
1. Tick y Precio de Raíz Cuadrada
Tick en los CLAMMs similares a Uniswap V3 se utiliza para marcar el precio de manera discreta, de modo que los LPs puedan proporcionar liquidez dentro de un rango fijo en lugar de todo el rango (de ahí el término "concentrada").
La liquidez puede colocarse en un rango entre dos ticks cualesquiera (que no necesitan ser adyacentes), es decir, un par de índices de tick (un tick inferior y un tick superior). Específicamente, el precio de cada tick (en un índice entero i) se define de la siguiente manera:
En la práctica, se utiliza el precio de raíz cuadrada (denotado como sqrtP o sqrtPrice):
También es posible calcular el tick actual basándose en el precio de raíz cuadrada actual:
Obviamente, mientras que solo se calcula un único precio de raíz cuadrada para un tick dado, múltiples precios de raíz cuadrada pueden apuntar al mismo tick. Para una explicación más detallada, consulte los documentos de Uniswap V3 y KyberSwap.
2. Curva de Reinversión
El CLAMM basado en Uniswap V3 sufre de la subutilización del pool por las comisiones de LP y las significativas comisiones de gas requeridas para reinvertir. Por ello, KyberSwap adoptó la curva de reinversión para abordar el problema.
La clave de la curva de reinversión es que las comisiones recaudadas en cada intercambio se acumulan como liquidez adicional en el pool como la liquidez de reinversión dentro de un rango infinito. Los tokens de reinversión se acuñan para los LPs y la liquidez de reinversión acumulada se asigna a los LPs en consecuencia. Además, la liquidez de reinversión también participa en el proceso de intercambio y cálculo de precios.
El código correspondiente a los cálculos introducidos anteriormente se muestra en la función computeSwapStep en el siguiente fragmento de código del pool correspondiente.

Debe tenerse en cuenta que, debido a la liquidez de reinversión, la liquidity en esta función es la suma de dos componentes: baseL para la liquidez base y reinvestL para la liquidez acumulada para la reinversión.
3. Intercambio en KyberSwap
La implementación de la función swap del pool de KyberSwap discutida anteriormente puede resumirse en el siguiente diagrama:

La lógica crucial relacionada con el cálculo del tick reside dentro del bucle while de intercambio, destacado por el rectángulo azul. Específicamente, la lógica principal involucra la función computeSwapStep y la función _updateLiquidityAndCrossTick. La primera calcula estados clave, como los montos de entrada y salida para el intercambio dado y nextSqrtP, mientras que la segunda maneja los casos en que ocurre un cruce de tick.
Tradicionalmente, cuando el precio aumenta, nos referimos a esto como desplazar el tick hacia la derecha/arriba; de lo contrario, decimos que el tick se mueve hacia la izquierda/abajo.
Para comprender mejor la vulnerabilidad que se discutirá más adelante, es esencial que exploremos la lógica de código relevante de la función computeSwapStep, como se ilustra en la siguiente figura:

Específicamente, la función calcReachAmount calcula los tokens de entrada necesarios para el precio objetivo targetSqrtP (líneas 50-57). Si el usedAmount es mayor que specifiedAmount, el tick no se cruza y nextSqrtP se calcula a partir de deltaL (es decir, el delta de liquidez, líneas 59-62). deltaL se determina usando la función estimateIncrementalLiquidity, y el precio final nextSqrtP se calcula con la función calcFinalPrice (líneas 70-79). Si se necesita menos entrada, nextSqrtP se establece en el precio del siguiente tick, pero este caso no se utiliza en el ataque.
Los pasos descritos anteriormente dejan claro que si el tick no se cruza, el nextSqrtP devuelto por computeSwapStep no debería ser mayor que el sqrtP del siguiente tick. Sin embargo, debido a la dependencia del precio en la liquidez (liquidez base y delta de liquidez) y la pérdida de precisión, el atacante puede manipular el nextSqrtP para que sea mayor mientras el tick no se cruza.
Análisis de la Vulnerabilidad
La causa raíz radica en el cálculo defectuoso del tick causado por la dirección de redondeo incorrecta dentro del cálculo del delta de liquidez (es decir, la función estimateIncrementalLiquidity) del contrato SwapMath (que es invocado por la función computeSwapStep). Esto, a su vez, afecta de manera inadecuada el cálculo del tick posteriormente.

Curiosamente, al examinar el comentario en la línea 188 (destacado por el rectángulo azul), encontramos que deltaL está destinado a redondearse hacia arriba para redondear hacia abajo el nextSqrtP. Sin embargo, deltaL se redondea incorrectamente hacia abajo debido al uso de la función mulDivFloor en la línea 189. En consecuencia, nextSqrtP se redondea inexactamente hacia arriba.
Análisis del Ataque
Los atacantes iniciaron múltiples transacciones de ataque, con cada transacción drenando múltiples pools. Por simplicidad, la siguiente discusión se basa en el primer ataque dentro de la transacción de ataque.
La lógica central del ataque consiste en los siguientes seis pasos:
-
Tomar prestados 2.000 WETH mediante préstamo flash de AAVE.
-
Intercambiar 6,850 WETH por 6,371 frxETH en el pool víctima 0xfd7b. Este paso se utiliza para empujar el tick actual y
currentSqrtPa una ubicación donde actualmente no hay liquidez.
currentSqrtPparece ser elegido aleatoriamente por el atacante, y el intercambio se detiene precisamente en este precio.- La liquidez base (
baseL) es cero después de este paso, pero la liquidez de reinversión (reinvestL) no es cero.
- Agregar liquidez al pool y luego eliminar parte de la liquidez. Este paso se utiliza para controlar el rango y la liquidez total a una cantidad deseada.
- El rango de tick se elige basándose en el
currentSqrtP. - La liquidez deseada para el ataque puede derivarse del rango de tick, aunque la lógica de cálculo correspondiente requiere mayor exploración.
- Intercambiar 387,170 WETH por 0,06 frxETH en el pool. Este paso se utiliza para manipular el tick actual de modo que
nextTick==currentTick. Específicamente, el intercambio en el paso 4 engaña astutamente al pool para que crea que el tick 111.310 no se cruza. Sin embargo, en realidad, elcurrentSqrtPes efectivamente mayor que elsqrtPdel tick 111.310.
- Intercambiar 0,06 frxETH por 396,244 WETH en el pool. Nótese que la dirección del intercambio es opuesta en comparación con el paso anterior. En este paso, la liquidez se cuenta doble para hacer rentable el intercambio y consecuentemente drenar el pool.
- Reembolsar el préstamo flash y obtener 6,364 WETH y 1,117 frxETH.
Para un examen en profundidad, consulte nuestro análisis exhaustivo, que incluye más detalles con cálculos y figuras.
Resumen
El problema fundamental en este incidente proviene del redondeo incorrecto durante el proceso de reinversión de KyberSwap, lo que lleva a cálculos inexactos de ticks y, en última instancia, al doble conteo de liquidez. Este incidente pone de relieve la naturaleza intrincada y escurridiza de los problemas de pérdida de precisión dentro de los protocolos DeFi, lo que supone un serio desafío para toda la comunidad.
Este ataque de 2023 destaca por su complejidad, con cálculos excepcionalmente sutiles y sirviendo como un ejemplo paradigmático de los muchos incidentes de seguridad relacionados con la precisión que han puesto a prueba significativamente a la comunidad. Además, tras extensas negociaciones con las autoridades, el atacante emitió un mensaje de tono provocador al público, exigiendo el control total sobre el protocolo.
Lee otros artículos de esta serie:
- Introducción: Los Diez Principales Incidentes de Seguridad "Asombrosos" de 2023
- #1: Cosechando Bots MEV Explotando Vulnerabilidades en Flashbots Relay
- #2: Incidente de Euler Finance: El Mayor Hackeo de 2023
- #4: Incidente de Curve: Un Error del Compilador Produce Bytecode Defectuoso a partir de Código Fuente Inocente
- #5: Platypus Finance: Sobreviviendo a Tres Ataques con un Golpe de Suerte
- #6: Incidente de Hundred Finance: Catalizando la Ola de Exploits Relacionados con la Precisión en Protocolos Bifurcados Vulnerables
- #7: Incidente de ParaSpace: Una Carrera Contra el Tiempo para Frustrar el Ataque más Crítico de la Industria hasta la Fecha
- #8: Incidente de SushiSwap: Un Torpe Intento de Rescate Lleva a una Serie de Ataques Imitadores
- #9: Bot MEV 0xd61492: De Depredador a Presa en un Exploit Ingenioso
- #10: Incidente de ThirdWeb: La Incompatibilidad Entre Módulos de Confianza Expone una Vulnerabilidad





