Riepilogo
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.
Link
È 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
feePayeralaccountnella richiesta, o al valore zero (new PublicKey(0)onew PublicKey("11111111111111111111111111111111")). - L'applicazione dovrebbe impostare il
recentBlockhashall' ultimo blockhash, o al valore zero (new PublicKey(0).toBase58()o"11111111111111111111111111111111"). - Il portafoglio deve ignorare il
feePayernella transazione e impostare ilfeePayeralaccountnella richiesta. - Il portafoglio deve ignorare il
recentBlockhashnella transazione e impostare ilrecentBlockhashall' ultimo blockhash.
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 temporanea per questo problema.
- Il portafoglio non deve impostare il
feePayere ilrecentBlockhash. - 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.1Host: example.comConnection: closeAccept: application/jsonAccept-Encoding: br, gzip, deflate
Risposta GET
HTTP/1.1 200 OKConnection: closeContent-Type: application/jsonContent-Length: 62Content-Encoding: gzip{"label":"Michael Vines","icon":"https://example.com/icon.svg"}
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"}
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 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.
Is this page helpful?