← Blog
1 de octubre, 2026 · 16 min

Auditamos nvm:erc4337 de Nevermined: x402 con un medidor off-chain

Nevermined extiende x402 con un scheme llamado nvm:erc4337: créditos, planes y session keys de ERC-4337 en lugar de una transferencia por request. Leímos la spec, los dos SDKs y los contratos, sondeamos el facilitator en vivo y censamos Base, Base Sepolia y Tempo. Los headers son x402. El resto no: el 402 no lleva precio, el facilitator firma la credencial que presenta el comprador y, por defecto, el medidor vive en una base de datos.

El scheme exact de x402 es una transferencia EIP-3009 por request. El comprador la firma, cualquier facilitator puede verificarla y la cadena la liquida. No puede expresar un paquete prepago de créditos, un plan mensual ni una tarjeta. Nevermined, que vende infraestructura de pagos para agentes, construyó dos schemes para esos casos: nvm:erc4337 para stablecoins en smart accounts y nvm:card-delegation para tarjetas. Ambos reutilizan los tres headers de x402 (PAYMENT-REQUIRED, PAYMENT-SIGNATURE, PAYMENT-RESPONSE) y su separación entre verify y settle.

Es uno de los intentos más completos de poner planes y créditos detrás de un 402. Es el mismo problema que abordamos desde el otro lado con el scheme upto. Y un agente comprador que encuentra nvm:erc4337 en un arreglo accepts necesita saber en qué se le pide confiar.

Nuestras fuentes, todas leídas el 1 de octubre de 2026: la spec x402 Smart Accounts Extension (v0.3, Draft, enero de 2026); la spec de card delegation (v0.1, Draft, febrero de 2026); el SDK de TypeScript @nevermined-io/payments 1.13.0 y el de Python payments-py 1.18.0, ambos publicados el 9 de septiembre (HEADs de los repositorios 28c9f92 y 7b0d0f1); el repositorio de contratos en c36dd03 con sus manifiestos de deployment; sondas sin autenticación contra las APIs de sandbox y live; y un censo de eventos en tres cadenas. El backend del facilitator vive en un repositorio privado. Todo lo que decimos sobre él viene de comentarios públicos del SDK, de la documentación o de comportamiento observado, y aclaramos cuál.

Qué pone nvm:erc4337 en el cable

Este es el 402 que produce buildPaymentRequired del SDK para una ruta protegida en el entorno live:

{
  "x402Version": 2,
  "resource": { "url": "/ask" },
  "accepts": [{
    "scheme":  "nvm:erc4337",
    "network": "eip155:8453",        // eip155:84532 en sandbox
    "planId":  "4331…3873",          // id de plan de 256 bits
    "extra":   { "version": "1", "agentId": "…", "httpVerb": "POST" }
  }],
  "extensions": {}
}

Compáralo con un requirement exact en la spec v2 de x402, que lleva amount, asset, payTo y maxTimeoutSeconds. Ninguno de los cuatro está aquí. Lo que cuesta un crédito vive en el registro del plan en la API de Nevermined. Cuántos créditos quema esta llamada vive en la configuración del middleware del vendedor, 'POST /ask': { planId, credits: 1 }, y nunca se envía. Un comprador puede consultar el precio de un crédito. No puede saber por el 402 cuánto le costará este request.

El comprador responde con un PAYMENT-SIGNATURE cuyo payload cambia la autorización EIP-3009 por session keys:

"payload": {
  "signature": "0x0184…",
  "authorization": {
    "from": "0xD4f5…eC8c",               // smart account del comprador
    "sessionKeysProvider": "zerodev",
    "sessionKeys": [
      { "id": "order",  "data": "0x20a1…" },  // comprar créditos si faltan
      { "id": "redeem", "data": "0x68e8…" }   // quemar créditos por request
    ]
  }
}

redeem permite al facilitator quemar créditos. order le permite comprar más cuando el saldo baja. La spec lista zerodev, biconomy y safe como proveedores de session keys. Todos los ejemplos que encontramos en la documentación y en las suites de tests usan zerodev. El hermano fiat, nvm:card-delegation, pone en network el valor "stripe", "braintree" o "visa", que no son identificadores CAIP-2, y su payload es un JWT.

El diseño es la imagen especular del que auditamos en Smart Sessions. Allí las session keys nunca se activaban para x402, porque la liquidación de exact es una transacción del facilitator, no una UserOperation. Aquí el pago está pensado como UserOperation desde el principio.

Quién firma el pago

En exact, firma la llave del comprador y nadie más puede hacerlo. La documentación de Nevermined dice lo mismo de su scheme: cobra "using secure, locally-signed payment authorizations", y la tabla de roles de la spec dice que el cliente "signs payment authorizations locally."

El SDK hace otra cosa. getX402AccessToken no firma nada. Hace un POST con el id del plan, el scheme y un delegationId a /api/v1/x402/permissions, autenticado con la API key de Nevermined del comprador, y devuelve el token que recibe. El constructor de requests compartido lo dice en una línea: los mints de x402 y de MPP reciben las mismas entradas, y "only the EIP-712 domain the backend signs under differs." El archivo de tipos es igual de directo: X402TokenVersion es la "EIP-712 struct version the backend signs the access token under."

La spec de tarjetas lo reconoce abiertamente. Su JWT "MUST be signed by the facilitator's private key", con iss igual a la URL del facilitator. La spec de ERC-4337 no lo dice, pero el catálogo público de errores llena el hueco. BCK.APIKEY.0017 dice "This API key was issued without a session key for this network." BCK.X402.0035 habla de una delegación cuyo "linked erc4337 permission is missing session keys (burnSessionKey / orderSessionKey)." Las session keys se aprovisionan por API key y por red, y se guardan del lado del servidor.

Así que la credencial que de verdad opera es la API key de Nevermined. Quien la tiene puede crear delegaciones y emitir tokens dentro de sus límites. Es un producto razonable: una cuenta de gasto con llaves acotadas, operada por una empresa. Pero no es el modelo de confianza que describe la spec, y un comprador no puede comprobar su propio pago sin la API de Nevermined.

Un bearer token reutilizable por defecto

El SDK documenta dos versiones de token. La versión 2 es "today's default: reusable bearer token, signature covers [from, sessionKeysProvider, sessionKeys, planId]."

Mira lo que queda fuera de esa firma: la red, el recurso del vendedor, el verbo HTTP, el monto y cualquier nonce o expiración. La sección 8.4 de la spec dice "Cross-network attacks MUST be prevented by including the network in signed data." La sección 8.1 dice que la protección contra replay SHOULD usar nonces o timestamps. El token por defecto no hace ninguna de las dos cosas. Sus únicos límites son los de la delegación: un techo en centavos y una vida en segundos, ambos aplicados por el facilitator. Cada settle de un token v2 vuelve a quemar (la frase del propio SDK es "settle always burned"). Así que quien tenga un token v2 filtrado puede comprar servicio en cualquier endpoint que acepte su plan, a cuenta del comprador original, hasta que se agote la delegación.

La versión 3 corrige el amarre. Agrega agentId, resourceUrl, httpVerb y un nonce aleatorio de 32 bytes al struct firmado, y el primer settle consume el token. Un segundo settle falla con BCK.X402.0059. Los comentarios del SDK suman tres advertencias:

La última advertencia invierte el riesgo habitual. Un token v3 ya gastado pasa verify sin problema. El handler del vendedor corre, lo que para un gateway como el nuestro significa una inferencia completa. Solo entonces settle lo rechaza. El middleware de Express guarda un mapa en proceso de tokens gastados con un TTL de una hora, para rechazar el siguiente replay antes del handler. Su comentario admite que el mapa "does not span processes or horizontally scaled instances." El middleware de FastAPI en 1.18.0 no tiene ese mapa. Cada replay corre el handler, y el body se retiene después.

Quién fija el precio

Verify y settle reciben maxAmount, un número de créditos, y lo aporta el vendedor. El 402 no lo lleva y el token v2 no lo firma. El middleware de Express evalúa los credits de la ruta antes de verify. Si credits es una función, la vuelve a evaluar después del handler y liquida el segundo número. Es pricing dinámico en el espíritu de upto, con una diferencia. En upto el comprador firma un máximo. Aquí los límites son el mínimo y el máximo por request del plan, que el contrato aplica solo a las quemas que llegan a la cadena, más el total de la delegación.

Cuando el saldo no alcanza, settle compra créditos primero. En palabras de la documentación, "the facilitator tops up their credits automatically, up to the delegation's limit." Y las delegaciones son "plan-agnostic by default." Una sola delegación de 100 dólares puede recargar cualquier plan que el agente toque. El SDK acepta planId, maxTransactions y apiKeyId para acotarla. Sin ellos, es un presupuesto abierto.

Servir primero, liquidar después

x402 deja que el servidor elija si liquida antes o después de hacer el trabajo. Medimos lo que cuesta liquidar después en la auditoría del hueco entre fases. Nevermined liquida después. Los dos SDKs además sirven la respuesta cuando la liquidación falla, salvo con un token v3 ya gastado.

El middleware de Python lo dice sin rodeos: "Log but don't fail the response if settlement fails", porque "the agent already delivered the value." El middleware de Express adjunta lo que haya devuelto settle a payment-response y cierra la respuesta. La liquidación también puede fallar como HTTP 200 con success: false. El SDK registra una advertencia y anota que "of the in-tree consumers only the MCP paywall actually branches on success."

La spec dice otra cosa. En sus pasos 29 y 30, si falla el redeem o el order, el servidor devuelve 402 PAYMENT-FAILED. Su propia advertencia concede que para entonces "the server has already performed work." Con créditos, este es un riesgo para el vendedor, no para el comprador. Un comprador cuyo saldo no cubre la quema, y cuya delegación no puede recargarlo, igual recibe la respuesta cada vez que verify y settle no coinciden.

Dónde vive el medidor

La spec describe la liquidación como UserOperations ejecutadas on-chain, con un hash de transacción en el recibo. La configuración de los planes describe otro default. Todo plan de créditos tiene un campo llamado onchainMirror. La referencia del CLI de Nevermined lo define: "false keeps the credit ledger off-chain (default). true mirrors each burn to the on-chain NFT1155Credits contract." Todos los helpers de configuración de créditos del SDK de TypeScript lo ponen en false. La versión 1.1 de la API eliminó su alias heredado, proofRequired.

Así que, en la configuración por defecto, un request quema créditos en la base de datos de Nevermined. Las session keys del token autorizan una quema que nunca llega a la cadena salvo que el vendedor lo active. Las órdenes, es decir, compras de paquetes de créditos y cobros pay-as-you-go, sí se liquidan on-chain.

Los contratos muestran qué probaría realmente una quema espejada. NFT1155Credits.burn todavía recibe un argumento de firma. Su comentario dice que los dos parámetros finales "are retained for ABI stability after the EIP-712 signed-burn flow was nullified (protocol#175 / nvm-monorepo#1253) and are ignored at runtime." La autorización sale del redemptionType del plan. Un holder siempre puede quemar sus propios créditos. ONLY_OWNER permite que el dueño del plan, es decir, el vendedor, queme los créditos de cualquier holder. ONLY_GLOBAL_ROLE se lo permite a cualquier titular de CREDITS_BURNER_ROLE.

Qué dice la cadena

Los manifiestos de deployment listan las mismas direcciones de proxy en Base, Base Sepolia y Tempo. Extrajimos todos los eventos que emitieron los contratos de registro, agreements, créditos y vault en Base y Tempo, y los últimos 30 días de eventos de créditos en el sandbox.

// Contratos del protocolo Nevermined, snapshot 2026-10-01 (~09:30 UTC)
// Base mainnet (8453): activo desde 2025-11-14, v1.5.0 desde 2026-06-30
AssetsRegistry    0x1B09…4Ae4   agentes registrados              273
                                planes registrados               396
AgreementsStore   0x1B8B…660C   agreements                       104
                                  vía FiatPaymentTemplate         90   // 2 emisores, ambos con FIAT_SETTLEMENT_ROLE
                                  vía EntryPoint v0.7             14   // 4 smart accounts
NFT1155Credits    0xb2F9…2d64   mints de créditos                 23   // incl. ExpirableV2 0xF7Fe…872F
                                quemas de créditos                37   // todas self-burns, 8 holders
                                primer / último evento            2026-02-23 / 2026-04-28
PaymentsVault     0x47A7…EA24   depósitos USDC                     6   // 3 pagadores, 5.81 USDC en total

// Tempo mainnet (4217): las mismas seis direcciones, desde el bloque 27,846,938
todos los contratos             logs                              18   // solo eventos de upgrade/autorización

// Base Sepolia (sandbox): últimos 30 días
NFT1155Credits                  mints 56, quemas 11                    // quemas de 2 holders

En Base mainnet, los contratos registraron 37 quemas de créditos en diez meses y medio. Las 37 fueron self-burns: el operador era el propio holder, que es el camino de las session keys. La última fue el 28 de abril. El vault recibió 5.81 USDC en total. De 104 agreements, 90 son pagos con tarjeta escritos on-chain por dos cuentas que tienen FIAT_SETTLEMENT_ROLE. En Tempo mainnet existen las mismas direcciones y no registraron nada más que sus propios upgrades. El sandbox tiene más movimiento, pero no mucho más.

Esto no mide el tráfico de Nevermined. Con el espejo apagado, el uso por request no deja rastro on-chain por diseño, y no podemos ver la base de datos. Lo que sí mide es qué poco se usa la maquinaria on-chain del scheme. Desde fuera puedes verificar registros de planes, registros de órdenes con tarjeta y un puñado de órdenes en USDC. Desde el 28 de abril, ningún request medido en mainnet ha dejado rastro on-chain.

Qué dice el registro en vivo

El endpoint de planes de la API live no pide autenticación. Descargamos todos los planes registrados en Base mainnet: 396 eventos PlanRegistered, de los cuales 373 resuelven y 23 devuelven 404.

// GET api.live.nevermined.app/api/v1/protocol/plans/{id}, 2026-10-01
planes resueltos                 373   // 128 dueños distintos
registry.credits.onchainMirror   false 372 · true 1
redemptionType                   ONLY_SUBSCRIBER 195 · ONLY_OWNER 178
price.isCrypto                   true 195 · false 178
billingModel                     credits 323 · pay-as-you-go 50
planes cripto con precio en un
  token sin código en Base         56   // USDC de Polygon 49, USDC de Arbitrum 6, USDC.e de Polygon 1
fee para el Safe 0x2020…9A90     1.0% en los 167 planes cripto que lo listan

Destacan tres cosas. Un plan de 373 espeja sus quemas on-chain. Casi la mitad, 178, usan ONLY_OWNER, el tipo de redención bajo el cual una quema espejada no necesita nada del comprador. Es la configuración del plan más reciente de la muestra. Y 56 planes cripto, registrados en marzo por tres dueños, tienen precio en direcciones de USDC de Polygon y Arbitrum que no tienen código de contrato en Base. El registro los aceptó en la cadena 8453 de todos modos.

Quién puede cambiar los contratos

Los contratos del protocolo son proxies UUPS gobernados por un AccessManager de OpenZeppelin. Llamar a upgradeToAndCall en NFT1155Credits requiere UPGRADE_ROLE. En Base mainnet, ese rol pertenece al mismo Safe que cobra el fee del 1%. Es un SafeL2 con umbral de un firmante sobre tres dueños. Uno de los tres es la EOA que figura como owner en el manifiesto de deployment. El retraso de ejecución del AccessManager para ese permiso es de un segundo.

NFT1155Credits se actualizó tres veces, la última el 30 de junio de 2026 para la v1.5.0. Es una configuración normal para un protocolo joven. También significa que un comprador que confía en las reglas de los contratos, como el tipo de redención, el límite por request o el reparto del vault, confía en una sola llave, no en código que no puede cambiar.

Qué hace bien Nevermined

Buena parte de la ingeniería es cuidadosa, y los comentarios del SDK son inusualmente francos. Casi todo lo que encontramos lo encontramos porque alguien lo dejó escrito.

Las delegaciones son la primitiva correcta: un techo de gasto, una expiración, alcance opcional por plan, por número de transacciones y por API key, y un solo presupuesto compartido por x402 y MPP. Los tokens v3 son la corrección correcta: atados al vendedor, atados al verbo, de un solo uso. El SDK se niega a atar un recurso en un mint v2 en vez de solo advertir. La spec de tarjetas resuelve bien el enrutamiento del dinero. Su sección 6.4 dice que la cuenta de destino "MUST NOT be accepted from the client", y la sección 6.2 incrementa el contador de gasto de forma atómica antes de crear el PaymentIntent.

El repositorio de contratos además agrega orderWithAuthorization al template pay-as-you-go: una orden sin gas pagada con una autorización EIP-3009 cuyo nonce está atado al id del agreement. Es la misma primitiva que usa exact. Y el facilitator ya exige autenticación. El 1 de octubre, un POST a /x402/verify o /x402/settle sin llave, en sandbox o en live, devolvió 401 BCK.AUTH.0002: "Anonymous access is not permitted on this endpoint." El SDK 1.13.0 publicado todavía describe ese guard como opcional.

Qué significa para LLM4Agents

Nevermined resuelve un problema que tenemos. Los pagos exact por llamada son limpios, pero cuestan una firma y una liquidación por request para agentes conversadores, y no pueden expresar un plan. Créditos respaldados por un presupuesto de delegación son la respuesta obvia, y ya operamos la mitad. Los depósitos a nuestro gateway se liquidan on-chain. Las deducciones por token salen de un ledger off-chain. La lección no es que off-chain sea malo. Es que un sistema de pagos debe decir con claridad qué partes son on-chain.

También nombra un riesgo para el ecosistema. nvm:erc4337 usa los headers de x402 y su vocabulario de verify/settle, pero un cliente x402 estándar no puede pagarlo. No hay monto que evaluar, nada que firmar localmente, y el token sale de la API de una empresa a cambio de una llave de cuenta. Si schemes así se extienden bajo el nombre x402, accepts[] deja de ser algo sobre lo que un comprador pueda razonar. Nuestro tooling de comprador debe tratar los schemes desconocidos como ajenos, no como x402.

Y es una checklist para nuestro lado vendedor. Vendemos llamadas caras. Un replay que corre el handler antes de ser rechazado cuesta inferencia real. Una política de fallo de settle que sirve el body es una fuga real. Un token sin nonce es una exposición real. Nevermined se topó con las tres y documentó sus correcciones en público.

Cómo mantenerse en la frontera

Primero, mantener el precio en el 402. Un requirement exact lleva amount, asset y payTo por construcción; toda ruta que vendamos debe conservar esa propiedad. Para llamadas medidas, usar upto con el máximo declarado. Si agregamos créditos, el 402 debe decir cuánto cuesta la llamada en créditos, o al menos el máximo.

Segundo, hacer que las credenciales de un solo uso y atadas al recurso sean el default, y rechazar replays en verify, antes de que corra el handler. El almacén de nonces gastados debe compartirse entre instancias, en Redis y no en un mapa de proceso, con un TTL al menos tan largo como la validez de la credencial.

Tercero, decidir la política de fallo de settle de forma explícita, ruta por ruta. Para inferencia, reservar el máximo en verify y liquidar el monto real después. Nunca servir ante un fallo determinista: una credencial gastada, un saldo insuficiente, una delegación revocada.

Cuarto, si lanzamos créditos prepago, hacer que el ledger sea verificable. Devolver un recibo firmado por llamada que incluya el saldo restante. Publicar periódicamente un compromiso on-chain del estado del ledger, como una raíz de Merkle, para que un comprador pueda probar una deducción sin llamar a nuestra API. Y declarar en la página de billing qué pasos son on-chain.

Quinto, tomar prestadas las delegaciones para agentes financiados con API key: techo de gasto, expiración, alcance por plan y por llave, y revocación por llave, emitidas desde el dashboard del dueño de la cuenta.

Sexto, en el tooling de comprador, reconocer nvm:erc4337 y nvm:card-delegation por nombre, etiquetarlos como "requiere una cuenta de Nevermined" y nunca pagarlos automáticamente. Luego vigilar tres cosas: las release notes del SDK para ver cuándo v3 pasa a ser el default, la próxima revisión de la spec de smart accounts, y si el ecosistema x402 adopta un registro para nombres de schemes de terceros.

Paga por llamada, con el precio en el 402

Un gateway compatible con OpenAI, pagado por llamada en USDC sobre x402.

Registra tu agente