Por Sara Deleyto · Artículo invitado · Con comentario jurídico de BACS
“Code is law” y su promesa
“Code is law” es uno de los principios más asociados al ecosistema blockchain. La idea parte de una promesa muy potente: sustituir algunos sistemas humanos basados en la confianza por reglas ejecutadas automáticamente mediante smart contracts. Sin jueces, sin intermediarios y, en teoría, sin necesidad de confiar en una persona o institución. Solo código determinista que ejecuta unas reglas previamente definidas.
Sobre el papel, parece una forma completamente nueva de establecer acuerdos. Si el código define una condición y la blockchain la ejecuta, el resultado debería ser incuestionable.
Sin embargo, hay una diferencia entre que un código ejecute exactamente lo que hemos programado y que ese resultado sea necesariamente el que queríamos obtener.
Qué garantiza realmente el código
Para entender esto nos remontamos a 2016, cuando apareció The DAO, uno de los experimentos más ambiciosos de la comunidad Ethereum. La idea era crear una organización descentralizada cuyos fondos y reglas estuvieran gestionados mediante smart contracts. Los participantes podían aportar ETH y participar en las decisiones sobre cómo utilizar esos fondos.
El problema apareció en la implementación de una de sus funciones de retirada. Un atacante consiguió aprovechar una vulnerabilidad de reentrancy para llamar repetidamente a la función antes de que el contrato actualizara el estado interno que registraba cuánto ETH debía recibir.
El resultado fue la extracción de una cantidad enorme de ETH de The DAO.
Desde una perspectiva puramente técnica, el contrato había ejecutado el código que contenía; la transacción era válida para la red. La blockchain no tenía un concepto de “esto no era lo que los participantes querían”.
Pero la comunidad sí lo tenía.
Ethereum tuvo que enfrentarse entonces a una decisión que no podía resolverse escribiendo una nueva función en Solidity: ¿debía aceptarse el resultado porque el código lo había permitido o debía intervenir la comunidad para revertir sus consecuencias?
La discusión terminó dividiendo a la comunidad. Finalmente se produjo un hard fork que dio lugar a la cadena que hoy conocemos como Ethereum, mientras que quienes mantuvieron el historial original continuaron con Ethereum Classic.
Para mí, The DAO muestra una primera limitación importante de “code is law”.
Un smart contract puede garantizar que unas reglas se ejecuten de forma determinista. Puede garantizar qué ocurre cuando se cumplen determinadas condiciones dentro del sistema. Pero no puede garantizar que esas reglas sean correctas, que contemplen todos los escenarios posibles o que representen exactamente la intención de quienes las diseñaron.
La inmutabilidad tampoco significa que un sistema sea necesariamente intocable. Significa que, una vez desplegado, el código y el estado tienen unas propiedades que dificultan o impiden modificar directamente lo que ya está en la cadena. Si queremos introducir mecanismos de actualización, pausas o recuperación, tenemos que haberlos contemplado previamente en la arquitectura.
Y esa diferencia entre ejecutar una regla y saber si esa regla es la correcta está en el centro de muchos de los límites de los smart contracts.
El mundo real no cabe on-chain
Una de las cosas más importantes que he aprendido trabajando con smart contracts es que, por muy seguros y deterministas que sean, están aislados por diseño.
Una blockchain puede verificar la información que existe dentro de su propia red: balances, transacciones, firmas, permisos o estados de un contrato. Pero no puede acceder directamente a lo que está ocurriendo fuera de ella.
Un smart contract no puede saber por sí mismo cuál es el precio actual de un activo en un mercado externo, si un vuelo ha aterrizado, si un producto físico ha sido entregado o si una determinada condición del mundo real se ha cumplido.
Esta limitación es importante porque significa que un contrato no puede simplemente reaccionar ante cualquier evento externo. Necesita que esa información entre primero en la blockchain.
Aquí aparecen los oráculos.
Los oráculos funcionan como un puente entre la blockchain y fuentes externas de información. Pueden obtener datos de mercados, APIs, bases de datos, sensores u otras redes y llevarlos on-chain para que un smart contract pueda utilizarlos.
Gracias a ellos, un contrato puede ejecutar lógica basada en información que originalmente no existía dentro de la blockchain: precios de activos, condiciones meteorológicas, resultados de eventos, estados de vuelos o cualquier otro dato que pueda ser transformado en una entrada que el contrato pueda interpretar.
Pero este mecanismo introduce una nueva superficie de riesgo. El smart contract puede verificar que ha recibido un determinado precio. Lo que no puede hacer por sí mismo es comprobar que ese precio representa correctamente la realidad.
Esto quedó especialmente claro en el incidente de Harvest Finance en 2020. El protocolo sufrió un ataque en el que se utilizaron grandes operaciones y flash loans para provocar movimientos temporales en los precios de determinados activos dentro de los pools que utilizaba el sistema. El atacante pudo aprovechar esas discrepancias para interactuar con el protocolo en condiciones favorables y extraer valor.
Lo interesante del caso no es solamente que existiera una vulnerabilidad económica. Es que el smart contract estaba ejecutando sus reglas sobre información que, desde su propia perspectiva, era válida.
El contrato no podía mirar fuera de la blockchain y decir: “este movimiento de precio es artificial” o “este precio no representa realmente el mercado”. Simplemente recibía los datos disponibles y ejecutaba la lógica programada sobre ellos.
Aquí aparece una distinción que considero fundamental en el diseño de sistemas on-chain: la integridad del código no garantiza la integridad de los datos que recibe.
Podemos tener un smart contract perfectamente programado, auditado y determinista y, aun así, obtener un resultado incorrecto si una de las entradas en las que basa sus decisiones puede ser manipulada.
Por eso, cuando conectamos blockchain con el mundo real, no basta con preguntarnos qué hace el contrato. También tenemos que preguntarnos de dónde procede la información, cómo se obtiene, cómo se valida, cuánto puede desviarse y qué ocurre cuando los datos dejan de comportarse como esperábamos.
Cuando algo sale mal
Una de las diferencias que más me ha llamado la atención al desarrollar smart contracts es que no todos los errores tienen la misma posibilidad de ser corregidos.
Durante la ejecución de una transacción, la EVM mantiene temporalmente los cambios que está realizando el contrato. Si una operación falla y la ejecución hace revert, esos cambios no llegan a consolidarse en el estado de la blockchain. Una transacción que revierte no deja detrás un estado parcialmente modificado por las operaciones revertidas.
Pero esto solo funciona mientras la transacción está ejecutándose.
Si el contrato ejecuta correctamente una operación y esta queda registrada on-chain, la situación es diferente. La blockchain no sabe si el resultado era deseado, si fue consecuencia de un error de programación o si el usuario simplemente tomó una mala decisión.
Desde el punto de vista de la EVM, la operación se ejecutó correctamente.
Aquí aparece una diferencia importante entre un error de ejecución y un error de lógica.
Un error de ejecución puede provocar un revert. Un error de lógica, en cambio, puede producir exactamente el resultado que el código ha definido, aunque ese resultado sea completamente distinto del que esperábamos.
Y cuando ese resultado ya ha modificado el estado de la blockchain, no existe una operación general que permita simplemente hacer “undo”.
Por eso la posibilidad de corregir un problema depende en gran medida de la arquitectura que hayamos diseñado antes de desplegar el contrato.
Un sistema puede incorporar pausas, límites, roles administrativos, funciones de recuperación o mecanismos de actualización. También puede diseñarse mediante patrones que permitan sustituir parte de la lógica posteriormente.
Pero todos estos mecanismos tienen algo en común: la posibilidad de corregir el sistema tuvo que ser contemplada previamente.
Si un contrato no incorpora ningún mecanismo de actualización o intervención y una vulnerabilidad permite modificar su estado de una forma no prevista, las posibilidades de actuar directamente sobre ese contrato pueden ser extremadamente limitadas.
Y aquí es donde la inmutabilidad deja de ser solamente una propiedad interesante y se convierte en una decisión de arquitectura.
Desplegar un contrato significa aceptar unas reglas que, dependiendo de cómo haya sido diseñado, pueden ser muy difíciles de modificar después. Por eso la seguridad no consiste únicamente en escribir una función que funcione correctamente. También consiste en pensar qué ocurre cuando esa función no se comporta como esperábamos.
En muchos sistemas tradicionales, una respuesta habitual sería corregir el software y modificar los datos afectados. En blockchain, la respuesta puede ser mucho más limitada. Incluso si podemos desplegar una nueva versión del contrato, los cambios que ya ocurrieron en la blockchain no desaparecen automáticamente. La nueva arquitectura tendrá que decidir cómo convivir con ese estado anterior y qué mecanismos existen para proteger a los usuarios afectados.
Los límites, vistos desde quien programa
Cuanto más trabajo con smart contracts, más claro tengo que su principal fortaleza —la capacidad de ejecutar reglas de forma determinista— es también una de sus principales limitaciones.
El código puede hacer exactamente aquello para lo que ha sido diseñado. Puede comprobar una condición, actualizar un estado, transferir un activo o rechazar una operación. Pero no puede decidir si la regla que estamos ejecutando era la regla correcta en primer lugar.
Tampoco puede anticipar todas las formas en las que un usuario puede interactuar con ella, todos los datos que puede recibir o todas las situaciones que pueden aparecer una vez que el contrato está funcionando en un entorno real.
Esto cambia bastante la forma de pensar sobre el desarrollo.
En una aplicación tradicional, podemos pensar en el código como una herramienta para resolver un problema concreto. En blockchain, el código forma parte de un sistema mucho más amplio: contratos, usuarios, incentivos económicos, interfaces, datos externos, mecanismos de gobernanza y, en muchos casos, activos del mundo real.
Un error en cualquiera de esas capas puede terminar afectando al comportamiento del sistema completo.
The DAO y Harvest Finance muestran dos versiones diferentes del mismo problema. En The DAO, el código ejecutó una lógica que contenía una vulnerabilidad. En Harvest Finance, el protocolo ejecutó correctamente sus reglas basándose en información que podía ser manipulada.
En ambos casos, el código no dejó de funcionar. El problema fue que el sistema completo era más complejo que la lógica que habíamos conseguido representar dentro del contrato.
Y creo que ahí empieza el verdadero límite de lo que un smart contract puede resolver.
Un contrato puede automatizar reglas, pero no puede automatizar completamente la realidad sobre la que esas reglas intentan actuar. Puede reducir determinados intermediarios y hacer que ciertas operaciones sean verificables sin depender de una autoridad central. Pero eso no significa que desaparezcan todas las formas de confianza, gobernanza o intervención humana.
Al contrario: cuanto más valor ponemos dentro de sistemas automáticos, más importante se vuelve diseñar correctamente todo aquello que existe alrededor del código.
Para mí, esta es una de las partes más interesantes de desarrollar en blockchain.
No se trata simplemente de preguntarse qué podemos poner on-chain. También tenemos que preguntarnos qué debería estar on-chain, qué información necesita el contrato para funcionar, de dónde procede esa información y qué ocurre cuando el mundo real no se comporta como nuestro código esperaba.
Quizá el límite de los smart contracts no esté en lo que pueden ejecutar. Está en todo aquello que no pueden comprender por sí mismos.
Comentario jurídico de BACS: donde termina el código, empieza el derecho
El artículo de Sara termina exactamente donde debe empezar el análisis jurídico: el límite de los smart contracts no está en lo que pueden ejecutar, sino en todo aquello que no pueden comprender por sí mismos. Desde el derecho, esa frase tiene una traducción precisa — y consecuencias prácticas.
La primera consecuencia es conceptual. Los dos casos que recorre el artículo demuestran que “code is law” es una metáfora incompleta: en The DAO el código ejecutó fielmente una regla defectuosa; en Harvest Finance ejecutó fielmente una regla correcta sobre datos manipulados. En ambos, la ejecución fue impecable y el resultado, injusto. El derecho conoce esta situación desde hace siglos: es la diferencia entre la validez formal de un acto y su legitimidad material — entre lo que se hizo conforme al procedimiento y lo que debía hacerse. Ningún sistema normativo serio ha sobrevivido confiando solo en la primera; por eso todos desarrollaron mecanismos de revisión: la nulidad, la anulación, el enriquecimiento injusto, la restitución. La comunidad de Ethereum, ante The DAO, improvisó exactamente eso — un mecanismo de revisión — mediante hard fork. Funcionó una vez, al coste de partir la cadena en dos. No es un procedimiento; fue una excepción.
La segunda consecuencia es de diseño. Sara señala que la posibilidad de corregir un contrato debe haberse previsto en la arquitectura antes del despliegue — pausas, roles, mecanismos de actualización. La tesis de BACS es que esa misma lógica alcanza a la capa jurídica: la resolución de disputas no es un parche externo al sistema, sino parte de su arquitectura, y debe diseñarse con la misma anticipación que un mecanismo de pausa. En la práctica, eso significa cláusulas de arbitraje incorporadas a los términos del protocolo o del producto desde el día uno, pensadas para este entorno: que definan qué registros técnicos (logs de gobernanza, datos de oráculos, informes de auditoría) se admiten como prueba y con qué estándar de autenticidad; que prevean el peritaje técnico y quién lo costea; y que contemplen medidas de urgencia a la velocidad a la que se mueven los activos, no a la de los procedimientos judiciales transfronterizos.
La tercera consecuencia cierra el círculo. Si el código no puede comprender la realidad, alguien tiene que traducir entre ambas: del hecho externo al dato on-chain (los oráculos que describe el artículo) y — el trayecto inverso, hoy casi inexplorado — de la decisión jurídica a la ejecución on-chain. Un laudo arbitral que pueda activar, dentro de las reglas del propio sistema, los mecanismos de pausa o recuperación previstos en la arquitectura convierte la resolución de disputas en lo que siempre debió ser: no papel que persigue a los activos, sino una función más del sistema. Esa capa — llamémosla oráculos legales — es, en nuestra opinión, la infraestructura que le falta al ecosistema, y construirla es la razón de ser de BACS.
El código automatiza reglas. El derecho responde de ellas. Un ecosistema maduro necesita que ambos estén diseñados para encontrarse.
BACS opera una Corte de Arbitraje especializada en activos digitales y tiene, por tanto, un interés institucional directo en los mecanismos que este comentario describe.
Sara Deleyto es desarrolladora Solidity y Web3 full stack, especializada en smart contracts, DeFi e inteligencia artificial. Escribe sobre los límites técnicos de los sistemas on-chain desde la experiencia de quien los programa. Este artículo se publica como colaboración invitada en BACS.