Riepilogo
Un protocollo standard per codificare richieste di transazioni Solana all'interno di URL per abilitare pagamenti e altri casi d'uso.
Questo standard si ispira a BIP 21 e EIP 681.
Motivazione
Un protocollo URL standard per richiedere trasferimenti nativi di SOL, trasferimenti di token SPL e transazioni Solana consente una migliore esperienza utente tra app e wallet nell'ecosistema Solana.
Questi URL possono essere codificati in codici QR o tag NFC, oppure inviati tra utenti e applicazioni per richiedere pagamenti e comporre transazioni.
Le applicazioni devono assicurarsi che una transazione sia stata confermata e sia valida prima di rilasciare beni o servizi in vendita, o concedere l'accesso a oggetti o eventi.
I wallet mobili dovrebbero registrarsi per gestire lo schema URL per fornire un'esperienza fluida ma sicura quando si incontrano URL Solana Pay nell'ambiente.
Standardizzando un approccio semplice per risolvere questi problemi, garantiamo una compatibilità di base tra applicazioni e wallet affinché gli sviluppatori possano concentrarsi su astrazioni di livello superiore.
Specifica: Richiesta di Trasferimento
Un URL di richiesta di trasferimento Solana Pay descrive una richiesta non interattiva per un trasferimento di SOL o token SPL.
solana:<recipient>?amount=<amount>&spl-token=<spl-token>&reference=<reference>&label=<label>&message=<message>&memo=<memo>
La richiesta è non interattiva perché i parametri nell'URL vengono utilizzati da un wallet per comporre direttamente una transazione.
Destinatario
È richiesto un singolo campo recipient come pathname. Il valore deve essere la
chiave pubblica codificata in base58 di un account SOL nativo. Non devono essere
utilizzati associated token account.
Invece, per richiedere un trasferimento di token SPL, deve essere utilizzato il
campo spl-token per specificare un mint di token SPL, da cui deve essere
derivato l'indirizzo del token associato del destinatario.
Importo
È consentito un singolo campo amount come parametro di query facoltativo. Il
valore deve essere un numero intero non negativo o un numero decimale di unità
"utente". Per SOL, questo significa SOL e non lamport. Per i token, utilizzare
uiAmountString e non amount.
0 è un valore valido. Se il valore è un numero decimale inferiore a 1, deve
avere uno 0 iniziale prima del .. La notazione scientifica è vietata.
Se non viene fornito un valore, il wallet deve richiedere all'utente l'importo. Se il numero di cifre decimali supera quanto supportato per SOL (9) o per lo SPL Token (specifico del mint), il wallet deve rifiutare l'URL come non valido.
Token SPL
È consentito un singolo campo spl-token come parametro di query facoltativo.
Il valore deve essere la chiave pubblica codificata in base58 di un account mint
di token SPL.
Se il campo viene fornito, deve essere utilizzata la convenzione
Associated Token Account e il
wallet deve includere un'istruzione TokenProgram.Transfer o
TokenProgram.TransferChecked come ultima istruzione della transazione.
Se il campo non viene fornito, l'URL descrive un trasferimento nativo di SOL e
il wallet deve includere invece un'istruzione SystemProgram.Transfer come
ultima istruzione della transazione.
Il wallet deve derivare l'indirizzo ATA dai campi recipient e spl-token. I
trasferimenti a token account ausiliari non sono supportati.
Riferimento
Sono consentiti più campi reference come parametri di query facoltativi. I
valori devono essere array di 32 byte codificati in base58. Questi possono
essere o meno chiavi pubbliche, sulla curva o al di fuori di essa, e possono
corrispondere o meno ad account su Solana.
Se i valori sono forniti, il wallet deve includerli nell'ordine fornito come
chiavi di sola lettura, non firmatarie, nell'istruzione SystemProgram.Transfer
o TokenProgram.Transfer/TokenProgram.TransferChecked nella transazione di
pagamento. I valori possono essere univoci o meno per la richiesta di pagamento
e possono corrispondere o meno a un account su Solana.
Poiché i validator di Solana indicizzano le transazioni tramite queste chiavi
account, i valori reference possono essere utilizzati come ID cliente (ID
utilizzabili prima di conoscere l'eventuale transazione di pagamento). Il metodo
RPC
getSignaturesForAddress
può essere utilizzato per localizzare le transazioni in questo modo.
Etichetta
È consentito un singolo campo label come parametro di query facoltativo. Il
valore deve essere una stringa UTF-8
codificata URL
che descrive la fonte della richiesta di trasferimento.
Ad esempio, potrebbe essere il nome di un brand, negozio, applicazione o persona che effettua la richiesta. Il wallet deve decodificare l'URL del valore e visualizzare il valore decodificato all'utente.
Messaggio
È consentito un singolo campo message come parametro di query facoltativo. Il
valore deve essere una stringa UTF-8
codificata URL
che descrive la natura della richiesta di trasferimento.
Ad esempio, potrebbe essere il nome di un articolo acquistato, un ID ordine o un messaggio di ringraziamento. Il wallet deve decodificare l'URL del valore e visualizzare il valore decodificato all'utente.
Memo
È consentito un singolo campo memo come parametro di query facoltativo. Il
valore deve essere una stringa UTF-8
codificata URL
che deve essere inclusa in un'istruzione SPL Memo
nella transazione di pagamento.
Il wallet deve decodificare l'URL del valore e dovrebbe visualizzare il valore decodificato all'utente. Il memo verrà registrato dai validator e non deve includere informazioni private o sensibili.
Se il campo viene fornito, il wallet deve includere un'istruzione MemoProgram
come penultima istruzione della transazione, immediatamente prima
dell'istruzione di trasferimento SOL o SPL Token, per evitare ambiguità con
altre istruzioni nella transazione.
Esempi
URL che descrive una richiesta di trasferimento di 1 SOL
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=1&label=Michael&message=Thanks%20for%20all%20the%20fish&memo=OrderId12345
URL che descrive una richiesta di trasferimento di 0,01 USDC
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=0.01&spl-token=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
URL che descrive una richiesta di trasferimento di SOL (l'utente viene richiesto di inserire l'importo)
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?label=Michael
Specifica: Richiesta di Transazione
Un URL di richiesta di transazione Solana Pay descrive una richiesta interattiva per qualsiasi transazione Solana.
solana:<link>
La richiesta è interattiva perché i parametri nell'URL vengono utilizzati da un wallet per effettuare una richiesta HTTP per comporre una transazione.
Link
È richiesto un singolo campo link come pathname. Il valore deve essere un URL
assoluto HTTPS condizionalmente
codificato in URL.
Se l'URL contiene parametri di query, deve essere codificato in URL. I parametri di query del protocollo possono essere aggiunti a questa specifica. La codifica URL del valore previene conflitti con i parametri del protocollo.
Se l'URL non contiene parametri di query, non dovrebbe essere codificato in URL. Questo produce un URL più breve e un codice QR meno denso.
In entrambi i casi, il wallet deve decodificare l'URL. Questo non ha effetto se il valore non è codificato in URL. Se il valore decodificato non è un URL assoluto HTTPS, il wallet deve rifiutarlo come malformato.
Richiesta GET
Il wallet dovrebbe effettuare una richiesta JSON HTTP GET all'URL. La
richiesta non dovrebbe identificare il wallet o l'utente.
Il wallet dovrebbe effettuare la richiesta con un header Accept-Encoding, e l'applicazione dovrebbe rispondere con un header Content-Encoding per la compressione HTTP.
Il wallet dovrebbe visualizzare il dominio dell'URL mentre viene effettuata la richiesta.
Risposta GET
Il wallet deve gestire le risposte HTTP di
errore client,
errore server
e di
reindirizzamento.
L'applicazione deve rispondere con queste, oppure con una risposta HTTP OK
JSON con un corpo di:
{ "label": "<label>", "icon": "<icon>" }
Il valore <label> deve essere una stringa UTF-8 che descrive la fonte della
richiesta di transazione. Ad esempio, potrebbe essere il nome di un marchio,
negozio, applicazione o persona che effettua la richiesta.
Il valore <icon> deve essere un URL HTTP o HTTPS assoluto di un'immagine
icona. Il file deve essere un'immagine SVG, PNG o WebP, altrimenti il wallet
deve rifiutarlo come malformato.
Il wallet non dovrebbe memorizzare nella cache la risposta se non come indicato dalle intestazioni di risposta del caching HTTP.
Il wallet dovrebbe visualizzare l'etichetta e renderizzare l'immagine icona all'utente.
Richiesta POST
Il wallet deve effettuare una richiesta HTTP POST JSON all'URL con un corpo
di:
{ "account": "<account>" }
Il valore <account> deve essere la chiave pubblica codificata in base58 di un
account che può firmare la transazione.
Il wallet dovrebbe effettuare la richiesta con un header Accept-Encoding, e l'applicazione dovrebbe rispondere con un header Content-Encoding per la compressione HTTP.
Il wallet dovrebbe visualizzare il dominio dell'URL mentre viene effettuata la
richiesta. Se è stata effettuata una richiesta GET, il wallet dovrebbe anche
visualizzare l'etichetta e renderizzare l'immagine icona dalla risposta.
Risposta POST
Il wallet deve gestire le risposte HTTP di
errore client,
errore server
e di
reindirizzamento.
L'applicazione deve rispondere con queste, oppure con una risposta HTTP OK
JSON con un corpo di:
{ "transaction": "<transaction>" }
Il valore <transaction> deve essere una
transazione serializzata
codificata in base64. Il wallet deve decodificare la transazione da base64 e
deserializzarla.
L'applicazione può rispondere con una transazione parzialmente o completamente firmata. Il wallet deve validare la transazione come non attendibile.
Firme Vuote
Se le
signatures
della transazione sono vuote:
- L'applicazione dovrebbe impostare il
feePayeralaccountnella richiesta, oppure al valore zero (new PublicKey(0)onew PublicKey("11111111111111111111111111111111")). - L'applicazione dovrebbe impostare il
recentBlockhashall' ultimo blockhash, oppure al valore zero (new PublicKey(0).toBase58()o"11111111111111111111111111111111"). - Il wallet deve ignorare il
feePayernella transazione e impostare ilfeePayeralaccountnella richiesta. - Il wallet deve ignorare il
recentBlockhashnella transazione e impostare ilrecentBlockhashall' ultimo blockhash.
Firme Non Vuote
Se le
signatures
della transazione non sono vuote:
- L'applicazione deve impostare il
feePayeralla chiave pubblica della prima firma. - L'applicazione deve impostare il
recentBlockhashall' ultimo blockhash. - L'applicazione deve serializzare e deserializzare la transazione prima di firmarla. Questo garantisce un ordinamento coerente delle chiavi dell'account, come soluzione alternativa per questo problema.
- Il wallet non deve impostare il
feePayere ilrecentBlockhash. - Il wallet deve verificare le firme e, se alcune non sono valide, il wallet deve rifiutare la transazione come malformata.
Il wallet deve firmare la transazione solo con il account nella richiesta, e
deve farlo solo se è prevista una firma per il account nella richiesta.
Se è prevista una firma diversa da quella per il account nella richiesta, il
wallet deve rifiutare la transazione come dannosa.
Campo Messaggio Facoltativo
L'applicazione può anche includere un campo facoltativo message nel corpo
della risposta:
{ "message": "<message>", "transaction": "<transaction>" }
Il valore <message> deve essere una stringa UTF-8 che descrive la natura della
risposta alla transazione.
Ad esempio, potrebbe essere il nome di un articolo acquistato, uno sconto applicato all'acquisto o un messaggio di ringraziamento. Il wallet dovrebbe visualizzare il valore all'utente.
Il wallet e l'applicazione dovrebbero consentire campi aggiuntivi nel corpo della richiesta e nel corpo della risposta, che potrebbero essere aggiunti da future specifiche.
Esempi
URL che descrive una richiesta di transazione
solana:https://example.com/solana-pay
URL che descrive una richiesta di transazione con parametri di query
solana:https%3A%2F%2Fexample.com%2Fsolana-pay%3Forder%3D12345
Esempio di Richiesta GET
GET /solana-pay?order=12345 HTTP/1.1Host: example.comConnection: closeAccept: application/jsonAccept-Encoding: br, gzip, deflate
Esempio di Risposta GET
HTTP/1.1 200 OKConnection: closeContent-Type: application/jsonContent-Length: 62Content-Encoding: gzip{"label":"Michael Vines","icon":"https://example.com/icon.svg"}
Esempio di Richiesta 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"}
Esempio di Risposta POST
HTTP/1.1 200 OKConnection: closeContent-Type: application/jsonContent-Length: 298Content-Encoding: gzip{"message":"Thanks for all the fish","transaction":"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAECC4JMKqNplIXybGb/GhK1ofdVWeuEjXnQor7gi0Y2hMcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQECAAAMAgAAAAAAAAAAAAAA"}
Estensioni
Formati e campi aggiuntivi possono essere incorporati in questa specifica per abilitare nuovi casi d'uso garantendo al contempo la compatibilità con app e wallet.
Si prega di aprire un issue su Github per proporre modifiche alla specifica al fine di richiedere feedback dagli sviluppatori di applicazioni e wallet.
Un esempio concreto di tale proposta.
Vedi Anche
- Specifica Solana Pay v1.1 - Ultima versione con miglioramenti
- Guida Rapida - Guide di implementazione
- Repository GitHub - Implementazioni di riferimento
Is this page helpful?