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エンドポイントを作成します。
Info

このビデオチュートリアルをチェックして、@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を介して任意のクライアントが相互作用できます。

Info

Actionsは、メタデータとユーザーがブロックチェーンウォレットで署名 (トランザク ションまたは認証メッセージ) するための情報を返すAPIエンドポイントとして考える ことができます。

Actions APIは、ActionのURLエンドポイントへの簡単なGET およびPOST リクエスト を行い、Actionsインターフェースに準拠したレスポンスを処理します。

  1. GET request は、このURLで利用可能なアクションに関する人間が読 み取れる情報をクライアントに提供し、関連するActionsのリストを返します。
  2. 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 LifecycleSolana Actions Execution and Lifecycle

Action URLからトランザクションを受け取る際、クライアントはこれらのトランザクショ ンをブロックチェーンに送信し、その状態のライフサイクルを管理する必要があります。

Actionsは、実行前にいくつかの無効化レベルもサポートしています。 GET およ びPOST リクエストは、アクションが実行可能かどうかを示すメタデータを返す場合が あります。(例:disabled フィールド)

例えば、投票ウィンドウが閉じたDAOガバナンス提案に対する投票を促進するActionエン ドポイントがあった場合、最初のGET request は「この提案は投票の対 象ではありません」というエラーメッセージと「賛成票」「反対票」ボタンを「無効」に します。

Blinks (ブロックチェーンリンク) は、Action APIを調査し、Actionsとのやり取りおよ び実行のためのユーザーインターフェイスを構築するクライアントアプリケーションで す。

Blinksに対応するクライアントアプリケーションは、Action互換のURLを検出し、解析し て、標準化されたユーザーインターフェイスでユーザーがそれらと相互作用できるように します。

Info

完全にAction APIを調査して完全なインターフェースを構築するクライアントアプリ ケーションはblinkと呼ばれます。 したがって、Actions APIを利用するすべてのクラ イアントがblinksというわけではありません。

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 を完了でき るリッチなユーザーインターフェースをレンダリングする必要があります。これには ウォレットでの署名も含まれます。

Info

すべての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にリンクできます:

  1. 明確なAction URLの共有:solana-action:https://actions.alice.com/donate

    この場合、サポートされているクライアントのみがblinkをレンダリングできます。 フォールバックリンクのプレビューや、非対応クライアント以外からアクセスできる サイトはありません。

  2. Actions APIにリンクされているウェブサイトへのリンクを actions.json file でウェブサイトのドメインルート上で共有し ます。

    例えば、https://alice.com/actions.jsonは、ユーザーがアリスに寄付できるウェ ブサイトのURLであるhttps://alice.com/donateと、アリスに寄付するためのアク ションがホストされているAPIのURLであるhttps://actions.alice.com/donateを マッピングします。

  3. Action URLを解析する方法を理解している “interstitial” サイトURLにAction URLを 埋め込む

    https://example.domain/?action=<action_url>

Blinksをサポートするクライアントは、上記のいずれかの形式を受け取り、クライアント 内で直接アクションを実行するためのインターフェースを正しくレンダリングする必要が あります。

Blinksをサポートしないクライアントには、基礎となるウェブサイトが存在する必要があ ります (ブラウザがユニバーサルフォールバックになります) 。

ユーザーがクライアント内のアクションボタンやテキスト入力フィールド以外の場所を タップした場合、基礎となるサイトに移動する必要があります。

Blinkのテストと検証 #

Solana Actionsとblinksはパーミッションレスのプロトコル/仕様であるにもかかわら ず、クライアントアプリケーションやウォレットは依然としてユーザーがトランザクショ ンに署名するのを最終的に促す必要があります。

Info

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仕様は、リクエスト/レスポンスのやり取りフローの一部である重要なセ クションで構成されています:

これらのリクエストはすべて、リッチなユーザーインターフェース向けの特定のメタデー タを収集し、Actions APIへのユーザー入力を促進するためにAction Client (例:ウォ レットアプリ、ブラウザ拡張機能、dApp、ウェブサイトなど) によって行われます。

それぞれのレスポンスは、アプリケーション(ウェブサイト、サーバーバックエンドなど) によって作成され、Action client に返されます。 最終的には、署名可能なトランザ クションまたはウォレットのメッセージを提供して、ユーザーが署名を承認し、ブロック チェーンに送信するように促します。

Info

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 リクエストに対しても返すことを検討すべきです。

Cross-Origin headers for actions.json

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 errorsserver errorsredirect responses を処理しなければならない。

  • エンドポイントはHTTP圧縮のために Content-Encoding header で応答するべきです。

  • エンドポイント はapplication/jsonContent-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ペイロードを含める必要があります。

ActionGetResponse
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 to action. The initial ActionGetResponse is required to have a type of action.

    • action - Standard action that will allow the user to interact with any of the LinkedActions
    • 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文字列を表示します) 。 値が指定されていない場合、 disabledfalse (デフォルトで有効) になります。 例えば、ガバナンス投票が終了した場 合、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 with disabled 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 の内容に対するボタンを表示すべきではあり ません。

LinkedAction
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:

ActionParameter
/**
 * 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 types of date or datetime-local, these values should be a string dates. For other string based input types, 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:

ActionParameterType
/**
 * 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 element
  • email - equivalent of HTML “email” input element
  • url - equivalent of HTML “url” input element
  • number - equivalent of HTML “number” input element
  • date - equivalent of HTML “date” input element
  • datetime-local - equivalent of HTML “datetime-local” input element
  • checkbox - equivalent to a grouping of standard HTML “checkbox” input elements. The Action API should return options 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 return options 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 return options 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:

ActionParameterSelectable
/**
 * 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エラーで応答するべきです。

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レスポンスには、以下のボディペイロードを含め る必要があります。

ActionPostResponse
/**
 * 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 included transaction has been confirmed on-chain, the client can fetch and render the next action. See Action Chaining for more details.

  • クライアントとアプリケーションは、将来の仕様更新によって追加される可能性のある リクエストボディおよびレスポンスボディの追加フィールドを許可するべきです。

Info

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

POSTレスポンス - トランザクション #

トランザクション のsignatures が空であるか、トランザクションが部分的に署名されていない場合:

  • クライアントはトランザクション内 のfeePayer を無視し、リクエスト内のaccountfeePayer として設定する必要があります。
  • また、クライアントはトランザクション内 のrecentBlockhash を無視し、 recentBlockhashlatest blockhash に設定する必要があります。
  • クライアントは署名する前にトランザクションをシリアライズしてデシリアライズする 必要があります。これによ り、this issue の回避策 として、アカウントキーの順序が一貫して保たれます。

トランザクションが部分的に署名されている場合:

  • クライアントは、既存の署名を無効にするた め、feePayerrecentBlockhash を変更してはいけません。
  • クライアントは既存の署名を検証し、無効な署名がある場合は、トランザクションを 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.

ActionError
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 the signature and user's account in the body. This callback url should respond with a NextAction.
  • 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 via links.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.

NextAction
/** 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 provided LinkedActions, 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 サーバーに送信するためのマッピングを提供することです。

Cross-Origin headers are required

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: ActionRuleObjectArray

ActionRuleObject
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 に正確にマップする完全一致ルールを示しています:

actions.json
{
  "rules": [
    {
      "pathPattern": "/buy",
      "apiPath": "/api/buy"
    }
  ]
}

次の例では、ワイルドカードパスマッチングを使用して、サイトのルートにある /actions/ の下の任意のパス (サブディレクトリは除く) から、サイトのルートに相対 的な /api/actions/ の下の対応するパスへリクエストをマッピングします。

actions.json
{
  "rules": [
    {
      "pathPattern": "/actions/*",
      "apiPath": "/api/actions/*"
    }
  ]
}

次の例では、ワイルドカードパスマッチングを使用して、サイトのルートにある /donate/ の下の任意のパス (サブディレクトリは除く) から、外部サイト上の絶対パ ス https://api.dialect.com/api/v1/donate/ へのリクエストをマッピングします

actions.json
{
  "rules": [
    {
      "pathPattern": "/donate/*",
      "apiPath": "https://api.dialect.com/api/v1/donate/*"
    }
  ]
}

次の例では、idempotentルールにワイルドカードのパスマッチを使い、 サイトのルート から /api/actions/ 以下のすべてのパス (サブディレクトリを 含む) へのリクエスト をそれ自身にマップしています:

Info

solana-action: URIを先頭に付けたり、追加のレスポンステストを実行することな く、与えられたパスがAction APIリクエストをサポートしているかどうかをblinkクラ イアントがより簡単に判断できるようにする。

actions.json
{
  "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 アカウントが含まれている場合、それをアクションプロ バイダーに検証可能に関連付けるには、以下の手順を行います:

  1. 与えられた identity のすべてのトランザクションを取得します。
  2. 各トランザクションのメモ文字列を解析して検証し、signature が格納されている reference に対して有効であることを確認する。
  3. 特定のトランザクションがオンチェーンの reference の最初のオンチェーンである ことを確認します。
    • このトランザクションが最初の発生である場合、トランザクションは検証済みと見 なされ、アクションプロバイダーに安全に関連付けることができます。
    • このトランザクションが最初の発生でない場合、無効と見なされ、アクションプロ バイダーに関連付けられません。

Solanaバリデータはトランザクションをアカウントキーによってインデックス付けするた め、getSignaturesForAddress RPCメソッドを使用して、identity アカウントを含むすべてのトランザクションを検索 できます。

このRPCメソッドのレスポンスには、すべての memo データがmemoフィールドに含まれ ます。 トランザクションに複数のMemo命令が使用されている場合、各メモメッセージは この memo フィールドに含まれ、それに応じて検証者が解析して Identity Verification Message を取得する必要があります。

これらのトランザクションは最初に UNVERIFIED と見なされるべきです。 これ は、identity がトランザクションに署名する必要がないためで、これにより、このア カウントを署名者以外として含むトランザクションが可能になります。 人工的にアトリ ビューションや使用カウントを膨らませる可能性があります。

Identity Verification Message は signaturereference に署名する identity によって作成されたことを確認する この署名検証に失敗した場合、トランザ クションは無効であり、アクションプロバイダに帰属する必要があります。

署名の検証が成功した場合、検証者はこのトランザクションが reference のチェーン 上での最初の発生であることを確認する必要があります。 そうでない場合は、トランザ クションは無効と見なされます。