Actions と Blinks
[Solana Actions] (#actions) は、Solanaブロックチェーン上のトランザクションをプレビュー、 署名、送信するための仕様準拠のAPIです。QRコード、ボタンやウィジェット、インターネッ ト上のウェブサイトなど、さまざまなコンテキストで利用できます。 Actionsにより、開発 者はSolanaエコシステム全体の機能を自分の環境に簡単に統合でき、別のアプリやウェブペー ジに移動することなくブロックチェーントランザクションを実行できます。
Blockchain links は、あらゆるSolana Actionsを共有可能でメタデータ豊富 なリンクに変換します。 BlinksはActionsに対応したクライアント (ブラウザ拡張ウォ レット、ボット) は、ユーザーに追加の機能を表示できます。 ウェブサイト上で は、Blinksはウォレット内でトランザクションプレビューを即座にトリガーし、分散型ア プリに移動することなく実行されます。Discordでは、ボットがBlinksをインタラクティ ブなボタンセットに展開するかもしれません。 これにより、URLを表示できる任意のウェ ブサーフェスでオンチェーンのやり取りが可能になります。
はじめに #
カスタムSolana Actionsの作成をすぐに始めるには:
npm install @solana/actions
- アプリケーション にSolana Actions SDK をインス トールします。
- Action に関するメタデータを返す GET request 用のAPIエンドポイ ントを構築します。
- ユーザーに署名可能なトランザクションを返す POST request を受 け付けるAPIエンドポイントを作成します。
このビデオチュートリアルをチェックして、@solana/actions SDKを使用してSolana Actionを構築する方法を学びましょう: how to build a Solana Action
こちら のsource code for an Action で、ネイティブSOLの転送を行うアクション と、this repo 内の他の例示アクションを確認することもできます。
カスタムSolana Actionsを本番環境にデプロイする場合:
- ドメインのルートに有効なactions.json file があることを確認しま す。
actions.json
ファイルを含むすべてのActionエンドポイント で、required Cross-Origin headers を返すようにアプリケー ションが対応していることを確認します。- test and debug your blinks/actions using the Blinks Inspector
アクションやblinksの構築に関するインスピレーションを求めている場合 は、Awesome Blinks リポジ トリをチェックして、コミュニティの作品 やideas for new ones から見つけてください。
Actions #
Solana Actionsの仕様は、アプリケーションから直接ユーザーに署名可能なトランザク ション (将来的には署名可能なメッセージ) を提供する一連の標準APIを使用します。 こ れらは公開URLにホストされ、URLを介して任意のクライアントが相互作用できます。
Actionsは、メタデータとユーザーがブロックチェーンウォレットで署名 (トランザク ションまたは認証メッセージ) するための情報を返すAPIエンドポイントとして考える ことができます。
Actions APIは、ActionのURLエンドポイントへの簡単なGET
およびPOST
リクエスト
を行い、Actionsインターフェースに準拠したレスポンスを処理します。
- GET request は、このURLで利用可能なアクションに関する人間が読 み取れる情報をクライアントに提供し、関連するActionsのリストを返します。
- the POST request returns a signable transaction or message that the client then prompts the user's wallet to sign and execute on the blockchain or in another offchain service.
Actionの実行とライフサイクル #
実際には、Actionsとのやり取りは通常のREST APIとのやり取りに非常に似ています:
- クライアントが最初の
GET
リクエストをAction URLに送信して、利用可能なアクショ ンに関するメタデータを取得します。 - エンドポイントは、エンドポイントに関するメタデータ (アプリケーションのタイトル やアイコンなど) と、このエンドポイントで利用可能なアクションの一覧を含むレスポ ンスを返します。
- クライアントアプリケーション (モバイルウォレット、チャットボット、ウェブサイト など) は、ユーザーがアクションを実行するためのUIを表示します。
- ユーザーがアクションを選択 (ボタンをクリックするなど) した場合、クライアントは
エンドポイントに
POST
リクエストを送信して、ユーザーが署名するトランザクショ ンを取得します。 - ウォレットはユーザーがトランザクションに署名するのを支援し、最終的にはトランザ クションをブロックチェーンに送信して確認します。
Solana Actions Execution and Lifecycle
Action URLからトランザクションを受け取る際、クライアントはこれらのトランザクショ ンをブロックチェーンに送信し、その状態のライフサイクルを管理する必要があります。
Actionsは、実行前にいくつかの無効化レベルもサポートしています。 GET
およ
びPOST
リクエストは、アクションが実行可能かどうかを示すメタデータを返す場合が
あります。(例:disabled
フィールド)
例えば、投票ウィンドウが閉じたDAOガバナンス提案に対する投票を促進するActionエン ドポイントがあった場合、最初のGET request は「この提案は投票の対 象ではありません」というエラーメッセージと「賛成票」「反対票」ボタンを「無効」に します。
Blinks #
Blinks (ブロックチェーンリンク) は、Action APIを調査し、Actionsとのやり取りおよ び実行のためのユーザーインターフェイスを構築するクライアントアプリケーションで す。
Blinksに対応するクライアントアプリケーションは、Action互換のURLを検出し、解析し て、標準化されたユーザーインターフェイスでユーザーがそれらと相互作用できるように します。
完全にAction APIを調査して完全なインターフェースを構築するクライアントアプリ ケーションはblinkと呼ばれます。 したがって、Actions APIを利用するすべてのクラ イアントがblinksというわけではありません。
Blink URL仕様 #
Blink URLは、ユーザー がlifecycle of executing an Action を完了でき るクライアントアプリケーションを記述しています。これには、ウォレットでの署名も含 まれます。
https://example.domain/?action=<action_url>
クライアントアプリケーションがblinkになるには:
-
Blink URLには、URLエンコードされたAction URL を値とするクエリパ ラメータ
action
が含まれている必要があります。 この値は、他のプロトコルパラ メータと競合しないように URL-encoded されなければなりません。 -
クライアントアプリケーションは、actionクエリパラメータを URL-decode し、提供されたAction APIリンクを調査する必要があります (Action URL scheme参照)。
-
クライアントは、ユーザーが lifecycle of executing an Action を完了でき るリッチなユーザーインターフェースをレンダリングする必要があります。これには ウォレットでの署名も含まれます。
すべてのblinkクライアントアプリケーション (例:ウェブサイトやdApp) がすべての アクションをサポートするわけではありません。 アプリケーション開発者は、自分の blinkインターフェースでサポートするアクションを選択できます。
次の例は、URLエンコードされたaction値 solana-action:https://actions.alice.com/donate を持つ有効なblink URLを示していま す:
https://example.domain/?action=solana-action%3Ahttps%3A%2F%2Factions.alice.com%2Fdonate
Blinks経由でActionsを検出する #
Blinksは、少なくとも3つの方法でActionsにリンクできます:
-
明確なAction URLの共有:
solana-action:https://actions.alice.com/donate
この場合、サポートされているクライアントのみがblinkをレンダリングできます。 フォールバックリンクのプレビューや、非対応クライアント以外からアクセスできる サイトはありません。
-
Actions APIにリンクされているウェブサイトへのリンクを
actions.json
file でウェブサイトのドメインルート上で共有し ます。例えば、
https://alice.com/actions.json
は、ユーザーがアリスに寄付できるウェ ブサイトのURLであるhttps://alice.com/donate
と、アリスに寄付するためのアク ションがホストされているAPIのURLであるhttps://actions.alice.com/donate
を マッピングします。 -
Action URLを解析する方法を理解している “interstitial” サイトURLにAction URLを 埋め込む
https://example.domain/?action=<action_url>
Blinksをサポートするクライアントは、上記のいずれかの形式を受け取り、クライアント 内で直接アクションを実行するためのインターフェースを正しくレンダリングする必要が あります。
Blinksをサポートしないクライアントには、基礎となるウェブサイトが存在する必要があ ります (ブラウザがユニバーサルフォールバックになります) 。
ユーザーがクライアント内のアクションボタンやテキスト入力フィールド以外の場所を タップした場合、基礎となるサイトに移動する必要があります。
Blinkのテストと検証 #
Solana Actionsとblinksはパーミッションレスのプロトコル/仕様であるにもかかわら ず、クライアントアプリケーションやウォレットは依然としてユーザーがトランザクショ ンに署名するのを最終的に促す必要があります。
Use the Blinks Inspector tool to inspect, debug, and test your blinks and actions directly in your browser. You can view the GET and POST response payloads, response headers, and test all inputs to each of your linked Actions.
Each client application or wallets may have different requirements on which Action endpoints their clients will automatically unfurl and immediately display to their users on social media platforms.
例えば、一部のクライアントは "allow list" アプローチを採用しており、Dialectの Actions Registry (詳細は下記) など、ユーザーのためのActionを展開する前に検証が必 要になることがあります。
すべてのblinksは、Dialectの dial.to blinks Interstitialサイト でレンダリングされ、署名が可能となりますが、そのレジストリステータスがblink内で 表示されます。
DialectのActions Registry #
公共の利益としてSolanaエコシステムのために、Dialect は Solana Foundationおよび他のコミュニティメンバーの協力を得て、事前に検証済みの既 知のソースからのブロックチェーンリンクの公開レジストリを維持しています。 ローン チ時点で、Dialectのレジストリに登録されたActionsのみが、Twitterフィードに投稿さ れた際に展開されます。
クライアントアプリケーションとウォレットは、この公開レジストリを使用するか、また は別のソリューションを使用してユーザーの安全とセキュリティを確保するかを自由に選 択できます。 Dialectのレジストリを通じて検証されない場合、ブロックチェーンリンク はblinkクライアントによって触れられず、通常のURLとしてレンダリングされます。
開発者はここでDialectによる検証を申請することができま す:dial.to/register
仕様 #
Solana Actions仕様は、リクエスト/レスポンスのやり取りフローの一部である重要なセ クションで構成されています:
- Solana Action URL scheme でAction URLを提供
- OPTIONS response to an Action URL to pass CORS requirements は、CORSの要件を満たすためにAction URLに対して行われるべきです。
- Action URLへの GET request
- サーバーからの GET response
- Action URLへの POST request
- サーバーからの POST response
これらのリクエストはすべて、リッチなユーザーインターフェース向けの特定のメタデー タを収集し、Actions APIへのユーザー入力を促進するためにAction Client (例:ウォ レットアプリ、ブラウザ拡張機能、dApp、ウェブサイトなど) によって行われます。
それぞれのレスポンスは、アプリケーション(ウェブサイト、サーバーバックエンドなど) によって作成され、Action client に返されます。 最終的には、署名可能なトランザ クションまたはウォレットのメッセージを提供して、ユーザーが署名を承認し、ブロック チェーンに送信するように促します。
The types and interfaces declared within this readme files are often the simplified version of the types to aid in readability.
For better type safety and improved developer experience, the
@solana/actions-spec
package contains more complex type definitions. You can
find the
source code for them here.
URLスキーム #
Solana Action URL は solana-action
プロトコルを使用して署名可能なSolanaトラン
ザクションまたはメッセージに対するインタラクティブな要求を記述します。
リクエストはインタラクティブです。URL内のパラメータはクライアントによって、署名 可能なトランザクションを構成するための一連の標準化されたHTTPリクエストや、ユー ザーがウォレットで署名するためのメッセージを作成するために使用されます。
solana-action:<link>
-
パス名には
link
フィールドが必要です。 値は条件付きで URLエンコード された完全なHTTPS URLである必要があります。 -
URLにクエリパラメータが含まれている場合、URLエンコードされていなければなりませ ん。 URLエンコードすることで、プロトコル仕様によって追加される可能性のある他の アクションプロトコルパラメータと競合しないようにします。
-
URLにクエリパラメータが含まれていない場合、URLエンコードしないでください。これ により、短いURLとより少ない密度のQRコードが生成されます。
いずれの場合も、クライアントは値 をURL-decodeし なければならない。 これは、値が URL エンコードされていない場合には効果はありませ ん。 デコードされた値が絶対的なHTTPSURLでない場合、ウォレットはmalformedとし て拒否する必要があります。
OPTIONSレスポンス #
Cross-Origin Resource Sharing (CORS) をActionsクライ アント (blinksを含む) で許可するために、すべてのActionエンドポイントは、同一オリ ジンドメインからのすべての後続のリクエストに対してCORSチェックを通過させることが できる有効なヘッダーを含むOPTIONSメソッドに対するHTTPリクエストに応答すべきで す。
Actionsクライアントは、後続のGETリクエストがすべてのCORSチェックを通過するかどう
かを確認するために、Action URLエンドポイントに対し
て"preflight"
リクエストを実行することがあります。 これらのCORSプレフライトチェックはOPTIONS
HTTPメソッドを使用して行われ、Actionsクライアント (blinksのような) が自身のオリ
ジンドメインからすべての後続のリクエストを適切に行うことができるように、必要なす
べてのHTTPヘッダーで応答するべきです。
必要最低限のHTTPヘッダーには以下のものが含まれます:
Access-Control-Allow-Origin
は値として*
を持ち、- これによりすべてのActionクライアントが安全にCORSチェックを通過し、必要なリク エストを行うことが保証されます。
Access-Control-Allow-Methods
は値としてGET,POST,PUT,OPTIONS
を持ち、- Actionsに必要なすべてのHTTPリクエスト方法がサポートされることを保証します。
Access-Control-Allow-Headers
は最低限Content-Type, Authorization, Content-Encoding, Accept-Encoding
の値を持つべ きです。
簡単のため、開発者はGET
response と同じ応答とヘッダー
をOPTIONS
リクエストに対しても返すことを検討すべきです。
actions.json
ファイルのレスポンスも、GET
およびOPTIONS
リクエストに対して
有効なクロスオリジンヘッダーを返さなければならず、特
にAccess-Control-Allow-Origin
ヘッダーの値は *
である必要があります。
詳細については以下のactions.json を参照してください。
GETリクエスト #
Actionクライアント (例えばウォレット、ブラウザ拡張機能など) は、ActionのURLエン
ドポイントにHTTP GET
JSONを要求する必要があります。
- リクエストはウォレットまたはユーザーを識別しないでください。
- クライアントは [
Accept-Encoding
ヘッダーを使用してリクエストを行う必要があり ます。(https://developer.mozilla.org/docs/Web/HTTP/Headers/Accept-Encoding) - クライアントは、リクエストが行われている間、URL のドメインを表示する必要があり ます。
GETレスポンス #
ActionのURLエンドポイント (例:アプリケーションまたはサーバーのバックエンド)
は、HTTP OK
JSON レスポンス (有効なペイロードをボディに含む) または適切なHTTP
エラーで応答するべきです。
-
クライアントはHTTP のclient errors 、server errors 、redirect responses を処理しなければならない。
-
エンドポイントはHTTP圧縮のために
Content-Encoding
header で応答するべきです。 -
エンドポイント は
application/json
のContent-Type
header ヘッダーで応答するべきです。 -
クライアント は、HTTP caching のレスポンスヘッダーに指示された場合を除き、レスポンスをキャッシュすべきではあ りません。
-
クライアントは
title
を表示し、icon
画像をユーザーにレンダリングするべきで す。
Error responses (i.e. HTTP 4xx and 5xx status codes) should return a JSON
response body following ActionError
to present a helpful error message to
users. See Action Errors.
GETレスポンスボディ #
HTTP OK
JSON レスポンスを持つ GET
レスポンスは、インターフェイスの仕様に従う
bodyペイロードを含める必要があります。
export type ActionType = "action" | "completed";
export type ActionGetResponse = Action<"action">;
export interface Action<T extends ActionType> {
/** type of Action to present to the user */
type: T;
/** image url that represents the source of the action request */
icon: string;
/** describes the source of the action request */
title: string;
/** brief summary of the action to be performed */
description: string;
/** button text rendered to the user */
label: string;
/** UI state for the button being rendered to the user */
disabled?: boolean;
links?: {
/** list of related Actions a user could perform */
actions: LinkedAction[];
};
/** non-fatal error message to be displayed to the user */
error?: ActionError;
}
-
type
- The type of action being given to the user. Defaults toaction
. The initialActionGetResponse
is required to have a type ofaction
.action
- Standard action that will allow the user to interact with any of theLinkedActions
completed
- Used to declare the "completed" state within action chaining.
-
icon
- アイコン画像のHTTPまたはHTTPSのURLを指定する必要があります。 ファイル はSVG、PNG、またはWebPイメージである必要があり、クライアント/ウォレット はmalformedとして拒否しなければなりません。 -
title
- アクションリクエストのソースを表すUTF-8文字列でなければなりません。 例えば、ブランド名、ストア名、アプリケーション名、またはリクエストを行っている 人名などです。 -
description
- アクションに関する情報を提供するUTF-8文字列である必要がありま す。 説明はユーザーに表示されます。 -
label
- ユーザーがクリックするためには、ボタンにレンダリングされるUTF-8文字 列である必要があります。 すべてのラベルは5ワードフレーズを超えないようにし、 ユーザーに取って欲しいアクションを確立するために動詞で始めるべきです。 例: 「NFTをミントする」「賛成票を投じる」「1 SOLをステークする」など。 -
disabled
- 値はレンダリングされたボタンの無効状態を表すブール値でなければな りません(label
文字列を表示します) 。 値が指定されていない場合、disabled
はfalse
(デフォルトで有効) になります。 例えば、ガバナンス投票が終了した場 合、disabled=true
を設定し、label
は"Vote Closed" と表示されることがありま す。 -
error
- 致命的でないエラーのためのオプションのエラー表示。 errorがある場合 は、クライアントはそれをユーザーに表示する必要があります。 If set, it should not prevent the client from interpreting the action or displaying it to the user (see Action Errors). For example, the error can be used together withdisabled
to display a reason like business constraints, authorization, the state, or an error of external resource. -
links.actions
- エンドポイントに関連するアクションのオプション配列。 ユー ザーは、リストされたアクションごとにUIを表示し、1つのみを実行する必要がありま す。 例えば、ガバナンス投票アクションエンドポイントは、ユーザーに"Vote Yes"、"Vote No"、"Abstain from Vote" の3つのオプションを提供することがありま す。-
もし
links.actions
が提供されていない場合、クライアントはルートのlabel
文字列を使用して単一のボタンを表示し、初期の GET リクエストと同じアクション URLエンドポイントに対して POST リクエストを行うべきです。 -
links.actions
が提供されている場合、クライアントはlinks.actions
フィー ルドに記載されている項目に基づいてボタンと入力フィールドのみを表示すべきで す。 クライアントはルートのlabel
の内容に対するボタンを表示すべきではあり ません。
-
export interface LinkedAction {
/** URL endpoint for an action */
href: string;
/** button text rendered to the user */
label: string;
/**
* Parameters to accept user input within an action
* @see {ActionParameter}
* @see {ActionParameterSelectable}
*/
parameters?: Array<TypedActionParameter>;
}
The ActionParameter
allows declaring what input the Action API is requesting
from the user:
/**
* Parameter to accept user input within an action
* note: for ease of reading, this is a simplified type of the actual
*/
export interface ActionParameter {
/** input field type */
type?: ActionParameterType;
/** parameter name in url */
name: string;
/** placeholder text for the user input field */
label?: string;
/** declare if this field is required (defaults to `false`) */
required?: boolean;
/** regular expression pattern to validate user input client side */
pattern?: string;
/** human-readable description of the `type` and/or `pattern`, represents a caption and error, if value doesn't match */
patternDescription?: string;
/** the minimum value allowed based on the `type` */
min?: string | number;
/** the maximum value allowed based on the `type` */
max?: string | number;
}
The pattern
should be a string equivalent of a valid regular expression. This
regular expression pattern should by used by blink-clients to validate user
input before before making the POST request. If the pattern
is not a valid
regular expression, it should be ignored by clients.
The patternDescription
is a human readable description of the expected input
requests from the user. If pattern
is provided, the patternDescription
is
required to be provided.
The min
and max
values allows the input to set a lower and/or upper bounds
of the input requested from the user (i.e. min/max number and or min/max
character length), and should be used for client side validation. For input
type
s of date
or datetime-local
, these values should be a string dates.
For other string based input type
s, the values should be numbers representing
their min/max character length.
If the user input value is not considered valid per the pattern
, the user
should receive a client side error message indicating the input field is not
valid and displayed the patternDescription
string.
The type
field allows the Action API to declare more specific user input
fields, providing better client side validation and improving the user
experience. In many cases, this type will resemble the standard
HTML input element.
The ActionParameterType
can be simplified to the following type:
/**
* Input field type to present to the user
* @default `text`
*/
export type ActionParameterType =
| "text"
| "email"
| "url"
| "number"
| "date"
| "datetime-local"
| "checkbox"
| "radio"
| "textarea"
| "select";
Each of the type
values should normally result in a user input field that
resembles a standard HTML input
element of the corresponding type
(i.e.
<input type="email" />
) to provide better client side validation and user
experience:
text
- equivalent of HTML “text” input elementemail
- equivalent of HTML “email” input elementurl
- equivalent of HTML “url” input elementnumber
- equivalent of HTML “number” input elementdate
- equivalent of HTML “date” input elementdatetime-local
- equivalent of HTML “datetime-local” input elementcheckbox
- equivalent to a grouping of standard HTML “checkbox” input elements. The Action API should returnoptions
as detailed below. The user should be able to select multiple of the provided checkbox options.radio
- equivalent to a grouping of standard HTML “radio” input elements. The Action API should returnoptions
as detailed below. The user should be able to select only one of the provided radio options.- Other HTML input type equivalents not specified above (
hidden
,button
,submit
,file
, etc) are not supported at this time.
In addition to the elements resembling HTML input types above, the following user input elements are also supported:
textarea
- equivalent of HTML textarea element. Allowing the user provide multi-line input.select
- equivalent of HTML select element, allowing the user to experience a “dropdown” style field. The Action API should returnoptions
as detailed below.
When type
is set as select
, checkbox
, or radio
then the Action API
should include an array of options
that each provide a label
and value
at
a minimum. Each option may also have a selected
value to inform the
blink-client which of the options should be selected by default for the user
(see checkbox
and radio
for differences).
This ActionParameterSelectable
can be simplified to the following type
definition:
/**
* note: for ease of reading, this is a simplified type of the actual
*/
interface ActionParameterSelectable extends ActionParameter {
options: Array<{
/** displayed UI label of this selectable option */
label: string;
/** value of this selectable option */
value: string;
/** whether or not this option should be selected by default */
selected?: boolean;
}>;
}
If no type
is set or an unknown/unsupported value is set, blink-clients should
default to text
and render a simple text input.
The Action API is still responsible to validate and sanitize all data from the user input parameters, enforcing any “required” user input as necessary.
For platforms other that HTML/web based ones (like native mobile), the equivalent native user input component should be used to achieve the equivalent experience and client side validation as the HTML/web input types described above.
GETレスポンスの例 #
以下の例は、ユーザーに "Claim Access Token" というラベルのボタンを表示することが 期待される単一の"root" アクションを提供します:
{
"title": "HackerHouse Events",
"icon": "<url-to-image>",
"description": "Claim your Hackerhouse access token.",
"label": "Claim Access Token" // button text
}
以下の例は、DAO提案に対して3つのボタンのいずれかをクリックして投票するための3つ の関連アクションリンクを提供します:
{
"title": "Realms DAO Platform",
"icon": "<url-to-image>",
"description": "Vote on DAO governance proposals #1234.",
"label": "Vote",
"links": {
"actions": [
{
"label": "Vote Yes", // button text
"href": "/api/proposal/1234/vote?choice=yes"
},
{
"label": "Vote No", // button text
"href": "/api/proposal/1234/vote?choice=no"
},
{
"label": "Abstain from Vote", // button text
"href": "/api/proposal/1234/vote?choice=abstain"
}
]
}
}
パラメータを使用した GET レスポンスの例 #
以下の例は、ユーザーからのテキスト入力を受け取り (parameters
を介して) 、最終
的なPOST
リクエストエンドポイント(LinkedAction
内の href
フィールドを介し
て) にその入力を含める方法を示しています :
以下の例のレスポンスは、ユーザーがクリックできる3つの関連アクションリンクを提供 します:1 SOLをステークする"Stake 1 SOL" 、5 SOLをステークする"Stake 5 SOL" 、お よび特定の"amount" 値を入力するテキスト入力フィールド「ステークする量」を提供し ます。これは、Action APIに送信されます:
{
"title": "Stake-o-matic",
"icon": "<url-to-image>",
"description": "Stake SOL to help secure the Solana network.",
"label": "Stake SOL", // not displayed since `links.actions` are provided
"links": {
"actions": [
{
"label": "Stake 1 SOL", // button text
"href": "/api/stake?amount=1"
// no `parameters` therefore not a text input field
},
{
"label": "Stake 5 SOL", // button text
"href": "/api/stake?amount=5"
// no `parameters` therefore not a text input field
},
{
"label": "Stake", // button text
"href": "/api/stake?amount={amount}",
"parameters": [
{
"name": "amount", // field name
"label": "SOL amount" // text input placeholder
}
]
}
]
}
}
以下の例のレスポンスは、ユーザーが入力する amount
を受け取り、それをPOSTリクエ
ストに送信します (クエリパラメータまたはサブパスとして使用できます) :
{
"icon": "<url-to-image>",
"label": "Donate SOL",
"title": "Donate to GoodCause Charity",
"description": "Help support this charity by donating SOL.",
"links": {
"actions": [
{
"label": "Donate", // button text
"href": "/api/donate/{amount}", // or /api/donate?amount={amount}
"parameters": [
// {amount} input field
{
"name": "amount", // input field name
"label": "SOL amount" // text input placeholder
}
]
}
]
}
}
POSTリクエスト #
クライアントは、次のボディペイロードを持つアクションURLへのHTTP POST
JSON リク
エストを行う必要があります:
{
"account": "<account>"
}
account
- 値は、トランザクションに署名する可能性のあるアカウントのbase58エン コードされた公開鍵でなければなりません。
クライアントは Accept-Encoding header を使用してリクエストを行うべきで、アプリケーションはHTTP圧縮のために Content-Encoding header で応答する可能性があります。
クライアントは、リクエストが行われている間、URL のドメインを表示する必要がありま
す。 GET
リクエストが行われた場合、クライアントは title
を表示し、GET リクエ
ストからの icon
イメージをレンダリングする必要があります。
POSTレスポンス #
ActionのPOST
エンドポイントは、HTTP OK
JSONレスポンス (有効なペイロードをボ
ディに含む) または適切なHTTPエラーで応答するべきです。
- クライアントはHTTP client errors 、 server errors 、およ びredirect responses を処理しなければなりません。
- エンドポイントは
application/json
のContent-Type
header で応答するべきです。
Error responses (i.e. HTTP 4xx and 5xx status codes) should return a JSON
response body following ActionError
to present a helpful error message to
users. See Action Errors.
POSTレスポンスボディ #
HTTP OK
JSONレスポンスを持つPOST
レスポンスには、以下のボディペイロードを含め
る必要があります。
/**
* Response body payload returned from the Action POST Request
*/
export interface ActionPostResponse<T extends ActionType = ActionType> {
/** base64 encoded serialized transaction */
transaction: string;
/** describes the nature of the transaction */
message?: string;
links?: {
/**
* The next action in a successive chain of actions to be obtained after
* the previous was successful.
*/
next: NextActionLink;
};
}
-
transaction
- 値はベース64エンコードされた シリアル化されたトランザクション でなければなりません。クライアントはトランザクションをbase64デコード し、deserialize it 必要があります。 -
message
- レスポンスに含まれるトランザクションの性質を記述するUTF-8文字列で ある必要があります。 クライアントはこの値をユーザーに表示する必要があります。 例えば、購入するアイテムの名前、購入に適用された割引、または感謝のメッセージな どです。 -
links.next
- An optional value use to "chain" multiple Actions together in series. After the includedtransaction
has been confirmed on-chain, the client can fetch and render the next action. See Action Chaining for more details. -
クライアントとアプリケーションは、将来の仕様更新によって追加される可能性のある リクエストボディおよびレスポンスボディの追加フィールドを許可するべきです。
アプリケーションは、部分的または完全に署名されたトランザクションで応答すること ができます。 ウォレットは untrusted としてトランザクションを検証する必要が あります。
POSTレスポンス - トランザクション #
トランザクション
のsignatures
が空であるか、トランザクションが部分的に署名されていない場合:
- クライアントはトランザクション内
の
feePayer
を無視し、リクエスト内のaccount
をfeePayer
として設定する必要があります。 - また、クライアントはトランザクション内
の
recentBlockhash
を無視し、recentBlockhash
を latest blockhash に設定する必要があります。 - クライアントは署名する前にトランザクションをシリアライズしてデシリアライズする 必要があります。これによ り、this issue の回避策 として、アカウントキーの順序が一貫して保たれます。
トランザクションが部分的に署名されている場合:
- クライアントは、既存の署名を無効にするた
め、
feePayer
やrecentBlockhash
を変更してはいけません。 - クライアントは既存の署名を検証し、無効な署名がある場合は、トランザクションを malformed として拒否する必要があります。
クライアントはリクエスト内の account
でトランザクションにのみ署名を行い、リク
エストの account
の署名が期待される場合のみこれを行うべきです。
リクエスト内の account
の署名以外の署名が期待される場合、クライアントはトラン
ザクションを malicious として拒否する必要があります。
Action Errors #
Actions APIs should return errors using ActionError
in order to present
helpful error messages to the user. Depending on the context, this error could
be fatal or non-fatal.
export interface ActionError {
/** simple error message to be displayed to the user */
message: string;
}
When an Actions API responds with an HTTP error status code (i.e. 4xx and 5xx),
the response body should be a JSON payload following ActionError
. The error is
considered fatal and the included message
should be presented to the user.
For API responses that support the optional error
attribute (like
ActionGetResponse
), the error is considered non-fatal and the
included message
should be presented to the user.
Action Chaining #
Solana Actions can be "chained" together in a successive series. After an Action's transaction is confirmed on-chain, the next action can be obtained and presented to the user.
Action chaining allows developers to build more complex and dynamic experiences within blinks, including:
- providing multiple transactions (and eventually sign message) to a user
- customized action metadata based on the user's wallet address
- refreshing the blink metadata after a successful transaction
- receive an API callback with the transaction signature for additional validation and logic on the Action API server
- customized "success" messages by updating the displayed metadata (e.g. a new image and description)
To chain multiple actions together, in any ActionPostResponse
include a
links.next
of either:
PostNextActionLink
- POST request link with a same origin callback url to receive thesignature
and user'saccount
in the body. This callback url should respond with aNextAction
.InlineNextActionLink
- Inline metadata for the next action to be presented to the user immediately after the transaction has confirmed. No callback will be made.
export type NextActionLink = PostNextActionLink | InlineNextActionLink;
/** @see {NextActionPostRequest} */
export interface PostNextActionLink {
/** Indicates the type of the link. */
type: "post";
/** Relative or same origin URL to which the POST request should be made. */
href: string;
}
/**
* Represents an inline next action embedded within the current context.
*/
export interface InlineNextActionLink {
/** Indicates the type of the link. */
type: "inline";
/** The next action to be performed */
action: NextAction;
}
NextAction #
After the ActionPostResponse
included transaction
is signed by the user and
confirmed on-chain, the blink client should either:
- execute the callback request to fetch and display the
NextAction
, or - if a
NextAction
is already provided vialinks.next
, the blink client should update the displayed metadata and make no callback request
If the callback url is not the same origin as the initial POST request, no callback request should be made. Blink clients should display an error notifying the user.
/** The next action to be performed */
export type NextAction = Action<"action"> | CompletedAction;
/** The completed action, used to declare the "completed" state within action chaining. */
export type CompletedAction = Omit<Action<"completed">, "links">;
Based on the type
, the next action should be presented to the user via blink
clients in one of the following ways:
-
action
- (default) A standard action that will allow the user to see the included Action metadata, interact with the providedLinkedActions
, and continue to chain any following actions. -
completed
- The terminal state of an action chain that can update the blink UI with the included Action metadata, but will not allow the user to execute further actions.
If no links.next
is not provided, blink clients should assume the current
action is final action in the chain, presenting their "completed" UI state after
the transaction is confirmed.
actions.json #
actions.json
file の目的は、クライアントにSolana Actionsをサ
ポートするウェブサイトURLを指示し、 GET requests をActions API
サーバーに送信するためのマッピングを提供することです。
actions.json
ファイルのレスポンスは、GET
および OPTIONS
リクエストに対して
有効なクロスオリジンヘッダーも返さなければなりません。具体的に
は、Access-Control-Allow-Origin
ヘッダーの値は *
である必要があります。
詳細については上記の OPTIONS response を参照してください。
actions.json
ファイルは保存され、ドメインのルートに普遍的にアクセスできるよう
にする必要があります。
例えば、ウェブアプリケーションが my-site.com
にデプロイされている場合、
actions.json
ファイルは https://my-site.com/actions.json
からアクセスできま
す。このファイルは、Access-Control-Allow-Origin
ヘッダーの値を *
にすること
で、任意のブラウザからクロスオリジンでアクセス可能であるべきです。
ルール #
rules
フィールドを使用すると、ウェブサイトの相対パスルートパスを他のパスのセッ
トにマップすることができます。
Type: ActionRuleObject
の Array
interface ActionRuleObject {
/** relative (preferred) or absolute path to perform the rule mapping from */
pathPattern: string;
/** relative (preferred) or absolute path that supports Action requests */
apiPath: string;
}
-
pathPattern
- 受信する各パス名と一致するパターン。 -
apiPath
- 完全なパス名または外部 URL として定義されている ロケーション先。
ルール - pathPattern #
各入力パス名に一致するパターン。 絶対または相対パスとして定義でき、次の形式をサ ポートします:
-
Exact Match: 正確なURLパスに一致します。
- 例:
/exact-path
- 例:
https://website.com/exact-path
- 例:
-
Wildcard Match: ワイルドカードを使用して、URLパス内の任意の文字列に一致さ せます。 これは単一(
*
) または複数のセグメント(**
) を一致させます。 (Path Matching 参照)- 例:
/trade/*
は、/trade/123
および/trade/abcと一致し、/trade/
の後の 最初のセグメントのみをキャプチャします。 - 例:
/category/*/item/**
は/category/123/item/456
と/category/abc/item/def
と一致します。 - 例:
/api/actions/trade/*/confirm
は/api/actions/trade/123/confirm
と一 致します。
- 例:
ルール - apiPath #
アクション要求の宛先パス。 完全なパス名または外部 URL として定義できます。
- 例:
/exact-path
- 例:
https://api.example.com/v1/donate/*
- 例:
/api/category/*/item/*
- 例:
/api/swap/**
ルール - クエリパラメータ #
元のURLからのクエリパラメータは常に保存され、マップされたURLに追加されます。
ルール - パスマッチング #
次の表は、パスマッチングパターンの構文を示しています。
Operator | 一致 |
---|---|
* | パスセグメント単位で一致し、パス区切り文字/を含みません。 |
** | 任意の文字列と一致し、複数のパスセグメント間の任意のパス区切り文字/を含みます。 他の演算子が含まれる場合、**演算子は最後の演算子でなければなりません。 |
? | サポートされていないパターン。 |
ルール例 #
次の例は、サイトのルートからの /buy
へのリクエストを、サイトのルートからの相対
パス /api/buy
に正確にマップする完全一致ルールを示しています:
{
"rules": [
{
"pathPattern": "/buy",
"apiPath": "/api/buy"
}
]
}
次の例では、ワイルドカードパスマッチングを使用して、サイトのルートにある
/actions/
の下の任意のパス (サブディレクトリは除く) から、サイトのルートに相対
的な /api/actions/
の下の対応するパスへリクエストをマッピングします。
{
"rules": [
{
"pathPattern": "/actions/*",
"apiPath": "/api/actions/*"
}
]
}
次の例では、ワイルドカードパスマッチングを使用して、サイトのルートにある
/donate/
の下の任意のパス (サブディレクトリは除く) から、外部サイト上の絶対パ
ス https://api.dialect.com/api/v1/donate/
へのリクエストをマッピングします
{
"rules": [
{
"pathPattern": "/donate/*",
"apiPath": "https://api.dialect.com/api/v1/donate/*"
}
]
}
次の例では、idempotentルールにワイルドカードのパスマッチを使い、 サイトのルート
から /api/actions/
以下のすべてのパス (サブディレクトリを 含む) へのリクエスト
をそれ自身にマップしています:
solana-action:
URIを先頭に付けたり、追加のレスポンステストを実行することな
く、与えられたパスがAction APIリクエストをサポートしているかどうかをblinkクラ
イアントがより簡単に判断できるようにする。
{
"rules": [
{
"pathPattern": "/api/actions/**",
"apiPath": "/api/actions/**"
}
]
}
アクションアイデンティティ #
アクションエンドポイントには、ユーザーが署名するPOST response 内のトランザクションに Action Identity を含めることができます。 これにより、イ ンデクサおよび分析プラットフォームが特定のアクションプロバイダー (サービス) に チェーン上の活動を簡単に帰属させ、検証することができます。
Action Identity は、メモ命令を使用してトランザクションに含ま れる特別な形式のメッセージに署名するために使用されるキーペアです。 この Identifier Message は、特定のアクション アイデンティティ、によって検証可能にな り、トランザクションを特定のアクション プロバイダーに属させることができます。
キーペアは、取引自体に署名する必要はありません。 これにより、ウォレットとアプリ ケーションは、他の署名がユーザーに返されたトランザクションにない場合、トランザク ションの配信性を向上させることができます( POST レスポンストランザクション を参照してくださ い)。
アクションプロバイダーのユースケースが、ユーザーの前にトランザクションをプリサイ ンするバックエンドサービスを必要とする場合、このキーペアをアクションアイデンティ ティとして使用する必要があります。 これにより、トランザクションに含まれるアカウ ントが32バイト削減され、トランザクション全体のサイズが小さくなります。
Action Identifier Message #
Action Identifier Messageは、単一の SPL Memo 命令 を使用して、トランザクションに含まれるコロン別のUTF-8文字列です。
protocol:identity:reference:signature
protocol
- 使用されるプロトコルの値 ( URL Scheme に基づきsolana-action
に設定)identity
- 値は、 アクションアイデンティティキーペアのベース58エンコードされ た公開鍵アドレスでなければなりませんreference
- 値はベース58エンコードされた32バイトの配列でなければなりません。 これは公開鍵かもしれませんし、曲線上であるかどうかにかかわらず、Solana上のアカ ウントに対応しているかもしれませんし、対応していないかもしれません。signature
-reference
値の署名を作成するためにアクションアイデンティティ キーペアが署名したbase58エンコードされた署名です。
reference
の値は、1つのトランザクションで1回だけ使用する必要があります。 アク
ションプロバイダーにトランザクションを関連付けるためには、reference
値の最初の
使用のみが有効と見なされます。
トランザクションには複数のMemo命令が含まれていることがあります。
getSignaturesForAddress
を実行すると、結果のmemoフィールドは各 memo
命令のメッセージを1つの文字列とし
て返し、それぞれがセミコロンで区切られます。
Identifier MessageのMemo命令には他のデータを含めてはいけません。
identity
およびreference
は、識別メッセージ Memo命令ではない命令の読み取り専
用、署名者でない
keys
としてトランザクションに含めるべきです。
Identifier Message Memo 命令は、指定されたゼロアカウントでなければなりません。ア カウントが提供された場合、Memo プログラムでは有効な署名者である必要があります。 アクションを識別するために、これは柔軟性を制限し、はユーザーエクスペリエンスを低 下させる可能性があります。 そのため、アンチパターンであると考えられており、は避 けなければなりません。
アクションアイデンティティ認証 #
トランザクションに identity
アカウントが含まれている場合、それをアクションプロ
バイダーに検証可能に関連付けるには、以下の手順を行います:
- 与えられた
identity
のすべてのトランザクションを取得します。 - 各トランザクションのメモ文字列を解析して検証し、
signature
が格納されているreference
に対して有効であることを確認する。 - 特定のトランザクションがオンチェーンの
reference
の最初のオンチェーンである ことを確認します。- このトランザクションが最初の発生である場合、トランザクションは検証済みと見 なされ、アクションプロバイダーに安全に関連付けることができます。
- このトランザクションが最初の発生でない場合、無効と見なされ、アクションプロ バイダーに関連付けられません。
Solanaバリデータはトランザクションをアカウントキーによってインデックス付けするた
め、getSignaturesForAddress
RPCメソッドを使用して、identity
アカウントを含むすべてのトランザクションを検索
できます。
このRPCメソッドのレスポンスには、すべての memo
データがmemoフィールドに含まれ
ます。 トランザクションに複数のMemo命令が使用されている場合、各メモメッセージは
この memo
フィールドに含まれ、それに応じて検証者が解析して Identity
Verification Message を取得する必要があります。
これらのトランザクションは最初に UNVERIFIED と見なされるべきです。 これ
は、identity
がトランザクションに署名する必要がないためで、これにより、このア
カウントを署名者以外として含むトランザクションが可能になります。 人工的にアトリ
ビューションや使用カウントを膨らませる可能性があります。
Identity Verification Message は signature
が reference
に署名する
identity
によって作成されたことを確認する この署名検証に失敗した場合、トランザ
クションは無効であり、アクションプロバイダに帰属する必要があります。
署名の検証が成功した場合、検証者はこのトランザクションが reference
のチェーン
上での最初の発生であることを確認する必要があります。 そうでない場合は、トランザ
クションは無効と見なされます。