Specifica Solana Pay v1.1

Un protocollo standard per codificare richieste di transazione Solana all'interno di URL per abilitare pagamenti e altri casi d'uso.

È stato raggiunto un consenso approssimativo su questa specifica ed esistono implementazioni in Phantom, FTX e Slope.

Questo standard trae ispirazione da 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 dovrebbero 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 mobile dovrebbero registrarsi per gestire lo schema URL per fornire un'esperienza fluida e sicura quando vengono incontrati URL Solana Pay nell'ambiente.

Standardizzando un approccio semplice per risolvere questi problemi, garantiamo la compatibilità di base tra applicazioni e wallet in modo che 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.

Per richiedere invece un trasferimento di SPL Token, deve essere utilizzato il campo spl-token per specificare un mint di SPL Token, dal quale deve essere derivato l'indirizzo del token account associato del destinatario.

Importo

È consentito un singolo campo amount come parametro di query opzionale. Il valore deve essere un numero intero non negativo o 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 l'SPL Token (specifico del mint), il wallet deve rifiutare l'URL come malformato.

SPL Token

È consentito un singolo campo spl-token come parametro di query opzionale. Il valore deve essere la chiave pubblica codificata in base58 di un account mint di SPL Token.

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 opzionali. I valori devono essere array di 32 byte codificati in base58. Questi possono essere o meno chiavi pubbliche, sulla curva o fuori dalla curva, e possono corrispondere o meno ad account su Solana.

Se i valori vengono forniti, il portafoglio deve includerli nell'ordine specificato come chiavi di sola lettura e non firmatarie nell'istruzione SystemProgram.Transfer o TokenProgram.Transfer/TokenProgram.TransferChecked nella transazione di pagamento. I valori possono essere univoci o meno rispetto alla richiesta di pagamento e possono corrispondere o meno a un account su Solana.

Poiché i validator di Solana indicizzano le transazioni tramite queste chiavi di account, i valori reference possono essere utilizzati come ID client (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 in URL che descrive la fonte della richiesta di trasferimento.

Ad esempio, potrebbe essere il nome di un marchio, negozio, applicazione o persona che effettua la richiesta. Il portafoglio dovrebbe 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 in 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 portafoglio dovrebbe 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 in URL che deve essere inclusa in un'istruzione SPL Memo nella transazione di pagamento.

Il portafoglio deve decodificare l'URL del valore e dovrebbe visualizzare il valore decodificato all'utente. Il memo verrà registrato dai validator e non dovrebbe 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 (all'utente viene richiesto 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 al fine di comporre una transazione.

È richiesto un singolo campo link come pathname. Il valore deve essere un URL assoluto HTTPS condizionalmente codificato come URL.

Se l'URL contiene parametri di query, deve essere codificato come URL. A questa specifica possono essere aggiunti parametri di query del protocollo. La codifica URL del valore evita conflitti con i parametri del protocollo.

Se l'URL non contiene parametri di query, non dovrebbe essere codificato come 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 come 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 della cache HTTP.

Il wallet dovrebbe visualizzare l'etichetta e renderizzare l'immagine dell'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' intestazione Accept-Encoding, e l'applicazione dovrebbe rispondere con un' intestazione 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 dell'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 portafoglio deve decodificare la transazione in base64 e deserializzarla.

L'applicazione può rispondere con una transazione parzialmente o completamente firmata. Il portafoglio 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, o al valore zero (new PublicKey(0) o new PublicKey("11111111111111111111111111111111")).
  • L'applicazione dovrebbe impostare il recentBlockhash all' ultimo blockhash, o al valore zero (new PublicKey(0).toBase58() o "11111111111111111111111111111111").
  • Il portafoglio deve ignorare il feePayer nella transazione e impostare il feePayer al account nella richiesta.
  • Il portafoglio deve ignorare il recentBlockhash nella transazione e impostare il recentBlockhash all' ultimo blockhash.

Se le signatures della transazione non sono vuote:

  • L'applicazione deve impostare il feePayer alla chiave pubblica della prima firma.
  • L'applicazione deve impostare il recentBlockhash all' ultimo blockhash.
  • L'applicazione deve serializzare e deserializzare la transazione prima di firmarla. Questo garantisce un ordinamento coerente delle chiavi dell'account, come soluzione temporanea per questo problema.
  • Il portafoglio non deve impostare il feePayer e il recentBlockhash.
  • Il portafoglio deve verificare le firme e, se qualcuna è non valida, il portafoglio deve rifiutare la transazione come malformata.

Il portafoglio 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 qualsiasi firma diversa da una firma per il account nella richiesta, il portafoglio deve rifiutare la transazione come dannosa.

L'applicazione può anche includere un campo opzionale 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 specifiche future.

Esempio

URL che descrive una richiesta di transazione.
solana:https://example.com/solana-pay
URL che descrive una richiesta di transazione con parametri query.
solana:https%3A%2F%2Fexample.com%2Fsolana-pay%3Forder%3D12345
Richiesta GET
GET /solana-pay?order=12345 HTTP/1.1
Host: example.com
Connection: close
Accept: application/json
Accept-Encoding: br, gzip, deflate
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"}
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"}
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 applicazioni e wallet.

Si prega di aprire una issue su Github per proporre modifiche alla specifica al fine di sollecitare feedback dagli sviluppatori di applicazioni e wallet.

Un esempio concreto di una tale proposta.

Is this page helpful?

Gestito da

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