x402 en Nano: un pago que no puede correr en paralelo
Todos los schemes de x402 hasta ahora le piden al buyer firmar una autorización que el facilitator puede enviar. Un scheme propuesto para Nano pide algo distinto: un bloque de ledger completo y ya válido. Esa decisión elimina las fees y el paralelismo de un solo golpe. Leímos el PR #3432 en el head 2c5607a, recalculamos un bloque real de mainnet desde sus campos y medimos cuánto cuesta el proof-of-work.
Nano es una red de moneda nativa (ticker XNO) con un ledger block-lattice: cada cuenta tiene su propia cadena de bloques, y un pago es un bloque "send" agregado a la cadena del pagador. No hay fees. El PR agrega un archivo, specs/schemes/exact/scheme_exact_nano.md, de 445 líneas. Lo abrió el 2026-09-09 kilkelly, quien dice en el cuerpo del PR que es voluntario de la Nano Foundation y que la spec se compartió internamente con ella. Al 2026-10-22 sigue abierto y sin merge, con última actualización el 2026-10-16. Una implementación de referencia en TypeScript se promete en otro PR tras la aprobación.
Nos importa por dos razones. Es el segundo scheme de moneda nativa en el repo después de Bitcoin Lightning (scheme_exact_lnbtc.md, commit 6fe0d4bf, 2026-09-23, de #2861). Y su diseño deja a la vista tres propiedades de los pagos x402 que EIP-3009 esconde: el objeto firmado no tiene expiración, la siguiente acción del propio pagador puede invalidarlo, y serializa al pagador.
Qué pide el scheme
El requirement es simple. asset es siempre XNO, amount va en unidades raw (1 XNO = 10^30 raw, así que el ejemplo de la spec 10000000000000000000000000000 es 0.01 XNO), payTo es una cuenta nano_, y maxTimeoutSeconds acota cuánto tiempo hace polling el facilitator, no cuánto dura algo válido.
El payload es un state block completo:
"payload": { "block": {
"type": "state",
"account": "nano_3qgmh1...", // pagador
"previous": "F47B2310...", // hash del frontier actual del pagador
"representative": "nano_1hza3f...",
"balance": "20000000000000000000000000000", // balance DESPUÉS del send
"link": "19D3D919...", // clave pública del receptor
"link_as_account": "nano_3ah94b...", // debe ser igual a payTo
"signature": "3BFBA64A...",
"work": "ffffffd2e1234567"
} }
Fíjate en lo que falta: no hay campo amount. Un send block de Nano declara el balance nuevo. El monto es la diferencia entre el balance previo del pagador y ese número. El facilitator tiene que consultar el balance previo a la red para saber qué está pagando el buyer. Por eso la spec necesita un chequeo de delta de balance, y es el primer punto donde este scheme difiere de EIP-3009, donde el mensaje firmado lleva el valor.
El flujo es verify y luego settle. Verify corre 14 chequeos ordenados. Settle los repite todos, llama al RPC del nodo process con subtype: send, espera medio segundo y hace polling de block_info cada segundo hasta que confirmed sea true o se agote maxTimeoutSeconds. La spec define 18 códigos de error compartidos por ambas etapas, de error_previous_not_frontier a error_block_awaiting_confirmation.
Chequeo 1: reconstruimos un bloque real
Una spec así solo sirve si un implementador independiente puede reproducir sus números. Un comentarista del PR, pursekeeper (un agente autónomo que opera un facilitator público de Nano), aportó test vectors de un pago real en mainnet, el bloque 1D60903E…D0BEB. No lo tomamos por bueno. Le pedimos el bloque a un nodo público y recalculamos el hash nosotros: Blake2b con salida de 32 bytes sobre un preámbulo de 32 bytes que termina en 0x06, luego la clave pública de la cuenta, previous, la clave del representative, el balance en 16 bytes big-endian y link.
node block_info: 1D60903EFD920FA78746E18F08C021EE7B8155205709DF5A4125BBDCF96D0BEB
nuestro cálculo: 1D60903EFD920FA78746E18F08C021EE7B8155205709DF5A4125BBDCF96D0BEB
subtype send, confirmed true, height 99, amount 1000000000000000000000000000 raw (0.001 XNO)
Idéntico. Los chequeos 7 y 8 de la spec se pueden implementar desde el texto. No verificamos la firma Ed25519-Blake2b en sí, así que no afirmamos nada del chequeo 7 más allá del hash.
Chequeo 2: el work es sobre previous, no sobre el bloque
La sección del payload dice que el work "MUST be generated using previous as input". La review de pursekeeper notó que un revisor al que le pagaron asumió el hash del bloque. Probamos ambos sobre el mismo bloque, cuyo work es 3f6ff9e7b7ba27a7 y cuyo umbral de send en la red es fffffff800000000 (confirmado en vivo con active_difficulty del nodo: send fffffff800000000, receive fffffe0000000000).
valor del work sobre previous: fffffffb24be3db3 (>= fffffff800000000: válido)
valor del work sobre hash bloque: 06827dd571ecd105 (bajo el umbral: inválido)
La spec tiene razón, y la distinción importa por una razón práctica. El work depende solo del hash previo. Se puede calcular apenas el pagador sabe cuál es el padre del siguiente bloque, antes de que exista cualquier pago. Volvemos a qué compra eso y qué lo rompe.
Un hueco en el texto: el chequeo 14, "Work Difficulty Check", dice que el work debe cumplir "the Nano network's current minimum difficulty threshold for a send transaction" y no nombra el valor, la entrada ni el RPC. Un facilitator que se equivoque no tiene a qué recurrir en la spec. Los valores de arriba salen de un nodo en vivo, y el facilitator que sondeamos anuncia el mismo umbral en su respuesta de /supported.
Cuánto cuesta el work
Nano reemplaza las fees por proof-of-work como anti-spam. El número esperado de intentos Blake2b-8 es 2^64 dividido por (2^64 menos el umbral). Para send son 2^29 = 536,870,912 intentos. Para receive el umbral es 64 veces más fácil: 2^23 = 8,388,608.
Medimos. Un solo core de esta máquina corre hashlib.blake2b(digest_size=8) de Python a 912,834 hashes por segundo, así que un core necesita en promedio unos 9.8 minutos por un send y unos 9 segundos por un receive. Luego corrimos la búsqueda en 72 procesos, cinco pruebas cada una:
send (fffffff800000000) 0.8 s, 4.6 s, 22.9 s, 33.8 s, 39.1 s mediana 22.9 s
receive (fffffe0000000000) 0.2 s, 0.3 s, 0.4 s, 0.4 s, 0.9 s mediana 0.39 s
La dispersión es el punto. El proof-of-work es una búsqueda geométrica, así que el tiempo hasta un nonce válido varía un orden de magnitud entre corridas. Nuestro código es Python sin optimizar en CPU. Las wallets usan GPUs y work servers, y un agente también. Leemos estos números solo como orden de magnitud: un send es un cómputo pesado que puede tardar segundos o minutos en hardware común, y un receive es casi gratis.
Compáralo con el costo del lado buyer en los otros schemes. Una autorización EIP-3009 es una firma, microsegundos. Aquí el buyer precalcula el work o paga la latencia dentro del round trip del 402, que está en el camino crítico de una compra por llamada.
La regla del frontier: un pago en vuelo
El chequeo 12, "Frontier Hash Check", exige que el previous del bloque sea igual al confirmed_frontier de la cuenta, obtenido con include_confirmed: true. Léelo dos veces. No es el frontier de la cuenta, es el confirmado.
Síguelo. El primer pago se firma con previous = H0 y produce un bloque con hash H1. Hasta que H1 se confirma, el frontier confirmado sigue siendo H0. Un segundo pago construido sobre H1 falla el chequeo 12. Un segundo pago construido sobre H0 es un fork del primero y, según el apéndice de la propia spec, solo uno de los dos puede confirmarse. Así que una cuenta Nano puede tener exactamente un pago x402 en vuelo, y el siguiente no se puede verificar hasta que el anterior esté cementado.
El facilitator que sondeamos reporta /verify en 85 ms y /settle en 649 ms de punta a punta sobre un bloque real (medición de su operador, del hilo del PR; nosotros no lo cronometramos). Si eso se sostiene, una cuenta llega a unos 1.5 pagos por segundo antes de contar la generación de work. Los pagos EIP-3009 desde una misma dirección no tienen esa restricción, porque cada autorización lleva su propio nonce aleatorio de 32 bytes y conmutan.
La sección de settlement de la spec nombra el modo de falla: si la cuenta del pagador gana un bloque entre verify y settle, "like an auto-receive block or another concurrent payment", el send block deja de coincidir con el frontier y el facilitator MUST devolver error_previous_not_frontier. El cliente debe construir un bloque nuevo. El mismo evento invalida también cualquier work precalculado sobre el previous viejo. De ahí se sigue (inferencia nuestra, no dicha en la spec) que una cuenta de agente que auto-recibe fondos mueve su propio frontier todo el tiempo y desperdicia su work precalculado. Separar cuentas de entrada y de salida es el diseño natural.
El bloque nunca expira
EIP-3009 tiene validBefore. Un bloque Nano no tiene ese campo. El apéndice de la spec es explícito: los bloques válidos "do not expire", y maxTimeoutSeconds "bounds the Facilitator's polling period ... not expiration". El bloque sigue siendo válido hasta que cambia el frontier del pagador.
Dos consecuencias.
Primera: la única forma que tiene el buyer de retirar un pago sin liquidar es publicar un bloque distinto en la misma cuenta, lo que deja al firmado sin poder procesarse. La spec no lo dice así. Pursekeeper lo propuso como nit opcional en el hilo, y el texto actual (445 líneas, commit de arriba) todavía lo omite. Una librería de buyer que quiera una operación de cancelación tiene que implementarla.
Segunda: un bloque firmado lo puede difundir cualquiera que lo tenga, a cualquier nodo, sin facilitator. El bloque se compromete con payTo a través de link, así que un bloque filtrado solo puede pagarle al receptor previsto. El daño no es robo. Es doble entrega: el seller liquida vía facilitator, el bloque se confirma y un segundo actor también lo presenta. La spec lo maneja con la regla del "Scenario 2": cuando un settle devuelve error_block_already_confirmed, el seller entrega solo si sus propios registros dicen que el recurso no se entregó, con clave el hash del bloque. Es la misma idea de ledger de entregas a la que llegó nuestra auditoría de recovery desde el otro lado.
La spec usa un resultado de settlement de tres vías, no un booleano: confirmado, ya confirmado, esperando confirmación. Para el tercer caso dice que no se entregue, que se vuelva a liquidar y, tras una cota que elige el seller, que se responda 402 otra vez, con una regla para el bloque que confirma tarde. Nuestra auditoría de finality preguntó qué significa un success de settle en cada cadena; esta es la respuesta escrita de una cadena a qué significa "todavía no".
Forks, y quién protege al seller
Entre verify y settle, un pagador malicioso puede publicar un bloque en conflicto con el mismo previous. El que llegue primero al quórum de representatives gana; el otro se rechaza para siempre. Si el seller entregara en verify, lo robarían. El flujo de la spec entrega después de que settle devuelve confirmado, así que perder la carrera del fork significa no entregar.
El apéndice agrega una recomendación de "fork protection": el seller debería recordar el valor de previous de cada intento en vuelo y rechazar un segundo payload con el mismo previous. Es un SHOULD, con el estado en el seller. La cadena impone la seguridad; la memoria del seller solo ahorra trabajo desperdiciado.
El quórum es concreto en la red en vivo. El nodo que consultamos reporta un quórum de 67% del peso online, con 8.54 x 10^37 raw (unos 85.4 millones de XNO) de stake online, y 225,586,751 bloques cementados, 432 unchecked al momento de preguntar. La confirmación en este modelo es el quórum de representatives votando, que la spec equipara con finality irreversible. No probamos la afirmación; es del protocolo.
Historial de review: quién lo ha corrido
Este PR tuvo una review práctica poco común. Pursekeeper corrió su propio facilitator contra borradores sucesivos y envió cuatro sugerencias, todas aceptadas: una razón distinta cuando el frontier se mueve, una sección explícita de no-expiración, copiar el representative desde account_info para no re-delegar en silencio el peso de voto del pagador, y la entrada del work. Cuando el autor agregó un vocabulario de errores y chequeos extra de scheme, red y cuenta, el comentarista aportó test vectors como PR a la rama del autor (kilkelly/x402-nano-exact-scheme-proposal#1, que seguía abierto cuando miramos).
Según el mismo comentarista, tres facilitators independientes implementan el texto: el suyo, la referencia x402nano y gosuda/x402-facilitator. Confirmamos que el repo de gosuda tiene un directorio scheme/nano y que facilitator.pursekeeper.dev/supported responde por exact en nano:mainnet con work: required y el umbral de send. No corrimos esos facilitators. Tampoco verificamos lo que dicen de sellers en vivo, que es suyo.
El resumen honesto: el scheme está más avanzado en implementación que en review. El PR lleva la etiqueta specs y 18 comentarios, y no se ha enviado ninguna review formal. El mismo comentarista dice que la spec de lnbtc recibió 22 comentarios antes del merge; ese número es suyo, no lo contamos.
Qué cambiaríamos
Cuatro ediciones cerrarían los huecos que quedan.
Primera: nombrar el umbral en el chequeo 14 y decir que se calcula sobre previous. Los valores son públicos y el error es fácil.
Segunda: agregar la receta de cancelación a "Blocks have no expiry": publicar cualquier bloque en la misma cuenta, como un bloque change con el mismo representative y balance.
Tercera: declarar el límite de concurrencia en el Summary. Hoy solo se deduce leyendo el chequeo 12 junto a la sección de settlement. Un seller que emite muchos 402 al mismo pagador, como un agente que lanza llamadas en paralelo, necesita saber que la segunda llamada no verificará.
Cuarta: simplificar la lista de chequeos. Los chequeos 7 y 8 verifican ambos la firma, y el 8 describe el cálculo del hash del que depende el 7. El orden también es inusual: el chequeo de existencia del bloque está en la posición 10, antes del chequeo de cuenta en la 11. Es cosmético, pero una spec que otros lenguajes implementan debería tener un único orden canónico de operaciones.
Qué significa para LLM4Agents
Nuestros rails de billing son stablecoins en Solana y Polygon. Nano es una moneda nativa con precio flotante, así que un quote 402 en USD necesitaría un tipo de cambio congelado al momento del quote y una ventana corta. Es la misma forma de riesgo de quote de nuestra auditoría de precios con fecha, en otro lugar. El scheme hoy no encaja con nuestro modelo de precio estable y no proponemos agregarlo.
Aun así vale leerlo como insumo de diseño, porque obliga a tres preguntas que nuestro stack debe responder sea cual sea el rail. ¿Nuestro estado de settlement tiene un tercer valor para "difundido, sin confirmar", o solo éxito y falla? ¿Nuestro ledger de entregas usa el id de settlement como clave para que un pago repetido no se entregue dos veces? ¿Puede una cuenta de buyer hacer compras en paralelo con nosotros, o algún rail la serializa?
El punto del paralelismo es el que tiene dientes. Una flota de agentes que comparte una cuenta fondeada es una configuración normal para un operador. En un rail EIP-3009 funciona. En un rail estilo Nano colapsa a una compra a la vez, y el arreglo es una cuenta fondeada por worker concurrente. Cualquier guía para buyers que publiquemos debería decir qué rails conmutan.
Cómo mantenerse en la frontera
En orden:
Primero, no construir soporte de Nano. Seguir el #3432. El disparador para reconsiderar es una review de maintainer más el aterrizaje de la implementación de referencia, no la cantidad de facilitators.
Segundo, hacer que la interfaz de nuestro facilitator sea de tres valores para settlement (confirmado, pendiente, fallido) y que la entrega use el id de settlement como clave, como hace el Scenario 2. Es independiente del rail y rinde en los casos de preconfirmación que ya medimos en Base.
Tercero, escribir una tabla de rails para buyers: por cada scheme soportado, si los pagos firmados de una misma cuenta conmutan, si un pago firmado expira y cómo cancela un buyer. Nano es la primera fila donde las respuestas son no, no y "publicar otro bloque".
Cuarto, agregar una prueba de compras en paralelo al harness de buyer: N llamadas pagadas concurrentes desde una cuenta, verificar N éxitos. No cuesta nada en los rails actuales y es la prueba de regresión de cualquier rail serializado futuro.
Quinto, mantener la pregunta de FX del quote 402 en la lista de cosas a resolver antes de cualquier rail de activo volátil. Un quote en USD con un monto en un activo flotante necesita un tipo de cambio y una expiración explícitos en la respuesta, no implícitos.
Sexto, seguir a los vecinos: los PRs de scheme de Canton, BSV y Bitcoin Cash siguen abiertos. Cada rail de moneda nativa trae sus propias respuestas a las mismas tres preguntas. Nuestra auditoría de Sui encontró que el estado de dedup termina en la capa que nadie revisa. El primer rail de moneda nativa en hacer merge fijará el precedente de cómo escriben los demás.
Paga por llamada, en stablecoins, sobre una API compatible con OpenAI
Un 402, una firma, más de 345 modelos. Sin suscripción, sin mínimo.
Registra tu agente