El riesgo del contrato inteligente en DeFi


Escrito original por Jan Xie

Las finanzas son el arte de la gestión de riesgos. Existen riesgos tanto en los activos como en las operaciones. Un activo tiene un precio, el precio es un reflejo de su valor intrínseco y riesgo sintetizado. No podemos evaluar un activo sin analizar su riesgo. Los riesgos en las operaciones son principalmente de humanos que son propensos a errores y corrompibles. La evaluación del riesgo de activos y operaciones está en el centro de las finanzas, sin importar si se refiere a las finanzas tradicionales basadas en activos tradicionales o nuevas finanzas descentralizadas brillantes (también conocidas como DeFi) que se ejecutan en activos criptográficos nativos.

El control de daños es la clave

El riesgo de los criptoactivos se compone de riesgos externos, como cambios en la regulación, y riesgos internos, como fallas de diseño y bugs de implementación. En Ethereum, el activo nativo es ETH, y los activos no nativos son lo que llamamos tokens ERC, que se refiere a los tokens que cumplen con cualquiera de los estándares ERC20 y sus acompañantes como ERC721 y ERC777, etc. El riesgo del activo nativo es menor que el riesgo de un activo no nativo porque este último puede verse afectado tanto por bugs del cliente de Ethereum como por bugs del contrato inteligente. Para los tokens ERC y DeFi, los bugs en un contrato inteligente son la mayor preocupación porque DeFi como sistema es una red complicada entrelazada a través de contratos inteligentes infinitos creados por diferentes desarrolladores de diferentes lugares. Llamamos a los riesgos causados ​​por bugs del contrato inteligente riesgos de los contratos inteligentes.

Muchos esfuerzos de investigación se han centrado en las vulnerabilidades de los contratos inteligentes, y hemos encontrado muchos métodos de defensa. Si estas interesado, aquí hay una buena encuesta. Sin embargo, se sabe comúnmente que eliminar bugs en cualquier contrato inteligente no trivial (o cualquier programa) es imposible. Vivimos en un mundo lleno de errores de comunicación y aleatoriedad, que causan “distorsión” en cada paso: no podemos convertir la idea en nuestra mente en una especificación precisa y de manera similar, no podemos convertir una especificación en una implementación perfecta.

Si esta es la cruel realidad, no solo deberíamos considerar defensas proactivas y reactivas en nuestra implementación de criptoactivos, sino también métodos de control de daños que pueden minimizar la pérdida cuando sucede algo malo, para evitar convertir una mariposa en un cisne negro. Existen muchos patrones de diseño que pueden ser adoptados por contratos inteligentes para el control de daños, el más importante (creo) es la descentralización del estado de la aplicación porque la centralización del estado de la aplicación amplificará el daño causado por los errores del contrato inteligente. Permítanme explicar con más detalle lo que quiero decir exactamente con eso.

El riesgo de los tokens ERC

Los estándares de token ERC difieren en la interfaz pero comparten algunas características comunes. El patrón básico de un token ERC es usar un contrato de token para administrar el libro mayor(ledger) de tokens, y los usuarios interactúan con el contrato de token para emitir, transferir o ‘quemar’ tokens. Todos los registros del libro mayor(ledger) de tokens se almacenan en el contrato de tokens, y el contrato en sí es simplemente una cuenta en Ethereum.

Por ejemplo, supongamos que hay un token ERC ‘Copa’, Alice tiene 100 Copas y Bob tiene 50 Copas. El token ledger es un contrato inteligente de Ethereum ubicado en la dirección / cuenta 0x1234. Este contrato de token 0x1234 mantiene una base de datos interna, que almacena registros como “Alice tiene 100 copas” y “Bob tiene 50 copas”. Cuando Alice quiere transferir 30 Copas a Bob, envía un mensaje firmado al contrato 0x1234 que dice “transfiere 30 Copas a Bob”, el contrato 0x1234 verificará que el mensaje es de Alice y modificará su base de datos interna, actualizará registros relevantes para “Alice tiene 70 Copas” y “Bob tiene 80 Copas”.

El problema aquí es que toda la lógica y el estado se mantienen en el contrato único 0x1234. Alice y Bob no tienen acceso directo a sus propios registros porque los registros se mantienen bajo custodia del contrato 0x1234. Todos los usuarios de este token interactúan con este contrato, y la única forma de administrar sus tokens es enviando un mensaje al contrato 0x1234.

En otras palabras, el contrato de token es un punto central. El punto central en cualquier sistema es también el punto de ataque más lucrativo. Cualquier problema con el punto central afecta a todos los usuarios porque mantiene todos los tokens / registros y todos tienen que interactuar con él. Por ejemplo, con las vulnerabilidades ‘transferFlaw’ / ‘allowAnyone’ causadas por el desbordamiento de enteros o la vulnerabilidad ‘ItchySwap’ causada por una autorización no cautelosa, un atacante puede robar los tokens de otros mientras el propietario no tiene interacción con el contrato. Con la vulnerabilidad ‘ownerAnyone’, un atacante puede tomar el control del contrato del token para bloquear los tokens de todos. En todos estos ejemplos, una vez que se rompe el contrato del token, todos están en problemas.

Un token ERC está en manos de un contrato de token, no de usuarios individuales, y esto es muy diferente de los tokens nativos como Ether de Ethereum. Los registros de saldos de ETH no se almacenan en ningún contrato inteligente, sino que los usuarios los controlan directamente. Cada propietario de ETH tiene su propia cuenta y registro de saldo. Por ejemplo, si Alice tiene 100 ETH y Bob tiene 50 ETH en la blockchain Ethereum, Alice tiene un “saldo = 100” en su propia cuenta y Bob tiene un “saldo = 50” en su propia cuenta. El saldo de Alice solo se puede disminuir con la presencia de su firma, y ​​lo mismo es cierto para la cuenta de Bob. Los registros de propiedad de ETH se descentralizan en varias cuentas en lugar de centralizarse en una sola cuenta. Mientras sus claves privadas estén seguras, nadie podrá robarles Ether. Por el contrario, la interfaz de ataque de un token ERC es más grande porque un atacante siempre puede intentar romper el contrato del token, lo cual es mucho más fácil que romper el protocolo en sí.

Los diferentes riesgos inherentes hacen que los tokens ERC y el Ether sean dos clases diferentes de activos. Un contrato inteligente que se ejecuta en una red descentralizada no es lo mismo que la red descentralizada. El problema de centralización es introducido por los tokens ERC nuevamente en la capa de aplicación, amplificando el daño potencial de cualquier bug de contrato inteligente, y desafortunadamente, sabemos que los humanos siempre cometerán errores. Siempre habrá errores. La descentralización de la red / capa de consenso no puede resolver un problema de centralización en la capa de aplicación.

Cómo quitar el amplificador de riesgo

El punto de centralización surge en los tokens ERC porque su estado no es un ciudadano de primera clase en el modelo de programación de Ethereum. Una parte del estado es un archivo adjunto al código, pero no se puede hacer referencia a él y compararlo directamente. Es natural poner el estado con las mismas reglas de validación (por ejemplo, registros del mismo token) en el mismo contrato, sin embargo, este contrato se convierte en un punto de centralización. Esta es una consecuencia del modelo de programación de Ethereum.

En CKB, el patrón se invierte porque el estado es un ciudadano de primera clase. El estado es el objeto con el que los usuarios juegan directamente, y el código es un archivo adjunto al estado. Podemos comparar y agrupar el estado con las mismas reglas de validación de forma natural, incluso cuando estos estados son mantenidos directamente por diferentes usuarios.

Nos referimos a un token no nativo en CKB como ‘Token definido por el usuario’ o UDT(User Defined Token). Para un UDT dado, la definición del activo (código) y los registros de activos (estado) están separados, y los registros de diferentes usuarios (direcciones) también están separados. La definición del activo describe la lógica del token, por ejemplo, “El límite de emisión es 1M” o “Bob puede emitir nuevos tokens”, y los registros son información como “Alice tiene 100 tokens”. La definición de activos es un contrato creado por un desarrollador de tokens y almacenado en una Cell propiedad del desarrollador (Cell de definición de activos), mientras que los registros se mantienen en las Cells de los usuarios, y todos usan el mismo type script. Cada usuario usa su propia Cell para almacenar sus propios registros de tokens. Estos registros de token comparten las mismas reglas de validación definidas por la Cell de definición de activos. Con esta estructura, los registros se almacenan de forma descentralizada.

Como muestra la demostración anterior, el token de Alice se almacena en la propia Cell de Alice y está protegido por su propio script de bloqueo, que es Secp256k1 de forma predeterminada. Incluso si hay un error en la definición del activo, un atacante no puede modificar el registro de Alice porque hacerlo requiere la clave privada de Alice. Debido a que el token está en manos de Alice directamente, no hay forma de que un atacante pueda manipular la cerradura de Alice. Al descentralizar el estado de un token, se puede controlar el daño de un error en la definición de activos.

Todavía existe la posibilidad de bugs que afecten a todos: por ejemplo, puede haber un bug en la definición de activos que permita a cualquiera emitir más tokens de lo esperado. El beneficio de UDT es, primero, que se elimina una gran parte de los bugs; y segundo, la Cell de definición de activos está protegida por un bloqueo que puede ser parte de la lógica de autenticación de emisión de tokens de forma natural. Siempre es fácil utilizar el mecanismo de autenticación proporcionado por el protocolo. Este desacoplamiento de la autorización y la lógica empresarial es una buena práctica de ingeniería, y es un valor predeterminado en CKB. UDT está más descentralizado que los tokens ERC, por lo que el riesgo del contrato inteligente de UDT es menor que el token ERC pero aún mayor que un token nativo.

Si estas interesado en UDT, hay varias discusiones en Nervos Talk.

Un DAO seguro de Nervos

La descentralización del estado de la aplicación también puede ayudar al diseño de la aplicación DeFi. El Nervos DAO es la primera aplicación en DeFi CKB. Es un contrato inteligente con el que los usuarios pueden interactuar de la misma manera que cualquier contrato inteligente en CKB. Una función de Nervos DAO es proporcionar una contramedida de dilución para los titulares de CKByte. Al depositar en Nervos DAO, los titulares obtienen recompensas secundarias proporcionales, que garantizan que sus valores almacenados solo se vean afectadas por la emisión primaria con tope rígido como en Bitcoin. Hay más de 1 billón de CKBytes depositados en el DAO al momento de escribir y el número está aumentando, lo que lo convierte en un contrato muy atractivo para los atacantes. ¿Deberíamos estar preocupados?

Tal vez no tanto, porque los CKBytes bloqueados en el DAO de Nervos no se agrupan en un solo contrato inteligente, ¡pero aún en manos de diferentes usuarios! Cuando un usuario desea depositar en Nervos DAO, él / ella construye la transacción de depósito seleccionando Cells (UTXO de CKBytes) y establece sus referencias de type script a 0x82d76d1b75fe2fd9a27dfbaa65a039221a380d76c926f378d3f81cf3e7e13f2e, que apunta al script de Nervos DAO. Los scripts de bloqueo no se modifican para esas Cells. Debido a que los type scripts del DAO de Nervos están desacoplados de los scripts de bloqueo de los usuarios, un atacante nunca puede gastar esos CKBytes depositados sin el permiso de los usuarios.

Para retirar los CKBytes depositados, se deben proporcionar testigos (firmas) de los scripts de bloqueo correspondientes. Esta validación está garantizada por la red CKB, no por ningún contrato inteligente, y no hay otra solución. El script de Nervos DAO está ahí para asegurarse de que el cálculo de la compensación sea correcto en el retiro, no para retener fondos.

El impacto en DeFi

Es difícil analizar el impacto del riesgo del contrato inteligente en DeFi cuantitativamente, pero podemos obtener algunas pistas del producto de seguro proporcionado por Nexus Mutual, que es una ‘alternativa descentralizada al seguro’. Su primer producto, SmartContractCover, permite al usuario comprar cobertura de seguro en cualquier contrato inteligente para que pueda recibir una compensación si el contrato inteligente es hackeado. La prima de un SmartContractCover está determinada por el mercado, correlacionada positivamente con el período y el monto de la cobertura. De acuerdo con este post, la cobertura de seguro de 1000 DAI en Nuo por 90 días te costará 6.41 DAI, mientras que la cobertura de seguro de 1 ETH en Uniswap por 365 días te costará 0.013 ETH. En base a estos números, podemos llegar a una estimación de que el costo anualizado del riesgo del contrato inteligente es de alrededor del 2%.

El costo del 2% es una ineficiencia del mercado causada por el riesgo del contrato inteligente, y es por eso que es importante una mejora en el modelo de programación del contrato inteligente. Un modelo de programación diferente puede reducir el riesgo del contrato inteligente y brindarnos un mercado de DeFi más eficiente.

Gracias a Haseeb Qureshi, Cipher Wang, Matt Quinn y Christopher Heymann por sus comentarios en el borrador de esta publicación.