Ethereum: de historia a labs

Artículo 38 de 48

79%

completado al llegar aquí

Sistemas distribuidosNota de investigación14 min de lectura

EIP-7702: cuando una EOA aprende trucos de smart account

EIP-7702 a fondo: tupla de autorización, indicador de delegación persistente, chain_id 0, nonces y los riesgos de delegar código desde una EOA.

Ruta Ethereum: 0/48

Prerequisitos recomendados

Si alguno de estos conceptos todavía está medio nebuloso, empieza por aquí. Te ahorra tropiezos y un par de cejas fruncidas.

Tu equipo opera una dirección de tesorería que es una EOA, una cuenta controlada por una clave privada. Lleva años recibiendo depósitos y está registrada en contrapartes, exchanges y listas de direcciones permitidas. Ahora quieres agrupar un approve y un swap en una sola operación, o que un tercero pague el gas. Migrar a una smart account nueva implica cambiar la dirección en todos lados. ¿Se puede darle comportamiento de contrato a la dirección que ya existe?

EIP-7702 responde que sí. Añade un tipo de transacción que permite a una EOA escribir en su propio campo de código un puntero a un contrato ya desplegado. Desde ese momento, quien llame a la EOA ejecuta el código de ese contrato en el contexto de la EOA. El estándar es final y se activó en mainnet con la actualización Pectra, en la época 364032, el 7 de mayo de 2025.

Brújula de lectura

Actor, evidencia y estado

Antes de avanzar, ubica quién actúa, qué prueba queda y qué parte del sistema cambia.

Actor

La clave de la EOA

Firma la tupla de autorización y conserva todo su poder después de delegar.

Evidencia

Tupla firmada y código 0xef0100

La firma recupera la autoridad; el código de la cuenta muestra el delegado vigente.

Estado

Código y nonce de la EOA

La delegación persiste hasta que otra autorización la cambia o la borra.

Preguntas guía

  • Después de delegar, ¿la clave privada sigue pudiendo mover los fondos sin pasar por el código delegado?
  • ¿Cuánto dura una delegación y cómo se revoca?
  • ¿Qué hace que una autorización firmada sea válida en una sola red o en todas?
  • ¿Qué invariantes de contratos existentes dejan de cumplirse cuando una EOA tiene código?

El problema histórico: dos mundos de cuentas

La motivación del EIP nombra tres funciones que las EOAs no tenían: batching (varias operaciones atómicas, como aprobar y gastar en una sola transacción), patrocinio (que la cuenta X pague por la cuenta Y) y desescalar privilegios (subclaves con permisos menores, por ejemplo gastar un token pero no ETH, o hasta cierto porcentaje por día).

ERC-4337 ya daba esas funciones, pero a cuentas nuevas que son contratos. EIP-7702 se las da a direcciones existentes. Los autores lo diseñaron para no abrir un ecosistema paralelo: la dirección que la EOA firma puede apuntar directamente a código de wallet compatible con ERC-4337, y la EOA delegada puede entrar en bundles del EntryPoint existente.

Un dato histórico importa para entender el diseño final. El primer borrador proponía código temporal: se fijaba durante la transacción y se borraba al terminar. Se descartó porque invitaba a usarlo como un sistema de scripts desechables, compitiendo con las smart accounts. La versión final hace la delegación persistente, y el subtítulo del EIP lo dice sin rodeos: un tipo de transacción que fija el código de una EOA de forma permanente. En la práctica, dura hasta que otra autorización lo cambie.

Anatomía de la autorización

La transacción nueva es de tipo 0x04 (SET_CODE_TX_TYPE). Tiene los campos de una transacción EIP-1559 más un authorization_list, una lista de tuplas con esta forma:

Texto
authorization_list = [[chain_id, address, nonce, y_parity, r, s], ...]
 
mensaje firmado por la EOA = keccak256(0x05 || rlp([chain_id, address, nonce]))

address es el contrato al que se delega. nonce es el nonce que debe tener la EOA en el momento de procesar la tupla. y_parity, r y s son la firma secp256k1 de la clave de la EOA. El byte 0x05 (MAGIC) va delante del RLP en el mensaje firmado. Una transacción set-code con la lista vacía es inválida, y tampoco puede crear contratos: el destino no puede ser nulo.

La firma de la tupla y la firma de la transacción son independientes. Quien envía la transacción y paga el gas puede ser otra cuenta, un relayer o un bundler. Eso habilita el patrocinio, y también significa que cualquiera que tenga una tupla firmada puede incluirla mientras siga siendo válida.

Para cada tupla, el cliente verifica que chain_id sea 0 o el de la red actual, recupera la dirección firmante (la "autoridad"), comprueba que su código esté vacío o ya sea una delegación y que su nonce coincida con el de la tupla. Si todo pasa, escribe en el código de la autoridad el indicador de delegación 0xef0100 || address (23 bytes) e incrementa su nonce. Si una tupla falla, se salta y se procesa la siguiente; si hay varias de la misma autoridad, gana la última válida.

Dos detalles de orden afectan a la operación diaria. Primero, la lista se procesa después de incrementar el nonce del emisor; si la EOA envía su propia transacción set-code, la tupla debe firmarse con el nonce actual más uno. Segundo, la delegación escrita no se revierte si la ejecución de la transacción falla después.

Figura 1

Estado de una EOA antes, durante y después de delegar

Fuentes:

[1]
Estado de una EOA antes, durante y después de delegar
Cómo leer esta figura

La figura muestra cuatro estados de la misma dirección de izquierda a derecha. Primero, una EOA con nonce n y código vacío. Segundo, una transacción de tipo 0x04 con la tupla chain_id, D y n, firmada por la clave de la EOA; el cliente recupera la autoridad, comprueba el nonce y escribe el código 0xef0100 seguido de la dirección D, dejando el nonce en n más uno. Tercero, cuando cualquier cuenta llama a la EOA se carga el código del contrato D y se ejecuta con el saldo y el almacenamiento de la EOA; EXTCODESIZE de la EOA devuelve 23. Cuarto, una tupla posterior que apunta a la dirección cero borra el indicador y deja el hash de código vacío. Una nota recuerda que la clave privada puede firmar transacciones y nuevas tuplas en cualquiera de los estados.

Visual original de TrautsLab. La tupla de autorización escribe un puntero en el campo de código de la EOA; las llamadas posteriores ejecutan el código del delegado con el saldo y el almacenamiento de la EOA, y una nueva tupla hacia la dirección cero restaura el código vacío.

Traza de ejecución: qué cambia en la EVM

Cuando una instrucción CALL, CALLCODE, DELEGATECALL o STATICCALL apunta a una cuenta con indicador, o una transacción tiene esa cuenta como destino, el cliente carga el código del delegado y lo ejecuta en el contexto de la EOA: el saldo, el almacenamiento y address(this) son los de la EOA. Si el delegado apunta a su vez a otra delegación, solo se sigue el primer salto. Si apunta a un precompilado, el código se considera vacío.

La lectura de código no sigue la delegación. EXTCODESIZE sobre la EOA devuelve 23 (el tamaño del indicador) y EXTCODEHASH devuelve el hash del indicador, mientras que CODESIZE y CODECOPY, ejecutados dentro de la llamada, ven el código del delegado. Los autores lo hicieron así para que una cuenta no pueda aparentar temporalmente un codehash ajeno.

Para tus contratos esto tiene una consecuencia práctica: la comprobación "si tiene código, es un contrato" ahora clasifica como contrato a una EOA delegada. Un token que llama a un callback de recepción cuando el destino tiene código lo hará también con esa EOA, y la transferencia dependerá de que el delegado implemente el callback.

El costo intrínseco suma 25.000 de gas (PER_EMPTY_ACCOUNT_COST) por cada tupla, válida o no. Si la autoridad no está vacía, se suman 12.500 al contador global de reembolsos. Además, la regla de EIP-3607 se relaja: una cuenta cuyo código es un indicador de delegación sigue pudiendo originar transacciones.

Invariantes que se rompen: lectura de riesgo para custodia

La sección de compatibilidad del EIP enumera tres invariantes que dejan de valer. El saldo de una cuenta ya no solo baja por transacciones que ella origina: cualquier llamada al código delegado puede gastarlo. El nonce de una EOA puede subir durante la ejecución, porque el delegado puede crear contratos. Y tx.origin == msg.sender ya no implica estar en el marco superior de la transacción, lo que rompe protecciones del tipo require(tx.origin == msg.sender).

De la especificación se deduce una regla que un equipo de custodia no puede olvidar: la delegación agrega comportamiento, pero no quita poder a la clave. La clave puede seguir firmando transacciones normales y puede firmar una tupla nueva que cambie el delegado. Un límite diario o un esquema multifirma programado en el delegado solo se aplica a quien pasa por ese código; quien tenga la clave lo esquiva. Si la política de custodia exige que ninguna persona sola mueva fondos, una EOA delegada no la cumple.

La persistencia exige gestionar la revocación. Para volver a una EOA pura se firma una tupla hacia 0x0000000000000000000000000000000000000000; el cliente restaura el hash de código vacío en lugar de escribir un indicador. Mientras tanto, una tupla firmada que no se usó sigue siendo válida mientras el nonce de la cuenta coincida con el de la tupla. Si sospechas que una tupla se filtró, consumir ese nonce con cualquier transacción la invalida.

El campo chain_id decide el alcance. Con el ID de una red, la tupla solo vale ahí. Con chain_id = 0, vale en todas las redes donde el nonce coincida, y en cada una la dirección delegada puede contener código distinto o ninguno. La herramienta cast de Foundry, en su código fuente, muestra una advertencia y pide confirmación antes de firmar una autorización con ID 0.

Por último, el EIP es explícito con las wallets: una aplicación no debe poder pedirle al usuario que firme una autorización, porque no existe una forma segura de ofrecer esa interfaz. El código delegado tiene acceso total a la cuenta y debe ser auditado por la propia wallet.

Diseñar un delegado que no regale la cuenta

La sección de seguridad lista lo que el delegado debe exigir que la clave de la cuenta firme: un nonce propio para evitar repeticiones, el value, el gas y el destino con su calldata. Sin cada uno de esos campos, un patrocinador malicioso puede repetir efectos, mandar valor no previsto, dejar la llamada sin gas o llamar a funciones arbitrarias. En palabras del EIP, un delegado mal implementado puede dar a un atacante un control casi completo de la EOA.

La inicialización es otro punto débil. Un contrato normal se inicializa en su despliegue, pero aquí no hay initcode: el delegado empieza con el almacenamiento que la EOA ya tenga. Si la primera llamada de configuración no exige una firma de la clave de la EOA, un observador puede adelantarse e inicializar la cuenta con valores suyos.

Cambiar de delegado es una migración de almacenamiento. Dos contratos distintos pueden interpretar los mismos slots de forma incompatible. El EIP recomienda que los delegados usen espacios de nombres como los de ERC-7201, que deriva la ubicación de cada estructura a partir de un identificador único.

Los relayers también asumen riesgo. La cuenta autorizada puede invalidar una operación patrocinada subiendo su nonce o vaciando los activos antes de que se ejecute, y el relayer pierde el gas. El EIP sugiere fianzas o sistemas de reputación, y recomienda a los clientes aceptar como máximo una transacción pendiente por cada EOA delegada.

Política de firma

¿Firmamos esta autorización?

Reglas de decisión rápida

  • ¿El chain_id es el de la red objetivo?

    chain_id distinto de 0

    → Rechazar tuplas con 0 salvo decisión documentada.

  • ¿El delegado está auditado y fijado?

    dirección y codehash conocidos

    → Lista cerrada de delegados aprobados.

  • ¿El delegado exige firma sobre nonce, value, gas y destino?

    revisión del código

    → Bloquear si falta cualquiera de los cuatro.

  • ¿La política de custodia exige más de una persona?

    la clave sigue siendo suficiente

    → Usar una smart account, no una EOA delegada.

Cada pregunta se responde con datos de la tupla o del código delegado.

Lab propuesto: delegar, observar y revocar en una red local

El objetivo es ver el indicador en el estado. En una red local con Prague activo, se despliega un delegado de prueba, se firma la tupla y se envía la transacción desde otra cuenta. Los comandos son ilustrativos: dependen de la versión de Foundry y de las variables que definas.

Bash
# 1. Firmar la tupla [chain_id, DELEGATE, nonce] con la clave de la EOA
SIGNED_AUTH=$(cast wallet sign-auth "$DELEGATE" --private-key "$EOA_PK" --rpc-url "$RPC")
 
# 2. Otra cuenta envía la transacción de tipo 0x04 y paga el gas
cast send "$EOA_ADDR" "initialize(bytes)" "$INIT_SIG" --auth "$SIGNED_AUTH" \
  --private-key "$RELAYER_PK" --rpc-url "$RPC"
 
# 3. Observar: el código de la EOA debe empezar por 0xef0100 seguido de DELEGATE
cast code "$EOA_ADDR" --rpc-url "$RPC"

La validación observable tiene tres partes: cast code devuelve 23 bytes con el prefijo 0xef0100; una segunda tupla firmada hacia la dirección cero deja el código vacío; y una tupla reutilizada después de que la EOA mueva su nonce es ignorada. Como teardown basta detener la red. El riesgo de repetirlo en mainnet es firmar con una clave real una autorización hacia un contrato sin auditar.

Conexiones dentro de la serie

Referencias

Bibliografía académica

Formato IEEENumerado para ingeniería, sistemas y protocolos.
  1. [1]

    V. Buterin, S. Wilson, A. Dietrichs y lightclient, "EIP-7702: Set Code for EOAs," Ethereum Improvement Proposals, no. 7702, 2024.

    Especificación final: tupla de autorización, indicador de delegación, costos y consideraciones de seguridad.

  2. [2]

    ethereum.org, "Pectra," Ethereum roadmap, actualizado el 16 de octubre de 2026.

    official docsID: ETH-PECTRAAbrir fuente (abre en otra pestaña)

    Activación de Pectra en mainnet en la época 364032, el 7 de mayo de 2025.

  3. [3]

    Foundry contributors, "cast wallet sign-auth," foundry-rs/foundry, crates/cast/src/cmd/wallet/mod.rs.

    source codeID: FOUNDRY-CAST-SIGN-AUTHAbrir fuente (abre en otra pestaña)

    Firma de tuplas EIP-7702, advertencia para chain_id 0 y nonce más uno cuando la propia cuenta transmite.

  4. [4]

    F. Giordano, H. Croubois, E. García y E. Lau, "ERC-7201: Namespaced Storage Layout," Ethereum Improvement Proposals, no. 7201, 2023.

    Fórmula para ubicar el almacenamiento en un espacio de nombres y evitar colisiones.

  5. [5]

    V. Buterin, Y. Weiss, D. Tirosh, S. Nacson, A. Forshtat, K. Gazso y T. Hess, "ERC-4337: Account Abstraction Using Alt Mempool," Ethereum Improvement Proposals, no. 4337, 2021.

    Soporte de cuentas delegadas con EIP-7702 mediante el marcador 0x7702 y el parámetro eip7702Auth.

Fuentes primarias, papers seminales y especificaciones técnicas citadas en esta investigación.

Rutas vecinas

Si este tema te abrió hambre, sigue por aquí.

Series y labs que comparten área o dependen de esta ruta. Pocas opciones, para no convertir la curiosidad en menú infinito.

Sigue leyendo

Ideas conectadas con este artículo

Una ruta corta para continuar sin abrir veinte pestañas y perder el hilo.

Los comentarios se cargan al final de la lectura para no meter peso antes de tiempo.