Zusammenfassung
Ein Standardprotokoll zur Kodierung von Solana-Transaktionsanfragen in URLs, um Zahlungen und andere Anwendungsfälle zu ermöglichen.
Ein grober Konsens über diese Spezifikation wurde erreicht, und Implementierungen existieren in Phantom, FTX und Slope.
Dieser Standard orientiert sich an BIP 21 und EIP 681.
Motivation
Ein Standard-URL-Protokoll für die Anforderung nativer SOL-Überweisungen, SPL-Token-Überweisungen und Solana-Transaktionen ermöglicht eine bessere Benutzererfahrung über Apps und Wallets im Solana-Ökosystem hinweg.
Diese URLs können in QR-Codes oder NFC-Tags kodiert oder zwischen Benutzern und Anwendungen gesendet werden, um Zahlungen anzufordern und Transaktionen zu erstellen.
Anwendungen sollten sicherstellen, dass eine Transaktion bestätigt wurde und gültig ist, bevor sie Waren oder Dienstleistungen freigeben, die verkauft werden, oder Zugang zu Objekten oder Veranstaltungen gewähren.
Mobile Wallets sollten sich registrieren, um das URL-Schema zu verarbeiten und eine nahtlose und dennoch sichere Erfahrung zu bieten, wenn Solana Pay URLs in der Umgebung angetroffen werden.
Durch die Standardisierung eines einfachen Ansatzes zur Lösung dieser Probleme gewährleisten wir grundlegende Kompatibilität von Anwendungen und Wallets, sodass sich Entwickler auf höhere Abstraktionsebenen konzentrieren können.
Spezifikation: Überweisungsanfrage
Eine Solana Pay Überweisungsanfrage-URL beschreibt eine nicht-interaktive Anfrage für eine SOL- oder SPL-Token-Überweisung.
solana:<recipient>?amount=<amount>&spl-token=<spl-token>&reference=<reference>&label=<label>&message=<message>&memo=<memo>
Die Anfrage ist nicht-interaktiv, da die Parameter in der URL von einer Wallet verwendet werden, um direkt eine Transaktion zu erstellen.
Empfänger
Ein einzelnes recipient-Feld ist als Pfadname erforderlich. Der Wert muss der
base58-kodierte öffentliche Schlüssel eines nativen SOL-Kontos sein. Associated
Token Accounts dürfen nicht verwendet werden.
Stattdessen muss das Feld spl-token verwendet werden, um eine SPL-Token-Mint
anzugeben, von der die zugehörige Token-Adresse des Empfängers abgeleitet werden
muss.
Betrag
Ein einzelnes Feld amount ist als optionaler Abfrageparameter zulässig. Der
Wert muss eine nicht-negative Ganzzahl oder Dezimalzahl in "Benutzer"-Einheiten
sein. Für SOL bedeutet das SOL und nicht Lamports. Für Token verwenden Sie
uiAmountString und nicht amount.
0 ist ein gültiger Wert. Wenn der Wert eine Dezimalzahl kleiner als 1 ist,
muss er eine führende 0 vor dem . haben. Wissenschaftliche Notation ist
nicht zulässig.
Wenn kein Wert angegeben wird, muss die Wallet den Benutzer zur Eingabe des Betrags auffordern. Wenn die Anzahl der Dezimalstellen die für SOL (9) oder das SPL-Token (mint-spezifisch) unterstützte Anzahl überschreitet, muss die Wallet die URL als fehlerhaft ablehnen.
SPL-Token
Ein einzelnes Feld spl-token ist als optionaler Abfrageparameter zulässig. Der
Wert muss der base58-codierte öffentliche Schlüssel eines SPL-Token-Mint-Kontos
sein.
Wenn das Feld angegeben wird, muss die
Associated Token Account-Konvention
verwendet werden, und die Wallet muss eine Anweisung TokenProgram.Transfer
oder TokenProgram.TransferChecked als letzte Anweisung der Transaktion
einfügen.
Wenn das Feld nicht angegeben wird, beschreibt die URL eine native
SOL-Übertragung, und die Wallet muss stattdessen eine Anweisung
SystemProgram.Transfer als letzte Anweisung der Transaktion einfügen.
Die Wallet muss die ATA-Adresse aus den Feldern recipient und spl-token
ableiten. Übertragungen an zusätzliche Token-Konten werden nicht unterstützt.
Referenz
Mehrere Felder reference sind als optionale Abfrageparameter zulässig. Die
Werte müssen base58-codierte 32-Byte-Arrays sein. Diese können öffentliche
Schlüssel sein oder nicht, auf oder außerhalb der Kurve liegen und können Konten
auf Solana entsprechen oder nicht.
Wenn die Werte bereitgestellt werden, muss das Wallet sie in der angegebenen
Reihenfolge als schreibgeschützte, nicht signierende Schlüssel in die
SystemProgram.Transfer- oder
TokenProgram.Transfer/TokenProgram.TransferChecked-Anweisung in der
Zahlungstransaktion einschließen. Die Werte können für die Zahlungsanforderung
eindeutig sein oder nicht und können einem Konto auf Solana entsprechen oder
nicht.
Da Solana-Validatoren Transaktionen anhand dieser Kontoschlüssel indexieren,
können reference-Werte als Client-IDs verwendet werden (IDs, die verwendet
werden können, bevor die endgültige Zahlungstransaktion bekannt ist). Die
RPC-Methode
getSignaturesForAddress
kann verwendet werden, um Transaktionen auf diese Weise zu lokalisieren.
Label
Ein einzelnes label-Feld ist als optionaler Abfrageparameter zulässig. Der
Wert muss eine
URL-kodierte
UTF-8-Zeichenkette sein, die die Quelle der Übertragungsanforderung beschreibt.
Dies könnte beispielsweise der Name einer Marke, eines Geschäfts, einer Anwendung oder einer Person sein, die die Anfrage stellt. Das Wallet sollte den Wert URL-dekodieren und den dekodierten Wert dem Benutzer anzeigen.
Nachricht
Ein einzelnes message-Feld ist als optionaler Abfrageparameter zulässig. Der
Wert muss eine
URL-kodierte
UTF-8-Zeichenkette sein, die die Art der Übertragungsanforderung beschreibt.
Dies könnte beispielsweise der Name eines gekauften Artikels, eine Bestellnummer oder eine Danksagung sein. Das Wallet sollte den Wert URL-dekodieren und den dekodierten Wert dem Benutzer anzeigen.
Memo
Ein einzelnes memo-Feld ist als optionaler Abfrageparameter zulässig. Der Wert
muss eine
URL-kodierte
UTF-8-Zeichenkette sein, die in einer
SPL Memo-Anweisung in der Zahlungstransaktion
enthalten sein muss.
Das Wallet muss den Wert URL-dekodieren und sollte den dekodierten Wert dem Benutzer anzeigen. Das Memo wird von Validatoren aufgezeichnet und sollte keine privaten oder sensiblen Informationen enthalten.
Wenn das Feld angegeben wird, muss die Wallet eine MemoProgram-Anweisung als
vorletzte Anweisung der Transaktion einfügen, unmittelbar vor der SOL- oder
SPL-Token-Übertragungsanweisung, um Mehrdeutigkeiten mit anderen Anweisungen in
der Transaktion zu vermeiden.
Beispiele
URL, die eine Übertragungsanfrage für 1 SOL beschreibt
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=1&label=Michael&message=Thanks%20for%20all%20the%20fish&memo=OrderId12345
URL, die eine Übertragungsanfrage für 0,01 USDC beschreibt
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=0.01&spl-token=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
URL, die eine Übertragungsanfrage für SOL beschreibt (Benutzer wird zur Eingabe des Betrags aufgefordert)
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?label=Michael
Spezifikation: Transaktionsanfrage
Eine Solana Pay-Transaktionsanfrage-URL beschreibt eine interaktive Anfrage für jede beliebige Solana-Transaktion.
solana:<link>
Die Anfrage ist interaktiv, da die Parameter in der URL von einer Wallet verwendet werden, um eine HTTP-Anfrage zum Erstellen einer Transaktion zu stellen.
Link
Ein einzelnes link-Feld ist als Pfadname erforderlich. Der Wert muss eine
bedingt
URL-codierte
absolute HTTPS-URL sein.
Wenn die URL Abfrageparameter enthält, muss sie URL-codiert sein. Protokollabfrageparameter können zu dieser Spezifikation hinzugefügt werden. Die URL-Codierung des Werts verhindert Konflikte mit Protokollparametern.
Wenn die URL keine Abfrageparameter enthält, sollte sie nicht URL-codiert sein. Dies erzeugt eine kürzere URL und einen weniger dichten QR-Code.
In beiden Fällen muss die Wallet den Wert URL-decodieren. Dies hat keine Auswirkung, wenn der Wert nicht URL-codiert ist. Wenn der decodierte Wert keine absolute HTTPS-URL ist, muss die Wallet ihn als fehlerhaft ablehnen.
GET-Anfrage
Die Wallet sollte eine HTTP-GET-JSON-Anfrage an die URL stellen. Die Anfrage
sollte weder die Wallet noch den Benutzer identifizieren.
Die Wallet sollte die Anfrage mit einem Accept-Encoding-Header stellen, und die Anwendung sollte mit einem Content-Encoding-Header für HTTP-Komprimierung antworten.
Die Wallet sollte die Domain der URL anzeigen, während die Anfrage gestellt wird.
GET-Antwort
Die Wallet muss HTTP-
Client-Fehler,
Server-Fehler
und
Weiterleitungsantworten
verarbeiten. Die Anwendung muss mit diesen oder mit einer HTTP-OK-JSON-Antwort
mit folgendem Body antworten:
{ "label": "<label>", "icon": "<icon>" }
Der <label>-Wert muss eine UTF-8-Zeichenkette sein, die die Quelle der
Transaktionsanfrage beschreibt. Dies könnte beispielsweise der Name einer Marke,
eines Geschäfts, einer Anwendung oder einer Person sein, die die Anfrage stellt.
Der <icon>-Wert muss eine absolute HTTP- oder HTTPS-URL eines Icon-Bildes
sein. Die Datei muss ein SVG-, PNG- oder WebP-Bild sein, andernfalls muss die
Wallet sie als fehlerhaft ablehnen.
Die Wallet sollte die Antwort nicht zwischenspeichern, außer wie durch HTTP-Caching-Antwortheader angewiesen.
Die Wallet sollte das Label anzeigen und das Icon-Bild für den Benutzer rendern.
POST-Anfrage
Die Wallet muss eine HTTP-POST-JSON-Anfrage an die URL mit folgendem Body
stellen:
{ "account": "<account>" }
Der <account>-Wert muss der base58-kodierte öffentliche Schlüssel eines Konten
sein, das die Transaktion signieren kann.
Die Wallet sollte die Anfrage mit einem Accept-Encoding-Header stellen, und die Anwendung sollte mit einem Content-Encoding-Header für HTTP-Komprimierung antworten.
Die Wallet sollte die Domain der URL anzeigen, während die Anfrage gestellt
wird. Wenn eine GET-Anfrage gestellt wurde, sollte die Wallet auch das Label
anzeigen und das Icon-Bild aus der Antwort rendern.
POST-Antwort
Die Wallet muss HTTP-
Client-Fehler,
Server-Fehler
und
Weiterleitungsantworten
verarbeiten. Die Anwendung muss mit diesen oder mit einer HTTP-OK-JSON-Antwort
mit folgendem Body antworten:
{ "transaction": "<transaction>" }
Der <transaction>-Wert muss eine base64-codierte
serialisierte Transaktion
sein. Das Wallet muss die Transaktion base64-decodieren und
deserialisieren.
Die Anwendung kann mit einer teilweise oder vollständig signierten Transaktion antworten. Das Wallet muss die Transaktion als nicht vertrauenswürdig validieren.
Leere Signaturen
Wenn die
signatures
der Transaktion leer sind:
- Die Anwendung sollte den
feePayerauf denaccountin der Anfrage oder auf den Nullwert (new PublicKey(0)odernew PublicKey("11111111111111111111111111111111")) setzen. - Die Anwendung sollte den
recentBlockhashauf den neuesten Blockhash oder auf den Nullwert (new PublicKey(0).toBase58()oder"11111111111111111111111111111111") setzen. - Das Wallet muss den
feePayerin der Transaktion ignorieren und denfeePayerauf denaccountin der Anfrage setzen. - Das Wallet muss den
recentBlockhashin der Transaktion ignorieren und denrecentBlockhashauf den neuesten Blockhash setzen.
Wenn die
signatures
der Transaktion nicht leer sind:
- Die Anwendung muss den
feePayerauf den öffentlichen Schlüssel der ersten Signatur setzen. - Die Anwendung muss den
recentBlockhashauf den neuesten Blockhash setzen. - Die Anwendung muss die Transaktion vor dem Signieren serialisieren und deserialisieren. Dies gewährleistet eine konsistente Reihenfolge der Kontoschlüssel als Workaround für dieses Problem.
- Das Wallet darf den
feePayerund denrecentBlockhashnicht setzen. - Das Wallet muss die Signaturen verifizieren, und falls eine ungültig ist, muss das Wallet die Transaktion als fehlerhaft ablehnen.
Das Wallet darf die Transaktion nur mit dem account in der Anfrage signieren,
und zwar nur dann, wenn eine Signatur für den account in der Anfrage erwartet
wird.
Wenn eine andere Signatur als eine Signatur für den account in der Anfrage
erwartet wird, muss das Wallet die Transaktion als bösartig ablehnen.
Die Anwendung kann auch ein optionales message-Feld im Antworttext enthalten:
{ "message": "<message>", "transaction": "<transaction>" }
Der <message>-Wert muss eine UTF-8-Zeichenkette sein, die die Art der
Transaktionsantwort beschreibt.
Dies könnte beispielsweise der Name eines gekauften Artikels, ein auf den Kauf angewendeter Rabatt oder eine Dankesnachricht sein. Das Wallet sollte den Wert dem Benutzer anzeigen.
Das Wallet und die Anwendung sollten zusätzliche Felder im Anfrage- und Antworttext zulassen, die durch zukünftige Spezifikationen hinzugefügt werden können.
Beispiel
URL, die eine Transaktionsanfrage beschreibt.
solana:https://example.com/solana-pay
URL, die eine Transaktionsanfrage mit Abfrageparametern beschreibt.
solana:https%3A%2F%2Fexample.com%2Fsolana-pay%3Forder%3D12345
GET-Anfrage
GET /solana-pay?order=12345 HTTP/1.1Host: example.comConnection: closeAccept: application/jsonAccept-Encoding: br, gzip, deflate
GET-Antwort
HTTP/1.1 200 OKConnection: closeContent-Type: application/jsonContent-Length: 62Content-Encoding: gzip{"label":"Michael Vines","icon":"https://example.com/icon.svg"}
POST-Anfrage
POST /solana-pay?order=12345 HTTP/1.1Host: example.comConnection: closeAccept: application/jsonAccept-Encoding: br, gzip, deflateContent-Type: application/jsonContent-Length: 57{"account":"mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN"}
POST-Antwort
HTTP/1.1 200 OKConnection: closeContent-Type: application/jsonContent-Length: 298Content-Encoding: gzip{"message":"Thanks for all the fish","transaction":"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAECC4JMKqNplIXybGb/GhK1ofdVWeuEjXnQor7gi0Y2hMcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQECAAAMAgAAAAAAAAAAAAAA"}
Erweiterungen
Zusätzliche Formate und Felder können in diese Spezifikation aufgenommen werden, um neue Anwendungsfälle zu ermöglichen und gleichzeitig die Kompatibilität mit Apps und Wallets sicherzustellen.
Bitte öffnen Sie ein Github-Issue, um Änderungen an der Spezifikation vorzuschlagen und Feedback von Anwendungs- und Wallet-Entwicklern einzuholen.
Is this page helpful?