Ringkasan
Protokol standar untuk mengodekan permintaan transaksi Solana dalam URL guna memungkinkan pembayaran dan kasus penggunaan lainnya.
Konsensus kasar mengenai spesifikasi ini telah tercapai, dan implementasinya sudah ada di Phantom, FTX, dan Slope.
Standar ini mengambil inspirasi dari BIP 21 dan EIP 681.
Motivasi
Protokol URL standar untuk meminta transfer SOL native, transfer Token SPL, dan transaksi Solana memungkinkan pengalaman pengguna yang lebih baik di seluruh aplikasi dan dompet dalam ekosistem Solana.
URL ini dapat dikodekan dalam kode QR atau tag NFC, atau dikirim antara pengguna dan aplikasi untuk meminta pembayaran dan menyusun transaksi.
Aplikasi harus memastikan bahwa transaksi telah dikonfirmasi dan valid sebelum mereka merilis barang atau layanan yang dijual, atau memberikan akses ke objek atau acara.
Dompet seluler harus terdaftar untuk menangani skema URL guna memberikan pengalaman yang mulus namun aman ketika URL Solana Pay ditemukan di lingkungan.
Dengan menstandarkan pendekatan sederhana untuk menyelesaikan masalah-masalah ini, kami memastikan kompatibilitas dasar aplikasi dan dompet sehingga pengembang dapat fokus pada abstraksi tingkat yang lebih tinggi.
Spesifikasi: Permintaan Transfer
URL permintaan transfer Solana Pay mendeskripsikan permintaan non-interaktif untuk transfer SOL atau Token SPL.
solana:<recipient>?amount=<amount>&spl-token=<spl-token>&reference=<reference>&label=<label>&message=<message>&memo=<memo>
Permintaan bersifat non-interaktif karena parameter dalam URL digunakan oleh dompet untuk langsung menyusun transaksi.
Penerima
Satu field recipient diperlukan sebagai pathname. Nilainya harus berupa pubkey
yang dikodekan base58 dari akun SOL native. associated token account tidak boleh
digunakan.
Sebaliknya, untuk meminta transfer SPL Token, field spl-token harus digunakan
untuk menentukan mint SPL Token, dari mana alamat token terkait penerima harus
diturunkan.
Jumlah
Satu field amount diperbolehkan sebagai parameter query opsional. Nilainya
harus berupa bilangan bulat non-negatif atau desimal dalam satuan "pengguna".
Untuk SOL, itu adalah SOL dan bukan lamport. Untuk token, gunakan
uiAmountString dan bukan amount.
0 adalah nilai yang valid. Jika nilainya adalah bilangan desimal kurang dari
1, harus memiliki 0 di depan sebelum .. Notasi ilmiah dilarang.
Jika nilai tidak disediakan, wallet harus meminta pengguna untuk memasukkan jumlah. Jika jumlah tempat desimal melebihi yang didukung untuk SOL (9) atau SPL Token (spesifik mint), wallet harus menolak URL sebagai tidak valid.
SPL Token
Satu field spl-token diperbolehkan sebagai parameter query opsional. Nilainya
harus berupa pubkey yang dikodekan base58 dari akun mint SPL Token.
Jika field disediakan, konvensi
Associated Token Account
harus digunakan, dan wallet harus menyertakan instruksi TokenProgram.Transfer
atau TokenProgram.TransferChecked sebagai instruksi terakhir dari transaksi.
Jika field tidak disediakan, URL mendeskripsikan transfer SOL native, dan wallet
harus menyertakan instruksi SystemProgram.Transfer sebagai instruksi terakhir
dari transaksi.
Wallet harus menurunkan alamat ATA dari field recipient dan spl-token.
Transfer ke akun token tambahan tidak didukung.
Referensi
Beberapa field reference diperbolehkan sebagai parameter query opsional.
Nilainya harus berupa array 32 byte yang dikodekan base58. Ini bisa atau tidak
bisa berupa pubkey, di atau di luar kurva, dan mungkin atau tidak sesuai dengan
akun di Solana.
Jika nilai disediakan, dompet harus menyertakannya dalam urutan yang diberikan
sebagai kunci read-only, non-signer ke instruksi SystemProgram.Transfer atau
TokenProgram.Transfer/TokenProgram.TransferChecked dalam transaksi
pembayaran. Nilai tersebut mungkin unik atau tidak untuk permintaan pembayaran,
dan mungkin sesuai atau tidak dengan akun di Solana.
Karena validator Solana mengindeks transaksi berdasarkan kunci akun ini, nilai
reference dapat digunakan sebagai ID klien (ID yang dapat digunakan sebelum
mengetahui transaksi pembayaran akhir). Metode RPC
getSignaturesForAddress
dapat digunakan untuk menemukan transaksi dengan cara ini.
Label
Satu bidang label diperbolehkan sebagai parameter query opsional. Nilainya
harus berupa string UTF-8 yang
di-encode URL
yang menjelaskan sumber permintaan transfer.
Sebagai contoh, ini mungkin nama merek, toko, aplikasi, atau orang yang membuat permintaan. Dompet harus melakukan decode URL pada nilai tersebut dan menampilkan nilai yang telah di-decode kepada pengguna.
Pesan
Satu bidang message diperbolehkan sebagai parameter query opsional. Nilainya
harus berupa string UTF-8 yang
di-encode URL
yang menjelaskan sifat permintaan transfer.
Sebagai contoh, ini mungkin nama barang yang dibeli, ID pesanan, atau ucapan terima kasih. Dompet harus melakukan decode URL pada nilai tersebut dan menampilkan nilai yang telah di-decode kepada pengguna.
Memo
Satu bidang memo diperbolehkan sebagai parameter query opsional. Nilainya
harus berupa string UTF-8 yang
di-encode URL
yang harus disertakan dalam instruksi SPL Memo
dalam transaksi pembayaran.
Dompet harus melakukan decode URL pada nilai tersebut dan sebaiknya menampilkan nilai yang telah di-decode kepada pengguna. Memo akan dicatat oleh validator dan tidak boleh menyertakan informasi pribadi atau sensitif.
Jika field disediakan, wallet harus menyertakan instruksi MemoProgram sebagai
instruksi kedua dari terakhir dalam transaksi, tepat sebelum instruksi transfer
SOL atau SPL Token, untuk menghindari ambiguitas dengan instruksi lain dalam
transaksi.
Contoh
URL yang mendeskripsikan permintaan transfer untuk 1 SOL
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=1&label=Michael&message=Thanks%20for%20all%20the%20fish&memo=OrderId12345
URL yang mendeskripsikan permintaan transfer untuk 0.01 USDC
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=0.01&spl-token=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
URL yang mendeskripsikan permintaan transfer untuk SOL (pengguna diminta memasukkan jumlah)
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?label=Michael
Spesifikasi: Permintaan Transaksi
URL permintaan transaksi Solana Pay mendeskripsikan permintaan interaktif untuk transaksi Solana apa pun.
solana:<link>
Permintaan bersifat interaktif karena parameter dalam URL digunakan oleh wallet untuk membuat permintaan HTTP guna menyusun transaksi.
Link
Satu field link diperlukan sebagai pathname. Nilainya harus berupa URL HTTPS
absolut yang di-encode secara kondisional sesuai
URL-encoding.
Jika URL mengandung parameter query, URL tersebut harus di-encode. Parameter query protokol mungkin ditambahkan ke spesifikasi ini. URL-encoding nilai mencegah konflik dengan parameter protokol.
Jika URL tidak mengandung parameter query, sebaiknya tidak di-encode. Ini menghasilkan URL yang lebih pendek dan kode QR yang kurang padat.
Dalam kedua kasus, wallet harus melakukan URL-decode pada nilai tersebut. Ini tidak berpengaruh jika nilai tidak di-encode. Jika nilai yang di-decode bukan URL HTTPS absolut, wallet harus menolaknya sebagai tidak valid.
Permintaan GET
Wallet sebaiknya membuat permintaan JSON GET HTTP ke URL. Permintaan sebaiknya
tidak mengidentifikasi wallet atau pengguna.
Wallet sebaiknya membuat permintaan dengan header Accept-Encoding, dan aplikasi sebaiknya merespons dengan header Content-Encoding untuk kompresi HTTP.
Dompet harus menampilkan domain dari URL saat permintaan sedang dibuat.
Respons GET
Dompet harus menangani
kesalahan klien
HTTP,
kesalahan server,
dan
respons pengalihan.
Aplikasi harus merespons dengan ini, atau dengan respons JSON HTTP OK dengan
body:
{ "label": "<label>", "icon": "<icon>" }
Nilai <label> harus berupa string UTF-8 yang menjelaskan sumber dari
permintaan transaksi. Sebagai contoh, ini bisa berupa nama merek, toko,
aplikasi, atau orang yang membuat permintaan.
Nilai <icon> harus berupa URL HTTP atau HTTPS absolut dari gambar ikon. File
tersebut harus berupa gambar SVG, PNG, atau WebP, atau dompet harus menolaknya
sebagai tidak valid.
Dompet tidak boleh menyimpan respons dalam cache kecuali diinstruksikan oleh header respons HTTP caching.
Dompet harus menampilkan label dan merender gambar ikon kepada pengguna.
Permintaan POST
Dompet harus membuat permintaan JSON HTTP POST ke URL dengan body:
{ "account": "<account>" }
Nilai <account> harus berupa kunci publik yang dikodekan base58 dari akun yang
mungkin menandatangani transaksi.
Dompet sebaiknya membuat permintaan dengan header Accept-Encoding, dan aplikasi sebaiknya merespons dengan header Content-Encoding untuk kompresi HTTP.
Dompet harus menampilkan domain dari URL saat permintaan sedang dibuat. Jika
permintaan GET telah dibuat, dompet juga harus menampilkan label dan merender
gambar ikon dari respons.
Respons POST
Dompet harus menangani
kesalahan klien
HTTP,
kesalahan server,
dan
respons pengalihan.
Aplikasi harus merespons dengan ini, atau dengan respons JSON HTTP OK dengan
body:
{ "transaction": "<transaction>" }
Nilai <transaction> harus berupa
transaksi terserialisasi
yang dikodekan base64. Dompet harus mendekode base64 transaksi tersebut dan
mendeserialisasinya.
Aplikasi dapat merespons dengan transaksi yang ditandatangani sebagian atau sepenuhnya. Dompet harus memvalidasi transaksi tersebut sebagai tidak terpercaya.
Tanda Tangan Kosong
Jika
signatures
transaksi kosong:
- Aplikasi harus menetapkan
feePayerkeaccountdalam permintaan, atau nilai nol (new PublicKey(0)ataunew PublicKey("11111111111111111111111111111111")). - Aplikasi harus menetapkan
recentBlockhashke blockhash terbaru, atau nilai nol (new PublicKey(0).toBase58()atau"11111111111111111111111111111111"). - Dompet harus mengabaikan
feePayerdalam transaksi dan menetapkanfeePayerkeaccountdalam permintaan. - Dompet harus mengabaikan
recentBlockhashdalam transaksi dan menetapkanrecentBlockhashke blockhash terbaru.
Jika
signatures
transaksi tidak kosong:
- Aplikasi harus menetapkan
feePayerke kunci publik tanda tangan pertama. - Aplikasi harus menetapkan
recentBlockhashke blockhash terbaru. - Aplikasi harus menserialisasi dan mendeserialisasi transaksi sebelum menandatanganinya. Ini memastikan urutan kunci akun yang konsisten, sebagai solusi untuk masalah ini.
- Dompet tidak boleh menetapkan
feePayerdanrecentBlockhash. - Dompet harus memverifikasi tanda tangan, dan jika ada yang tidak valid, dompet harus menolak transaksi tersebut sebagai tidak valid.
Dompet hanya boleh menandatangani transaksi dengan account dalam permintaan,
dan hanya boleh melakukannya jika tanda tangan untuk account dalam permintaan
diharapkan.
Jika ada tanda tangan selain tanda tangan untuk account dalam permintaan yang
diharapkan, dompet harus menolak transaksi tersebut sebagai berbahaya.
Aplikasi juga dapat menyertakan kolom message opsional dalam body respons:
{ "message": "<message>", "transaction": "<transaction>" }
Nilai <message> harus berupa string UTF-8 yang mendeskripsikan sifat respons
transaksi.
Sebagai contoh, ini bisa berupa nama item yang dibeli, diskon yang diterapkan pada pembelian, atau catatan terima kasih. Dompet harus menampilkan nilai tersebut kepada pengguna.
Dompet dan aplikasi harus mengizinkan kolom tambahan dalam body permintaan dan body respons, yang mungkin ditambahkan oleh spesifikasi di masa mendatang.
Contoh
URL yang mendeskripsikan permintaan transaksi.
solana:https://example.com/solana-pay
URL yang mendeskripsikan permintaan transaksi dengan parameter kueri.
solana:https%3A%2F%2Fexample.com%2Fsolana-pay%3Forder%3D12345
Permintaan GET
GET /solana-pay?order=12345 HTTP/1.1Host: example.comConnection: closeAccept: application/jsonAccept-Encoding: br, gzip, deflate
Respons GET
HTTP/1.1 200 OKConnection: closeContent-Type: application/jsonContent-Length: 62Content-Encoding: gzip{"label":"Michael Vines","icon":"https://example.com/icon.svg"}
Permintaan 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"}
Respons POST
HTTP/1.1 200 OKConnection: closeContent-Type: application/jsonContent-Length: 298Content-Encoding: gzip{"message":"Thanks for all the fish","transaction":"AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAECC4JMKqNplIXybGb/GhK1ofdVWeuEjXnQor7gi0Y2hMcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQECAAAMAgAAAAAAAAAAAAAA"}
Ekstensi
Format dan kolom tambahan dapat diintegrasikan ke dalam spesifikasi ini untuk memungkinkan kasus penggunaan baru sambil memastikan kompatibilitas dengan aplikasi dan dompet.
Silakan buka issue di Github untuk mengusulkan perubahan pada spesifikasi guna mendapatkan masukan dari pengembang aplikasi dan dompet.
Is this page helpful?