Compartir técnicas de desarrollo de contratos: Aprendiendo del código fuente de Uniswap
Recientemente, al escribir un tutorial de desarrollo de un intercambio descentralizado, referencié la implementación del código de Uniswap V3 y aprendí muchos puntos de conocimiento valiosos. Como desarrollador que intenta por primera vez desarrollar contratos Defi, estas técnicas serán muy útiles para los principiantes que deseen aprender el desarrollo de contratos.
A continuación comparto algunos trucos que he aprendido, algunos de los cuales incluso podrían considerarse habilidades ingeniosas.
Dirección de despliegue de contratos predecible
Normalmente, el contrato desplegado obtiene una dirección que parece aleatoria, debido a que está relacionada con el nonce, por lo que es difícil predecir la dirección del contrato. Sin embargo, en ciertos escenarios, necesitamos deducir la dirección del contrato a partir de la transacción y la información relacionada. Esto es muy útil en situaciones como la evaluación de los permisos de transacción o la obtención de la dirección del pool.
Uniswap crea contratos utilizando el método CREATE2 al agregar el parámetro salt, lo que permite predecir la dirección del contrato creado. La lógica de generación de direcciones es: nueva dirección = hash("0xFF", dirección del creador, salt, initcode).
Uso inteligente de las funciones de callback
En ciertos escenarios, el contrato A llama al método del contrato B, y B, en el método que se llama, hace una devolución de llamada a A; este método es muy práctico.
Por ejemplo, en Uniswap, al llamar al método swap del contrato UniswapV3Pool para realizar una transacción, se llamará a swapCallback, pasando el Token necesario calculado para la transacción actual. El llamador debe transferir el Token requerido para la transacción al UniswapV3Pool dentro del callback, en lugar de dividir el método swap en dos partes para que el llamador lo invoque. Esto asegura la seguridad del método swap, garantizando que toda la lógica se ejecute de manera completa, sin la necesidad de registros de variables engorrosos para asegurar la seguridad.
Utilizar la transmisión de información mediante excepciones, implementar la estimación de transacciones con try catch
En el contrato Quoter de Uniswap, el método swap del UniswapV3Pool se ejecuta envuelto en un try catch. Esto es para simular el método swap y estimar los tokens necesarios para la transacción. Dado que en la estimación no se produce realmente un intercambio de tokens, se generará un error. Uniswap lanza un error especial en la función de callback de la transacción y luego captura ese error, extrayendo la información necesaria del mensaje de error.
Este método parece un atajo, pero es muy práctico. No es necesario modificar el método swap para estimar la demanda de transacciones, la lógica es más simple.
Usar grandes números para resolver problemas de precisión
En el código de Uniswap hay una gran cantidad de lógica de cálculo, como calcular el token intercambiado según el precio actual y la liquidez. Para evitar la pérdida de precisión durante la operación de división, el proceso de cálculo a menudo utiliza la operación "<< FixedPoint96.RESOLUTION", es decir, desplazar a la izquierda 96 bits, lo que equivale a multiplicar por 2^96. Después de desplazar a la izquierda, se realiza la operación de división, garantizando la precisión en condiciones normales de transacciones sin desbordamientos.
Calcular beneficios con Share
En Uniswap, es necesario registrar los ingresos por comisiones de los proveedores de liquidez LP(. Evidentemente, no se puede registrar la comisión de cada LP en cada transacción, ya que esto consumiría una gran cantidad de Gas.
La solución de Uniswap es registrar feeGrowthInside0LastX128 y feeGrowthInside1LastX128 en la estructura Position, que representan las tarifas que cada posición debería recibir en función de la última vez que se retiraron las tarifas. Solo se necesita registrar la tarifa total y la tarifa que debe distribuirse a cada liquidez; al retirar LP, se calcula la tarifa que se puede retirar según la liquidez mantenida. Esto es similar a poseer acciones de una empresa; al retirar ganancias, solo se necesita conocer la ganancia por acción histórica de la empresa y la ganancia en la última retirada.
![Serie para principiantes en Web3: Consejos de desarrollo de contratos que aprendí del código de Uniswap])https://img-cdn.gateio.im/webp-social/moments-45e66af69435e6d4412ae506e77ab893.webp(
No es necesario obtener información no esencial de la cadena
El almacenamiento en la cadena es relativamente costoso y no toda la información necesita estar en la cadena o ser obtenida de la cadena. Por ejemplo, muchas de las interfaces llamadas por el sitio web frontal de Uniswap son interfaces tradicionales de Web2.
La lista de grupos de transacciones, la información del grupo de transacciones, etc., se pueden almacenar en una base de datos común; algunos pueden necesitar sincronización periódica desde la cadena, pero no es necesario llamar en tiempo real a la interfaz RPC de servicios de cadena o nodos para obtener los datos relacionados.
Por supuesto, las transacciones clave deben realizarse en la cadena.
División razonable de contratos, aprovechando contratos estándar existentes
Un proyecto puede contener varios contratos desplegados en la práctica. Incluso si solo hay un contrato desplegado, el código puede dividirse en varios contratos para su mantenimiento mediante herencia.
Por ejemplo, el contrato NonfungiblePositionManager de Uniswap hereda de varios contratos. Al revisar la implementación del contrato ERC721Permit, se descubre que utiliza directamente el contrato @openzeppelin/contracts/token/ERC721/ERC721.sol. Esto facilita la gestión de posiciones a través de NFTs y permite aprovechar los contratos estándar existentes para mejorar la eficiencia del desarrollo.
Resumen
La práctica es el mejor método de aprendizaje. Intentar implementar por tu cuenta una versión simplificada de un intercambio descentralizado te permitirá comprender más a fondo la implementación del código de Uniswap y aprender más sobre los puntos de conocimiento en proyectos reales.
![Serie para principiantes de Web3: Consejos de desarrollo de contratos que aprendí del código de Uniswap])https://img-cdn.gateio.im/webp-social/moments-f95ddc9d89809cf11dbe65b9bafda157.webp(
Esta página puede contener contenido de terceros, que se proporciona únicamente con fines informativos (sin garantías ni declaraciones) y no debe considerarse como un respaldo por parte de Gate a las opiniones expresadas ni como asesoramiento financiero o profesional. Consulte el Descargo de responsabilidad para obtener más detalles.
Revelación del código fuente de Uniswap: 7 técnicas de desarrollo de contratos que ayudan a los novatos de DeFi a despegar
Compartir técnicas de desarrollo de contratos: Aprendiendo del código fuente de Uniswap
Recientemente, al escribir un tutorial de desarrollo de un intercambio descentralizado, referencié la implementación del código de Uniswap V3 y aprendí muchos puntos de conocimiento valiosos. Como desarrollador que intenta por primera vez desarrollar contratos Defi, estas técnicas serán muy útiles para los principiantes que deseen aprender el desarrollo de contratos.
A continuación comparto algunos trucos que he aprendido, algunos de los cuales incluso podrían considerarse habilidades ingeniosas.
Dirección de despliegue de contratos predecible
Normalmente, el contrato desplegado obtiene una dirección que parece aleatoria, debido a que está relacionada con el nonce, por lo que es difícil predecir la dirección del contrato. Sin embargo, en ciertos escenarios, necesitamos deducir la dirección del contrato a partir de la transacción y la información relacionada. Esto es muy útil en situaciones como la evaluación de los permisos de transacción o la obtención de la dirección del pool.
Uniswap crea contratos utilizando el método CREATE2 al agregar el parámetro salt, lo que permite predecir la dirección del contrato creado. La lógica de generación de direcciones es: nueva dirección = hash("0xFF", dirección del creador, salt, initcode).
Uso inteligente de las funciones de callback
En ciertos escenarios, el contrato A llama al método del contrato B, y B, en el método que se llama, hace una devolución de llamada a A; este método es muy práctico.
Por ejemplo, en Uniswap, al llamar al método swap del contrato UniswapV3Pool para realizar una transacción, se llamará a swapCallback, pasando el Token necesario calculado para la transacción actual. El llamador debe transferir el Token requerido para la transacción al UniswapV3Pool dentro del callback, en lugar de dividir el método swap en dos partes para que el llamador lo invoque. Esto asegura la seguridad del método swap, garantizando que toda la lógica se ejecute de manera completa, sin la necesidad de registros de variables engorrosos para asegurar la seguridad.
Utilizar la transmisión de información mediante excepciones, implementar la estimación de transacciones con try catch
En el contrato Quoter de Uniswap, el método swap del UniswapV3Pool se ejecuta envuelto en un try catch. Esto es para simular el método swap y estimar los tokens necesarios para la transacción. Dado que en la estimación no se produce realmente un intercambio de tokens, se generará un error. Uniswap lanza un error especial en la función de callback de la transacción y luego captura ese error, extrayendo la información necesaria del mensaje de error.
Este método parece un atajo, pero es muy práctico. No es necesario modificar el método swap para estimar la demanda de transacciones, la lógica es más simple.
Usar grandes números para resolver problemas de precisión
En el código de Uniswap hay una gran cantidad de lógica de cálculo, como calcular el token intercambiado según el precio actual y la liquidez. Para evitar la pérdida de precisión durante la operación de división, el proceso de cálculo a menudo utiliza la operación "<< FixedPoint96.RESOLUTION", es decir, desplazar a la izquierda 96 bits, lo que equivale a multiplicar por 2^96. Después de desplazar a la izquierda, se realiza la operación de división, garantizando la precisión en condiciones normales de transacciones sin desbordamientos.
Calcular beneficios con Share
En Uniswap, es necesario registrar los ingresos por comisiones de los proveedores de liquidez LP(. Evidentemente, no se puede registrar la comisión de cada LP en cada transacción, ya que esto consumiría una gran cantidad de Gas.
La solución de Uniswap es registrar feeGrowthInside0LastX128 y feeGrowthInside1LastX128 en la estructura Position, que representan las tarifas que cada posición debería recibir en función de la última vez que se retiraron las tarifas. Solo se necesita registrar la tarifa total y la tarifa que debe distribuirse a cada liquidez; al retirar LP, se calcula la tarifa que se puede retirar según la liquidez mantenida. Esto es similar a poseer acciones de una empresa; al retirar ganancias, solo se necesita conocer la ganancia por acción histórica de la empresa y la ganancia en la última retirada.
![Serie para principiantes en Web3: Consejos de desarrollo de contratos que aprendí del código de Uniswap])https://img-cdn.gateio.im/webp-social/moments-45e66af69435e6d4412ae506e77ab893.webp(
No es necesario obtener información no esencial de la cadena
El almacenamiento en la cadena es relativamente costoso y no toda la información necesita estar en la cadena o ser obtenida de la cadena. Por ejemplo, muchas de las interfaces llamadas por el sitio web frontal de Uniswap son interfaces tradicionales de Web2.
La lista de grupos de transacciones, la información del grupo de transacciones, etc., se pueden almacenar en una base de datos común; algunos pueden necesitar sincronización periódica desde la cadena, pero no es necesario llamar en tiempo real a la interfaz RPC de servicios de cadena o nodos para obtener los datos relacionados.
Por supuesto, las transacciones clave deben realizarse en la cadena.
División razonable de contratos, aprovechando contratos estándar existentes
Un proyecto puede contener varios contratos desplegados en la práctica. Incluso si solo hay un contrato desplegado, el código puede dividirse en varios contratos para su mantenimiento mediante herencia.
Por ejemplo, el contrato NonfungiblePositionManager de Uniswap hereda de varios contratos. Al revisar la implementación del contrato ERC721Permit, se descubre que utiliza directamente el contrato @openzeppelin/contracts/token/ERC721/ERC721.sol. Esto facilita la gestión de posiciones a través de NFTs y permite aprovechar los contratos estándar existentes para mejorar la eficiencia del desarrollo.
Resumen
La práctica es el mejor método de aprendizaje. Intentar implementar por tu cuenta una versión simplificada de un intercambio descentralizado te permitirá comprender más a fondo la implementación del código de Uniswap y aprender más sobre los puntos de conocimiento en proyectos reales.
![Serie para principiantes de Web3: Consejos de desarrollo de contratos que aprendí del código de Uniswap])https://img-cdn.gateio.im/webp-social/moments-f95ddc9d89809cf11dbe65b9bafda157.webp(