Ethereum
14 min read

En Ethereum, las cuentas de propiedad externa (EOA) y los contratos inteligentes son entidades completamente separadas, o al menos hasta ahora. Las EOAs, son controladas por claves privadas y pueden iniciar transacciones, mientras que los contratos inteligentes pueden ejecutar código cuando reciben una llamada, pero no pueden iniciar transacciones por sí mismos.

El EIP-7702 reduce esta brecha al permitir que las EOAs tengan código asociado, difuminando así los límites entre ambas entidades. Esta propuesta representa un avance significativo hacia la abstracción nativa de cuentas, con el potencial de mejorar la usabilidad, seguridad y programabilidad dentro del ecosistema de Ethereum.

Visión general de las cuentas de Ethereum

Cada cuenta en Ethereum posee un estado compuesto por cuatro campos clave:

  • Nonce: Lleva la cuenta del número de transacciones enviadas desde la cuenta, para evitar ataques de repetición.
  • Balance: La cantidad de ETH que posee la cuenta.
  • Storage Hash: Una raíz Merkle que representa el almacenamiento de la cuenta.
  • Code Hash: El hash del código asociado a la cuenta, vacío en las EOAs (hasta ahora).

Tradicionalmente, las EOAs tienen un code hash vacío (0x), mientras que los contratos inteligentes almacenan el hash derivado del bytecode desplegado. Sin embargo, el EIP-7702 cambia esta situación: ahora las EOAs pueden contar con un code hash no vacío, formateado como (0xef0100 ++ address). Este valor, conocido como designador de delegación, apunta al contrato inteligente con el que la EOA se ha asociado.

De esta forma, cuando se envía una transacción destinada a una EOA, se comprueba si tiene almacenado un designador de delegación en su Code Hash. En caso afirmativo, la EOA se comparta como un contrato inteligente, ejecutándose el código al que apunta su designador de delegación. De forma similar a como funciona delegatecall en Solidity, se ejecutará el código desplegado en dicha dirección pero en el contexto de la EOA.

EIP-7702 vs. EIP-4337

EIP-4337 introdujo la abstracción de cuentas sin modificar el protocolo de Ethereum. Para ello, introdujo una infraestructura off-chain para procesar las operaciones de los usuarios, agruparlas y ejecutarlas on-chain a través del contrato inteligente EntryPoint.

Aunque eficaz, este enfoque presenta ciertas limitaciones:

  • Requiere la migración de EOAs a wallets basadas en contratos inteligentes.
  • Depende de infraestructura off-chain, incluidos mempools y bundlers, lo que añade complejidad y supuestos de confianza.
  • Introduce un posible punto único de fallo en el contrato EntryPoint.

El EIP-7702 aborda estos problemas permitiendo la abstracción nativa de cuentas dentro de la EVM. Permite a los usuarios conservar sus EOAs sin necesidad de migración y elimina la dependencia de infraestructuras off-chain.

Sin embargo, el EIP-7702 y el EIP-4337 no compiten entre sí, son complementarios. Los proveedores de wallets pueden integrar ambos enfoques:

  • EIP-4337 sirve de conjunto de herramientas para las funciones de abstracción de cuentas
  • EIP-7702 proporciona un adaptador para aplicar esas características a las EOAs existentes

Este enfoque híbrido permite a los desarrolladores aprovechar los puntos fuertes de ambas propuestas, mejorando la flexibilidad y la experiencia del usuario.


Cómo funciona EIP-7702

La transacción setcode

El EIP-7702 introduce un nuevo tipo de transacción (0x04), denominada setcode, que permite a una EOA asociarse a un contrato inteligente para delegar la ejecución de código. La transacción incluye los siguientes campos:

Mecanismo de autorización

Para establecer esta relación, se añade una estructura llamada authorizationList, que consta de tuplas de autorización con los siguientes campos [chain_id, address, nonce, y_parity, r, s], donde:

  • chain_id : Identifica la red.
  • address : Especifica el contrato inteligente desplegado al que apuntará la EOA para la delegación de código.
  • nonce : Garantiza la unicidad y evita los ataques de repetición.
  • signature : Firma generada por la EOA.

Cuando un usuario desea delegar la ejecución de su cuenta a un código específico, genera una tupla de autorización y la firma con:

MAGIC || rlp([chain_id, address, nonce])

donde MAGIC = 0x05.

Esta firma autoriza lo siguiente:

“La EOA que firma esta autorización concede el control al código desplegado en la dirección address y en la cadena chain_id.”

El campo chain_id puede ser 0, permitiendo que la firma se reproduzca en diferentes cadenas sobre la misma address y nonce. Esto permite a las EOAs cambiar a una cuenta inteligente en todas las cadenas EVM con una sola firma. Pero es necesario que el nonce coincida en todas las cadenas.

Cualquier usuario o entidad puede enviar una transacción setcode que incluya una authorizationList. Al ejecutarse la transacción, si todo es correcto, se asigna el designador de la delegación (0xef0100 || address) al Code Hash de la EOA solicitante.

Es importante señalar que el firmante de la autorización no necesariamente debe coincidir con el tx.origin de la transacción setcode. Además, el mecanismo de autorización permite actualizar varias EOAs en una sola transacción. Por ejemplo, Alice y Bob pueden firmar autorizaciones para diferentes contratos, y un proveedor de servicios puede enviar la transacción setcode con una authorizationList que incluya, entre otras, las autorizaciones de ambos. Esto posibilita el patrocinio de gas, reduce los costes y simplifica el proceso de actualización para proveedores de servicios y wallets.

Comportamiento de ejecución

Una vez que una EOA tiene asignado un designador de delegación, cualquier operación de ejecución de código (CALL, CALLCODE, STATICCALL, DELEGATECALL) utilizará el código del contrato al que apunta el designador de delegación.

Sin embargo, las operaciones de lectura de código (EXTCODESIZE, EXTCODECOPY, EXTCODEHASH) devolverán valores basados en el propio designador de delegación, en lugar del código al que apunta.

Ejemplos:

  • EXTCODESIZE(EOA) –> Devuelve 23, que es el tamaño del designador: 0xef0100 || address
  • EXTCODEHASH(EOA) –> Devuelve keccak256(0xef0100 || address).
  • CALL ——————> Ejecuta el código delegado en el contexto de la EOA.

Casos de uso e impacto potencial

Interacciones DeFi sin fricciones

Actualmente, las transacciones en DeFi suelen requerir múltiples aprobaciones y pasos separados, lo que no solo introduce fricción en la experiencia del usuario, sino que también aumenta los costes de gas. Gracias al EIP-7702, las EOAs pueden interactuar con contratos inteligentes de forma dinámica, agilizando las transacciones y minimizando los costes de gas.

Abstracción y patrocinio de gas

Al permitir que las EOAs deleguen la ejecución, las tasas de gas pueden abstraerse y optimizarse. Esto abre la puerta a modelos en los que terceros, como dApps o protocolos, patrocinen el coste de las transacciones, mejorando la accesibilidad y reduciendo barreras de entrada para los usuarios.

Mejor seguridad en wallets

Las EOAs podrán mejorar la seguridad y el control del usuario al adoptar funciones de wallets inteligentes como:

  • Autenticación multifactor (MFA) para una mayor protección.
  • Límites de transacciones y topes de gasto para evitar grandes transferencias no autorizadas.
  • Recuperación social y gestión de cuentas con guardianes.
Multifirmas programables nativos

El EIP-7702 permite la multi-firma dentro de las EOAs de forma nativa, eliminando la necesidad de depender de wallets de multi-firma externas. Esto permite casos de uso avanzados como:

  • Control de acceso basado en roles, definiendo permisos específicos para diferentes usuarios.
  • Autorizaciones basadas en sesiones, que conceden permisos temporales para acciones automatizadas.

Consideraciones de seguridad

Riesgos de ejecución de código

Si una EOA delega la ejecución en un contrato inseguro, puede provocar la pérdida de sus fondos. Es esencial desarrollar estos contratos con cuidado, y auditarlos antes de asignarlos como designador de delegación. De esta forma evitamos vulnerabilidades que puedan acabar en la péridad de los fondos de la EOA, entre otros posibles escenarios.

Compatibilidad con los contratos existentes

Muchos contratos inteligentes asumen que las EOAs carecen de código y realizan comprobaciones como tx.origin == msg.sender para diferenciar las EOAs de los contratos. EIP-7702 cambia este supuesto, lo que podría afectar gravemente a la lógica de estos contratos.

  • Los atacantes podrían actualizar una EOA para eludir los controles de acceso basados en contratos.
  • Los desarrolladores deben evitar usar tx.origin para la autenticación y, en su lugar, basarse en mecanismos seguros de control de acceso.
Requisito de la función receive

Una vez que una EOA ha delegado su ejecución a un contrato inteligente, las transferencias de ETH dirigidas a la EOA, son procesadas dicho código. Lo que significa que el contrato delegado debe ser capaz de gestionar los pagos entrantes de ETH.

Si el contrato no implementa la función receive() o fallback(), la EOA no podrá aceptar transferencias de ETH.

Funciones receive vs fallback en Solidity
Diferencias clave:
  • Función receive():
    • Se ejecuta cuando se envía ETH sin datos (msg.data vacío).
    • Debe marcarse como external payable.
    • Si no está implementada, se usará la función fallback() en su lugar (en caso de estar implementada).
  • Función fallback():
    • Se ejecuta cuando se envía ETH con datos o cuando la función receive() no extiste.
    • Puede utilizarse para registrar, desviar llamadas o gestionar transacciones inesperadas.
    • Debe marcarse como external, y puede opcionalmente ser payable para aceptar ETH.
Control de acceso y delegación maliciosa

Una vez que una EOA delega la ejecución, cualquiera puede interactuar con el código delegado. Por lo tanto, para evitar interacciones no autorizadas, se debe:

  • Implementar controles de acceso estrictos para proteger las funciones sensibles.
  • Si una función sólo debe ser invocada por la propia EOA, imponerlo con: require(msg.sender == address(this))
  • Extremar las precauciones, ya que los atacantes también pueden utilizar el phishing o la ingeniería social para engañar a los usuarios y hacer que deleguen en contratos maliciosos.
Limitaciones del constructor y riesgo de reinicialización

Los contratos desplegados como objetivos de delegación deben emplear inicializadores en lugar de constructores, de manera similar a los contratos inteligentes actualizables. Esto se debe a que el constructor se ejecuta en el momento del despliegue del contrato, cuando aún no existe una delegación activa. Como resultado, los cambios de estado realizados en el constructor afectan únicamente al contrato en sí, pero no a la EOA que posteriormente delegue en él.

Por lo tanto, para inicializar correctamente las variables de estado y garantizar un comportamiento correcto, los contratos destinados a la delegación deben utilizar una función inicializadora en lugar de un constructor, esto permite que el contrato se configure después de la delegación, en el contexto de la EOA.

Las funciones de inicialización deben estar adecuadamente protegidas para evitar llamadas no autorizadas que modifiquen el estado del contrato tras su configuración inicial. De lo contrario, un atacante podría aprovecharse para ejecutar un ataque de reinicialización y alterar el comportamiento del contrato. Para mitigar este riesgo, es recomendable implementar un mecanismo que impida que la inicialización pueda ejecutarse más de una vez.

Colisión de almacenamiento

Una EOA puede actualizar su designador de delegación las veces que quiera. De modo que puede cambiar el código que la gobierna, sin embargo no podemos olvidar que el almacenamiento de las EOAs es persistente, incluso cuando cambia entre diferentes implementaciones de contratos delegados. Esto significa que, aunque el código ejecutable puede cambiar, el almacenamiento subyacente sigue siendo el mismo. Si un contrato recién asignado tiene una estructura de almacenamiento diferente, puede sobrescribir o corromper involuntariamente variables de estado existentes.

Analogía con los contratos actualizables

Piense en una EOA en EIP-7702 como el proxy en un contrato actualizable:

  • En los contratos actualizables, el proxy contiene el almacenamiento, mientras que el contrato lógico contiene el código ejecutable.
  • Cuando se actualiza el contrato lógico, el proxy conserva su almacenamiento, por lo que el nuevo contrato debe mantener la misma estructura de almacenamiento para evitar la corrupción.
  • Del mismo modo, en el EIP-7702, una EOA conserva su almacenamiento mientras cambia entre diferentes contratos delegados, lo que significa que cada nuevo contrato debe respetar la estructura de almacenamiento existente.
Riesgos potenciales de los desajustes de almacenamiento
  • Datos corruptos o perdidos, rompiendo la funcionalidad del contrato.
  • Acceso no autorizado, si se sobrescriben los controles de acceso.
  • Pérdida de fondos, si se desajustan variables críticas como los saldos o las aprobaciones.
Garantizar la coherencia del almacenamiento

La gestión adecuada del almacenamiento y la coherencia del diseño son cruciales cuando se cambia entre contratos delegados, al igual que en los contratos inteligentes actualizables. Un enfoque para mitigar la colisión de almacenamiento es seguir el estándar EIP-7201 – Namespaced Storage Layout. Este método almacena variables de estado en slots personalizados, derivados de un hash único, en lugar de utilizar slots secuenciales, evitando así conflictos entre diferentes implementaciones.

Ataques de repetición y firmas débiles

Las firmas se utilizan para validar operaciones off-chain y autorizar transacciones en nombre de un firmante, lo que las hace especialmente útiles para las cuentas inteligentes. Con EIP-7702, las EOAs pueden asociar código a sus cuentas, lo que permite configuraciones complejas como el control de acceso basado en roles o las autorizaciones basadas en sesiones. Es muy probable que estas configuraciones se basen en firmas para su validación.

Sin embargo, si las firmas no se gestionan correctamente, los atacantes pueden reutilizarlas, provocando ejecuciones no deseadas. Por eso es crucial gestionar con cuidado la unicidad y el contexto de las firmas.

Para evitar este riesgo, los contratos inteligentes deben:

  • Incluir un nonce único a nivel de aplicación, que se valide para cada firma.
  • Establecer y hacer cumplir una fecha de caducidad.
  • Restringuir el valor s de la firma a su mitad inferior para mantener la unicidad de la firma.
  • Incluir el ID de la cadena para evitar repeticiones entre cadenas.

Costes de Gas

  • 25k gas por autorización.
  • 12.5k gas de devolución si la cuenta ya existe.
  • Los destinatarios de la delegación son «warmed« para una ejecución optimizada.
  • Se aplican costes de gas adicionales cuando se «calientan» tanto el objetivo como la delegación

Conclusión

El EIP-7702 representa un avance fundamental en la evolución de Ethereum, ya que aporta una abstracción nativa de cuentas sin requisitos de migración ni dependencia de infraestructuras off-chain. Al permitir que las EOAs adopten capacidades de contratos inteligentes, elimina fricciones en DeFi, mejora la seguridad de las wallets y abre nuevas posibilidades para la optimización del gas y la funcionalidad de las cuentas.

Sin embargo, es esencial seguir a las mejores prácticas de seguridad para mitigar los riesgos potenciales. Para ello, los desarrolladores deben:

  • Considerar cuidadosamente los destinatarios de la delegación.
  • Implementar rigurosos controles de acceso.
  • Garantizar una estructura de almacenamiento segura para evitar la corrupción.
  • Implementar funciones de inicialización seguras para evitar ataques de reinicialización.
  • Usar firmas estructuradas (EIP-712) para evitar vulnerabilidades de reutilización.

Al integrar estas medidas de seguridad, el EIP-7702 puede adoptarse de forma segura, allanando el camino para un ecosistema Ethereum más flexible, eficiente y seguro, al tiempo que se minimizan los riesgos y se garantiza la integridad de la red a largo plazo.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *