Desde el anuncio de UniswapV4, esta plataforma de intercambio ha experimentado una transformación significativa, pasando de una simple plataforma de intercambio a un proveedor de servicios de infraestructura. En particular, la función Hooks de V4 ha ganado una amplia atención. Después de una investigación en profundidad, he recopilado contenido para ayudar a todos a comprender mejor esta transformación y su implementación.
El objetivo de la innovación de UniswapV4 no es solo mejorar la tecnología AMM sino también expandir el ecosistema. En concreto, esta innovación incluye las siguientes características clave:
En las siguientes secciones, explicaré en detalle la importancia de estas características y sus principios de implementación.
fuente: https://twitter.com/jermywkh/status/1670779830621851650
UniswapV4 adopta un método de mantenimiento de registros similar a la contabilidad de doble entrada para realizar un seguimiento de los cambios de saldo de los tokens correspondientes a cada operación. Este método de contabilidad por partida doble requiere registrar cada transacción en varias cuentas simultáneamente y garantizar que el saldo de activos entre estas cuentas permanezca equilibrado. Por ejemplo, supongamos que un usuario intercambia 100 TokenA por 50 TokenB del grupo. El registro en el libro mayor sería el siguiente:
En UniswapV4, este método de mantenimiento de registros se utiliza principalmente para operaciones importantes y una variable de almacenamiento denominada lockState.currencyDelta[moneda] se utiliza en el código para registrar la cantidad de cambios en el saldo del token. Si el valor de este delta es positivo, representa el aumento esperado en la cantidad de tokens en el grupo, mientras que un valor negativo representa la disminución esperada en la cantidad de tokens. Alternativamente, si el valor es positivo, indica la cantidad de token faltante en el grupo (la cantidad esperada a recibir), mientras que un valor negativo indica el exceso de token en el grupo (la cantidad esperada que los usuarios retiren). La siguiente lista muestra los efectos de varias operaciones en Token Delta:
Entre estas operaciones, sólo "liquidar" y "tomar" implican la transferencia real de tokens, mientras que otras operaciones son las únicas responsables de actualizar el valor de TokenDelta.
Aquí usamos un ejemplo simple para ilustrar cómo actualizar TokenDelta. Supongamos que hoy cambiamos 100 TokenA por 50 TokenB:
Cuando se completa toda la operación de intercambio, tanto TokenADelta como TokenBDelta se restablecen a 0. Esto significa que la operación se ha equilibrado por completo, garantizando así la coherencia de los saldos de las cuentas.
Anteriormente, se mencionó que UniswapV4 utiliza variables de almacenamiento para registrar TokenDelta. Sin embargo, dentro del contrato, leer y escribir en variables de almacenamiento es bastante costoso. Esto nos lleva a otro EIP presentado por Uniswap: EIP1153 - Códigos de operación de almacenamiento transitorio.
UniswapV4 planea utilizar los códigos de operación TSTORE y TLOAD proporcionados por EIP1153 para actualizar TokenDelta. Las variables de almacenamiento que adoptan códigos de operación de almacenamiento transitorio se descartarán una vez finalizada la transacción (similar a las variables de memoria), lo que reduce las tarifas de gas.
Se ha confirmado que EIP1153 se incluirá en la próxima actualización de Cancún, y UniswapV4 también ha declarado que entrará en funcionamiento después de la actualización de Cancún, como se informa aquí.
fuente: https://etherworld.co/2022/12/13/transient-storage-for-beginners/
UniswapV4 introduce un mecanismo de bloqueo, lo que significa que antes de realizar cualquier operación del Pool, primero debe llamar a PoolManager.lock() para adquirir un bloqueo. Durante la ejecución de lock(), verifica si el valor de TokenDelta es 0; de lo contrario, se revertirá. Una vez que PoolManager.lock() se adquiere con éxito, llama a la función lockAcquired() de msg.sender. Dentro de la función lockAcquired() se realizan las operaciones relacionadas con el Pool, como swap y modificarPosition.
El proceso se ilustra a continuación. Cuando un usuario necesita realizar una operación de intercambio de tokens, debe llamar a un contrato inteligente con la función lockAcquired() (conocido como contrato de devolución de llamada). El contrato de devolución de llamada primero llama a PoolManager.lock(), y luego PoolManager llama a la función lockAcquired() del Contrato de devolución de llamada. Dentro de la función lockAcquired(), se define la lógica relacionada con las operaciones del Pool, como swap, liquidación y toma. Finalmente, cuando lock() está a punto de finalizar, PoolManager verifica si el TokenDelta asociado con esta operación se ha restablecido a 0, asegurando que el saldo de activos en el Pool permanezca intacto.
El contrato Singleton significa que UniswapV4 ha abandonado el modelo Factory-Pool anterior. Cada grupo ya no es un contrato inteligente independiente, sino que todos los grupos comparten un único contrato único. Este diseño, combinado con el mecanismo de Contabilidad Flash, solo requiere actualizar las Variables de Almacenamiento necesarias, reduciendo aún más la complejidad y el costo de las operaciones.
En el siguiente ejemplo, utilizando UniswapV3 como ejemplo, el intercambio de ETH por DAI requeriría al menos cuatro transferencias de tokens (operaciones de escritura de almacenamiento). Esto incluye múltiples cambios registrados para los tokens USDC, USDT y DAI. Sin embargo, con las mejoras en UniswapV4, junto con el mecanismo de Contabilidad Flash, solo se necesita una transferencia de Token (mover DAI del Pool al usuario), lo que reduce significativamente la cantidad de operaciones y costos.
fuente: https://twitter.com/Uniswap/status/1671208668304486404
En la última actualización de UniswapV4, la característica más notable es la arquitectura Hooks. Esta actualización aporta una gran flexibilidad en términos de disponibilidad del Pool. Los Hooks son acciones adicionales que se activan a través del Contrato de Hooks al realizar operaciones específicas en el Pool. Estas acciones se clasifican en inicializar (crear grupo), modificar posición (agregar/eliminar liquidez), intercambiar y donar. Cada categoría tiene acciones previas y posteriores a la ejecución.
Este diseño permite a los usuarios ejecutar lógica personalizada antes y después de operaciones específicas, lo que la hace más flexible y amplía la funcionalidad de UniswapV4.
fuente: https://github.com/Uniswap/v4-core/blob/main/whitepaper-v4-draft.pdf
A continuación, usaremos un ejemplo de orden limitada para explicar el proceso de operación real de Hooks en UniswapV4. Antes de comenzar, expliquemos brevemente el principio de implementación de órdenes limitadas en UniswapV4.
La implementación UniswapV4 de la orden límite funciona agregando liquidez a un rango de precios específico y luego ejecutando la operación de eliminación de liquidez si se intercambia la liquidez en ese rango.
Por ejemplo, digamos que agregamos liquidez en el rango de precios de 1900-2000 para ETH, y luego el precio de ETH aumenta de 1800 a 2100. En este punto, toda la liquidez de ETH que agregamos anteriormente en el rango de precios 1900-2000 se ha intercambiado por USDC (suponiendo que sea en el grupo ETH-USDC). Al eliminar la liquidez en este momento, podemos lograr un efecto similar al de ejecutar una orden de mercado de ETH en el rango de precios actual de 1900-2000.
Este ejemplo está tomado de GitHub de UniswapV4. En este ejemplo, el contrato de enlace de orden limitada proporciona dos enlaces, a saber, afterInitialize y afterSwap. El gancho afterInitialize se utiliza para registrar el rango de precios (tick) al crear un grupo, con el fin de determinar qué órdenes límite se han igualado después de que alguien realiza un intercambio.
Cuando el usuario necesita realizar una orden, el contrato Hook ejecuta la operación de adición de liquidez en función del rango de precios y la cantidad especificados por el usuario. En el contrato Hook para órdenes limitadas, puede ver la función place() . La lógica principal es llamar a la función lockAcquiredPlace() después de adquirir el bloqueo para ejecutar la operación de adición de liquidez, lo que equivale a colocar una orden limitada.
fuente: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L246
Después de que el usuario complete un token de intercambio dentro de este grupo, el grupo invocará la función afterSwap() del contrato Hook. La lógica principal de afterSwap es eliminar la liquidez de las órdenes realizadas previamente que se han ejecutado entre el rango de precios anterior y el rango de precios actual. Este comportamiento es equivalente a que se complete el pedido.
fuente: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L192
A continuación se muestra un diagrama de flujo que ilustra el proceso de ejecución de una orden limitada:
Lo anterior es todo el proceso de implementación de Limit-Order utilizando el mecanismo Hook.
Los ganchos tienen varios puntos interesantes que creo que vale la pena compartir.
La decisión de realizar operaciones específicas antes/después está determinada por el byte más a la izquierda de la dirección del contrato Hook. 1 byte equivale a 8 bits, lo que corresponde a 8 acciones adicionales. El grupo comprobará si el bit de esa acción es 1 para determinar si se debe invocar la función de enlace correspondiente del contrato de enlace. Esto también significa que la dirección del contrato Hook debe diseñarse de una manera específica y no puede elegirse arbitrariamente como el contrato Hook. Este diseño tiene como objetivo principal reducir el consumo de gas y trasladar el costo al despliegue por contrato para lograr operaciones más eficientes. (PD: en la práctica, se pueden usar diferentes sales CREATE2 para calcular por fuerza bruta las direcciones del contrato que cumplen con las condiciones)
Además de poder realizar operaciones adicionales antes y después de cada acción, Hooks también admite la implementación de tarifas dinámicas. Al crear un grupo, puede especificar si desea habilitar tarifas dinámicas. Si las tarifas dinámicas están habilitadas, se llama a la función getFee() del contrato Hook al intercambiar tokens. El contrato Hook puede determinar el monto de las tarifas a cobrar en función del estado actual del Pool. Este diseño permite un cálculo de tarifas flexible en función de las circunstancias reales, lo que aumenta la flexibilidad del sistema.
Cada Pool necesita determinar el contrato Hook durante su creación, y no se puede cambiar después (aunque diferentes Pools pueden compartir el mismo contrato Hook). Esto se debe principalmente a que los Hooks se consideran parte de PoolKey y PoolManager usa PoolKey para identificar en qué grupo operar. Incluso si los activos son los mismos, si el contrato Hook es diferente, se considerará un Pool diferente. Este diseño garantiza que el estado y las operaciones de diferentes Pools se puedan gestionar de forma independiente, garantizando la coherencia de los Pools. Sin embargo, también aumenta la complejidad del enrutamiento a medida que aumenta el número de Pools (quizás UniswapX esté diseñado para resolver este problema).
UniswapV4 claramente enfatiza la expansión de todo el ecosistema Uniswap, convirtiéndolo en infraestructura para permitir que se construyan más servicios sobre la base de Uniswap Pools. Esto ayuda a mejorar la competitividad de Uniswap y reduce el riesgo de servicios alternativos. Sin embargo, aún está por verse si logrará el éxito esperado. Algunos aspectos destacados incluyen la combinación de Flash Accounting y EIP1153, y creemos que más servicios adoptarán estas características en el futuro, lo que dará lugar a varios escenarios de aplicación. Este es el concepto central de UniswapV4 y esperamos que proporcione una comprensión más profunda de cómo funciona UniswapV4. Si hay algún error en el artículo, no dude en señalarlo. También damos la bienvenida a discusiones y comentarios.
Finalmente, nos gustaría agradecer a Anton Cheng y Ping Chen por revisar el artículo y brindar comentarios valiosos.
Desde el anuncio de UniswapV4, esta plataforma de intercambio ha experimentado una transformación significativa, pasando de una simple plataforma de intercambio a un proveedor de servicios de infraestructura. En particular, la función Hooks de V4 ha ganado una amplia atención. Después de una investigación en profundidad, he recopilado contenido para ayudar a todos a comprender mejor esta transformación y su implementación.
El objetivo de la innovación de UniswapV4 no es solo mejorar la tecnología AMM sino también expandir el ecosistema. En concreto, esta innovación incluye las siguientes características clave:
En las siguientes secciones, explicaré en detalle la importancia de estas características y sus principios de implementación.
fuente: https://twitter.com/jermywkh/status/1670779830621851650
UniswapV4 adopta un método de mantenimiento de registros similar a la contabilidad de doble entrada para realizar un seguimiento de los cambios de saldo de los tokens correspondientes a cada operación. Este método de contabilidad por partida doble requiere registrar cada transacción en varias cuentas simultáneamente y garantizar que el saldo de activos entre estas cuentas permanezca equilibrado. Por ejemplo, supongamos que un usuario intercambia 100 TokenA por 50 TokenB del grupo. El registro en el libro mayor sería el siguiente:
En UniswapV4, este método de mantenimiento de registros se utiliza principalmente para operaciones importantes y una variable de almacenamiento denominada lockState.currencyDelta[moneda] se utiliza en el código para registrar la cantidad de cambios en el saldo del token. Si el valor de este delta es positivo, representa el aumento esperado en la cantidad de tokens en el grupo, mientras que un valor negativo representa la disminución esperada en la cantidad de tokens. Alternativamente, si el valor es positivo, indica la cantidad de token faltante en el grupo (la cantidad esperada a recibir), mientras que un valor negativo indica el exceso de token en el grupo (la cantidad esperada que los usuarios retiren). La siguiente lista muestra los efectos de varias operaciones en Token Delta:
Entre estas operaciones, sólo "liquidar" y "tomar" implican la transferencia real de tokens, mientras que otras operaciones son las únicas responsables de actualizar el valor de TokenDelta.
Aquí usamos un ejemplo simple para ilustrar cómo actualizar TokenDelta. Supongamos que hoy cambiamos 100 TokenA por 50 TokenB:
Cuando se completa toda la operación de intercambio, tanto TokenADelta como TokenBDelta se restablecen a 0. Esto significa que la operación se ha equilibrado por completo, garantizando así la coherencia de los saldos de las cuentas.
Anteriormente, se mencionó que UniswapV4 utiliza variables de almacenamiento para registrar TokenDelta. Sin embargo, dentro del contrato, leer y escribir en variables de almacenamiento es bastante costoso. Esto nos lleva a otro EIP presentado por Uniswap: EIP1153 - Códigos de operación de almacenamiento transitorio.
UniswapV4 planea utilizar los códigos de operación TSTORE y TLOAD proporcionados por EIP1153 para actualizar TokenDelta. Las variables de almacenamiento que adoptan códigos de operación de almacenamiento transitorio se descartarán una vez finalizada la transacción (similar a las variables de memoria), lo que reduce las tarifas de gas.
Se ha confirmado que EIP1153 se incluirá en la próxima actualización de Cancún, y UniswapV4 también ha declarado que entrará en funcionamiento después de la actualización de Cancún, como se informa aquí.
fuente: https://etherworld.co/2022/12/13/transient-storage-for-beginners/
UniswapV4 introduce un mecanismo de bloqueo, lo que significa que antes de realizar cualquier operación del Pool, primero debe llamar a PoolManager.lock() para adquirir un bloqueo. Durante la ejecución de lock(), verifica si el valor de TokenDelta es 0; de lo contrario, se revertirá. Una vez que PoolManager.lock() se adquiere con éxito, llama a la función lockAcquired() de msg.sender. Dentro de la función lockAcquired() se realizan las operaciones relacionadas con el Pool, como swap y modificarPosition.
El proceso se ilustra a continuación. Cuando un usuario necesita realizar una operación de intercambio de tokens, debe llamar a un contrato inteligente con la función lockAcquired() (conocido como contrato de devolución de llamada). El contrato de devolución de llamada primero llama a PoolManager.lock(), y luego PoolManager llama a la función lockAcquired() del Contrato de devolución de llamada. Dentro de la función lockAcquired(), se define la lógica relacionada con las operaciones del Pool, como swap, liquidación y toma. Finalmente, cuando lock() está a punto de finalizar, PoolManager verifica si el TokenDelta asociado con esta operación se ha restablecido a 0, asegurando que el saldo de activos en el Pool permanezca intacto.
El contrato Singleton significa que UniswapV4 ha abandonado el modelo Factory-Pool anterior. Cada grupo ya no es un contrato inteligente independiente, sino que todos los grupos comparten un único contrato único. Este diseño, combinado con el mecanismo de Contabilidad Flash, solo requiere actualizar las Variables de Almacenamiento necesarias, reduciendo aún más la complejidad y el costo de las operaciones.
En el siguiente ejemplo, utilizando UniswapV3 como ejemplo, el intercambio de ETH por DAI requeriría al menos cuatro transferencias de tokens (operaciones de escritura de almacenamiento). Esto incluye múltiples cambios registrados para los tokens USDC, USDT y DAI. Sin embargo, con las mejoras en UniswapV4, junto con el mecanismo de Contabilidad Flash, solo se necesita una transferencia de Token (mover DAI del Pool al usuario), lo que reduce significativamente la cantidad de operaciones y costos.
fuente: https://twitter.com/Uniswap/status/1671208668304486404
En la última actualización de UniswapV4, la característica más notable es la arquitectura Hooks. Esta actualización aporta una gran flexibilidad en términos de disponibilidad del Pool. Los Hooks son acciones adicionales que se activan a través del Contrato de Hooks al realizar operaciones específicas en el Pool. Estas acciones se clasifican en inicializar (crear grupo), modificar posición (agregar/eliminar liquidez), intercambiar y donar. Cada categoría tiene acciones previas y posteriores a la ejecución.
Este diseño permite a los usuarios ejecutar lógica personalizada antes y después de operaciones específicas, lo que la hace más flexible y amplía la funcionalidad de UniswapV4.
fuente: https://github.com/Uniswap/v4-core/blob/main/whitepaper-v4-draft.pdf
A continuación, usaremos un ejemplo de orden limitada para explicar el proceso de operación real de Hooks en UniswapV4. Antes de comenzar, expliquemos brevemente el principio de implementación de órdenes limitadas en UniswapV4.
La implementación UniswapV4 de la orden límite funciona agregando liquidez a un rango de precios específico y luego ejecutando la operación de eliminación de liquidez si se intercambia la liquidez en ese rango.
Por ejemplo, digamos que agregamos liquidez en el rango de precios de 1900-2000 para ETH, y luego el precio de ETH aumenta de 1800 a 2100. En este punto, toda la liquidez de ETH que agregamos anteriormente en el rango de precios 1900-2000 se ha intercambiado por USDC (suponiendo que sea en el grupo ETH-USDC). Al eliminar la liquidez en este momento, podemos lograr un efecto similar al de ejecutar una orden de mercado de ETH en el rango de precios actual de 1900-2000.
Este ejemplo está tomado de GitHub de UniswapV4. En este ejemplo, el contrato de enlace de orden limitada proporciona dos enlaces, a saber, afterInitialize y afterSwap. El gancho afterInitialize se utiliza para registrar el rango de precios (tick) al crear un grupo, con el fin de determinar qué órdenes límite se han igualado después de que alguien realiza un intercambio.
Cuando el usuario necesita realizar una orden, el contrato Hook ejecuta la operación de adición de liquidez en función del rango de precios y la cantidad especificados por el usuario. En el contrato Hook para órdenes limitadas, puede ver la función place() . La lógica principal es llamar a la función lockAcquiredPlace() después de adquirir el bloqueo para ejecutar la operación de adición de liquidez, lo que equivale a colocar una orden limitada.
fuente: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L246
Después de que el usuario complete un token de intercambio dentro de este grupo, el grupo invocará la función afterSwap() del contrato Hook. La lógica principal de afterSwap es eliminar la liquidez de las órdenes realizadas previamente que se han ejecutado entre el rango de precios anterior y el rango de precios actual. Este comportamiento es equivalente a que se complete el pedido.
fuente: https://github.com/Uniswap/v4-periphery/blob/main/contracts/hooks/examples/LimitOrder.sol#L192
A continuación se muestra un diagrama de flujo que ilustra el proceso de ejecución de una orden limitada:
Lo anterior es todo el proceso de implementación de Limit-Order utilizando el mecanismo Hook.
Los ganchos tienen varios puntos interesantes que creo que vale la pena compartir.
La decisión de realizar operaciones específicas antes/después está determinada por el byte más a la izquierda de la dirección del contrato Hook. 1 byte equivale a 8 bits, lo que corresponde a 8 acciones adicionales. El grupo comprobará si el bit de esa acción es 1 para determinar si se debe invocar la función de enlace correspondiente del contrato de enlace. Esto también significa que la dirección del contrato Hook debe diseñarse de una manera específica y no puede elegirse arbitrariamente como el contrato Hook. Este diseño tiene como objetivo principal reducir el consumo de gas y trasladar el costo al despliegue por contrato para lograr operaciones más eficientes. (PD: en la práctica, se pueden usar diferentes sales CREATE2 para calcular por fuerza bruta las direcciones del contrato que cumplen con las condiciones)
Además de poder realizar operaciones adicionales antes y después de cada acción, Hooks también admite la implementación de tarifas dinámicas. Al crear un grupo, puede especificar si desea habilitar tarifas dinámicas. Si las tarifas dinámicas están habilitadas, se llama a la función getFee() del contrato Hook al intercambiar tokens. El contrato Hook puede determinar el monto de las tarifas a cobrar en función del estado actual del Pool. Este diseño permite un cálculo de tarifas flexible en función de las circunstancias reales, lo que aumenta la flexibilidad del sistema.
Cada Pool necesita determinar el contrato Hook durante su creación, y no se puede cambiar después (aunque diferentes Pools pueden compartir el mismo contrato Hook). Esto se debe principalmente a que los Hooks se consideran parte de PoolKey y PoolManager usa PoolKey para identificar en qué grupo operar. Incluso si los activos son los mismos, si el contrato Hook es diferente, se considerará un Pool diferente. Este diseño garantiza que el estado y las operaciones de diferentes Pools se puedan gestionar de forma independiente, garantizando la coherencia de los Pools. Sin embargo, también aumenta la complejidad del enrutamiento a medida que aumenta el número de Pools (quizás UniswapX esté diseñado para resolver este problema).
UniswapV4 claramente enfatiza la expansión de todo el ecosistema Uniswap, convirtiéndolo en infraestructura para permitir que se construyan más servicios sobre la base de Uniswap Pools. Esto ayuda a mejorar la competitividad de Uniswap y reduce el riesgo de servicios alternativos. Sin embargo, aún está por verse si logrará el éxito esperado. Algunos aspectos destacados incluyen la combinación de Flash Accounting y EIP1153, y creemos que más servicios adoptarán estas características en el futuro, lo que dará lugar a varios escenarios de aplicación. Este es el concepto central de UniswapV4 y esperamos que proporcione una comprensión más profunda de cómo funciona UniswapV4. Si hay algún error en el artículo, no dude en señalarlo. También damos la bienvenida a discusiones y comentarios.
Finalmente, nos gustaría agradecer a Anton Cheng y Ping Chen por revisar el artículo y brindar comentarios valiosos.