Actions та Blinks
Solana Actions - це API, що відповідають специфікації, які повертають транзакції в блокчейні Solana для попереднього перегляду, підпису та відправлення в різних контекстах, включаючи QR-коди, кнопки + віджети, а також вебсайти в інтернеті. Actions роблять простою інтеграцію можливостей екосистеми Solana у ваше середовище розробники, дозволяючи виконувати блокчейн-транзакції без необхідності переходу до іншого додатка або вебсторінки.
Blockchain links – або blinks – перетворюють будь-який Solana Action на посилання, яким можна поділитися і яке містить багато метаданих. Blinks дозволяють клієнтам, що підтримують Action (браузерні гаманці, боти), відображати додаткові можливості для користувача. На вебсайті blink може одразу ж викликати попередній перегляд транзакції в гаманці без переходу до децентралізованого додатка; у Discord бот, blink може бути розгорнутий у наборі інтерактивних кнопок. Це дозволяє взаємодіяти з блокчейном на будь-якій вебплатформі, здатній відображати URL.
Початок роботи #
Щоб швидко розпочати створення Solana Actions:
npm install @solana/actions
- встановіть Solana Actions SDK у вашому додатку
- побудуйте API ендпоінт для GET запиту, який повертає метадані про ваш Action
- створіть API ендпоінт, який приймає POST запит і повертає транзакцію, яку користувач може підписати
Перегляньте цей відеоурок про
те, як створити Solana Action
за допомогою SDK @solana/actions
.
Ви також можете знайти вихідний код для Action, який виконує нативний переказ SOL, тут, а також кілька інших прикладів Action у цьому репозиторії.
Під час розгортання ваших Solana Action у продакшн:
- переконайтеся, що у вашому додатку є дійсний файл actions.json у корені вашого домену
- переконайтеся, що ваш додаток відповідає з
необхідними заголовками Cross-Origin на всіх Action
ендпоінтах, включаючи файл
actions.json
- test and debug your blinks/actions using the Blinks Inspector
Якщо ви шукаєте натхнення для створення Action та blink, перегляньте репозиторій Awesome Blinks, де можна знатий творіння спільноти та навіть ідеї для нових blink.
Actions #
Специфікація Solana Actions використовує набір стандартних API для надання транзакцій, які можна підписати (а згодом і повідомлень, що також можна підписати), безпосередньо від додатка до користувача. Вони розміщуються за загальнодоступними URL-адресами й відповідно доступні для будь-якого клієнта за своїм URL.
Ви можете розглядати Actions як API ендпоінт, який повертає метадані та щось для підпису користувачем (транзакцію або повідомлення для аутентифікації) за допомогою їх блокчейн-гаманця.
API Actions полягає у здійсненні простих GET та POST запитів до Action URL ендпоінту й обробці відповідей, що відповідають інтерфейсу 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:
- клієнт робить початковий
GET
запит до URL-адреси Action, щоб отримати метадані про доступні дії - ендпоінт повертає відповідь, яка містить метадані про нього (такі як заголовок та іконка додатка) та перелік доступних дій для цього ендпоінта
- клієнтський додаток (наприклад, мобільний гаманець, чат-бот або вебсайт) відображає інтерфейс для користувача для виконання однієї з дій
- після того як користувач обрав дію (натиснувши кнопку), клієнт виконує
POST
запит до ендпоінту, щоб отримати транзакцію для підпису користувачем - гаманець допомагає користувачеві підписати транзакцію і відправляє її до блокчейну для підтвердження
Виконання Solana Actions та життєвий цикл
Отримуючи транзакції з Actions URL, клієнти повинні обробляти відправку цих транзакцій до блокчейну і керувати їх життєвим циклом.
Actions також підтримують певний рівень валідації перед виконанням. Запити GET
і POST
можуть повертати деякі метадані, які вказують, чи можна виконати дію
(наприклад, з полем disabled
).
Наприклад, якщо існує Action ендпоінт, що дозволяє голосувати за пропозицію управління DAO, але період голосування закритий, початковий GET запит може повернути повідомлення про помилку "This proposal is no longer up for a vote", а кнопки "Vote Yes" та "Vote No" будуть відключені.
Blinks #
Blinks (blockchain links) - це клієнтські додатки, які аналізують Action API та створюють користувацькі інтерфейси для взаємодії та виконання Actions.
Клієнтські додатки, які підтримують blink, просто виявляють сумісні Action URL, розбирають їх і дозволяють користувачам взаємодіяти з ними у стандартизованих користувацьких інтерфейсах.
Будь-який клієнтський додаток, який повністю аналізує Actions API для побудови повного інтерфейсу для нього, є blink. Тому не всі клієнти, який використовує Actions API, є blink.
Blink URL Специфікація #
URL blink описує клієнтський додаток, яка дозволяє користувачеві завершити повний цикл виконання Action, включаючи підпис з їх гаманцем.
https://example.domain/?action=<action_url>
Для того щоб будь-яка клієнтська програма могла використовувати blink:
-
Blink URL повинна містити параметр запиту
action
, значення якого буде URL закодованим для Action URL. Це значення повинно бути закодовано, щоб уникнути конфліктів з іншими параметрами протоколу. -
Клієнтський додаток повинний декодувати URL параметр запиту
action
і інтроспектувати надане посилання Action API (див. Action URL scheme). -
Клієнт повинен відображати користувацький інтерфейс, який дозволяє завершити весь життєвий цикл виконання Action, включаючи підпис з їх гаманця.
Не всі клієнтські blink програми (наприклад, вебсайти або dApps) підтримують усі Actions. Розробники додатків можуть вибирати, які Actions вони хочуть підтримувати у своїх blink інтерфейсах.
Наведений приклад демонструє дійсну blink URL-адресу зі значенням параметра
action
, який URL закодовано solana-action:https://actions.alice.com/donate
:
https://example.domain/?action=solana-action%3Ahttps%3A%2F%2Factions.alice.com%2Fdonate
Виявлення Actions за допомогою Blinks #
Blink можуть бути пов'язані з Actions принаймні трьома способами:
-
Поширення за допомогою явного Action URL:
solana-action:https://actions.alice.com/donate
У цьому випадку лише підтримувані клієнти можуть відтворювати blink. Не буде доступно жодного альтернативного попереднього перегляду посилання або сайту, який можна було б відвідати за межами непідтримуваного клієнта.
-
Поширення посилання на вебсайт, який пов'язаний з Actions API за допомогою
actions.json
файлуу кореневій директорії домену вебсайту.Наприклад,
https://alice.com/actions.json
відображає посиланняhttps://alice.com/donate на веб-сайті, де користувачі можуть здійснити пожертвування на користь Alice, на API URL
https://actions.alice.com/donate\`, де знаходяться Actions для здійснення пожертвування Alice. -
Вбудовування Action URL в "проміжний" URL веб-сайту, який розуміє, як парсити Actions.
https://example.domain/?action=<action_url>
Клієнти, які підтримують блінки, повинні мати можливість приймати будь-який з вищезазначених форматів і правильно відображати інтерфейс для безпосереднього виконання дії в клієнті.
Для клієнтів, які не підтримують blink, повинен бути доступний базовий вебсайт (що робить браузер універсальним резервом).
Якщо користувач натискає на будь-яке місце в клієнтській програмі, крім кнопки дії або поля введення тексту, його повинно перенаправити на базовий сайт.
Тестування та Верифікація 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.
Наприклад, деякі клієнти можуть працювати за принципом "дозволеного списку", що може вимагати перевірки перед тим, як їхній клієнт розгорне Action для користувачів, таких як Dialect's Actions Registry (детально описаний нижче).
Усі blinks все ще будуть відображатися та дозволяти підписання на сайті проміжної сторінки Dialect's dial.to, з вказанням їх статусу в реєстрі blink.
Dialect's Actions Registry #
З користю для екосистеми Solana, Dialect разом із допомогою Solana Foundation та інших членів спільноти підтримує публічний реєстр блокчейн-посилань, які були попередньо перевірені відомими джерелами. На момент запуску, лише Actions зареєстровані в реєстрі Dialect, будуть розгортатися в стрічці Twitter після публікації.
Клієнтські додатки та гаманці можуть вільно вибирати чи використовувати цей публічний реєстр або інше рішення, щоб забезпечити безпеку та захист користувачів. Якщо посилання на блокчейн не підтверджено через реєстр Dialect, blink клієнт його ігнорує і відображає як звичайний URL.
Розробники можуть подати заявку на верифікацію через Dialect за цим посиланням: dial.to/register
Специфікація #
Специфікація Solana Actions складається з ключових розділів, які є частиною процесу взаємодії запит/відповідь:
- Solana Action URL scheme яка надає Action URL
- OPTIONS відповідь на Action URL для виконання вимог CORS
- GET запит до Action URL
- GET відповідь від сервера
- POST запит до Action URL
- 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 Scheme #
Solana Action URL описує інтерактивний запит для транзакції або повідомлення
Solana, яке можна підписати, використовуючи протокол solana-action
.
Запит є інтерактивним через те, що параметри в URL використовуються клієнтом для створення серії стандартизованих HTTP-запитів для складання транзакції або повідомлення, яке користувач може підписати за допомогою свого гаманця.
solana-action:<link>
-
Єдине поле
link
є обов’язковим як шлях. Значення повинно бути умовно URL закодованим абсолютним HTTPS URL. -
Якщо URL містить параметри запиту, вони повинні бути URL закодовані. Кодування значень дозволяє уникнути конфліктів з параметрами протоколу Actions, які можуть бути додані за допомогою специфікації протоколу.
-
Якщо URL не містить параметрів запиту, його не потрібно кодувати. Це забезпечує коротший URL і менш щільний QR-код.
У будь-якому випадку клієнти повинні URL декодувати значення. Це не вплине на значення, якщо воно не закодоване. Якщо декодоване значення не є абсолютним HTTPS URL адресою, гаманець повинен відхилити його як неправильний формат.
OPTIONS відповідь #
Для забезпечення міжсайтового обміну ресурсами
(CORS) у клієнтах
Actions (включаючи blink), всі Actions ендпоінти повинні відповідати на
HTTP-запити для методу OPTIONS
з коректними заголовками, що дозволяють
клієнтам успішно проходити перевірку CORS для всіх наступних запитів з їхнього
власного початкового домену.
Action клієнт може виконувати
"попередні"
запити до енпоінта Action URL, щоб перевірити, чи пройде наступний GET запит на
Action URL всі перевірки CORS. Ці попередні перевірки CORS виконуються за
допомогою HTTP-методу OPTIONS
і повинні відповідати з усіма необхідними
HTTP-заголовками, що дозволяють Action клієнтам (таким як blink) належним чином
виконувати всі наступні запити з їх вихідного домену.
Мінімальний набір обов'язкових HTTP заголовків включає:
Access-Control-Allow-Origin
зі значенням*
- це забезпечує можливість всім Action клієнтам безпечно проходити перевірку CORS для здійснення всіх необхідних запитів
Access-Control-Allow-Methods
зі значенням "GET,POST,PUT,OPTIONS"- це забезпечує підтримку всіх необхідних HTTP методів для Action
Access-Control-Allow-Headers
з мінімальним значеннямContent-Type, Authorization, Content-Encoding, Accept-Encodding
Для спрощення, розробники повинні очікувати повернення такої самої відповіді та
заголовків на запити методу OPTIONS
, як на їхні відповіді запиту методу
GET
.
Відповідь файлу actions.json
також повинна містити дійсні заголовки
Cross-Origin для запитів GET
і OPTIONS
, зокрема значення заголовка
Access-Control-Allow-Origin
повинно бути *
.
Дивіться нижче для деталей щодо actions.json.
GET запит #
Action клієнт (наприклад, гаманець, браузерне розширення тощо) повинен
здійснювати HTTP GET
JSON запит до Action's URL ендпоінт.
- Запит не повинен ідентифікувати гаманець або користувача.
- Клієнт повинен робити запит з заголовком
Accept-Encoding
. - Клієнт повинен відображати домен URL під час виконання запиту.
Відповідь на GET запит #
Action's URL ендпоінт (наприклад, додаток або серверна частина) повинна
відповісти HTTP-статусом OK
із JSON-відповіддю (з коректним вмістом тіла) або
відповідною HTTP-помилкою.
-
Клієнт повинен обробляти HTTP помилки клієнта, помилки сервера, та перенаправляти відповіді.
-
Ендпоінт повинний відповісти з заголовком
Content-Encoding
для HTTP компресії. -
Ендпоінт повинний відповісти з заголовком
Content-Type
зapplication/json
. -
Клієнт повинен ігнорувати кешування відповіді, за винятком випадків, коли це зазначено в заголовках відповіді HTTP кешування.
-
Клієнт повинен відображати заголовок (
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 запиту #
Відповідь на GET
запит з HTTP OK
JSON повинна містити тіло з вмістом, що
відповідає специфікації інтерфейсу:
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 слів і мають починатися з дієслова, щоб чітко позначити дію, яку ви хочете, щоб користувач виконав. Наприклад, "Mint NFT", "Vote Yes" або "Stake 1 SOL". -
disabled
- Значення повинно бути булевим для відображення стану відключення кнопки (яка показує рядок з підписом label). Якщо значення не вказано, параметрdisabled
повинен за замовчуванням бутиfalse
(тобто ввімкнено за замовчуванням). Наприклад, якщо кінцевий ендпоінт призначений для голосування в управлінні, яке вже завершилося, встановітьdisabled=true
, а значенняlabel
може бути "Vote Closed". -
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
- Опціональний масив пов'язаних дій для ендпоінта. Користувачам повинно відображатися інтерфейсне вікно для кожної з перелічених дій і очікувати, що вони виконають лише одну. Наприклад, ендпоінт дії голосування в управлінні може повертати три варіанти для користувача: "Vote Yes", "Vote No" і "Abstain from Vote".-
Якщо не надано
links.actions
, клієнт повинен відобразити одну кнопку з кореневим рядком міткиlabel
і виконати POST запит до того ж URL-ендпоінту дії, що й початковий GET запит. -
Якщо надано будь-які
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":
{
"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' запиту (через поле 'href' у 'LinkedAction'):
Приклад відповіді, яка надає користувачеві 3 пов'язаних дії для стейкінгу SOL: кнопку з написом "Stake 1 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 запит #
Клієнт повинен виконати HTTP POST
JSON-запит до URL дії з тілом запиту:
{
"account": "<account>"
}
account
- Значення повинно бути закодованим у форматі Base58 публічним ключем облікового запису, який може підписати транзакцію.
Клієнт повинен робити запит з заголовком Accept-Encoding, а додаток може відповісти з заголовком Content-Encoding для HTTP стиснення.
Клієнт повинен відображати домен URL адреси дії під час виконання запиту. Якщо
був зроблений GET
запит, клієнт також повинен відображати title
і
відтворювати зображення icon
з отриманої GET відповіді.
POST відповідь #
Ендпоінт Action's POST повинен відповісти з HTTP OK
JSON-відповіддю (з дійсним
вмістом у тілі) або відповідною HTTP-помилкою.
- Клієнт повинен обробляти HTTP-помилки, такі як помилки клієнта, помилки сервера, та перенаправляти відповіді.
- Ендпоінт повинен відповісти з заголовком
Content-Type
зapplication/json
.
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 відповіді #
Відповідь на POST
запит з HTTP OK
JSON повинна містити тіло з вмістом:
/**
* 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
- Значення повинно бути закодованою у форматі base64 серіалізованої транзакції. Клієнт повинен декодувати транзакцію з base64 і провести її [десеріалізацію] (https://solana-labs.github.io/solana-web3.js/classes/Transaction.html#from). -
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. -
Клієнт та додаток повинні дозволяти додаткові поля у тілі запиту та тілі відповіді, які можуть бути додані у майбутніх оновленнях специфікації.
Додаток може відповісти частково або повністю підписаною транзакцією. Клієнт і гаманець повинні позначити транзакцію як ненадійну.
POST Відповідь - Транзакція #
Якщо підписи транзакції порожні або транзакція не була частково підписана:
- Клієнт повинен ігнорувати
feePayer
у транзакції і встановитиfeePayer
на обліковий запис у запиті. - Клієнт повинен ігнорувати
recentBlockhash
у транзакції і встановитиrecentBlockhash
на останній блокхеш. - Клієнт повинен серіалізувати та десеріалізувати транзакцію перед її підписанням. Це забезпечує послідовний порядок ключів облікових записів, як обхідне рішення для цієї проблеми.
Якщо транзакцію було частково підписано:
- Клієнт не повинен змінювати
feePayer
абоrecentBlockhash
, оскільки це може призвести до недійсності наявних підписів. - Клієнт повинен перевірити наявні підписи і якщо який-небудь з них недійсний, клієнт повинен відхилити транзакцію як неправильно сформовану.
Клієнт повинен підписувати транзакцію лише з обліковим записом у запиті і робити це тільки в тому випадку, якщо очікується підпис для облікового запису у запиті.
Якщо очікується будь-який підпис, крім підпису для облікового запису у запиті, клієнт повинен відхилити транзакцію як зловмисну.
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 Action і надавати
відображення, яке можна використовувати для виконання
GET запитів до сервера Actions API.
Відповідь файлу actions.json
також повинна містити дійсні заголовки
Cross-Origin для запитів GET
і OPTIONS
, зокрема значення заголовка
Access-Control-Allow-Origin
повинно бути *
.
Дивіться вище для деталей щодо відповіді OPTIONS.
Файл 'actions.json' повинен бути збережений і доступний у кореневій директорії домену.
Наприклад, якщо ваш веб-додаток розгорнуто на my-site.com
, то файл
actions.json
повинен бути доступний за адресою
https://my-site.com/actions.json
. Цей файл також повинен бути доступним через
Cross-Origin у будь-якому браузері за допомогою заголовка
Access-Control-Allow-Origin
зі значенням *
.
Rules #
Поле rules
дозволяє додатку зіставляти набір відносних маршрутів вебсайту з
іншими шляхами.
Type: Array
of 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.
- Приклад:
/api/exact-path
- Приклад:
https://api.example.com/v1/donate/*
- Приклад:
/api/category/*/item/*
- Приклад:
/api/swap/**
Правила - Query Parameters #
Параметри запиту з оригінального URL завжди зберігаються і додаються до відображеного URL.
Правила - Path Matching #
Наступна таблиця наводить синтаксис для шаблонів відповідності шляхів:
Оператор | Matches |
---|---|
* | Один сегмент шляху, не включаючи оточуючих символів роздільника шляху / символів. |
** | Відповідає нулю або більше символам, включаючи будь-які символи роздільника шляху / між кількома сегментами шляху. Якщо використовуються інші оператори, оператор ** повинен бути останнім оператором. |
? | Непідтримуваний шаблон. |
Rules Приклади #
Наступний приклад демонструє правило точного збігу для зіставлення запитів до '/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/*"
}
]
}
Наступний приклад використовує збіг шляхів з підстановкою для ідемпотентного
правила зіставлення запитів до будь-якого шляху (включаючи підкаталоги) під
/api/actions/
з кореня вашого сайту на цей же шлях:
Ідемпотентні правила дозволяють blink клієнтам легше визначити, чи підтримує
заданий шлях запити Action API, без необхідності додавання префікса
solana-action:
URI або виконання додаткового тестування відповідей.
{
"rules": [
{
"pathPattern": "/api/actions/**",
"apiPath": "/api/actions/**"
}
]
}
Action Identity #
Action ендпоінти можуть включати Action Identity в транзакціях, які повертаються у їхній POST відповіді для підпису користувачем. Це дозволяє індексаторам та аналітичним платформам легко та надійно приписувати активність у блокчейні до конкретного Action Provider (тобто сервісу) у перевірюваний спосіб.
Action Identity — це пара ключів, яка використовується для підпису спеціально сформованого повідомлення, що включається у транзакцію за допомогою інструкції Memo. Це Identifier Message можна достовірно приписати певному Action Identity, а отже, і транзакціям, певного Action Provider.
Пара ключів не обов'язково повинна підписувати саму транзакцію. Це дозволяє гаманцям та додаткам покращити доставку транзакцій, коли на транзакції, повернутій користувачеві, немає інших підписів (див. Транзакція POST відповіді).
Якщо для випадку використання Action Provider потрібно, щоб його бекенд-сервіси попередньо підписали транзакцію перед користувачем, вони повинні використовувати цю пару ключів як свій Action Identity. Це дозволить зменшити кількість облікових записів, які включаються в транзакцію, що знижує загальний розмір транзакції на 32 байти.
Action Identity повідомлення #
Повідомлення Action Identity є рядком UTF-8, розділеним двокрапками, яке включається у транзакцію за допомогою єдиної інструкції SPL Memo.
protocol:identity:reference:signature
protocol
- Значення протоколу, що використовується (встановлене якsolana-action
) відповідно до URL Scheme вищеidentity
- Значення повинно бути публічною адресою ключа Action Identity, закодованою у форматі base58reference
- Значення повинно бути масивом із 32 байтів, закодованим у форматі base58. Це можуть бути або не бути публічні ключі, у межах або поза кривою, і можуть або не можуть відповідати обліковим записам у Solana.signature
- Підпис, закодований у форматі base58, створений від підпису пари ключів Action Identity тільки значеннямreference
.
Значення reference
повинно бути використане лише один раз і лише в одній
транзакції. Для приписування транзакцій Action Provider лише перше використання
значення reference
вважається дійсним.
Транзакції можуть мати кілька інструкцій Memo. Під час виконання
getSignaturesForAddress
,
поле результатів memo
поверне кожну інструкцію Memo як окремий рядок,
розділений крапкою з комою.
Інструкція Memo повинна містити лише Identifier Message і не повинна містити інших даних.
Параметри identity
і reference
повинні бути включені як
ключі
типу read-only, non-signer в транзакцію для інструкції, яка НЕ є інструкцією
Memo для повідомлення ідентифікатора.
Інструкція Memo Identifier Message не повинна мати жодних наданих облікових записів. Якщо будь-які облікові записи надані, програма Memo вимагає, щоб ці облікові записи були дійсними підписниками. Для цілей ідентифікації дій це обмежує гнучкість і може погіршити досвід користувача. Тому це вважається антипаттерном і повинно бути уникнене.
Перевірка Action Identity #
Будь-яка транзакція, яка включає обліковий запис identity
, може бути надійно
пов'язана з Action Provider у багатокроковому процесі:
- Отримайте всі транзакції для даного
identity
. - Проаналізуйте та перевірте рядок memo кожної транзакції, переконуючись, що
підпис
signature
є дійсним для збереженого значенняreference
. - Перевірте, що конкретна транзакція є першим випадком
reference
на ланцюжку:- Якщо ця транзакція є першим випадком
reference
, транзакція вважається перевіреною і може бути безпечно приписана Action Provider. - Якщо ця транзакція НЕ є першим випадком
reference
, вона вважається недійсною і, отже, не приписується Action Provider.
- Якщо ця транзакція є першим випадком
Оскільки валідатори Solana індексують транзакції за ключами облікових записів,
метод RPC
getSignaturesForAddress
може бути використаний для пошуку всіх транзакцій, які включають обліковий запис
identity
.
Відповідь цього методу RPC містить усі дані Memo у полі memo
. Якщо у
транзакції використовувалися кілька інструкцій Memo, кожне повідомлення memo
буде включено в це поле memo
, і його слід відповідно проаналізувати
перевіряючому для отримання Identity Verification Message.
Ці транзакції повинні спочатку вважатися НЕПЕРЕВІРЕНІ. Це пов’язано з тим,
що для підписання транзакції не потрібен identity
, що дозволяє будь-якій
транзакції включати цей обліковий запис, як такий, що не підписує. Це потенційно
може штучно збільшувати кількість приписувань та використань.
Identity Verification Message слід перевірити, щоб забезпечити, що підпис був
створений identity
, який підписав reference
. Якщо перевірка цього підпису не
вдалася, транзакцію вважають недійсною і вона не повинна приписуватися Action
Provider.
Якщо перевірка підпису успішна, перевіряючий повинен переконатися, що ця
транзакція є першим випадком reference
на ланцюжку. Якщо це не так, транзакцію
вважають недійсною.