Cargando precios…

Cómo leer una cuenta de monedero con contrato inteligente y sus sesiones

Una transacción de cuenta inteligente no es una única transacción. Es una UserOperation que enruta un EntryPoint compartido, envía un bundler y puede patrocinar un paymaster. Aprende a leer cada campo antes de aprobar.

Cómo leer una cuenta de monedero con contrato inteligente y sus sesiones

Por qué una cuenta inteligente implica un modelo mental distinto

Si alguna vez has copiado una dirección, la has consultado en un explorador de bloques y has intentado descifrar qué hacía una transacción, partes de la suposición de que una clave controla una cuenta. Las carteras de contrato inteligente rompen esa suposición. La dirección que ves en Etherscan o en un explorador similar no es una clave. Es un contrato. El contrato posee activos, aplica reglas y decide qué instrucciones acepta. El usuario, más exactamente el conjunto de claves o sesiones autorizadas a actuar en ese momento, envía instrucciones a ese contrato a través de un conducto independiente.

Por eso una sola acción en cadena suele parecer ruidosa en un explorador de bloques. Lo que aparece como una transacción es, internamente, varias capas: la intención firmada por el usuario, un retransmisor que la envía, un contrato EntryPoint que la valida, la lógica opcional de un pagador que paga el gas y la callData que ejecuta la acción real dentro de la cuenta inteligente. La forma en cadena resulta desconocida al principio, y esa falta de familiaridad es justo en lo que confían los atacantes.

Transacción frente a UserOperation: la distinción esencial

Una transacción normal de Ethereum tiene seis campos legibles: from, to, value, data, gas limit y signature. Una UserOperation, definida en el estándar ERC-4337, añade campos pensados para la ejecución delegada y patrocinada. Los más importantes para la lectura son: sender, que es la dirección de la cuenta inteligente; nonce, que es por cuenta y no está vinculado al contador global de transacciones como lo está el nonce de una EOA; initCode, que despliega la cuenta en el primer uso; callData, que es lo que ejecutará la cuenta inteligente si se aprueba; y signature, que puede ser una firma ECDSA, una firma BLS agregada de un empaquetador o un gancho de validador definido por la propia cuenta.

También hay una capa de pago de gas que no existe en las transacciones simples. paymasterAndData apunta a un contrato de pagador que reembolsará al empaquetador. El pagador puede inspeccionar tu UserOperation antes de aceptar patrocinarla y, en algunas implementaciones, puede modificar el paso postOp, que se ejecuta después de que tu llamada termine. Esa retrollamada posterior a la operación es una superficie de ataque real: un pagador malicioso puede leer los datos de retorno de tu llamada y utilizarlos de formas que no has autorizado. Trata a los pagadores como tratarías a cualquier contraparte, porque en sentido estricto eso es lo que son.

Leer una UserOperation implica comprobar, como mínimo, cuatro cosas: que sender apunte a un contrato que realmente posees o esperas, que callData apunte a direcciones que has autorizado (una sesión o una lista blanca aprobada por un guardián), que los parámetros de gas no sean absurdamente altos y que el pagador sea uno en el que confías para que se comporte correctamente.

El contrato EntryPoint: riesgo de infraestructura compartida

Cada smart account de ERC-4337 en la mainnet de Ethereum comparte una única dirección de EntryPoint en el momento de escribir esto. El estándar permite explícitamente varias versiones de EntryPoint, pero en la práctica un despliegue canónico concentra la mayor parte de la actividad. Esta centralización es una decisión de diseño deliberada: un EntryPoint compartido permite que los bundlers, los paymasters y las implementaciones de cuentas interoperen sin integraciones por pares. También concentra el riesgo.

Si el EntryPoint se actualiza, queda bajo el control de una votación de gobernanza o resulta tener una vulnerabilidad, cada smart account que se enruta a través de él queda expuesta a la vez. Esto no es hipotético. A finales de 2023, se divulgó un incidente de auditoría alrededor de una biblioteca relacionada con el EntryPoint y se parchó en todas las integraciones. No se perdió nada a gran escala, pero la lección se mantuvo: la infraestructura compartida es un único punto de fallo, y la seguridad de tu cuenta solo es tan fuerte como el componente más débil de esa pila.

Leer datos en cadena debería, por tanto, incluir una comprobación rápida de que el EntryPoint a través del cual se enruta tu cuenta es la versión que esperas. La mainnet y la mayoría de L2 publican direcciones canónicas de EntryPoint, y herramientas como Etherscan etiquetan los despliegues auditados. Si ves un UserOperation enviándose a un EntryPoint no canónico, trátalo como una señal de alerta importante: podría ser un relayer de phishing o un fork diseñado para capturar firmas.

Claves de sesión: sub-aprobaciones con alcance y tiempo limitado

Las sesiones son la característica que más vale la pena entender, porque también es la parte que se abusa con más frecuencia. Una clave de sesión es un firmante secundario que concedes a una aplicación concreta durante una ventana de tiempo definida, con un conjunto definido de permisos. En la práctica esto se parece a una dApp pidiendo permiso para operar en Uniswap en tu nombre durante la próxima hora, con un límite de gasto, contra una lista blanca de contratos de tokens.

En cadena, una sesión vive como estado dentro de tu smart account. Los campos relevantes, en el orden en que suelen aparecer en el almacenamiento, son: una dirección de clave de sesión autorizada; un timestamp o número de bloque de expiración; un límite de gasto por periodo (a menudo diario o por época); una lista blanca de destinos o de selectores; y un policy hook que puede aplicar reglas adicionales. Las implementaciones varían. Los módulos de Safe, los Zodiac Heads, las sesiones de Biconomy y los validadores de sesión de Kernel codifican esto de forma ligeramente distinta, y la disposición exacta de los slots importa cuando lees el almacenamiento directamente.

El punto a recordar es que las sesiones son acotadas, pero no seguras por defecto. Una sesión limitada al router de Uniswap es solo tan buena como el router de Uniswap. Una sesión que concede una lista blanca de selectores puede aún golpear selectores peligrosos si la aplicación sabe cuáles llamar. Y las sesiones que no imponen un límite de gasto con reinicio por periodo pueden vaciar fondos con el tiempo una vez que el usuario deja de prestar atención.

Dos hábitos prácticos ayudan. Primero, lee el slot de almacenamiento exacto o la vista decodificada que muestra la UI de la wallet antes de firmar la concesión de la sesión, y trátala como la fuente de verdad, no como el texto promocional de la dApp. Segundo, prefiere sesiones con un límite por periodo y un límite por llamada, para que una única llamada descontrolada no pueda superar un máximo razonable.

Leyendo un único UserOperation en detalle

Imagina que ves un hash 0xabc... en tu wallet y quieres saber qué hizo realmente. Abre la transacción en un explorador de bloques y luego haz clic en la transacción del EntryPoint cuyo callData empieza por handleOps. La pestaña de transacciones internas se convierte en la verdadera historia.

Paso 1: validateUserOp

El EntryPoint primero vuelve a llamar a la función validateUserOp de tu cuenta. Aquí es donde se comprueba la firma, se validan los nonces frente a la protección contra replay y se aplican las políticas de sesión. Una validación fallida revierte todo el bundle, así que una ejecución exitosa es evidencia de que al menos un firmante válido aprobó la operación.

Paso 2: execute

Si la validación pasa, el EntryPoint llama a la función execute de tu cuenta con el callData que proporcionaste. Esta es la acción visible para el usuario: un swap, una transferencia, una interacción con un contrato. Leer el callData de esta llamada interna te da el destino real, el valor y el selector de función que el usuario quería.

Paso 3: postOp

Tras la ejecución, se ejecuta el postOp del paymaster, que se usa para cosas como liquidar deudas de gas, reembolsar gas no usado o pagar al bundler. Cualquier cambio de estado aquí fue autorizado por tu elección de paymaster, no por ti directamente. Cualquier cosa rara que ocurra aquí, como transferencias extra de tokens o aprobaciones nuevas, es una señal para investigar más a fondo.

Juntar esas tres capas te dice quién autorizó qué, qué se ejecutó y qué efectos secundarios ocurrieron después. La mayoría de patrones de phishing se vuelven visibles a este nivel una vez que sabes qué buscar.

Paymasters y bundlers: visibilidad y confianza

Un bundler es la parte que toma tu UserOperation, lo empaqueta con otros y envía la transacción en cadena real al EntryPoint. Como el bundler es quien llama a EntryPoint.handleOps, la dirección del bundler es la que paga el gas a nivel de cadena. Tú, como propietario de la smart account, nunca necesitas ETH para pagar gas si un paymaster está dispuesto a patrocinar. Esto resulta cómodo, y también es una relación de confianza.

El compromiso de un paymaster se codifica en cadena de dos formas: el stake que ha depositado en el EntryPoint, que puede ser slashed por mal comportamiento bajo las reglas del estándar, y la política de su función validatePaymasterUserOp, que decide si patrocina. El slashing existe, pero es un respaldo tosco, no una garantía fina. Un paymaster puede, aun así, observar, censurar o hacer front-running de las operaciones que ve.

El front-running es el riesgo menos discutido. Un paymaster que ve tu swap antes de que se ejecute puede copiar la operación a su propia dirección, ejecutarla en el mismo bloque y capturar la mejora de precio que esperabas. Esto no es teórico; es la misma dinámica que el MEV, reempaquetada para el mundo de la account abstraction. Existen mitigaciones (mempools privadas, esquemas commit-reveal, capas de intención firmada), pero requieren uso activo. Los bundlers y paymasters públicos por defecto no ofrecen esa protección.

Leer datos en cadena también ayuda aquí. Si ves de forma consistente que tus operaciones caen en el mismo número de slot o justo después de una dirección concreta, ese bundler o paymaster te está observando de cerca. Cambiar a una mempool privada, o usar paymasters que se comprometan explícitamente con políticas de no front-running y tengan un historial verificable, es una mejora real en seguridad.

Revocar sesiones y permisos en la cadena

El error más común que cometen los usuarios de cuentas inteligentes es tratar una sesión como si revocarla en la interfaz de la dApp fuera suficiente. Normalmente no lo es. La interfaz de la dApp puede simplemente olvidarse de la sesión mientras la concesión en la cadena sigue activa hasta su expiración. Hasta que el contrato de la cuenta inteligente aplique un tiempo de inactividad o hasta que revoques activamente, la clave de sesión aún puede firmar operaciones que el EntryPoint aceptará.

La revocación real tiene tres formas prácticas. La primera es llamar a la función de revocación de la cuenta inteligente, si existe, con el identificador de la clave de sesión. La segunda es rotar el firmante principal de la cuenta, lo que invalida cualquier sesión cuya autoridad estuviera vinculada al firmante. La tercera es dejar que la sesión expire de forma natural, lo cual solo funciona si estableciste desde el principio una ventana lo suficientemente corta.

Leer la revocación en la cadena significa comprobar dos cosas: el espacio de almacenamiento de la sesión, que debería reflejar el estado revocado o expirado, y la secuencia de nonces de la cuenta, que ya no debería avanzar para la clave revocada. Si ves que una clave de sesión sigue firmando operaciones después de una supuesta revocación, ese es el momento de detenerse e investigar. Podría ser una interfaz obsoleta, o podría ser una sesión que nunca se acotó correctamente y ahora está siendo explotada.

Cómo seguir la actividad de las cuentas inteligentes de forma inteligente

La actividad de las cuentas inteligentes se mueve rápido, y el rastro en la cadena solo tiene sentido una vez que entiendes las capas que hay debajo. Seguir quién enruta tus operaciones, qué pagadores las patrocinan y qué sesiones siguen activas es una batalla perdida si lo haces a mano. Zippfeed muestra titulares de monederos y protocolos con puntuación de sentimiento (alcista, neutral o bajista) y una calificación de importancia, para que puedas detectar los patrones detrás del ruido antes de tu próxima firma.

Preguntas frecuentes

¿Es más segura una billetera con contrato inteligente que una billetera de criptomonedas normal?
Puede serlo, pero depende de la implementación y de tus hábitos. Una cuenta inteligente te permite establecer límites diarios, exigir varias firmas, rotar claves y recuperar el acceso sin frases semilla. Esas funciones ayudan. Los nuevos riesgos son la infraestructura compartida del EntryPoint, la confianza en el paymaster y las sesiones que no se revocan correctamente. Una clave de sesión mal utilizada puede vaciar fondos igual de rápido que una frase semilla filtrada, así que la seguridad está en cómo configuras y auditas, no solo en la tecnología. Esto es formación, no asesoramiento financiero.
¿Qué es una UserOperation en términos sencillos?
Una UserOperation es una pseudotransacción diseñada para cuentas inteligentes bajo ERC-4337. Incluye un sender, un nonce, initCode, callData, la firma y datos del paymaster, y se envía a un contrato EntryPoint compartido en lugar de ejecutarse directamente. Piénsalo como una instrucción sellada que el EntryPoint valida y ejecuta en nombre de tu cuenta, pagando el gas opcionalmente a través de un paymaster.
¿Debo aprobar cada solicitud de clave de sesión que hace una dApp?
Trata las claves de sesión como tratarías una clave de API en tus herramientas de trabajo. Otorga el menor alcance posible, la caducidad más corta razonable y un límite de gasto claro por llamada y por periodo. Lee el almacenamiento que muestra la interfaz del monedero antes de firmar y revoca las sesiones en cuanto dejes de usar la dApp. No hay motivo para aceptar sesiones amplias y de larga duración en interacciones rutinarias.
¿Cómo revoco una sesión de monedero inteligente en la cadena?
Llama a la función de revocación de la cuenta si existe, o rota el firmante principal para que cualquier sesión dependiente quede invalidada. Dejar que una sesión caduque de forma natural solo sirve si el tiempo de espera es corto. Verifica siempre en la cadena después, revisando el slot de almacenamiento de la sesión en un explorador de bloques; que la interfaz de una dApp olvide la sesión no significa que el permiso en la cadena haya desaparecido.