Resumen
Un protocolo estándar para codificar solicitudes de transacciones de Solana dentro de URLs para permitir pagos y otros casos de uso.
Este estándar se inspira en BIP 21 y EIP 681.
Motivación
Un protocolo de URL estándar para solicitar transferencias nativas de SOL, transferencias de Tokens SPL y transacciones de Solana permite una mejor experiencia de usuario en aplicaciones y billeteras del ecosistema Solana.
Estas URLs pueden ser codificadas en códigos QR o etiquetas NFC, o enviadas entre usuarios y aplicaciones para solicitar pagos y componer transacciones.
Las aplicaciones deben asegurarse de que una transacción haya sido confirmada y sea válida antes de liberar bienes o servicios que se estén vendiendo, o conceder acceso a objetos o eventos.
Las billeteras móviles deben registrarse para gestionar el esquema de URL y proporcionar una experiencia fluida pero segura cuando se encuentren URLs de Solana Pay en el entorno.
Al estandarizar un enfoque simple para resolver estos problemas, aseguramos la compatibilidad básica de aplicaciones y billeteras para que los desarrolladores puedan enfocarse en abstracciones de nivel superior.
Especificación: Solicitud de Transferencia
Una URL de solicitud de transferencia de Solana Pay describe una solicitud no interactiva para una transferencia de SOL o Tokens SPL.
solana:<recipient>?amount=<amount>&spl-token=<spl-token>&reference=<reference>&label=<label>&message=<message>&memo=<memo>
La solicitud es no interactiva porque los parámetros en la URL son utilizados por una billetera para componer directamente una transacción.
Destinatario
Se requiere un único campo recipient como el pathname. El valor debe ser la
clave pública codificada en base58 de una cuenta nativa de SOL. No se deben usar
cuentas de token asociadas.
En su lugar, para solicitar una transferencia de Tokens SPL, se debe usar el
campo spl-token para especificar un mint de Token SPL, del cual se debe
derivar la dirección de token asociada del destinatario.
Cantidad
Se permite un solo campo amount como parámetro de consulta opcional. El valor
debe ser un número entero no negativo o un número decimal en unidades de
"usuario". Para SOL, eso es SOL y no lamports. Para tokens, utiliza
uiAmountString y no amount.
0 es un valor válido. Si el valor es un número decimal menor que 1, debe
tener un 0 inicial antes del .. La notación científica está prohibida.
Si no se proporciona un valor, la billetera debe solicitar al usuario la cantidad. Si el número de decimales excede lo admitido para SOL (9) o el SPL Token (específico del mint), la billetera debe rechazar la URL como malformada.
SPL Token
Se permite un solo campo spl-token como parámetro de consulta opcional. El
valor debe ser la clave pública codificada en base58 de una cuenta de mint de
SPL Token.
Si se proporciona el campo, se debe utilizar la convención de
associated token account, y
la billetera debe incluir una instrucción TokenProgram.Transfer o
TokenProgram.TransferChecked como la última instrucción de la transacción.
Si no se proporciona el campo, la URL describe una transferencia nativa de SOL,
y la billetera debe incluir una instrucción SystemProgram.Transfer como la
última instrucción de la transacción en su lugar.
La billetera debe derivar la dirección ATA de los campos recipient e
spl-token. No se admiten transferencias a cuentas de tokens auxiliares.
Referencia
Se permiten múltiples campos reference como parámetros de consulta opcionales.
Los valores deben ser matrices de 32 bytes codificadas en base58. Estos pueden o
no ser claves públicas, dentro o fuera de la curva, y pueden o no corresponder
con cuentas en Solana.
Si se proporcionan los valores, la billetera debe incluirlos en el orden
proporcionado como claves de solo lectura y sin firma en la instrucción
SystemProgram.Transfer o
TokenProgram.Transfer/TokenProgram.TransferChecked en la transacción de
pago. Los valores pueden ser o no únicos para la solicitud de pago, y pueden
corresponder o no a una cuenta en Solana.
Debido a que los validadores de Solana indexan las transacciones mediante estas
claves de cuenta, los valores reference pueden usarse como IDs de cliente (IDs
utilizables antes de conocer la transacción de pago eventual). El método RPC
getSignaturesForAddress
puede usarse para localizar transacciones de esta manera.
Etiqueta
Se permite un solo campo label como parámetro de consulta opcional. El valor
debe ser una cadena UTF-8
codificada en URL
que describa la fuente de la solicitud de transferencia.
Por ejemplo, esto podría ser el nombre de una marca, tienda, aplicación o persona que realiza la solicitud. La billetera debe decodificar la URL del valor y mostrar el valor decodificado al usuario.
Mensaje
Se permite un solo campo message como parámetro de consulta opcional. El valor
debe ser una cadena UTF-8
codificada en URL
que describa la naturaleza de la solicitud de transferencia.
Por ejemplo, esto podría ser el nombre de un artículo que se está comprando, un ID de pedido, o una nota de agradecimiento. La billetera debe decodificar la URL del valor y mostrar el valor decodificado al usuario.
Memo
Se permite un solo campo memo como parámetro de consulta opcional. El valor
debe ser una cadena UTF-8
codificada en URL
que debe incluirse en una instrucción SPL Memo en
la transacción de pago.
La billetera debe decodificar la URL del valor y debería mostrar el valor decodificado al usuario. El memo será registrado por los validadores y no debe incluir información privada o sensible.
Si se proporciona el campo, la billetera debe incluir una instrucción
MemoProgram como la penúltima instrucción de la transacción, inmediatamente
antes de la instrucción de transferencia de SOL o Token SPL, para evitar
ambigüedades con otras instrucciones en la transacción.
Ejemplos
URL que describe una solicitud de transferencia de 1 SOL
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=1&label=Michael&message=Thanks%20for%20all%20the%20fish&memo=OrderId12345
URL que describe una solicitud de transferencia de 0.01 USDC
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=0.01&spl-token=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
URL que describe una solicitud de transferencia de SOL (se solicita al usuario el monto)
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?label=Michael
Especificación: Solicitud de Transacción
Una URL de solicitud de transacción de Solana Pay describe una solicitud interactiva para cualquier transacción de Solana.
solana:<link>
La solicitud es interactiva porque los parámetros en la URL son utilizados por una billetera para realizar una solicitud HTTP y componer una transacción.
Enlace
Se requiere un único campo link como pathname. El valor debe ser una URL
absoluta HTTPS condicionalmente
codificada en URL.
Si la URL contiene parámetros de consulta, debe estar codificada en URL. Se pueden agregar parámetros de consulta del protocolo a esta especificación. Codificar el valor en URL evita conflictos con los parámetros del protocolo.
Si la URL no contiene parámetros de consulta, no debería estar codificada en URL. Esto produce una URL más corta y un código QR menos denso.
En cualquier caso, la billetera debe decodificar la URL del valor. Esto no tiene efecto si el valor no está codificado en URL. Si el valor decodificado no es una URL absoluta HTTPS, la billetera debe rechazarlo como malformado.
Solicitud GET
La billetera debería realizar una solicitud JSON HTTP GET a la URL. La
solicitud no debería identificar la billetera ni al usuario.
La billetera debería realizar la solicitud con un encabezado Accept-Encoding, y la aplicación debería responder con un encabezado Content-Encoding para compresión HTTP.
La billetera debe mostrar el dominio de la URL mientras se realiza la solicitud.
Respuesta GET
La billetera debe manejar los
errores del cliente
HTTP,
errores del servidor,
y
respuestas de redireccionamiento.
La aplicación debe responder con estos, o con una respuesta JSON HTTP OK con
un cuerpo de:
{ "label": "<label>", "icon": "<icon>" }
El valor <label> debe ser una cadena UTF-8 que describa la fuente de la
solicitud de transacción. Por ejemplo, esto podría ser el nombre de una marca,
tienda, aplicación o persona que realiza la solicitud.
El valor <icon> debe ser una URL HTTP o HTTPS absoluta de una imagen de icono.
El archivo debe ser una imagen SVG, PNG o WebP, o la billetera debe rechazarla
como malformada.
La billetera no debe almacenar en caché la respuesta excepto según lo indiquen los encabezados de respuesta de almacenamiento en caché HTTP.
La billetera debe mostrar la etiqueta y renderizar la imagen del icono al usuario.
Solicitud POST
La billetera debe realizar una solicitud JSON HTTP POST a la URL con un cuerpo
de:
{ "account": "<account>" }
El valor <account> debe ser la clave pública codificada en base58 de una
cuenta que puede firmar la transacción.
La billetera debe realizar la solicitud con un encabezado Accept-Encoding, y la aplicación debe responder con un encabezado Content-Encoding para la compresión HTTP.
La billetera debe mostrar el dominio de la URL mientras se realiza la solicitud.
Si se realizó una solicitud GET, la billetera también debe mostrar la etiqueta
y renderizar la imagen del icono de la respuesta.
Respuesta POST
La billetera debe manejar los
errores del cliente
HTTP,
errores del servidor,
y
respuestas de redireccionamiento.
La aplicación debe responder con estos, o con una respuesta JSON HTTP OK con
un cuerpo de:
{ "transaction": "<transaction>" }
El valor <transaction> debe ser una
transacción serializada
codificada en base64. La wallet debe decodificar la transacción en base64 y
deserializarla.
La aplicación puede responder con una transacción parcial o totalmente firmada. La wallet debe validar la transacción como no confiable.
Firmas Vacías
Si las
signatures
de la transacción están vacías:
- La aplicación debe establecer el
feePayeralaccounten la solicitud, o el valor cero (new PublicKey(0)onew PublicKey("11111111111111111111111111111111")). - La aplicación debe establecer el
recentBlockhashal blockhash más reciente, o el valor cero (new PublicKey(0).toBase58()o"11111111111111111111111111111111"). - La wallet debe ignorar el
feePayeren la transacción y establecer elfeePayeralaccounten la solicitud. - La wallet debe ignorar el
recentBlockhashen la transacción y establecer elrecentBlockhashal blockhash más reciente.
Firmas No Vacías
Si las
signatures
de la transacción no están vacías:
- La aplicación debe establecer el
feePayera la clave pública de la primera firma. - La aplicación debe establecer el
recentBlockhashal blockhash más reciente. - La aplicación debe serializar y deserializar la transacción antes de firmarla. Esto garantiza un orden consistente de las claves de cuenta, como solución alternativa para este problema.
- La wallet no debe establecer el
feePayerni elrecentBlockhash. - La wallet debe verificar las firmas y, si alguna no es válida, la wallet debe rechazar la transacción como mal formada.
La wallet solo debe firmar la transacción con el account en la solicitud, y
debe hacerlo únicamente si se espera una firma para el account en la
solicitud.
Si se espera cualquier firma excepto una firma para el account en la
solicitud, la wallet debe rechazar la transacción como maliciosa.
Campo de Mensaje Opcional
La aplicación también puede incluir un campo opcional message en el cuerpo de
la respuesta:
{ "message": "<message>", "transaction": "<transaction>" }
El valor <message> debe ser una cadena UTF-8 que describa la naturaleza de la
respuesta de la transacción.
Por ejemplo, este podría ser el nombre de un artículo que se está comprando, un descuento aplicado a la compra o una nota de agradecimiento. La billetera debe mostrar el valor al usuario.
La billetera y la aplicación deben permitir campos adicionales en el cuerpo de la solicitud y el cuerpo de la respuesta, que pueden ser agregados por especificaciones futuras.
Ejemplos
URL que describe una solicitud de transacción
solana:https://example.com/solana-pay
URL que describe una solicitud de transacción con parámetros de consulta
solana:https%3A%2F%2Fexample.com%2Fsolana-pay%3Forder%3D12345
Ejemplo de Solicitud GET
GET /solana-pay?order=12345 HTTP/1.1Host: example.comConnection: closeAccept: application/jsonAccept-Encoding: br, gzip, deflate
Ejemplo de Respuesta GET
HTTP/1.1 200 OKConnection: closeContent-Type: application/jsonContent-Length: 62Content-Encoding: gzip{"label":"Michael Vines","icon":"https://example.com/icon.svg"}
Ejemplo de Solicitud POST
POST /solana-pay?order=12345 HTTP/1.1Host: example.comConnection: closeAccept: application/jsonAccept-Encoding: br, gzip, deflateContent-Type: application/jsonContent-Length: 57{"account":"mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN"}
Ejemplo de Respuesta POST
HTTP/1.1 200 OKConnection: closeContent-Type: application/jsonContent-Length: 298Content-Encoding: gzip{"message":"Thanks for all the fish","transaction":"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAECC4JMKqNplIXybGb/GhK1ofdVWeuEjXnQor7gi0Y2hMcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQECAAAMAgAAAAAAAAAAAAAA"}
Extensiones
Pueden incorporarse formatos y campos adicionales en esta especificación para habilitar nuevos casos de uso mientras se garantiza la compatibilidad con aplicaciones y billeteras.
Por favor, abre un issue en Github para proponer cambios a la especificación con el fin de solicitar retroalimentación de los desarrolladores de aplicaciones y billeteras.
Un ejemplo real de tal propuesta.
Ver También
- Especificación de Solana Pay v1.1 - Última versión con mejoras
- Guía de Inicio Rápido - Guías de implementación
- Repositorio de GitHub - Implementaciones de referencia
Is this page helpful?