Actions and Blinks
Solana Actions 是符合规范的 API,返回 Solana 区块链上的交易,供预 览、签名和在各种上下文中发送,包括二维码、按钮 + 小部件和互联网上的网站。Actions 使开发人员能够轻松地将 Solana 生态系统中的操作集成到他们的环境中,允许你执行区块 链交易而无需导航到不同的应用程序或网页。
区块链链接——或称 blinks——将任何 Solana Action 转化为可共享的、富含元 数据的链接。 Blinks 允许支持 Action 的客户端(浏览器扩展钱包、机器人)为用户显示 额外的功能。 在网站上,blink 可能会立即在钱包中触发交易预览,而无需访问去中心化 应用程序;在 Discord 中,机器人可能会将 blink 扩展为一组交互式按钮。 这将链上交 互的能力推向任何能够显示 URL 的网页表面。
开始使用 #
快速开始创建自定义 Solana Actions:
npm install @solana/actions
- 在您的应用程序中安装 Solana Actions SDK
- 为 GET request 构建一个 API 端点,返回关于 Action 的元数据
- 创建一个 API 端点,接受POST request 和返回用户的可签名交易
查看此视频教程:
如何构建Solana Action 学习使用
@solana/actions
SDK
您也可以找到 [Action
的源代码](https://github.com/solana-developers/solana-actions/blob/main/examples es/next-js/src/app/api/actions/transfer-sol/route.ts) 在这里进行原生 SOL 转移 和其他几个示例操作可以在 这个库 查看。
当部署您自定义的 Solana Action 投入到生产中时:
- 确保您的应用程序在您的域名的根目录上有有效的 actions.json 文件
- 确保您的应用程序响应所有 Action 端点使用
required Cross-Origin headers,包括
actions.json
文件 - test and debug your blinks/actions using the Blinks Inspector
如果你正在寻求围绕建 Action 和 blinks 的灵感,查看 Awesome Blinks 代码库 , 有一些社区作品甚 至新的创意.
Actions #
Solana Actions 规范使用一组标准 API 将可签名的交易(最终是可签名的消息)从应用程 序直接传递给用户。 它们托管在公开可访问的 URL 上,因此任何客户端都可以通过其 URL 进行交互。
你可以将 Actions 视为一个 API 端点,它将返回元数据和供用户使用其区块链钱包签名 的内容(交易或身份验证消息)。
Actions API 包括对 Action 的 URL 端点进行简单的GET
和POST
请求,并处理符合
Actions 接口的响应。
- GET 请求返回元数据,为客户端提供有关此 URL 上可用操作的可读信 息,以及相关操作的可选列表。
- 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 交互非常相似:
- 客户端向 Action URL 发出初始
GET
请求以获取有关可用 Actions 的元数据 - 端点返回包含端点元数据(如应用程序的标题和图标)和此端点可用操作列表的响应
- 客户端应用程序(如移动钱包、聊天机器人或网站)显示用户执行其中一个操作的 UI
- 用户选择一个操作(通过点击按钮)后,客户端向端点发出
POST
请求以获取用户签名的 交易 - 钱包促使用户签署交易并最终将交易发送到区块链进行确认
Solana Actions Execution and Lifecycle
从 Actions URL 接收交易时,客户端应处理这些交易的提交到区块链并管理其状态生命周 期。
Actions 还支持在执行前进行某种程度的无效化。 GET
和POST
请求可能会返回一些元数
据,说明操作是否可以执行(如disabled
字段)。
例如,如果有一个 Action 端点用于对 DAO 治理提案进行投票,而投票窗口已关闭,初始 GET 请求可能会返回错误消息“此提案不再接受投票”,并将“投赞成票”和 “投反对票”按钮设置为“禁用”。
Blinks #
Blinks(区块链链接)是客户端应用程序,它们检查 Action API 并构建与 Actions 交互 和执行的用户界面。
支持 blinks 的客户端应用程序只需检测与 Action 兼容的 URL,解析它们,并允许用户在 标准化的用户界面中与它们交互。
任何完全检查 Actions API 以构建完整界面的客户端应用程序都是一个 blink。 因 此,并非所有使用 Actions API 的客户端都是 blinks。
Blink URL 规范 #
一个 blink URL 描述了一个客户端应用程序,使用户能够完成 执行 Action 的完整生命周期,包括使用他们的钱 包签名。
https://example.domain/?action=<action_url>
要使任何客户端应用程序成为 blink:
-
blink URL 必须包含一个查询参数
action
,其值是 URL 编码的 Action URL。 此值必须是 URL 编码 的,以避免与任何其他协议参数冲突。 -
客户端应用程序必须 URL 解码
action
查 询参数并检查提供的 Action API 链接(参见 Action URL 方案)。 -
客户端必须呈现一个丰富的用户界面,使用户能够完 成执行 Action 的完整生命周期,包括使用他们 的钱包签名。
并非所有 blink 客户端应用程序(例如网站或 dApps)都将支持所有 Actions。 应用程 序开发人员可以选择他们希望在 blink 界面中支持的 Actions。
以下示例演示了一个有效的 blink URL,其action
值
为solana-action:https://actions.alice.com/donate
,并进行了 URL 编码:
https://example.domain/?action=solana-action%3Ahttps%3A%2F%2Factions.alice.com%2Fdonate
Detecting Actions via Blinks #
Blinks 可以通过至少 3 种方式链接到 Actions:
-
共享一个显式的 Action URL:
solana-action:https://actions.alice.com/donate
在这种情况下,只有支持的客户端可以渲染 blink。 在这种情况下,只有支持的客户端 可以渲染 blink。不会有回退链接预览,或显示不支持的客户端之外访问的网站。
-
共享一个链接到 Actions API 的网站链接,通过网站域根目录 的
actions.json
文件。例如,
https://alice.com/actions.json
将https://alice.com/donate
,一个用户 可以向 Alice 捐款的网站 URL,映射到 API URLhttps://actions.alice.com/donate
,在该 URL 上托管了向 Alice 捐款的 Actions。 -
在一个“中间”网站 URL 中嵌入一个 Action URL,该网站 URL 知道如何解析 Actions。
https://example.domain/?action=<action_url>
支持 blinks 的客户端应能够采用上述任何格式并正确渲染界面,以便直接在客户端中执行 操作。
对于不支持 blinks 的客户端,应有一个底层网站(使浏览器成为通用回退)。
如果用户在客户端的任何地方点击,而不是操作按钮或文本输入字段,他们应该被带到底层 网站。
Blink Testing and Verification #
While Solana Actions and blinks are a permissionless protocol/specification, client applications and wallets are still required to ultimately facilitate users to sign the transaction.
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.
For example, some clients may operate on an "allow list" approach that may require verification prior to their client unfurling an Action for users such as Dialect's Actions Registry (detailed below).
All blinks will still render and allow for signing on Dialect's dial.to blinks Interstitial site, with their registry status displayed in the blink.
Dialect's Actions Registry #
As a public good for the Solana ecosystem, Dialect maintains a public registry — together with the help of Solana Foundation and other community members — of blockchain links that have are from pre-verified from known sources. As of launch, only Actions that have been registered in the Dialect registry will unfurl in the Twitter feed when posted.
Client applications and wallets can freely choose to use this public registry or another solution to help ensure user security and safety. If not verified through the Dialect registry, the blockchain link will not be touched by the blink client, and will be rendered as a typical URL.
Developers can apply to be verified by Dialect here: dial.to/register
规范 #
Solana Actions 规范包括请求/响应交互流程中的关键部分:
- Solana Action URL 方案 提供一个 Action URL
- 选项响应 针对通过 CORS 要求的操作 URL
- 对 Action URL 的 GET 请求
- 服务器返回的 GET 响应
- 对 Action URL 的 POST 请求
- 服务器返回的 POST 响应
这些请求都是由 Action 客户端(例如钱包应用程序、浏览器扩展、dApp、网站等)发出 的,以收集丰富用户界面的特定元数据并促进用户输入到 Actions API。
每个响应都是由应用程序(例如网站、服务器后端等)制作并返回给 Action 客户端。最 终,提供一个可签名的交易或消息,供钱包提示用户批准、签名并发送到区块链。
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
字段是必需的,作为路径名。 单个link
字段是必需的,作为路径名。该值 必须是条件性 URL 编码的 绝对 HTTPS URL。 -
如果 URL 包含查询参数,则必须进行 URL 编码。 URL 编码的值可防止与任何 Actions 协议参数冲突,这些参数可能会通过协议规范添加。
-
如果 URL 不包含查询参数,则不应进行 URL 编码。这会生成一个更短的 URL 和一个更 少密集的二维码。
在任何情况下,客户端都必须 URL 解码该 值。 如果该值未进行 URL 编码,则不会产生任何影响。 如果解码后的值不是绝对的 HTTPS URL,钱包必须将其拒绝为格式错误。
OPTIONS response #
In order to allow Cross-Origin Resource Sharing
(CORS) within Actions
clients (including blinks), all Action endpoints should respond to HTTP requests
for the OPTIONS
method with valid headers that will allow clients to pass CORS
checks for all subsequent requests from their same origin domain.
An Actions client may perform
"preflight"
requests to the Action URL endpoint in order check if the subsequent GET request
to the Action URL will pass all CORS checks. These CORS preflight checks are
made using the OPTIONS
HTTP method and should respond with all required HTTP
headers that will allow Action clients (like blinks) to properly make all
subsequent requests from their origin domain.
At a minimum, the required HTTP headers include:
Access-Control-Allow-Origin
with a value of*
- this ensures all Action clients can safely pass CORS checks in order to make all required requests
Access-Control-Allow-Methods
with a value ofGET,POST,PUT,OPTIONS
- ensures all required HTTP request methods are supported for Actions
Access-Control-Allow-Headers
with a minimum value ofContent-Type, Authorization, Content-Encoding, Accept-Encoding
For simplicity, developers should consider returning the same response and
headers to OPTIONS
requests as their GET
response.
The actions.json
file response must also return valid Cross-Origin headers for
GET
and OPTIONS
requests, specifically the Access-Control-Allow-Origin
header value of *
.
See actions.json below for more details.
GET 请求 #
Action 客户端(例如钱包、浏览器扩展等)应向 Action 的 URL 端点发出 HTTP GET
JSON 请求。
- 请求不应识别钱包或用户。
- 客户端应发起
带
Accept-Encoding
请求头的 请求 - 客户端应在请求时显示 URL 的域名。
GET 响应 #
Action 的 URL 端点(例如应用程序或服务器后端)应以 HTTP OK
JSON 响应(正文中包
含有效负载)或适当的 HTTP 错误进行响应。
-
端点应使 用
Content-Encoding
请求头进 行 HTTP 压缩响应。 -
端点应以
application/json
类型 的Content-Type
请求头进 行响应。 -
The client should not cache the response except as instructed by HTTP caching response headers.
-
The client should display the
title
and render theicon
image to user.
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
响应应包括一个遵循接口规范的正文负载:
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 图像,否则客户端/钱包必须将其拒绝为格式错误。 -
title
- 该值必须是表示操作请求来源的 UTF-8 字符串。 例如,这可能是发出请求的 品牌、商店、应用程序或个人的名称。 -
description
- 该值必须是提供操作信息的 UTF-8 字符串。 描述应显示给用户。 -
label
- 该值必须是将在按钮上呈现给用户点击的 UTF-8 字符串。 所有标签不应超过 5 个单词短语,并应以动词开头,以明确你希望用户采取的操作。 例如,“铸造 NFT”、“ 投赞成票”或“质押 1 SOL”。 -
disabled
- 该值必须是布尔值,表示呈现按钮的禁用状态(显示label
字符串)。如 果未提供值,disabled
应默认为false
(即默认启用)。 例如,如果操作端点是一个 已关闭的治理投票,设置disabled=true
,标签可以是“投票已关闭”。 -
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,并 期望只执行一个。 例如,一个治理投票操作端点可能会返回三个选项供用户选择:“投赞 成票”、“投反对票”和“弃权”。-
If no
links.actions
is provided, the client should render a single button using the rootlabel
string and make the POST request to the same action URL endpoint as the initial GET request. -
If any
links.actions
are provided, the client should only render buttons and input fields based on the items listed in thelinks.actions
field. The client should not render a button for the contents of the rootlabel
.
-
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”的按钮:
{
"title": "HackerHouse Events",
"icon": "<url-to-image>",
"description": "Claim your Hackerhouse access token.",
"label": "Claim Access Token" // button text
}
以下示例响应提供了 3 个相关的操作链接,允许用户点击 3 个按钮之一来对 DAO 提案进 行投票:
{
"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 个链接操作来质押 SOL:一个标签为“质押 1 SOL”的按钮, 另一个标签为“质押 5 SOL”的按钮,以及一个允许用户输入特定“金额”值的文本输入字段, 该值将发送到 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 编码的账户公钥,该账户可以签署交易。
The client should make the request with an Accept-Encoding header and the application may respond with a Content-Encoding header for HTTP compression.
客户端应在请求时显示操作 URL 的域名。 如果发出了GET
请求,客户端还应显
示title
并呈现icon
图像。
POST 响应 #
Action 的POST
端点应以 HTTP OK
JSON 响应(正文中包含有效负载)或适当的 HTTP
错误进行响应。
- 客户端必须处理 HTTP 客户端错误、服务器错误和重定向响应。
- 端点应以
application/json
类型的Content-Type
响应头进 行响应。
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
- The value must be a base64-encoded serialized transaction. The client must base64-decode the transaction and deserialize it. -
message
- 该值必须是描述响应中包含的交易性质的 UTF-8 字符串。 The client should display this value to the user. 例如,这可能是购买商品的名称、购买时应 用的折扣或感谢信。 -
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. -
客户端和应用程序应允许请求正文和响应正文中的其他字段,这些字段可能会通过未来的 规范更新添加。
应用程序可以响应部分或完全签名的交易。 The client and wallet must validate the transaction as untrusted.
POST Response - Transaction #
If the transaction
signatures
are empty or the transaction has NOT been partially signed:
- The client must ignore the
feePayer
in the transaction and set thefeePayer
to theaccount
in the request. - The client must ignore the
recentBlockhash
in the transaction and set therecentBlockhash
to the latest blockhash. - 客户端必须在签名之前序列化和反序列化交易。这确保了账户密钥的顺序一致,作 为此问题的解决方法。
If the transaction has been partially signed:
- The client must NOT alter the
feePayer
orrecentBlockhash
as this would invalidate any existing signatures. - The client must verify existing signatures, and if any are invalid, the client must reject the transaction as malformed.
The client must only sign the transaction with the account
in the request, and
must do so only if a signature for the account
in the request is expected.
If any signature except a signature for the account
in the request is
expected, the client must reject the transaction as 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
文件的目的是允许应用程序指示客户端哪些网站 URL 支
持 Solana Actions,并提供一个映射,可用于对 Actions API 服务器执行
GET 请求 。
The actions.json
file response must also return valid Cross-Origin headers for
GET
and OPTIONS
requests, specifically the Access-Control-Allow-Origin
header value of *
.
See OPTIONS response above for more details.
actions.json
文件应存储在域的根目录下,并且可以被普遍访问。
例如,如果你的 web 应用程序部署在my-site.com
,那么actions.json
文件应可以通
过https://my-site.com/actions.json
访问。This file should also be Cross-Origin
accessible via any browser by having a Access-Control-Allow-Origin
header
value of *
.
规则 #
rules
字段允许应用程序将一组网站的相对路径映射到另一组路径。
类型: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 #
匹配每个传入路径名的模式。 它可以是绝对路径或相对路径,并支持以下格式:
-
精确匹配:匹配确切的 URL 路径。
- 示例:
/exact-path
- 示例:
https://website.com/exact-path
- 示例:
-
通配符匹配:使用通配符匹配 URL 路径中的任何字符序列。 这可以匹配单个(使 用
*
)或多个段(使用**
)。(见下文的路径匹配 )。- 示例:
/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。 它可以定义为绝对路径名或 外部 URL。
- 示例:
/api/exact-path
- 示例:
https://api.example.com/v1/donate/*
- 示例:
/api/category/*/item/*
- Example:
/api/swap/**
规则 - 查询参数 #
原始 URL 中的查询参数始终保留并附加到映射的 URL。
规则 - 路径匹配 #
下表概述了路径匹配模式的语法:
操作符 | 匹配 |
---|---|
* | 单个路径段,不包括周围的路径分隔符/字符。 |
** | 匹配零个或多个字符,包括多个路径段之间的任何路径分隔符/字符。 如果包含其他操作符,** 操作符必须是最后一个操作符。 |
? | 不支持的模式。 |
规则示例 #
以下示例演示了一个精确匹配规则,将来自站点根目录的/buy
请求映射到站点根目录下的
确切路径/api/buy
:
{
"rules": [
{
"pathPattern": "/buy",
"apiPath": "/api/buy"
}
]
}
The following example uses wildcard path matching to map requests to any path
(excluding subdirectories) under /actions/
from your site's root to a
corresponding path under /api/actions/
relative to your site's root:
{
"rules": [
{
"pathPattern": "/actions/*",
"apiPath": "/api/actions/*"
}
]
}
The following example uses wildcard path matching to map requests to any path
(excluding subdirectories) under /donate/
from your site's root to a
corresponding absolute path https://api.dialect.com/api/v1/donate/
on an
external site:
{
"rules": [
{
"pathPattern": "/donate/*",
"apiPath": "https://api.dialect.com/api/v1/donate/*"
}
]
}
以下示例使用通配符路径匹配的幂等规则将来自站点根目录的/api/actions/
下的任何路
径(包括子目录)请求映射到自身:
幂等规则允许闪烁客户端更容易确定给定路径是否支持 Action API 请求,而无需
以solana-action:
URI 为前缀或执行额外的响应测试。
{
"rules": [
{
"pathPattern": "/api/actions/**",
"apiPath": "/api/actions/**"
}
]
}
Action Identity #
在返回给用户签署的 POST 响应中的事务中,操作端点可能包含一个 Action Identity。 这样允许索引器和分析平台以可验证的方式轻松地将链上活动归因于 特定的 Action Provider(即服务)。
Action Identity 是一个密钥对,用于签署包含在交易中的特殊格式 消息,使用 Memo 指令。 这种 Identifier Message 可以被验证地归属于特定的 Action Identity,从而将交易归属于特定的 Action Provider。
密钥对本身不需要签署交易。 这允许钱包和应用程序在没有其他签名的情况下提高返回给 用户的交易的可交付性(参见 POST response transaction)。
如果 Action Provider 的用例要求其后端服务在用户之前预签交易,他们应使用此密钥对 作为其 Action Identity。 这将减少交易中包含的一个账户,从而将总交易大小减少 32 字节。
Action Identifier Message #
Action Identifier Message 是一个使用单个 SPL Memo 指令包含在交易中的以冒号分隔的 UTF-8 字符串。
protocol:identity:reference:signature
protocol
- 使用的协议的值(根据上面的 URL Scheme 设置 为solana-action
)identity
- 值必须是 Action Identity 密钥对的 base58 编码的公钥地址reference
- 值必须是 base58 编码的 32 字节数组。这可能是也可能不是公钥,可能 在曲线上也可能不在曲线上,可能与 Solana 上的账户对应也可能不对应。signature
- 由 Action Identity 密钥对仅签署reference
值创建的 base58 编码签 名。
reference
值必须仅使用一次并且在单个交易中使用。 为了将交易与 Action Provider
关联,只有第一次使用reference
值被认为是有效的。
交易可能有多个 Memo 指令。 当执
行getSignaturesForAddress
时,结果memo
字段将返回每个 memo 指令的消息作为单个字符串,每个字符串用分号分
隔。
Identifier Message 的 Memo 指令不应包含其他数据。
The identity
and the reference
should be included as read-only, non-signer
keys
in the transaction on an instruction that is NOT the Identifier Message Memo
instruction.
Identifier Message Memo 指令必须不提供任何账户。 如果提供了任何账户,Memo 程序要 求这些账户是有效的签名者。 为了识别操作,这限制了灵活性并可能降低用户体验。 因此 被认为是一种反模式,必须避免。
Action Identity 验证 #
任何包含identity
账户的交易都可以通过多步骤过程验证地与 Action Provider 关联:
- 获取给定
identity
的所有交易。 - 解析并验证每个交易的 memo 字符串,确保
signature
对存储的reference
是有效 的。 - 验证特定交易是链上首次出现的
reference
:- 如果此交易是首次出现,则交易被认为是验证的,可以安全地归属于 Action Provider。
- 如果此交易不是首次出现,则被认为是无效的,因此不归属于 Action Provider。
由于 Solana 验证器按账户密钥索引交
易,getSignaturesForAddress
RPC
方法可用于定位所有包含identity
账户的交易。
此 RPC 方法的响应包括memo
字段中的所有 Memo 数据。 如果交易中使用了多个 Memo 指
令,每个 memo 消息将包含在此memo
字段中,验证者必须相应地解析以获取 Identity
Verification Message。
这些交易应初步视为 UNVERIFIED。 这是因为identity
不需要签署交易,这允许任何
交易将此账户作为非签名者包含在内。 可能会人为地增加归属和使用计数。
应检查 Identity Verification Message 以确保signature
是由identity
签
署reference
创建的。 如果此签名验证失败,则交易无效,不应归属于 Action
Provider。
如果签名验证成功,验证者应确保此交易是链上首次出现的reference
。 如果不是,则交
易被认为无效。