ERC-7824 y Nitrolite: state channels auditados para pagos de agentes
Un gateway de LLM cobra por token, no por request. Esa es exactamente la forma para la que se inventaron los state channels. Así que leímos ERC-7824, leímos el código que realmente se desplegó bajo ese nombre, y encontramos que describen dos protocolos distintos.
El settlement por llamada tiene un piso. x402 con EIP-3009 cuesta una firma por request y una transferencia on-chain por settlement. El batching empuja la transferencia hacia afuera — eso hacen el settlement diferido y los nanopagos de Circle Gateway — pero el pagador sigue firmando una vez por llamada, y el ledger de quién debe qué vive en la base de datos del facilitator.
Un state channel invierte eso. Abres una vez on-chain, luego intercambias actualizaciones de balance co-firmadas off-chain mientras dure la relación, y cierras una vez. El costo por actualización son dos firmas y cero gas. Para un agente que pasa un millón de tokens por un router, esa es la curva de costo correcta.
ERC-7824 es el estándar que reclama ese territorio. Nitrolite es su implementación de referencia, hoy desplegada como Yellow Network. Esto es lo que encontramos al auditar ambos.
El spec que nunca se mergeó
ERC-7824 existe como el pull request #728 contra el repositorio ethereum/ERCs. Lo abrió Louis Bellet el 2024-11-22, con State Channels y la Layer-3 Foundation como coautores. Son 483 líneas en un solo archivo, ERCS/erc-7824.md. Nunca se mergeó.
El bot que controla los merges de ERCs publicó ese mismo día que el archivo "requires 1 more review from Editors". Esa review no llegó. El último comentario sustantivo del autor en el hilo es del 2025-04-01. Un bot de CI marcó errores en la rama el 2025-09-26. El PR se tocó por última vez el 2026-07-02 y sigue abierto, sigue en status: Draft. No hay página canónica de ERC-7824 en eips.ethereum.org, porque no se mergeó nada que la genere.
El borrador en sí es un diseño de state channel limpio y convencional. Los canales se configuran con un struct:
struct Channel {
address[] participants; // Lista de participantes del canal
address adjudicator; // Contrato que valida las transiciones de estado
uint64 challenge; // Duración en segundos del periodo de disputa
uint64 nonce; // Único por participantes + adjudicator
}
El estado lleva una version, un array Allocation[], un intent de {OPERATE, INITIALIZE, RESIZE, FINALIZE} y las firmas de los participantes. Un contrato de custodia implementa IChannel con create, join, close, resize, challenge y checkpoint. La lógica de aplicación vive en un IAdjudicator enchufable que valida un estado candidato contra pruebas. El borrador incluye un ejemplo trabajado — un adjudicator Remittance que verifica que la asignación del pagador bajó exactamente lo que subió la del cobrador.
El propio ejemplo del borrador abre un canal con challenge: 3600 y el comentario // 1 hour challenge period. Retén ese número.
Lo que realmente se desplegó
La implementación vive en layer-3/nitrolite — la URL erc7824/nitrolite redirige ahí. Etiquetó v1.0.0 el 2026-02-17 y está en v1.4.1 desde el 2026-06-18. Su directorio contracts/src contiene ChannelHub.sol, ChannelEngine.sol, EscrowDepositEngine.sol y EscrowWithdrawalEngine.sol.
No hay adjudicator. No hay IChannel, ni join, ni resize, ni Allocation[]. Ninguna de las interfaces que el ERC estandariza aparece en el código desplegado.
Lo que las reemplazó está documentado en la propia descripción de protocolo del repo. Un canal ahora es estrictamente de dos partes: un User y un Node. Su estado lleva dos sub-ledgers por cadena, homeLedger y nonHomeLedger, cada uno con asignaciones absolutas más flujos netos acumulados. El movimiento cross-chain es un escrow optimista de dos fases, no un bridge atómico. Un canal puede migrar su home chain, intercambiando los roles de ambos ledgers a mitad de protocolo. El modelo mental que ofrece el documento es preciso y honesto: "Off-chain protocol decides what should happen. On-chain contract enforces the latest authorized accounting state. Bridging is non-atomic but recoverable."
Ese es un protocolo materialmente distinto del que describe el ERC. Quien implementara ERC-7824 desde el texto del borrador produciría un contrato incapaz de hablar con un solo node Nitrolite desplegado.
Los números duros son constantes de ChannelHub.sol, y son los que importan para dimensionar la exposición de un agente:
uint8 public constant VERSION = 1;
uint32 public constant MIN_CHALLENGE_DURATION = 1 days;
uint32 public constant MAX_CHALLENGE_DURATION = 7 days;
uint32 public constant ESCROW_DEPOSIT_UNLOCK_DELAY = 3 hours;
uint32 public constant MAX_DEPOSIT_ESCROW_STEPS = 64;
uint256 public constant TRANSFER_GAS_LIMIT = 100000;
uint64 public constant VALIDATOR_ACTIVATION_DELAY = 1 days;
La línea 1398 del contrato exige que def.challengeDuration esté entre MIN_CHALLENGE_DURATION y MAX_CHALLENGE_DURATION. El ejemplo del propio borrador del ERC — un periodo de challenge de una hora — revertiría en todos los hubs desplegados.
Para un agente autónomo eso no es un detalle. Es la latencia de salida. Si el node deja de co-firmar, el camino unilateral más rápido del agente hacia su propio dinero son 24 horas de periodo de challenge, y el operador puede configurar hasta siete días. Compáralo con x402 sobre EIP-3009, donde los fondos nunca quedan bloqueados: el agente firma una autorización de transferencia por llamada y conserva la custodia de todo lo que no gastó.
El censo on-chain
Verificamos qué hay realmente en vivo. Cada registro de deployment de mainnet en contracts/deployments/ apunta a la misma dirección — 0x1a2f750170474d4c54f8d318d9d4343588b4c4d1 — en ocho chain IDs de mainnet: Ethereum (1), Base (8453), Polygon (137), BNB Smart Chain (56), Linea (59144), World Chain (480), Flare (14) y XRPL EVM Sidechain (1440000). Cinco testnets llevan la misma. Todos están etiquetados prod v1.3.0 y todos se desplegaron el 2026-05-22, con menos de una hora de diferencia entre sí.
Leer el hub en Base confirma el registro:
$ HUB=0x1a2f750170474d4c54f8d318d9d4343588b4c4d1
$ cast call $HUB 'NODE()(address)' --rpc-url https://mainnet.base.org
0xBffaA37E34FB9Aa11B23eb6cC939abBB45D6CCB6
$ cast call $HUB 'MIN_CHALLENGE_DURATION()(uint32)' --rpc-url https://mainnet.base.org
86400
NODE es un immutable fijado en el constructor. _requireValidDefinition rechaza cualquier createChannel cuya definición nombre otro node. Un hub, una contraparte, para todos en esa cadena. Esto no es un mercado de nodes; es el rail de un solo operador con un contrato de settlement público debajo.
Después contamos las transacciones. El endpoint compatible con Etherscan de Blockscout devuelve la lista de transacciones externas de un contrato, y los selectores de cuatro bytes decodifican limpio:
$ curl -s "https://base.blockscout.com/api?module=account&action=txlist\
&address=$HUB&startblock=0&endblock=99999999&sort=asc" \
| jq -r '.result[].input[0:10]' | sort | uniq -c | sort -rn
Base, desde el deployment del 2026-05-22 hasta la última transacción del 2026-09-13: 64 transacciones externas de 15 emisores distintos. Desglosadas — 23 depositToChannel, 17 withdrawFromChannel, 16 createChannel, 3 depositToNode, 3 closeChannel, 1 registerNodeValidator, más el propio deployment.
Ethereum mainnet: 13 transacciones, 3 emisores, 4 canales abiertos y 4 cerrados, última actividad el 2026-06-17. Polygon: 10 transacciones, 3 emisores, 2 abiertos y 2 cerrados, última actividad el 2026-06-17.
La ausencia más interesante está en el histograma de selectores. En las tres cadenas no hay ni un solo challengeChannel, ni un solo checkpointChannel, ni una llamada de escrow o migración. El camino de disputa — el mecanismo que hace funcionar todo el modelo de confianza — nunca se ejerció en mainnet.
Session keys: el primitivo del agente, y dónde se detiene
Para un agente autónomo, el contrato interesante es SessionKeyValidator.sol. Permite a una wallet delegar autoridad de firma a una hot key, que es exactamente como quieres que un agente tenga poder de gasto: la root key en una bóveda, la session key en el proceso.
El diseño es de dos pasos y está bien hecho. El participante firma un struct SessionKeyAuthorization — dirección de la session key más un metadataHash que cubre "expiration timestamp, nonce, permissions" — bajo un type hash dedicado que impide replayar firmas abi.encode(address, bytes32) no relacionadas como autorizaciones. La session key firma luego el estado real. On-chain se verifican ambas firmas.
Dos cosas de ese contrato importan más que el diseño.
Primero, su propio encabezado declara el modelo de seguridad sin rodeos: "Off-chain enforcement (the Node) should validate session key expiration and usage limits. On-chain validation only checks cryptographic validity." El metadataHash es un hash. El contrato nunca lo abre. Expiración, nonce y permisos son política del node, no consenso.
Segundo, y este es el hallazgo que debería cambiar cómo despliegas:
function validateChallengeSignature(bytes32, bytes calldata, bytes calldata, address)
external pure returns (ValidationResult)
{
revert ChallengeWithSessionKeyNotSupported();
}
Una session key puede gastar. Una session key no puede hacer challenge. Si el node se apaga, el agente que solo tiene su hot key no tiene salida on-chain — debe escalar a la root key que todo el patrón de delegación existía para mantener offline. La llave que opera no es la llave que puede defenderse.
El modelo de allowances off-chain tiene sus propios bordes, documentados en la referencia de session keys del repo. Las allowances son topes por asset declarados en el registro: [{"asset": "usdc", "amount": "100.0"}]. Si excedes uno, el node rechaza con insufficient session key allowance. Un array vacío significa cero gasto. Hasta ahí, bien.
Pero el campo application es opcional y "defaults to clearnode if not provided" — y las session keys registradas bajo el nombre de aplicación clearnode "bypass spending allowance validation and application restrictions" con "full permissions". Un integrador que omite un string opcional acuña una root key en lugar de una acotada. Solo la expiración sigue vinculando.
Tres restricciones más que vale la pena codificar en cualquier cliente: el parámetro scope está documentado pero marcado como "not yet implemented"; solo puede haber una session key activa por par wallet-más-aplicación, así que una segunda instancia de agente registrándose bajo la misma aplicación invalida en silencio a la primera; y al reautenticar con una key existente, las allowances del request "will be ignored" en favor de las guardadas en el registro inicial, de modo que no puedes apretar un tope reautenticando.
Contrástalo con las alternativas. En x402 sobre EIP-3009, validAfter y validBefore son argumentos del contrato del token — la cadena impone la ventana. En Spend Permissions el periodo y el tope son estado del contrato. En la delegación ERC-7710 los caveats los imponen contratos enforcer al redimir. Los límites de session key de Nitrolite los impone el servidor de la contraparte.
En qué estás confiando realmente
El documento de seguridad y limitaciones del proyecto es inusualmente franco, y es el lugar correcto para empezar cualquier cálculo de exposición. Su evaluación de apertura: "the protocol in its current form is not fully trust-minimized."
Los usuarios deben confiar en el node para liveness, liquidez cross-chain, relay cross-chain, enforcement oportuno, equivalencia de símbolos de asset y configuración de profundidad de reorg. Dos entradas merecen leerse dos veces.
Sobre el ruteo de transferencias off-chain: "the on-chain contract cannot enforce atomicity between two independent channel updates. A malicious node could apply the sender's state while withholding the receiver's credit, capturing the transferred funds." Cada pago off-chain entre dos usuarios del mismo node son dos actualizaciones de canal separadas, y nada on-chain las une.
Sobre el registro de validators: el operador del node elige qué signature validators acepta el hub. "A malicious or compromised node could register a validator that approves forged user signatures, then use it to create channels or close them without the user's knowledge." La defensa es VALIDATOR_ACTIVATION_DELAY — un día. El documento es explícito sobre qué compra eso: "Once registered, a validator cannot be deactivated — the 1-day window is the entire response budget." A los usuarios se les dice que vigilen el evento ValidatorRegistered y revoquen los approvals de ERC-20 apenas lo vean.
Para un agente, "vigila un evento durante 24 horas y reacciona" es un servicio de monitoreo, no una nota al pie. Y la lista de limitaciones conocidas confirma que nada de eso existe todavía: sin red de validators, sin servicios de watchtower, sin verificación formal, sin operaciones de estado off-chain trustless. Todo está en el roadmap.
La sala de settlement
Lo más nativo para agentes del repositorio no es un contrato. El 2026-07-15 el proyecto mergeó un directorio agent-skills/ que contiene yellow-settlement-room — un archivo de skill escrito para que un agente IA lo lea y actúe, enseñándole a abrir una app session multiparte sobre el node de Yellow.
El modelo que describe es genuinamente útil y no es algo que x402 ofrezca. Una app session tiene N participantes con signatureWeight por participante y un quorum; abre con asignaciones en cero; los depositantes comprometen sus propios fondos; los participantes reasignan off-chain sin gas por paso; el reparto final se co-firma una vez. Como lo plantea la skill: "A payment rail moves value from one payer to one payee; a swarm of agents settling over a rail needs a separate escrow per pair. One session settles all of them at once."
Las reglas de diseño de la skill son estrictas en los lugares correctos. Un agente, una key, un proceso. El proposer empaqueta un hash de estado con packAppStateUpdateV1, lo envía a cada firmante y recolecta firmas hasta que el peso sumado alcanza el quorum — y la skill señala que "the protocol carries no transport for moving the hash out and the signatures back; that is the integrator's to build." El conjunto de participantes es inmutable tras la creación.
Su sección de trust boundary merece citarse entera, porque es la declaración más clara del intercambio en todo el proyecto: ningún agente de la sesión puede tomar la asignación de otro, ya que cada cambio requiere quorum. Pero "funds become enforceable on-chain only once released back to a channel as a node-co-signed state. If the node will not co-sign, there is no on-chain path out of the session." Y: "A session has no dispute mechanism, challenge, or timeout of its own. If quorum is never reached, funds stay in the session."
Entonces la capa de canal tiene un challenge de 1 a 7 días. La capa de app session encima no tiene challenge alguno. El techo de exposición es lo que el participante depositó — que es el número a dimensionar, deliberadamente, por sesión.
Dos ecosistemas que no se tocan
Buscamos x402 en todo el repositorio layer-3/nitrolite. Cero resultados. Ni en los contratos, ni en los SDKs, ni en la documentación, ni en la agent skill. La implementación de state channels más completa del ecosistema EVM y el protocolo dominante de pagos de agentes no tienen superficie de integración entre sí, en ninguna dirección.
El drift de nombres agrava la distancia. erc7824.org — el sitio que el propio borrador del ERC enlaza como su documentación — todavía le dice al desarrollador npm install @erc7824/nitrolite y lo apunta a wss://clearnet.yellow.com/ws. El último release de ese paquete npm es 0.5.3, publicado el 2025-12-18. El SDK que el repositorio realmente distribuye es @yellow-org/sdk, en 1.4.0 en npm, con un acompañante @yellow-org/sdk-compat descrito en el propio llms.txt del repo como un "migration bridge from v0.5.3". El endpoint de sandbox en la agent skill actual es wss://nitronode-sandbox.yellow.org/v1/ws. Clearnode fue renombrado a Nitronode. Incluso el llms.txt del repositorio apunta a directorios sdk/ts-mcp y sdk/mcp-go que no existen — el árbol tiene sdk/mcp y sdk/go.
Un desarrollador que encuentra ERC-7824 por el repositorio de ERCs, sigue el link de discussions-to, aterriza en el sitio de documentación e instala lo que recomienda, obtiene un paquete de nueve meses de antigüedad para una generación de protocolo que ya fue superada dos veces. Eso es un problema de discovery, y para un estándar cuyo valor entero es la interoperabilidad, es del tipo caro.
El proyecto lo sabe. Distribuye drift guards deterministas — tests de drift de ABI que comparan los ABIs commiteados del SDK contra los artefactos de Foundry, tests de drift de RPC y DTO, y un smoke de runtime que levanta un Nitronode local en ws://127.0.0.1:7824/ws y ejercita ping, getConfig, getAssets y getAppSessions. La disciplina de ingeniería dentro del repo es real. Solo que no llegó a la puerta de entrada pública.
Qué significa para LLM4Agents
El argumento de costo a favor de los canales es correcto y conviene decirlo sin rodeos. Una relación con un gateway es duradera y de alta frecuencia — exactamente el perfil donde el settlement por llamada sobrepaga y un canal gana. Si un agente corre cien mil completions por nosotros, firmar cien mil autorizaciones de pago es la forma equivocada, y la granularidad por token que permite un canal es estrictamente mejor que redondear cada llamada hacia arriba a un cargo mínimo.
Pero el ledger de confianza hoy no favorece adoptarlo como rail por defecto, y las razones son específicas, no vagas.
La duración mínima de challenge es un día. x402 sobre EIP-3009 no bloquea nada: el balance no gastado del agente se queda en su propia wallet, y el peor caso de que un gateway se apague es un request fallido. Bajo un canal, el peor caso son 24 horas mínimo antes de completar una salida unilateral, y esa salida requiere la root key, porque SessionKeyValidator se niega a validar firmas de challenge. Un agente diseñado alrededor de una hot session key no tiene recuperación autoservicio. Eso invierte la propiedad que más nos importa — los agentes que operan sin supervisión deben poder recuperarse sin supervisión.
Los topes de gasto en los que se apoyaría un operador de agentes los impone la contraparte. Esa es una clase de seguridad distinta de los topes on-chain que venimos siguiendo en Spend Permissions y los enforcers de ERC-7710, y no debería describirse a clientes como equivalente. El default application: "clearnode" que produce en silencio una key sin tope es el tipo de footgun que pertenece detrás de un wrapper, no en una guía de integración.
Y el estándar todavía no es un estándar. Construir una integración con forma de IChannel contra el borrador de ERC-7824 no compra nada, porque ningún hub desplegado lo implementa. Construir contra @yellow-org/sdk v1 es construir contra el protocolo de un solo vendor con un contrato público debajo — una elección legítima, pero hay que tomarla con ese nombre puesto.
Donde los canales sí encajan hoy en nuestro stack es más estrecho y más defendible: una capa de settlement entre agentes, no entre un agente y nosotros. El modelo de app session — N agentes, pesos, quorum, un reparto final — resuelve un problema que x402 genuinamente no resuelve, que es el settlement multiparte sin escrows por pares. Un enjambre orquestado repartiendo el costo de un trabajo de research compartido es una instancia real de esa forma. El gateway no tiene que ser participante del canal para ser útil dentro de uno.
Cómo mantenerse en la frontera
Orden de trabajo concreto, del más valioso al menos.
Publicar la comparativa de latencia de salida, con números
Ya corremos x402 como rail primario. Documentar cuál es el peor caso de tiempo-hasta-fondos de un agente en cada opción: cero para EIP-3009 por llamada, 1 a 7 días bajo un canal Nitrolite, ilimitado dentro de una app session sin quorum. La latencia de salida es el número con el que los operadores de agentes deberían comparar rails, y nadie lo está publicando. Hacerlo página, mantenerlo vigente, citar las constantes.
Prototipar la sala de settlement contra el sandbox
Construir un trabajo multi-agente sobre wss://nitronode-sandbox.yellow.org/v1/ws usando @yellow-org/sdk v1: tres agentes, pesos iguales, quorum unánime, un presupuesto compartido, un reparto final. Aprender dónde duele el transporte de recolección de firmas, porque el protocolo no lo provee y tendríamos que hacerlo nosotros. Es una semana de trabajo y resuelve si las app sessions pertenecen a nuestra historia de costo compartido.
Convertir la auditoría de delegación en un check repetible
El hallazgo que importó aquí — una hot key que puede gastar pero no salir — salió de leer un revert en un validator. Cada rail de delegación que evaluemos debería recibir las mismas tres preguntas: qué impone la cadena, qué impone la contraparte, y ¿puede la key delegada firmar su propia recuperación? Aplicarlo a cada nuevo rail de pagos de agentes antes de que llegue a una página de cara al cliente.
Publicar una skill, no solo un SDK
Yellow publicó un SKILL.md que enseña a un agente a usar su protocolo correctamente, con el trust boundary declarado en el archivo y una instrucción de no suavizarlo. Ese es el formato de distribución correcto para un rail de cara a agentes, y es barato. Nuestra superficie MCP debería ir acompañada de una skill que codifique nuestros propios límites — topes de presupuesto, orden de fallback, qué pasa ante un 402 — para que un agente integre bien al primer intento en vez de adivinar.
Vigilar la llegada del watchtower
Tres ítems del roadmap de Nitrolite cambiarían esta evaluación: una red de validators, servicios de watchtower, y enforcement on-chain que elimine el supuesto de confianza en la liquidez del node. Si llegan los watchtowers y las session keys ganan un camino de challenge, la objeción de latencia de salida se disuelve en buena medida y los canales pasan a ser candidato serio para relaciones duraderas con el gateway. Reejecutar esta auditoría cuando caiga el primero de los tres.
El resumen honesto: ERC-7824 nombró un problema real y el equipo de Nitrolite construyó una respuesta que funciona, con un documento de seguridad más franco que el de la mayoría de protocolos auditados. Lo que no tienen es un estándar mergeado, un segundo operador de node, un camino de disputa ejercitado, ni una key delegada capaz de defenderse sola. Para un gateway de LLM que cobra a agentes autónomos, esos cuatro huecos son justo los que importan — así que lo seguimos de cerca y no enrutamos nada por ahí, todavía.
Paga por token, conserva la custodia
x402 sobre EIP-3009 en un gateway compatible con OpenAI. Nada bloqueado, nada de qué salir.
Registra tu agente