Specifica Solana Pay v1

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.

È 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 feePayer al account nella richiesta, oppure al valore zero (new PublicKey(0) o new PublicKey("11111111111111111111111111111111")).
  • L'applicazione dovrebbe impostare il recentBlockhash all' ultimo blockhash, oppure al valore zero (new PublicKey(0).toBase58() o "11111111111111111111111111111111").
  • Il wallet deve ignorare il feePayer nella transazione e impostare il feePayer al account nella richiesta.
  • Il wallet deve ignorare il recentBlockhash nella transazione e impostare il recentBlockhash all' ultimo blockhash.

Firme Non Vuote

Se le signatures della transazione non sono vuote:

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.1
Host: example.com
Connection: close
Accept: application/json
Accept-Encoding: br, gzip, deflate

Esempio di Risposta GET

HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
Content-Length: 62
Content-Encoding: gzip
{"label":"Michael Vines","icon":"https://example.com/icon.svg"}

Esempio di Richiesta POST

POST /solana-pay?order=12345 HTTP/1.1
Host: example.com
Connection: close
Accept: application/json
Accept-Encoding: br, gzip, deflate
Content-Type: application/json
Content-Length: 57
{"account":"mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN"}

Esempio di Risposta POST

HTTP/1.1 200 OK
Connection: close
Content-Type: application/json
Content-Length: 298
Content-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

Is this page helpful?

Gestito da

© 2026 Solana Foundation.
Tutti i diritti riservati.
Resta connesso