Resumen
Un protocolo estándar para codificar solicitudes de transacciones de Solana dentro de URLs para habilitar pagos y otros casos de uso.
Se ha alcanzado un consenso general sobre esta especificación, y existen implementaciones en Phantom, FTX y Slope.
Este estándar se inspira en BIP 21 y EIP 681.
Motivación
Un protocolo URL estándar para solicitar transferencias nativas de SOL, transferencias de tokens SPL y transacciones de Solana permite una mejor experiencia de usuario entre aplicaciones y billeteras en el ecosistema de Solana.
Estas URLs pueden codificarse en códigos QR o etiquetas NFC, o enviarse 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 manejar el esquema de URL para proporcionar una experiencia fluida pero segura cuando se encuentran URLs de Solana Pay en el entorno.
Al estandarizar un enfoque simple para resolver estos problemas, garantizamos una 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 ruta. El valor debe ser la pubkey
codificada en base58 de una cuenta nativa de SOL. No se deben usar associated
token accounts.
En su lugar, para solicitar una transferencia de SPL Token, se debe utilizar el
campo spl-token para especificar un mint de SPL Token, a partir del cual se
debe derivar la dirección de token asociada del destinatario.
Cantidad
Se permite un único campo amount como parámetro de consulta opcional. El valor
debe ser un número entero no negativo o decimal de unidades de "usuario". Para
SOL, eso es SOL y no lamports. Para tokens, utilice
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 .. Se prohíbe la notación científica.
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 mal formada.
SPL Token
Se permite un único campo spl-token como parámetro de consulta opcional. El
valor debe ser la clave pública codificada en base58 de una cuenta 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 a partir de los campos recipient y
spl-token. No se admiten transferencias a cuentas de token auxiliares.
Referencia
Se permiten múltiples campos reference como parámetros de consulta opcionales.
Los valores deben ser arreglos de 32 bytes codificados 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 o no ser únicos para la solicitud de pago, y pueden o
no corresponder a una cuenta en Solana.
Debido a que los validadores de Solana indexan las transacciones por estas
claves de cuenta, los valores reference pueden utilizarse como IDs de cliente
(IDs utilizables antes de conocer la eventual transacción de pago). El método
RPC
getSignaturesForAddress
puede utilizarse para localizar transacciones de esta manera.
Etiqueta
Se permite un único campo label como parámetro de consulta opcional. El valor
debe ser una cadena UTF-8
codificada en URL
que describa el origen 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 único 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 único 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üedad 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 hacer una solicitud HTTP y componer una transacción.
Enlace
Se requiere un único campo link como pathname. El valor debe ser una URL HTTPS
absoluta condicionalmente
codificada en URL.
Si la URL contiene parámetros de consulta, debe estar codificada en URL. Los parámetros de consulta del protocolo pueden agregarse a esta especificación. Codificar el valor en URL previene conflictos con los parámetros del protocolo.
Si la URL no contiene parámetros de consulta, no debe 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 el valor. Esto no tiene efecto si el valor no está codificado en URL. Si el valor decodificado no es una URL HTTPS absoluta, la billetera debe rechazarlo como mal formado.
Solicitud GET
La billetera debe realizar una solicitud JSON GET HTTP a la URL. La solicitud
no debe identificar la billetera ni al usuario.
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.
Respuesta GET
La billetera debe manejar las respuestas HTTP de
error del cliente,
error del servidor
y
redirección.
La aplicación debe responder con estas, 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 rechazarlo
como malformado.
La billetera no debe almacenar en caché la respuesta excepto según lo indiquen las cabeceras 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 pueda firmar la transacción.
La billetera debe realizar la solicitud con una cabecera Accept-Encoding, y la aplicación debe responder con una cabecera 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 las respuestas HTTP de
error del cliente,
error del servidor
y
redirección.
La aplicación debe responder con estas, o con una respuesta JSON HTTP OK con
un cuerpo de:
{ "transaction": "<transaction>" }
El valor de <transaction> debe ser una
transacción serializada
codificada en base64. La billetera debe decodificar la transacción en base64 y
deserializarla.
La aplicación puede responder con una transacción parcial o totalmente firmada. La billetera 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
feePayeren elaccountde la solicitud, o en el valor cero (new PublicKey(0)onew PublicKey("11111111111111111111111111111111")). - La aplicación debe establecer el
recentBlockhashen el blockhash más reciente, o en el valor cero (new PublicKey(0).toBase58()o"11111111111111111111111111111111"). - La billetera debe ignorar el
feePayerde la transacción y establecer elfeePayeren elaccountde la solicitud. - La billetera debe ignorar el
recentBlockhashde la transacción y establecer elrecentBlockhashen el blockhash más reciente.
Si las
signatures
de la transacción no están vacías:
- La aplicación debe establecer el
feePayeren la clave pública de la primera firma. - La aplicación debe establecer el
recentBlockhashen el 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 billetera no debe establecer el
feePayerni elrecentBlockhash. - La billetera debe verificar las firmas y, si alguna no es válida, la billetera debe rechazar la transacción como malformada.
La billetera solo debe firmar la transacción con el account de la solicitud, y
debe hacerlo únicamente si se espera una firma para el account de la
solicitud.
Si se espera cualquier firma que no sea una firma para el account de la
solicitud, la billetera debe rechazar la transacción como maliciosa.
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, esto 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 en el cuerpo de la respuesta, que pueden ser añadidos por futuras especificaciones.
Ejemplo
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
Solicitud GET
GET /solana-pay?order=12345 HTTP/1.1Host: example.comConnection: closeAccept: application/jsonAccept-Encoding: br, gzip, deflate
Respuesta GET
HTTP/1.1 200 OKConnection: closeContent-Type: application/jsonContent-Length: 62Content-Encoding: gzip{"label":"Michael Vines","icon":"https://example.com/icon.svg"}
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"}
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
Formatos y campos adicionales pueden incorporarse a 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 desarrolladores de aplicaciones y billeteras.
Is this page helpful?