Solana Pay仕様 v1

概要

URL内でSolanaトランザクションリクエストをエンコードし、支払いやその他のユースケースを可能にするための標準プロトコルです。

この標準は、BIP 21およびEIP 681から着想を得ています。

動機

ネイティブSOL転送、SPLトークン転送、およびSolanaトランザクションをリクエストするための標準URLプロトコルにより、Solanaエコシステム内のアプリとウォレット間でより良いユーザーエクスペリエンスが実現されます。

これらのURLは、QRコードやNFCタグにエンコードされたり、ユーザーとアプリケーション間で送信されて、支払いをリクエストしたりトランザクションを構成したりすることができます。

アプリケーションは、販売する商品やサービスを提供したり、オブジェクトやイベントへのアクセスを許可したりする前に、トランザクションが確認され有効であることを確認する必要があります。

モバイルウォレットは、環境内でSolana Pay URLに遭遇したときにシームレスかつ安全なエクスペリエンスを提供するために、URLスキームを処理するよう登録する必要があります。

これらの問題を解決するためのシンプルなアプローチを標準化することで、アプリケーションとウォレットの基本的な互換性を確保し、開発者がより高レベルの抽象化に集中できるようにします。

仕様:転送リクエスト

Solana Pay転送リクエストURLは、SOLまたはSPLトークン転送の非対話型リクエストを記述します。

solana:<recipient>
?amount=<amount>
&spl-token=<spl-token>
&reference=<reference>
&label=<label>
&message=<message>
&memo=<memo>

このリクエストが非対話型である理由は、URL内のパラメータがウォレットによって直接トランザクションを構成するために使用されるためです。

受取人

パス名として単一のrecipientフィールドが必須です。値は、ネイティブSOLアカウントのbase58エンコードされた公開鍵である必要があります。associated token accountを使用してはいけません。

代わりに、SPLトークン転送をリクエストするには、spl-tokenフィールドを使用してSPLトークンミントを指定し、そこから受取人のassociated token accountのアドレスを導出する必要があります。

金額

単一の amount フィールドは、オプションのクエリパラメータとして使用できます。値は、「ユーザー」単位の非負の整数または小数でなければなりません。SOLの場合、lamportではなくSOLを使用します。トークンの場合は、uiAmountString を使用し、amount は使用しません

0 は有効な値です。値が 1 未満の小数の場合、. の前に先頭の 0 を付ける必要があります。科学的記数法は禁止されています。

値が指定されていない場合、ウォレットはユーザーに金額の入力を求める必要があります。小数点以下の桁数がSOL(9桁)またはSPLトークン(mint固有)でサポートされている桁数を超える場合、ウォレットはURLを不正な形式として拒否する必要があります。

SPLトークン

単一の spl-token フィールドは、オプションのクエリパラメータとして使用できます。値は、SPLトークンのmint accountのbase58エンコードされた公開鍵でなければなりません。

このフィールドが指定されている場合、Associated Token Account規約を使用する必要があり、ウォレットはトランザクションの最後のinstructionとして TokenProgram.Transfer または TokenProgram.TransferChecked instructionを含める必要があります。

このフィールドが指定されていない場合、URLはネイティブSOL転送を示し、ウォレットは代わりにトランザクションの最後のinstructionとして SystemProgram.Transfer instructionを含める必要があります。

ウォレットは recipient および spl-token フィールドからATAアドレスを導出する必要があります。補助token accountへの転送はサポートされていません。

リファレンス

複数の reference フィールドは、オプションのクエリパラメータとして使用できます。値は、base58エンコードされた32バイト配列でなければなりません。これらは公開鍵である場合もそうでない場合もあり、曲線上または曲線外にある場合もあり、Solana上のアカウントに対応する場合もしない場合もあります。

値が提供された場合、ウォレットは支払いトランザクション内のSystemProgram.TransferまたはTokenProgram.Transfer/TokenProgram.TransferCheckedインストラクションに、提供された順序で読み取り専用の非署名者キーとしてそれらを含める必要があります。これらの値は、支払いリクエストに固有である場合とそうでない場合があり、Solana上のアカウントに対応している場合とそうでない場合があります。

Solanaバリデーターはこれらのアカウントキーによってトランザクションをインデックス化するため、referenceの値はクライアントID(最終的な支払いトランザクションを知る前に使用可能なID)として使用できます。getSignaturesForAddressのRPCメソッドを使用して、この方法でトランザクションを特定できます。

ラベル

単一のlabelフィールドは、オプションのクエリパラメータとして許可されます。値は、送金リクエストの発信元を説明するURL エンコードされたUTF-8文字列である必要があります。

たとえば、これはリクエストを行うブランド、店舗、アプリケーション、または人物の名前である可能性があります。ウォレットは値をURLデコードし、デコードされた値をユーザーに表示する必要があります。

メッセージ

単一のmessageフィールドは、オプションのクエリパラメータとして許可されます。値は、送金リクエストの性質を説明するURL エンコードされたUTF-8文字列である必要があります。

たとえば、これは購入される商品の名前、注文ID、または感謝のメモである可能性があります。ウォレットは値をURLデコードし、デコードされた値をユーザーに表示する必要があります。

メモ

単一のmemoフィールドは、オプションのクエリパラメータとして許可されます。値は、支払いトランザクション内のSPL Memoインストラクションに含める必要があるURL エンコードされたUTF-8文字列である必要があります。

ウォレットは値をURLデコードし、デコードされた値をユーザーに表示する必要があります。メモはバリデーターによって記録されるため、プライベートまたは機密情報を含めるべきではありません。

このフィールドが指定されている場合、ウォレットはトランザクション内の他の命令との曖昧さを避けるため、SOLまたはSPLトークン転送命令の直前、トランザクションの最後から2番目の命令としてMemoProgram命令を含める必要があります。

1 SOLの転送リクエストを記述するURL

solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=1&label=Michael&message=Thanks%20for%20all%20the%20fish&memo=OrderId12345

0.01 USDCの転送リクエストを記述するURL

solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=0.01&spl-token=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

SOLの転送リクエストを記述するURL(ユーザーに金額の入力を促す)

solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?label=Michael

仕様: トランザクションリクエスト

Solana PayのトランザクションリクエストURLは、あらゆるSolanaトランザクションに対するインタラクティブなリクエストを記述します。

solana:<link>

このリクエストがインタラクティブである理由は、URL内のパラメータがウォレットによってHTTPリクエストを行い、トランザクションを構成するために使用されるためです。

リンク

パス名として単一のlinkフィールドが必須です。この値は、条件付きでURLエンコードされた絶対HTTPS URLである必要があります。

URLにクエリパラメータが含まれている場合は、URLエンコードする必要があります。このプロトコル仕様には、プロトコルクエリパラメータが追加される可能性があります。値をURLエンコードすることで、プロトコルパラメータとの競合を防ぎます。

URLにクエリパラメータが含まれていない場合は、URLエンコードすべきではありません。これにより、より短いURLと密度の低いQRコードが生成されます。

いずれの場合も、ウォレットは値をURLデコードする必要があります。値がURLエンコードされていない場合、これは効果がありません。デコードされた値が絶対HTTPS URLでない場合、ウォレットはそれを不正な形式として拒否する必要があります。

GETリクエスト

ウォレットは、このURLに対してHTTP GET JSONリクエストを行う必要があります。このリクエストは、ウォレットやユーザーを特定すべきではありません。

ウォレットはAccept-Encodingヘッダーを付けてリクエストを行う必要があり、アプリケーションはHTTP圧縮のためにContent-Encodingヘッダーを付けてレスポンスを返す必要があります。

ウォレットは、リクエストが行われている間、URLのドメインを表示する必要があります。

GETレスポンス

ウォレットは、HTTP クライアントエラーサーバーエラー、および リダイレクトレスポンス を処理する必要があります。アプリケーションは、これらで応答するか、次の本文を含むHTTP OK JSONレスポンスで応答する必要があります:

{ "label": "<label>", "icon": "<icon>" }

<label> の値は、トランザクションリクエストの送信元を説明するUTF-8文字列である必要があります。例えば、これはリクエストを行っているブランド、店舗、アプリケーション、または個人の名前である可能性があります。

<icon> の値は、アイコン画像の絶対HTTPまたはHTTPS URLである必要があります。ファイルはSVG、PNG、またはWebP画像である必要があり、そうでない場合、ウォレットは不正な形式として拒否する必要があります。

ウォレットは、 HTTPキャッシング レスポンスヘッダーで指示されている場合を除き、レスポンスをキャッシュすべきではありません。

ウォレットは、ラベルを表示し、アイコン画像をユーザーに表示する必要があります。

POSTリクエスト

ウォレットは、次の本文を含むHTTP POST JSONリクエストをURLに送信する必要があります:

{ "account": "<account>" }

<account> の値は、トランザクションに署名する可能性のあるアカウントのbase58エンコードされた公開鍵である必要があります。

ウォレットは、 Accept-Encodingヘッダー を使用してリクエストを行うべきであり、アプリケーションは、HTTP圧縮のために Content-Encodingヘッダー で応答する必要があります。

ウォレットは、リクエストが行われている間、URLのドメインを表示する必要があります。GET リクエストが行われた場合、ウォレットはレスポンスのラベルを表示し、アイコン画像も表示する必要があります。

POSTレスポンス

ウォレットは、HTTP クライアントエラーサーバーエラー、および リダイレクトレスポンス を処理する必要があります。アプリケーションは、これらで応答するか、次の本文を含むHTTP OK JSONレスポンスで応答する必要があります:

{ "transaction": "<transaction>" }

<transaction> 値は、base64エンコードされた シリアライズされたトランザクションである必要があります。ウォレットは、トランザクションをbase64デコードし、 デシリアライズする必要があります。

アプリケーションは、部分的または完全に署名されたトランザクションで応答する場合があります。ウォレットは、トランザクションを信頼できないものとして検証する必要があります。

空の署名

トランザクションの signatures が空の場合:

  • アプリケーションは、 feePayer をリクエスト内の account、またはゼロ値(new PublicKey(0) または new PublicKey("11111111111111111111111111111111"))に設定する必要があります。
  • アプリケーションは、 recentBlockhash最新のブロックハッシュ、またはゼロ値(new PublicKey(0).toBase58() または "11111111111111111111111111111111")に設定する必要があります。
  • ウォレットは、トランザクション内の feePayer を無視し、feePayer をリクエスト内の account に設定する必要があります。
  • ウォレットは、トランザクション内の recentBlockhash を無視し、recentBlockhash最新のブロックハッシュに設定する必要があります。

空でない署名

トランザクションの signatures が空でない場合:

  • アプリケーションは、 feePayer最初の署名の公開鍵に設定する必要があります。
  • アプリケーションは、 recentBlockhash最新のブロックハッシュに設定する必要があります。
  • アプリケーションは、署名する前にトランザクションをシリアライズおよびデシリアライズする必要があります。これにより、アカウントキーの一貫した順序が保証され、 この問題の回避策となります。
  • ウォレットは、 feePayer および recentBlockhashを設定してはなりません。
  • ウォレットは署名を検証する必要があり、無効な署名がある場合、ウォレットはトランザクションを不正な形式として拒否する必要があります。

ウォレットは、リクエスト内の account でのみトランザクションに署名する必要があり、リクエスト内の account の署名が必要な場合にのみ署名する必要があります。

リクエスト内の account の署名以外の署名が必要な場合、ウォレットはトランザクションを悪意のあるものとして拒否する必要があります。

オプションのメッセージフィールド

アプリケーションは、レスポンスボディにオプションの message フィールドを含めることもできます:

{ "message": "<message>", "transaction": "<transaction>" }

<message> の値は、トランザクションレスポンスの性質を説明するUTF-8文字列である必要があります。

たとえば、購入するアイテムの名前、購入に適用される割引、または感謝のメッセージなどが考えられます。ウォレットはこの値をユーザーに表示する必要があります。

ウォレットとアプリケーションは、リクエストボディとレスポンスボディに追加のフィールドを許可する必要があります。これらは将来の仕様によって追加される可能性があります。

トランザクションリクエストを記述するURL

solana:https://example.com/solana-pay

クエリパラメータを含むトランザクションリクエストを記述するURL

solana:https%3A%2F%2Fexample.com%2Fsolana-pay%3Forder%3D12345

GETリクエストの例

GET /solana-pay?order=12345 HTTP/1.1
Host: example.com
Connection: close
Accept: application/json
Accept-Encoding: br, gzip, deflate

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"}

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"}

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"}

拡張機能

この仕様には、アプリとウォレットとの互換性を確保しながら、新しいユースケースを可能にするために、追加のフォーマットとフィールドが組み込まれる場合があります。

アプリケーションとウォレット開発者からのフィードバックを得るために、仕様の変更を提案するGitHub issueを開いてください。

このような提案の実際の例。

関連項目

Is this page helpful?

管理運営

© 2026 Solana Foundation.
無断転載を禁じます。
つながろう