← Blog
20 de octubre, 2026 · 14 min

x402 en Solana: un pago, nueve beneficiarios y quién paga el rent

Un pull request abierto permitiría que un pago x402 en Solana pague a hasta nueve destinatarios de forma atómica, y que el facilitator financie cuentas de token que aún no existen. Ambas ideas son útiles. Ambas mueven un riesgo que la spec actual mantiene fuera del alcance del fee payer.

Hoy un pago exact en Solana es una transferencia a un solo payTo. Una plataforma que quiere una comisión, un revendedor que quiere un margen o un facilitator que quiere recuperar sus costos tiene que liquidar ese dinero por otra vía.

El PR #3221, de Ludo Galabru, propone una solución. Se abrió el 2026-08-21, seguía abierto el 2026-10-20 y su último movimiento fue el 2026-10-15. Es solo de spec. Leímos el diff completo y el hilo de revisión, modelamos la transacción que describe y revisamos qué hace con ella el cliente publicado. Las cifras de abajo salen de esas comprobaciones, con fecha.

Qué especifica el PR

El seller agrega extra.splits a los payment requirements. Cada entrada lleva un payTo, un amount absoluto en unidades base, un memo opcional y una bandera ataCreationRequired opcional.

// PaymentRequirements.extra (de la descripción del PR)
{
  "feePayer": "EwWqGE4ZFKLofuestmU4LDdK7XM1N4ALgdZccwYugwGd",
  "memo": "pi_3abc123def456",
  "splits": [
    { "payTo": "3pF8…", "amount": "50000", "memo": "platform fee", "ataCreationRequired": false }
  ]
}

Las reglas son estrictas y cortas:

Sin splits (y sin ataCreationRequired), nada cambia. Esa compatibilidad hacia atrás es el principal argumento del PR.

El PR adapta el modelo de splits del borrador de Solana charge intent en paymentauth.org. Abrimos ese borrador: tiene el mismo arreglo splits y una regla de suma que deja un resto positivo para el destinatario primario.

La capacidad se anuncia, no se asume

La primera ronda de revisión, el 2026-09-15, cambió más el diseño. phdargen (quien propuso un wire type similar para Sui en #2615) objetó que el soporte de splits fuera una política local no anunciada. La revisión del 2026-10-15 lo mueve a /supported:

// /supported, kinds[].extra
{ "feePayer": "EwWq…", "maxSplits": 8, "ataCreationSponsored": true }

Un maxSplits ausente significa cero. Un ataCreationSponsored ausente significa false. Un resource server no debe exceder lo que su facilitator anuncia, y el facilitator rechaza los requirements que lo hagan, con split_count_exceeded o split_ata_creation_not_authorized.

Es el patrón correcto. Nuestro post sobre los endpoints del facilitator cubre cómo funciona /supported; un buyer no puede leer la política privada de un facilitator, así que una política que importa tiene que estar en ese documento.

Meter nueve patas en 1,232 bytes

El PR dice que el techo práctico "puede ser menor que ocho" por el límite de 1,232 bytes de una transacción en Solana, y lo deja ahí. Hicimos la aritmética.

El modelo sigue al cliente publicado. Desempaquetamos @x402/svm 2.28.0 y leímos su código de construcción: un mensaje versión 0, un límite de compute units, un precio de compute units, una TransferChecked y una instrucción Memo. Sin memo del seller escribe un nonce aleatorio de 16 bytes como 32 caracteres hex. Agregamos una TransferChecked por split y, en el segundo caso, una CreateIdempotent por pata. El fee payer y el cliente son los dos firmantes.

# tamaño serializado en bytes, nuestro modelo, memo de 32 bytes, sin address lookup tables
splits   sin creación de ATA   creación de ATA en cada pata
0        496                   602
2        594                   784
4        692                   966
6        790                   1148
7        839                   1239   # sobre 1,232
8        888                   1330   # sobre 1,232

Ocho splits caben con holgura cuando los destinatarios ya tienen sus cuentas de token: 888 bytes. Si creas una cuenta por pata, el techo es de seis splits. Con un memo de seller de 256 bytes, el máximo en el caso con creación es de cuatro splits (1,191 bytes). Sin creación y con ese memo es diez, así que el tope de ocho se mantiene.

Cada instrucción de creación cuesta 91 bytes en nuestro modelo: seis referencias de cuenta, un índice de programa y un payload de un byte, más la clave del owner del destinatario en la tabla de cuentas (las claves del programa ATA y del programa system se pagan una sola vez). Cada transferencia extra cuesta 49 bytes, porque su cuenta de token de destino es la única clave nueva.

Dos advertencias. Es nuestro modelo, no una transacción capturada, y el PR también permite instrucciones Lighthouse y Memo inyectadas por la wallet que agregarían bytes. Y el PR no dice quién decide, por request, entre "ocho splits" y "seis splits con creación". Hoy la respuesta es: nadie lo comprueba hasta que se construye la transacción, y el cliente se entera cuando no le caben las instrucciones. Las address lookup tables podrían subir el techo, pero el PR indica que siguen sujetas a las reglas de la spec base sobre ellas.

Un seller debería calcular len(splits) + count(ataCreationRequired) contra un presupuesto antes de emitir el 402. La spec podría decirlo.

La excepción del rent, y quién puede drenarlo

La segunda función generó el hilo más largo. Una transferencia a una associated token account (ATA) inexistente falla. El issue #1020 (abierto desde 2026-01-23) pide que x402 cree automáticamente la cuenta del seller. El PR responde con una excepción acotada al aislamiento del fee payer: el fee payer puede aparecer únicamente como pagador de una instrucción CreateIdempotent para un destinatario que el seller marcó ataCreationRequired, y solo si el facilitator anuncia el patrocinio. El cliente consiente al firmar.

phdargen objetó primero que permitirlo para los splits pero no para payTo era inconsistente, y que el vector de griefing era peor para los splits, así que había que eliminar el patrocinio. Otro revisor, notorious-d-e-v, sostuvo lo contrario: patrocinar la creación es "uno de los mayores logros", porque el sponsor puede recuperar el rent mediante un split a sí mismo. El autor lo hizo simétrico y opt-in en cada lado.

El PR acota la exposición en "unos 0.002 SOL" por destinatario por mint. La medimos. El 2026-10-20, getMinimumBalanceForRentExemption(165) en mainnet devolvió 1,488,440 lamports (0.00148844 SOL). Una cuenta de 170 bytes devolvió 1,513,840, o sea 5,080 lamports por byte adicional. La cifra es entonces un cuarto menor que la del PR para una cuenta de token simple. Los mints Token-2022 con extensiones necesitan cuentas más grandes, y el costo escala linealmente con el tamaño.

La cota que da el PR es "como máximo una vez por destinatario por mint". Es cierta por destinatario. No es una cota por sponsor, porque los destinatarios los elige el seller, y en x402 cualquier seller es permissionless. Este es nuestro análisis, no una afirmación de la spec:

  1. Un atacante corre un resource server y un cliente.
  2. Cada request nombra un payTo nuevo con ataCreationRequired: true.
  3. El cliente del atacante paga el monto mínimo a esa clave nueva. El sponsor financia una cuenta nueva, 1,488,440 lamports.
  4. El owner de la clave transfiere los tokens de vuelta y cierra la cuenta. El rent vuelve a un destino que el owner elige.

El costo neto del atacante son las fees de transacción, porque el monto del pago le vuelve a sí mismo. Mil requests sacarían unos 1.49 SOL del sponsor. Las mitigaciones del PR son la bandera opt-in, la instrucción idempotente y una referencia a los controles de griefing de la sección 2.2 de la spec base para la rotación de payTo. El split de recuperación de costos ayuda solo si el sponsor puede poner precio en una pata en stablecoin a un costo en SOL y rechazar requests que no lo paguen. La spec no da fórmula, y un split al sponsor en stablecoin tiene que seguir el precio de SOL.

El facilitator ya tiene la información para negarse: el payTo es nuevo, la cuenta no existe y el seller es desconocido. Un sponsor que quiera esta función necesita una allowlist o un presupuesto de rent por seller, y la spec debería decir que se espera un presupuesto de rent.

El cliente publicado ignora los splits

Leímos el código del cliente en @x402/svm 2.28.0 (la versión actual, modificada por última vez el 2026-09-29). Construye el destino desde paymentRequirements.payTo y el monto desde paymentRequirements.amount, y lee solo extra.feePayer, extra.memo y extra.recentBlockhash. Las palabras splits y ataCreationRequired no aparecen en su cliente del esquema exact.

// @x402/svm 2.28.0, cliente exact
const transferIx = getTransferCheckedInstruction({
  source: sourceATA, mint: paymentRequirements.asset,
  destination: destinationATA,                 // ATA de payTo
  amount: BigInt(paymentRequirements.amount),  // el monto completo
  ...
});

Un seller que emite splits a este cliente recibe una transacción que paga el monto completo a payTo. Lo que sigue depende del facilitator:

El PR dice que las redes que no implementan la extensión "MUST reject requirements that carry a non-empty splits array rather than silently ignoring it". Es la regla correcta, y funciona solo si cada facilitator y cada cliente implementa el rechazo. El segundo fallo es el que importa. Es silencioso y falla a favor del merchant, así que nadie reclama.

Un seller puede protegerse hoy leyendo el /supported del facilitator y no emitiendo splits salvo que maxSplits esté presente. El PR lo exige. Del lado del cliente hace falta una regla explícita: rechazar un requirement cuyo extra traiga splits a menos que los entienda, y nunca pagar el monto completo a ciegas. Es también la defensa del cliente contra un servidor malicioso que inyecta un split para desviar fondos, que la sección 5.6 del PR exige verificar al cliente.

Preguntas abiertas en el hilo

El autor dejó dos. ¿Debe la pata primaria conservar su tolerancia al pago en exceso, o deben ser exactas todas las patas? ¿Y deben vivir los splits en línea en el documento SVM o como extensión independiente? En la revisión surgió una tercera: si un memo por split que nunca se verifica merece estar en la spec. El autor lo mantuvo porque un partner necesita identificar al destinatario en la pantalla de consentimiento.

Responderíamos la primera con "exacto en todas partes" para el caso de splits. La tolerancia existe para que una smart wallet pueda redondear fees. Con splits, una smart wallet que paga de más le paga la diferencia al merchant, lo cual es inofensivo pero implica que el resto del merchant no es función del requirement. Para conciliación, lo exacto es más fácil de razonar. Sobre la ubicación, una extensión agnóstica de red es más limpia: nuestra auditoría de Sui cubre otro binding abierto, y el comentario de phdargen dijo que el wire type se parecía a su propuesta para Sui, lo que sugiere que la forma es portable.

El PR no tiene implementación de referencia. Dice que una seguirá en otro PR. Hasta entonces la spec no está probada contra facilitators reales, y cifras como el techo de 1,232 bytes no están confirmadas.

Qué significa para LLM4Agents

Somos un seller de inferencia, pagada en stablecoin por llamada. Los splits nos importan por tres lados.

Primero, los agentes que revenden. Un agente que pone nuestra API delante de sus propios usuarios quiere un margen en cada llamada. Hoy debe operar su propia liquidación. Con splits, el pago único del usuario podría pagarnos a nosotros y al revendedor en una sola transacción atómica, sin hueco de custodia. Eso encaja mejor con la economía agente a agente que un balance agrupado.

Segundo, las comisiones de plataforma. Un marketplace de agentes puede cobrar su comisión en la misma transacción sin retener nunca los fondos del buyer.

Tercero, la amenaza. Todo lo anterior dice que un cliente o facilitator ciego a splits pierde patas en silencio. Nuestros buyers son agentes autónomos que corren la versión de SDK con la que fueron publicados. No podemos asumir que entiendan un campo que no está en su release. El modo de fallo es silencioso: el agente paga, el recurso se sirve, una contraparte queda corta. Tampoco ofreceríamos patrocinio de ATA como facilitator sin un presupuesto de rent por seller, por la razón del análisis de drenaje de arriba.

La ruta de pago que operamos hoy no cambia con este PR. No emitimos splits.

Cómo mantenerse en la frontera

Cinco pasos, en orden.

  1. Agrega una guarda a nuestro propio código cliente: si extra.splits está presente y el SDK instalado no conoce el campo, rechazar la firma. Cuesta pocas líneas y cierra el caso de pérdida silenciosa para cualquier agente que distribuyamos.
  2. Incorpora una comprobación de tamaño de transacción a la emisión de nuestro 402. Cuenta patas e instrucciones de creación contra el presupuesto de 1,232 bytes con el modelo de arriba, y limita a seis splits cuando hay creación.
  3. Sigue el #3221 y el PR de implementación de referencia para @x402/svm. Cuando llegue, córrelo en un fork de Solana contra un facilitator que entienda splits y captura tamaños reales de transacción para reemplazar nuestro modelo.
  4. Si alguna vez patrocinamos la creación de cuentas de token, ponle precio. Fija un presupuesto de rent por seller en lamports, exige un split de recuperación de costos y usa una allowlist de sellers. Vuelve a medir el rent al emitir en lugar de fijar 0.002 SOL.
  5. Decide la historia del revendedor. Si que los agentes revendan nuestra inferencia es un objetivo, los splits son el camino limpio, y conviene diseñar ahora el flujo de registro de revendedores para usarlos cuando los facilitators anuncien maxSplits. Nuestra auditoría de smart wallets cubre la otra mitad: cómo una wallet Squads o Swig pagaría estas transacciones multi-pata vía CPI.

Para el panorama de cadenas, mira el censo de los quince network bindings. De los PRs de esquema abiertos, este es el que más cambia el flujo de dinero, y lo hace sin una sola línea de código publicada.

Paga por llamada, en stablecoins, sobre una API compatible con OpenAI

Un 402, una firma, 345+ modelos. Sin suscripción, sin mínimo.

Registra tu agente