Modelos UTXO y de cuentas · Lección 3 de 6
El modelo de cuentas para analistas
10 min de lectura
Ethereum y las numerosas cadenas que copian su diseño mantienen un saldo actualizado para cada dirección, en lugar de un conjunto de monedas discretas. Esto cambia qué se puede rastrear, qué significa una «transacción» y quién es el verdadero actor detrás de una acción. Ahora que las cuentas inteligentes y la abstracción de cuentas son comunes, la dirección que firma, la dirección que paga el gas y la dirección que aparece en el campo from suelen ser tres direcciones distintas; un analista que las confunda atribuirá la actividad a la parte equivocada.
Estado, no monedas
Una cadena con modelo de cuentas almacena un estado global: un mapeo de cada dirección de 20 bytes a un registro de cuenta. En Ethereum, ese registro tiene cuatro campos:
| Campo | Significado | Uso para el analista |
|---|---|---|
nonce | Transacciones enviadas (EOA) o contratos creados (contrato) | Recuento de actividad, orden, comprobaciones de direcciones nuevas |
balance | Moneda nativa, en wei | Tenencias en un bloque |
codeHash | Hash del código de la cuenta (vacío para una EOA normal) | Diferenciar EOAs, contratos y EOAs delegadas |
storageRoot | Raíz del almacenamiento clave-valor de la cuenta | Dónde se encuentran realmente los saldos de tokens y los datos del contrato |
Cada bloque compromete el estado resultante mediante el stateRoot de su encabezado. Los saldos se consultan con eth_getBalance(address, block), y el almacenamiento de los contratos mediante eth_call (por ejemplo, el balanceOf de un token) o eth_getStorageAt.
La diferencia con el modelo UTXO es fundamental:
| Pregunta | Cadenas UTXO | Cadenas de cuentas |
|---|---|---|
| Unidad de valor | Salidas discretas, gastadas en su totalidad | Un único saldo por dirección |
| Cambio | Una nueva salida, a menudo a una dirección nueva | Ninguno: el resto permanece en el saldo |
| Vincular un pago saliente con uno entrante | Exacto por salida; ambiguo dentro de una transacción con varias entradas | Nunca exacto: todos los depósitos se combinan |
| Reutilización de direcciones | Desaconsejada | Normal; una dirección durante años |
| Protección contra la repetición | Cada salida se puede gastar una sola vez | Cada transacción debe usar el siguiente nonce |
Cuando llegan 10 ETH a una dirección que ya tiene 50 ETH, los datos no indican qué ETH salió después; cualquier atribución es una convención de rastreo (consulta la lección Rastreo de fondos hacia adelante y hacia atrás).
EOAs y contratos
Una cuenta de propiedad externa (EOA) está controlada por una clave privada y es el único tipo de cuenta que puede originar una transacción. Una cuenta de contrato tiene código y almacenamiento, no puede iniciar nada por sí sola y solo actúa cuando recibe una llamada. eth_getCode(address, block) devuelve 0x para una EOA y el bytecode desplegado para un contrato.
Tres dificultades hacen que esta comprobación no sea tan sencilla como parece:
- Temporalidad. El código existe solo a partir del bloque en el que se creó el contrato. Las direcciones se pueden calcular antes del despliegue (CREATE2 lo hace deliberadamente), por lo que una dirección sin código en el bloque N puede ser un contrato en el bloque N+1. Comprueba siempre el código en el bloque pertinente.
- Destrucción. Antes de la actualización Dencun (marzo de 2024),
SELFDESTRUCTeliminaba el código de un contrato. Desde EIP-6780, solo lo hace si se llama en la misma transacción en la que se creó el contrato; de lo contrario, solo envía el saldo a otra parte. - Delegación. Desde la actualización Pectra (mayo de 2025), una EOA puede contener el identificador de delegación de 23 bytes de EIP-7702,
0xef0100, seguido de una dirección delegada. Una regla simplista de «tiene código, por lo tanto es un contrato» la clasifica incorrectamente: la cuenta sigue estando controlada por su clave privada.
Por tanto, un clasificador sólido devuelve tres clases (EOA, contrato, EOA delegada) para un bloque determinado, no dos.
El nonce es un regalo para los analistas. Para una EOA, equivale al número de transacciones que ha enviado, por lo que una dirección con nonce 0 nunca ha enviado nada, y las discontinuidades o los aumentos repentinos en el uso del nonce revelan patrones operativos (consulta la lección Heurísticas del modelo de cuentas). Dos salvedades: cada autorización EIP-7702 que firma una EOA también incrementa su nonce, y el nonce de un contrato cuenta las creaciones de contratos, a partir de 1 según EIP-161. Las direcciones de los contratos se derivan del desplegador: CREATE usa la dirección y el nonce del desplegador, y CREATE2 usa el desplegador, una sal y el hash del código de creación; por eso, los vínculos con el desplegador constituyen evidencia sólida.
Estado e historial
Una consulta de estado responde «¿qué tenía esta dirección en el bloque N?». El historial responde «¿cómo llegó a tenerlo?» y se encuentra en varios lugares a la vez:
- transacciones de nivel superior (valor enviado, más el gas pagado por el emisor);
- trazas de llamadas internas (valor transferido por contratos);
- registros (transferencias de tokens y otros eventos);
- cambios de saldo que no son transacciones en absoluto: tarifas de prioridad acreditadas al destinatario de las tarifas del bloque, retiros de la capa de consenso acreditados directamente a direcciones desde abril de 2023 (EIP-4895: sin gas, sin ejecución de código y sin hash de transacción), asignaciones de génesis y, antes de septiembre de 2022, recompensas de minería.
Los nodos completos solo conservan el estado reciente, por lo que para consultar el estado de bloques antiguos se necesita un nodo de archivo o un proveedor que lo ofrezca (consulta la lección API de nodos y acceso a datos). La siguiente lección, Reconstrucción de saldos e historiales, muestra cómo reconstruir un saldo a partir de estos elementos y conciliarlo con el estado.
Transacciones internas
En el protocolo, una transacción es solo el mensaje firmado de nivel superior. Cuando un contrato reenvía ETH durante la ejecución, se trata de una llamada de mensaje: no tiene hash, recibo ni registro, a menos que el código emita uno. Los exploradores las llaman «transacciones internas», una etiqueta práctica pero engañosa.
Considera un retiro desde una cartera de contrato. La transacción del usuario envía 0 ETH al contrato de cartera 0x7c3E…12; durante la ejecución, el contrato llama a 0xD4e5…3a con el valor 0xde0b6b3a7640000, que equivale a 10^18 wei o 1 ETH. En la lista de transacciones de 0xD4e5…3a no aparece nada, pero su saldo aumentó en 1 ETH. Solo una traza (consulta la lección Transacciones, recibos y registros sin procesar de Ethereum) explica el cambio. Las subllamadas revertidas no transfieren nada y deben excluirse.
Los movimientos de tokens son diferentes: una transferencia ERC-20 es un cambio en el almacenamiento del contrato del token, anunciado mediante un evento Transfer, no una transacción interna (consulta la lección Lectura de transferencias de tokens).
Cuentas inteligentes y abstracción de cuentas
Una cuenta inteligente es una cartera implementada como contrato, con reglas como múltiples firmantes, límites de gasto, recuperación o gas patrocinado. Para el análisis, importan tres diseños.
Las carteras de contrato (las carteras multifirma son el caso clásico) mantienen fondos en una dirección de contrato. Los propietarios firman fuera de la cadena y uno de ellos, o un retransmisor, envía la transacción. El actor económico es el contrato; la EOA que envió la transacción puede ser solo el último firmante.
ERC-4337 añade abstracción de cuentas sin modificar el protocolo. Los usuarios firman una UserOperation (sus campos incluyen sender, nonce, callData, límites de gas, paymaster y signature) y la envían a un mempool separado. Un bundler agrupa muchas UserOperations en una transacción que llama a handleOps en un contrato EntryPoint único, que valida y ejecuta cada una y paga al bundler con el depósito de la cuenta o el de un paymaster. Para cada operación, emite:
UserOperationEvent(bytes32 indexed userOpHash, address indexed sender, address indexed paymaster, uint256 nonce, bool success, uint256 actualGasCost, uint256 actualGasUsed)
Las consecuencias son concretas: el from de la transacción es el bundler, una transacción puede incluir operaciones de usuarios sin relación entre sí, el recibo abarca todo el lote y el actor real es el sender del evento. Una consulta que enumera las cuentas inteligentes y sus patrocinadores de gas a partir de registros sin procesar:
-- Una fila por cada UserOperation ERC-4337, con el bundler, la cuenta inteligente y el paymaster
SELECT
l.block_number,
l.tx_hash,
t.from_address AS bundler,
'0x' || SUBSTR(l.topic2, 27, 40) AS smart_account, -- sender indexado
'0x' || SUBSTR(l.topic3, 27, 40) AS paymaster -- la dirección cero = ninguno
FROM logs l
JOIN transactions t ON t.hash = l.tx_hash
WHERE l.topic0 = '0x49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f'
AND l.address IN (SELECT address FROM entrypoint_contracts);
El valor de topic0 es el hash Keccak-256 de la firma del evento. Las direcciones indexadas se encuentran en topics de 32 bytes, rellenadas con ceros a la izquierda, por lo que la dirección son los últimos 40 caracteres hexadecimales; SUBSTR(topic, 27, 40) omite 0x y los 24 caracteres de relleno. Algunos motores llaman a la función SUBSTRING, y algunos almacenan los topics como datos binarios, en cuyo caso se recortan bytes. Limitar la consulta a direcciones EntryPoint conocidas (una por versión) evita que coincida con eventos similares de otros contratos.
EIP-7702 permite que una EOA existente adopte el comportamiento de una cuenta inteligente. Una transacción de tipo 4 contiene autorizaciones [chain_id, address, nonce, y_parity, r, s]; cada una establece como código del firmante el identificador de delegación, que persiste hasta que se reemplaza o se borra, y una autorización cuyo chain_id es 0 es válida en todas las cadenas. La dirección conserva su historial y su clave, pero ahora puede agrupar llamadas o hacer que otros paguen su gas. Los destinos de delegación también son evidencia: un panel público en la cadena publicado por la firma de trading Wintermute en junio de 2025 determinó que más del 80 % de las primeras delegaciones apuntaban a copias de un mismo contrato «sweeper» que vacía las carteras cuyas claves se han filtrado.
Quién firma y quién paga
| Patrón | Quién autoriza | from de la transacción (paga el gas) | Dónde encontrar al actor real |
|---|---|---|---|
| Transacción EOA normal | Clave de la EOA | La misma EOA | from |
| Cartera de contrato | Firmas de los propietarios en los datos de llamada | Un propietario o un retransmisor | to (la cartera) y sus eventos |
| Metatransacción (ERC-2771) | Firma del usuario | Un retransmisor mediante un reenviador de confianza | Datos de llamada decodificados |
| ERC-4337 | Reglas de validación de la cuenta inteligente | Bundler, reembolsado por la cuenta o el paymaster | UserOperationEvent.sender |
| EIP-7702 patrocinado | Autorización y carga firmada de la EOA | Un patrocinador | La EOA delegada a la que se llamó |
Nunca equipares a quien paga el gas con el actor hasta identificar el patrón. La financiación del gas sigue siendo evidencia útil, pero con el patrocinio puede apuntar a un servicio en lugar de al propietario (consulta la lección Heurísticas del modelo de cuentas).
Enfoque del examen: los cuatro campos de la cuenta (nonce, balance, codeHash, storageRoot) y qué significa el nonce para las EOAs y los contratos; por qué es imposible rastrear monedas individuales dentro de un saldo común; clasificar EOAs, contratos y EOAs delegadas mediante EIP-7702 en un bloque determinado, incluido el identificador0xef0100y el efecto de EIP-6780; cambios de saldo que no provienen de transacciones, como los retiros EIP-4895 y las recompensas por tarifas; transacciones internas como llamadas de mensaje visibles solo en las trazas; los roles de ERC-4337 (UserOperation, bundler, EntryPoint, paymaster) y los campos deUserOperationEvent; extraer una dirección de un topic indexado; distinguir quién firma, quién paga el gas y quién actúa.