Los confidential transfers de Solana volvieron. x402 no los ve.
Solana volvió a encender las transferencias cifradas de stablecoins en junio, y hace cuatro días logró que entren en una sola transacción. Todo facilitator de x402 sobre SVM verifica pagos leyendo un monto que ya no está ahí.
El scheme exact de x402 para Solana se apoya en una sola suposición: un facilitator puede mirar una transacción firmada, encontrar la transferencia y leer el número. Recorrimos esa maquinaria en x402 en Solana y el contrato de verify/settle en la auditoría del facilitator. La suposición se sostenía porque toda transferencia de stablecoin en Solana llevaba su monto en texto plano dentro de la instrucción.
La extensión de confidential transfers de Token-2022 rompe esa suposición a propósito. Cifra balances y montos con twisted ElGamal, prueba la corrección con zero-knowledge proofs y deja en la cadena una transferencia cuyo tamaño nadie puede leer. Se apagó en toda la red en junio de 2025 tras un bug en el verificador de pruebas. Volvió a estar activa. Esto es una auditoría de qué regresó, cuánto cuesta y dónde exactamente choca con x402.
Leer los feature gates directo de mainnet
No le creas a un blog —tampoco a este— cuando dice que una feature de Solana está viva. Los feature gates son cuentas comunes propiedad de Feature111111111111111111111111111111111111, con nueve bytes: un byte de tag Option y un u64 little-endian con el slot de activación. Agave declara los dos gates relevantes en su crate feature-set como disable_zk_elgamal_proof_program y reenable_zk_elgamal_proof_program.
# el gate de re-enable
curl -s https://api.mainnet-beta.solana.com -X POST \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"getAccountInfo",
"params":["zkexuyPRdyTVbZqEAREueqL2xvvoBhRgth9xGSc1tMN",
{"encoding":"base64"}]}'
# data: "AQAlSRkAAAAA" -> tag=1, slot=424224000
Decodificado contra getBlockTime, la cronología es inequívoca. El gate de disable zkdoVwnSFnSLtGJG7irJPEYUpmb4i7sGMGcnN6T9rnC se activó en el slot 347.760.000 — el primer slot de la época 805, 2025-06-19T06:07:13Z. El gate de re-enable se activó en el slot 424.224.000, primer slot de la época 982, 2026-06-04T10:18:07Z. El gate de disable no se volvió a usar.
El gate solo no alcanzaba: Token-2022 había sido parcheado para rechazar las instrucciones confidenciales. Su registro en el upgradeable loader muestra que el programa se redesplegó por última vez en el slot 427.147.035, 2026-06-17T20:57:58Z, dos semanas después del gate del runtime. Esa es la fecha en que la extensión quedó realmente usable de punta a punta, y la documentación de Confidential Balances ya no lleva la advertencia de feature deshabilitada.
Cómo se ve hoy un confidential transfer
La segunda fecha importa tanto como la primera. SIMD-0385 sube el tamaño máximo de transacción de 1.232 a 4.096 bytes y mueve la configuración de compute budget a un bitmask en el header. Su gate, txv1aq4pp281K9um3tnPgkfX8UqtFT6wcVW3hNezGLL, se activó en el slot 447.120.000 — época 1035, 2026-09-15T01:04:23Z. Hace cuatro días.
Esa es la diferencia entre un confidential transfer como problema de orquestación y un confidential transfer como transacción. Las pruebas son grandes; bajo el límite viejo había que verificarlas en transacciones separadas que escribían en cuentas temporales de proof context state, que luego el token program leía y que alguien tenía que cerrar después para recuperar la renta. Tres o cuatro transacciones dependientes, cada una un punto de falla que un agente debe reintentar.
Esta salió de mainnet esta mañana: versión 1, 2.687 bytes, 289.983 compute units, 10.000 lamports de fee. El log de instrucciones completo:
Program log: Instruction: TakePrivateLink
ConfidentialTransferInstruction::ApplyPendingBalance 7.968 CU
ConfidentialTransferInstruction::Transfer 15.363 CU
ConfidentialTransferInstruction::EmptyAccount 1.835 CU
Instruction: CloseAccount 1.724 CU
Program ZkE1Gama1Proof111...: VerifyCiphertextCommitmentEquality
Program ZkE1Gama1Proof111...: VerifyBatchedGroupedCiphertext3HandlesValidity
Program ZkE1Gama1Proof111...: VerifyBatchedRangeProofU128
Program ZkE1Gama1Proof111...: VerifyZeroCiphertext
Mira la estructura de costo. El trabajo propio del token program es trivial — la instrucción Transfer consumió 15.363 CU. El programa de la aplicación consumió 61.183 CU por todo lo que hizo. Los ~229.000 CU restantes, cerca de cuatro quintos de la transacción, son el runtime verificando cuatro zero-knowledge proofs: una equality proof de que el nuevo ciphertext de balance del emisor cifra el mismo valor que un commitment fresco, una grouped validity proof de que los ciphertexts del monto están bien formados bajo las llaves de origen, destino y auditor opcional, una batched range proof de que ningún monto hace underflow, y una zero-ciphertext proof para cerrar la cuenta.
El envío correspondiente, en el otro sentido, es aún más denso: 2.945 bytes, 356.204 CU, 15.000 lamports, y una secuencia que dice todo sobre el estado actual del rail.
Instruction: Wrap // SPL Token -> Token-2022
Instruction: MintTo
ConfidentialTransferInstruction::Deposit
ConfidentialTransferInstruction::ApplyPendingBalance
Instruction: Reallocate // "account needs resize, +300 bytes"
ConfidentialTransferInstruction::ConfigureAccount
ConfidentialTransferInstruction::Transfer
El emisor tuvo que envolver primero un token SPL clásico en un mint de Token-2022, porque el token que realmente tiene no puede hacer esto. Después depositar en el pending balance confidencial, aplicarlo, agrandar la cuenta del receptor en 300 bytes, configurarla con una llave pública ElGamal y recién entonces transferir. Siete pasos, una transacción, gracias a un feature gate de cuatro días.
Por qué el scheme exact de x402 no puede verificarlo
Ahora pon esa transacción frente a un facilitator. El scheme exact para SVM es explícito sobre qué constituye un pago:
La transacción MUST resultar en una transferencia de al menosPaymentRequirements.amount, del activo identificado porPaymentRequirements.asset, hacia el destinatario identificado porPaymentRequirements.payTo(la Associated Token Account derivada depayToyasset), usandospl-tokenTransferCheckedotoken-2022TransferChecked.
El spec exige después que un verificador confirme de forma determinista el mint correcto, la cuenta destino, el monto y el token program, y que exactamente una transferencia que cumpla esos requisitos aparezca entre las instrucciones top-level y el trace completo de CPI. Cero coincidencias es rechazo. Dos coincidencias también.
Un confidential transfer falla las tres patas de esa prueba, y las falla estructuralmente, no por accidente.
No hay TransferChecked
ConfidentialTransferInstruction::Transfer es otra instrucción con otro discriminador. El path estático del verificador de referencia busca un TransferChecked top-level; el path de smart wallet simula con innerInstructions: true y busca lo mismo en el trace de CPI. Ninguno lo encuentra. La transacción se rechaza con "no matching transfer", que es el resultado correcto por la razón equivocada — el pago pudo haber ocurrido perfectamente.
No hay monto que comparar
Aun si el matcher aprendiera el nuevo discriminador, la data de la instrucción lleva ciphertexts y referencias a pruebas, no un u64. No hay comparación posible contra PaymentRequirements.amount. El facilitator no puede distinguir un pago correcto de un pago de una unidad base, que es exactamente la propiedad que la extensión fue construida para dar.
El delta de balance es cero
La defensa post-settlement del spec contra TOCTOU es un fallback: si las inner instructions no están disponibles, compara el balance de la ATA destino antes y después y exige balanceAfter - balanceBefore >= required. En la transacción de envío de arriba, el balance público de ambas partes tras la ejecución es 0. El valor queda en el available balance cifrado. Un chequeo de delta sobre un confidential transfer devuelve cero para un pago de cualquier tamaño.
Esto no es un bug de x402. Es la consecuencia directa de un scheme basado en outcome definido sobre estado públicamente legible chocando con una extensión de token cuyo propósito es volver ese estado ilegible. Cualquier capa de verificación construida sobre la misma suposición — indexers, exportes contables, los flujos de disputa de la capa de extensiones de x402 — hereda el mismo punto ciego.
Qué sigue siendo público igual
Antes de diseñar alrededor del problema, conviene ser preciso sobre cuánta privacidad hay realmente en oferta. La documentación es directa: solo los montos de transferencia y los balances son privados; las direcciones de las token accounts siguen públicas. Emisor, receptor, timestamp y la forma del tráfico siguen en cadena. Para un agente que paga al mismo gateway 400 veces al día, el grafo de contrapartes es la señal interesante, y los confidential transfers no lo tocan.
Los bordes también filtran. Deposit y Withdraw mueven valor entre la mitad pública y la confidencial de la misma cuenta, y sus montos van en texto plano. Una de las transacciones de nuestra muestra es un Withdraw que parsea limpio a amount: 10000, decimals: 6 — un centavo, a la vista. Un agente que recarga un balance confidencial y lo drena por factura publicó ambos números y escondió solo el medio.
Después está la llave de auditor. Un mint puede llevar una llave pública ElGamal global de auditor; cuando está seteada, todo confidential transfer debe incluir el monto cifrado bajo ella, y la grouped validity proof es lo que fuerza a que los tres ciphertexts cifren el mismo valor. Quien tenga la llave secreta de auditor lee todos los montos de ese mint. Es rotable — UpdateMintData en la interfaz de Token-2022 lleva tanto auto_approve_new_accounts como una nueva auditor_elgamal_pubkey — y la rotación aplica solo a transferencias futuras.
La liquidez todavía no está
La pregunta interesante no es si esto funciona sino si alguien lo usa. Leímos las cuentas de los mints directamente y parseamos la lista TLV de extensiones.
PYUSD 2b1kV6Dk... token-2022 supply 726.572.154,38
ConfidentialTransferMint auto_approve=false auditor=none
authority 2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk
USDG 2u1tszSe... token-2022 supply 625.306.945,83
ConfidentialTransferMint auto_approve=false auditor=none
authority 2apBGMsS6ti9RyF5TwQTDswXBWskiJP2LD4cUEDqYJjk
USDC EPjFWdd5... spl-token mint de 82 bytes, sin extensiones
USDT Es9vMFrz... spl-token mint de 82 bytes, sin extensiones
EURC HzwqbKZw... spl-token mint de 82 bytes, sin extensiones
Dos cosas saltan. Primero, las dos stablecoins Token-2022 más grandes de Solana tienen la extensión inicializada pero con auto_approve_new_accounts en false, y ambas apuntan a la misma autoridad de confidential transfer. En esos mints un agente no puede autoservirse: después de ConfigureAccount, la cuenta debe ser aprobada por esa autoridad antes de poder usarse. La privacidad permisionada es una decisión de producto que un emisor tiene todo el derecho de tomar, y también es una dependencia dura en un camino de pago autónomo.
Segundo, USDC, USDT y EURC en Solana son mints SPL Token planos de 82 bytes. No pueden hacer confidential transfers en absoluto. La única ruta es envolverlos en un mint de Token-2022, que es exactamente lo que vimos: el mint destino de nuestra transacción de muestra es un wrapped mint creado por el programa SPL Token Wrap pWrapnbzNPTx9aZPAp3gpxAUrs3H4QQ1GHWMPMbDba2, y su PDA backpointer registra el mint sin envolver como Es9vMFrz… — USDT.
Su supply total es de 1.190.000 unidades base. 1,19 USDT. Un segundo mint con capacidad confidencial en la misma muestra tiene 0,042 unidades. Sobre la ventana de índice disponible del RPC público el 2026-09-19 — 2 horas y 12 minutos, de 03:49 a 06:01 UTC — exactamente 36 transacciones tocaron el proof program ZK ElGamal, ninguna falló, y las que pudimos decodificar fueron cuatro Transfer, cuatro ConfigureAccount y un Withdraw, todas movidas por un único programa de aplicación. Ninguna involucró PYUSD ni USDG.
Entonces: la criptografía está viva, la ergonomía acaba de mejorar un orden de magnitud, los emisores tienen el interruptor instalado pero sin accionar, y la liquidez wrapped que realmente se mueve es como un dólar. Así se ve un rail cuatro días después de que se removiera la restricción que lo volvía doloroso.
Tres formas de verificar un pago que no puedes leer
Si el settlement confidencial es hacia donde van eventualmente los pagos en stablecoins — y hay razones reales para que una empresa no publique su gasto de inferencia por llamada — entonces x402 necesita una historia de verificación que no dependa de leer el monto. Hay tres disponibles hoy, en orden creciente de cuánto ceden.
Darle al facilitator una llave de auditor. El encaje más limpio con el spec actual: el facilitator tiene el secreto de auditor del mint, descifra el monto y corre la misma comparación que corre hoy. El problema es la granularidad. La llave de auditor es por mint, no por merchant, así que un agente que paga a través de ese facilitator en ese mint le expone todos los montos. Eso es privacidad frente al público, no frente a la contraparte — un trade razonable para flujos regulados, inútil como default general.
Liquidar en público, custodiar en privado. Pagar con un TransferChecked común, exactamente como hoy, y usar balances confidenciales solo para tesorería entre pagos. La verificación no cambia, la extensión hace trabajo real — un observador ve los pagos pero no el runway del agente — y la filtración es el monto por transacción, que para inferencia medida ya es el número menos sensible. Es la única opción que no requiere ningún cambio de protocolo.
Mover la afirmación fuera de la cadena. x402 ya tiene una extensión offer-and-receipt en la que el resource server emite un recibo firmado con version, network, resourceUrl, payer, issuedAt y un transaction opcional. Su nota de diseño dice que los recibos son mínimos por default para reducir el riesgo de correlación — el mismo instinto que los confidential transfers, aplicado una capa más arriba. Un payee que puede descifrar su propio monto entrante es el emisor natural de una attestation de que el monto fue correcto. El facilitator deja de probar el pago y pasa a retransmitir una afirmación sobre él, lo cual es una garantía genuinamente más débil y debe etiquetarse como tal.
Qué significa para LLM4Agents
El gateway está del lado de la verificación, no del lado del pago. Nuestro path SVM deriva una ATA destino, hace match de exactamente un TransferChecked y compara un monto. Ese código es correcto hoy y seguirá siéndolo: nada de los confidential transfers cambia cómo se verifica una transferencia pública. La exposición es más angosta y más específica.
El primer ítem concreto es la calidad del error. Un agente que hoy pague con un confidential transfer de Token-2022 recibe un rechazo genérico de "no matching transfer", que se lee como un bug del cliente y le va a costar una tarde a alguien. Un facilitator que reconozca ConfidentialTransferInstruction::Transfer en el trace y devuelva una razón distinta y honesta — unsupported: confidential amount, x402 exact requiere una transferencia legible — convierte una sesión de debugging en un fix de una línea. Reconocer una instrucción no es lo mismo que soportarla, y son unas pocas horas de trabajo.
El segundo es la frontera contable. Todo lo que está aguas abajo del settlement en un gateway medido — reconciliación de uso, el path de refund de upto que auditamos en prompt caching versus billing medido, evidencia de disputas — asume que el monto liquidado es legible desde el estado de la cadena. Si alguna parte de esa reconciliación se apunta alguna vez a un rail confidencial, lee cero en silencio en vez de fallar. Las suposiciones que devuelven una respuesta incorrecta pero plausible son peores que las que revientan.
El tercero es estratégico, y rima con el argumento de wallets de agentes con attestation en TEE. La privacidad para pagos de agentes no es una feature, es un stack: montos confidenciales en cadena, un entorno de ejecución atestiguado que guarda las llaves, y recibos que revelan solo lo que la contraparte necesita. La capa de montos acaba de volver a estar online tras quince meses. Vale la pena entenderla antes de que un cliente pregunte si su gasto por llamada es público, porque la respuesta honesta hoy es que sí.
Cómo mantenerse en la frontera
Pasos concretos, en el orden en que rinden.
1. Agregar detección de confidential transfers al verificador SVM. Detectar los discriminadores de confidential transfer de Token-2022 en el top-level y en el trace de CPI, y devolver un código de error específico en lugar del no-match genérico. Barato, defensivo, útil de inmediato. Hacer lo mismo para el caso en que el delta de balance de la ATA destino es cero pero hay una instrucción confidencial de Token-2022 presente — esa combinación es diagnóstica.
2. Fijar la suposición del token program en tests. Escribir un test de regresión que afirme que el verificador rechaza un confidential transfer en vez de aceptarlo por alguna vía de delta de balance. El modo de falla a cubrir no es el rechazo, es un fallback que lee cero y lo llama match.
3. Vigilar los dos gates, no los blog posts. reenable_zk_elgamal_proof_program y enable_tx_v1 se consultan con una llamada RPC cada uno. Un job semanal que decodifique ambos — y relea los mints de PYUSD y USDG buscando un cambio en auto_approve_new_accounts o una llave de auditor recién seteada — es un script de cinco líneas y la señal más temprana posible de que un emisor decidió que los pagos confidenciales en stablecoin están listos.
4. Seguir transaction v1 por razones ajenas a la privacidad. Un límite de 4.096 bytes cambia qué entra de forma atómica en SVM en general: traces de CPI más grandes, más instrucciones junto a un pago, flujos de smart wallet más ricos dentro del sobre de una sola transacción que el scheme exact verifica. El path de verificación basado en simulación debería re-medirse contra transacciones v1 antes de que alguien más descubra el caso borde.
5. Definir la postura de privacidad antes de que la pidan. La respuesta realista de corto plazo para un gateway de inferencia es liquidar en público y custodiar en privado: sin cambio de protocolo, sin llave de auditor, sin dependencia de un mint permisionado. Decirlo explícitamente, y estar listos para revisarlo el día en que un emisor grande ponga auto_approve_new_accounts en true.
Pagos que un agente puede verificar, en un gateway que explica sus rechazos
Routing compatible con OpenAI, settlement x402 y códigos de error que nombran la razón real.
Registrar un agente