Действия и Blinks

Solana Действия - это API, соответствующие спецификации, которые позволяют просматривать, подписывать и отправлять транзакции на блокчейне Solana в различных контекстах, включая QR-коды, кнопки + виджеты и веб-сайты в Интернете. Действия упрощают для разработчиков интеграцию вещей, которые вы можете делать в экосистеме Solana, прямо в вашу среду, позволяя вам выполнять транзакции блокчейна без необходимости переходить в другое приложение или на другую веб-страницу.

Блокчейн-ссылки - или blinks - превращают любое действие Solana в ссылку, которой можно поделиться и которая содержит метаданные. Cсылки позволяют клиентам с поддержкой Action (кошельки расширения браузера, боты) отображать дополнительные возможности для пользователя. На веб-сайте мигание может немедленно вызвать предварительный просмотр транзакции в кошельке без перехода к децентрализованному приложению; в Discord бот может расширить мигание до интерактивного набора кнопок. Таким образом, возможность взаимодействия внутри цепочки распространяется на любую веб-поверхность, способную отображать URL.

Начало работы #

Чтобы быстро начать с создания пользовательских действий Solana:

npm install @solana/actions
  • установите Solana Actions SDK в вашем приложении
  • постройте конечную точку API для GET request, которая возвращает метаданные о вашем действии
  • создайте конечную точку API, которая принимает запрос POST и возвращает подписанную транзакцию для пользователя
Info

Посмотрите этот видеоурок на как создать действие Солана с помощью команды @solana/actions SDK.

Вы также можете найти исходный код Action, выполняющего нативную передачу SOL, здесь и несколько других примеров Actions в этом репозитории.

При развертывании ваших пользовательских действий Solana в производстве:

  • убедитесь, что ваше приложение имеет корректный файл actions.json в корне вашего домена
  • убедитесь, что ваше приложение отвечает с необходимыми заголовками Cross-Origin на всех конечных точках Action, включая файл actions.json.
  • test and debug your blinks/actions using the Blinks Inspector

Если вы ищете вдохновение для создания Actions и мигалок, загляните в репозиторий Awesome Blinks, где вы найдете несколько творений сообщества и даже идеи для новых.

Действия #

Спецификация Solana Действия использует набор стандартных API для доставки подписываемых транзакций (и, в конечном счете, подписываемых сообщений) из приложения непосредственно пользователю. Они размещаются на общедоступных URL-адресах и поэтому доступны по их URL-адресу любому клиенту для взаимодействия.

Info

Вы можете думать о Действиях как о конечной точке API, которая возвращает метаданные и что-то, что пользователь может подписать (либо транзакцию, либо сообщение аутентификации) с помощью своего кошелька блокчейна.

API Действия состоит из простых GET- и POST-запросов к конечной точке URL Действия и обработки ответов, соответствующих интерфейсу Действия.

  1. GET-запрос возвращает метаданные, которые предоставляют клиенту человекочитаемую информацию о том, какие действия доступны по данному URL, и необязательный список связанных действий.
  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.

Выполнение и Жизненный цикл Действий #

На практике взаимодействие с Действиями очень похоже на взаимодействие с типичным REST API:

  • клиент делает начальный GET-запрос к URL-адресу Действия, чтобы получить метаданные о доступных Действиях
  • конечная точка возвращает ответ, содержащий метаданные о конечной точке (например, название и иконку приложения) и список доступных действий для этой конечной точки
  • клиентское приложение (например, мобильный кошелек, чат-бот или веб-сайт) отображает пользовательский интерфейс для выполнения одного из действий
  • после того как пользователь выбирает действие (нажимает кнопку), клиент делает POST-запрос к конечной точке, чтобы получить транзакцию для подписания пользователем
  • кошелек помогает пользователю подписать транзакцию и в конечном итоге отправляет ее в блокчейн для подтверждения

Выполнение и жизненный цикл действий Solana

При получении транзакций от URL-адреса Действия клиенты должны обрабатывать отправку этих транзакций в блокчейн и управлять жизненным циклом их состояния.

Действия также поддерживают некоторый уровень проверки достоверности перед выполнением. GET- и POST-запросы могут возвращать некоторые метаданные, указывающие, может ли действие быть выполнено (как в случае с полем disabled). GET- и POST-запросы могут возвращать некоторые метаданные, указывающие, может ли действие быть выполнено (как в случае с полем disabled).

Например, если есть конечная точка действия, которая облегчает голосование по предложению управления DAO, окно голосования по которому закрылось, первоначальный GET-запрос может вернуть сообщение об ошибке "Это предложение больше не подлежит голосованию", а кнопки "Голосовать да" и "Голосовать нет" - как "отключенные".

Blinks (блокчейн-ссылки) - это клиентские приложения, которые исследуют Действия API и создают пользовательские интерфейсы для взаимодействия и выполнения Действий.

Клиентские приложения, поддерживающие мигание, просто обнаруживают совместимые с Действиями URL, анализируют их и позволяют пользователям взаимодействовать с ними в стандартных пользовательских интерфейсах.

Info

Любое клиентское приложение, которое полностью исследует Действия API, чтобы создать для него полноценный интерфейс, является мигающим. Поэтому не все клиенты, использующие API Actions, являются мигалками.

URL-адрес blink описывает клиентское приложение, которое позволяет пользователю завершить полный жизненный цикл выполнения действия, включая подписание с помощью своего кошелька.

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

Чтобы любое клиентское приложение стало blink:

  • URL-адрес должен содержать параметр запроса action, значение которого является URL-кодированным URL действия. Это значение должно быть закодировано в URL, чтобы не конфликтовать с другими параметрами протокола.

  • Клиентское приложение должно URL-декодировать параметр запроса action и просмотреть предоставленную ссылку Действия API (см. схему Action URL).

  • Клиент должен предоставлять богатый пользовательский интерфейс, позволяющий пользователю пройти весь жизненный цикл выполнения действия, включая подписание кошелька.

Info

Не все клиентские приложения blink (например, веб-сайты или dApps) будут поддерживать все действия.Разработчики приложений могут выбирать, какие действия они хотят поддерживать в своих интерфейсах мигания.

Следующий пример демонстрирует действительный URL-адрес мигания со значением действияsolana-action:https://actions.alice.com/donate, который закодирован в URL:

https://example.domain/?action=solana-action%3Ahttps%3A%2F%2Factions.alice.com%2Fdonate

Blinks могут быть связаны с действиями как минимум тремя способами:

  1. Совместное использование явного URL-адреса действия: solana-action:https://actions.alice.com/donate

    В этом случае только поддерживаемые клиенты могут отображать blink. Не будет ни предварительного просмотра резервной ссылки, ни сайта, который можно посетить за пределами неподдерживаемого клиента.

  2. Обмен ссылкой на веб-сайт, связанный с API Actions через файл actions.json в корневом домене сайта.

    Например, https://alice.com/actions.json сопоставляет https://alice.com/donate\`, URL веб-сайта, на котором пользователи могут пожертвовать Алисе, с API URL https://actions.alice.com/donate, на котором размещены Действия для пожертвования Алисе.

  3. Встраивание URL-адреса действия в URL-адрес "интерстициального" сайта, который понимает, как разбирать Действия.

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

Клиенты, поддерживающие мигалки, должны уметь принимать любой из вышеперечисленных форматов и корректно отображать интерфейс, чтобы облегчить выполнение действия непосредственно в клиенте.

Для клиентов, не поддерживающих мигания, должен быть предусмотрен базовый веб-сайт (что делает браузер универсальным запасным вариантом).

Если пользователь нажимает на любом месте клиента, которое не является кнопкой действия или полем ввода текста, он должен перейти на базовый сайт.

Хотя действия и blinks Solana представляют собой протокол/спецификацию без разрешений, клиентские приложения и кошельки все равно должны в конечном итоге помочь пользователям подписать транзакцию.

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.

Например, некоторые клиенты могут работать по принципу "разрешенного списка", который может требовать проверки перед тем, как их клиент развернет действие для пользователей, как, например, реестр действий Dialect (подробнее см. ниже).

Все blinks по-прежнему будут отображаться и позволять подписаться на Dialect's dial.to blinks Interstitial сайт, с их реестра статус отображается в blink.

Реестр действий Dialect #

В качестве общественного блага для экосистемы Solana, Dialect ведет публичный реестр - с помощью Solana Foundation и других членов сообщества - блокчейн-связей, которые были предварительно проверены из известных источников. С момента запуска в Твиттере будут появляться только те действия, которые были зарегистрированы в реестре Dialect.

Клиентские приложения и кошельки могут свободно выбирать, использовать этот публичный реестр или другое решение для обеспечения безопасности пользователей. Если ссылка на блокчейн не верифицирована в реестре Dialect, клиент blink не будет к ней прикасаться и отобразит ее как обычный URL.

Разработчики могут подать заявку на верификацию в Dialect здесь: dial.to/register

Спецификация #

Спецификация Solana Действия состоит из ключевых разделов, которые являются частью потока взаимодействия запрос/ответ:

  • Схема Solana Действия URL, предоставляющая URL-адрес действия
  • Ответ OPTIONS на URL-адрес действия для соблюдения требований CORS
  • GET-запрос к URL-адресу действия
  • GET-ответ от сервера
  • POST-запрос к URL-адресу действия
  • POST-ответ от сервера

Каждый из этих запросов выполняется клиентом действия (например, приложением для кошелька, расширением для браузера, dApp, веб-сайтом и т. д.), чтобы собрать определенные метаданные для богатых пользовательских интерфейсов и облегчить ввод данных пользователем в API действий.

Каждый из ответов формируется приложением (например, веб-сайтом, серверным бэкендом и т. д.) и возвращается клиенту Действия. В конечном итоге, предоставляя кошельку возможность подписать транзакцию или сообщение, пользователь должен одобрить, подписать и отправить в блокчейн. В конечном итоге, предоставляя кошельку возможность подписать транзакцию или сообщение, пользователь должен одобрить, подписать и отправить в блокчейн.

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 #

URL-адрес действия Solana описывает интерактивный запрос на подписанную транзакцию или сообщение Solana с использованием протокола solana-action.

Запрос является интерактивным, поскольку параметры в URL используются клиентом для выполнения серии стандартизированных HTTP-запросов для создания подписываемой транзакции или сообщения, которое пользователь должен подписать с помощью своего кошелька.

solana-action:<link>
  • В качестве пути требуется одно поле link. Значение должно быть условно URL-encoded абсолютный HTTPS URL.

  • Если URL содержит параметры запроса, он должен быть кодирован в URL-кодировке. Значение кодировки предотвращает конфликты с параметрами протокола Действий, которые могут быть добавлены через спецификацию протокола.

  • Если URL содержит параметры запроса, он должен быть кодирован в URL-кодировке. Это создает более короткий URL и менее плотный QR-код.

Значение должно быть условно URL-encodedthe) абсолютный HTTPS URL. Это не влияет, если значение не имеет URL-кодировки. Если декодированное значение не является абсолютным HTTPS URL, кошелек должен отклонить его как malformed.

Ответ OPTIONS #

Чтобы разрешить кросс-оригинальный обмен ресурсами (CORS) в клиентах Actions (включая мигалки), все конечные точки Action должны отвечать на HTTP-запросы метода OPTIONS с корректными заголовками, которые позволят клиентам пройти CORS-проверку для всех последующих запросов из домена того же происхождения.

Клиент Actions может выполнять "префлайт" запросы к конечной точке Action URL, чтобы проверить, пройдет ли последующий GET-запрос к Action URL все CORS-проверки. Эти предварительные проверки CORS выполняются с помощью HTTP-метода OPTIONS и должны содержать все необходимые HTTP-заголовки, которые позволят Action-клиентам (например, blinks) правильно выполнять все последующие запросы из их исходного домена.

Как минимум, требуемые заголовки HTTP включают:

  • Access-Control-Allow-Origin со значением *
    • это гарантирует, что все клиенты действий смогут безопасно проходить проверку CORS для того, чтобы все необходимые запросы
  • Access-Control-Allow-Methods со значением GET,POST,PUT,OPTIONS
    • гарантирует, что все необходимые методы HTTP запроса поддерживаются для действий
  • Access-Control-Allow-Headers с минимальным значением Content-Type, авторизация, Содержимое-кодирование, Accept-Encoding

Для простоты разработчикам стоит подумать о том, чтобы возвращать на запросы OPTIONS тот же ответ и заголовки, что и на GET.

Cross-Origin headers for actions.json

Ответ файла actions.json должен также возвращать допустимые заголовки Cross-Origin для запросов GET и OPTIONS, в частности заголовок Access-Control-Allow-Origin в заголовке *.

Более подробную информацию см. в файле actions.json ниже.

Запрос GET #

Клиент Действия (например, кошелек, расширение браузера и т. д.) должен сделать HTTP GET JSON запрос к конечной точке URL Действия.

  • Запрос не должен идентифицировать кошелек или пользователя.
  • Клиент должен отправить запрос с заголовком Accept-Encoding.
  • Клиент должен отобразить домен URL по мере выполнения запроса.

GET Ответ #

Конечная точка URL Действия (например, приложение или бэкэнд сервера) должна ответить JSON-ответом HTTP OK (с корректной полезной нагрузкой в теле) или соответствующей 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 должен содержать тело полезной нагрузки, соответствующее спецификации интерфейса:

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, иначе клиент/кошелек отвергнет его как неверно сформированный. Файл должен быть изображением SVG, PNG или WebP, иначе клиент/кошелек отвергнет его как неверно сформированный.

  • title - Значение должно быть строкой UTF-8, представляющей источник запроса действия. Например, это может быть название бренда, магазина, приложения или человека, сделавшего запрос.

  • description - Значение должно быть строкой UTF-8, содержащей информацию о действии. Описание должно быть показано пользователю.

  • label - Значение должно представлять собой строку UTF-8, которая будет отображаться на кнопке для нажатия пользователем. Все метки не должны превышать 5 слов и должны начинаться с глагола, чтобы определить действие, которое вы хотите, чтобы пользователь совершил. Например, "Mint NFT", "Vote Yes" или "Stake 1 SOL".

  • disabled - значение должно быть булевым, чтобы представлять отключенное состояние отображаемой кнопки (которая отображает строку метки). Если значение не указано, то 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 with disabled to display a reason like business constraints, authorization, the state, or an error of external resource.

  • links.actions - Необязательный массив связанных действий для конечной точки. Пользователям должен быть показан пользовательский интерфейс для каждого из перечисленных действий, и ожидается, что они выполнят только одно из них. Например, конечная точка действия голосования по вопросам управления может возвращать пользователю три варианта: "Голосовать да", "Голосовать нет" и "Воздержаться от голосования".

    • Если поле links.actionsне указано, клиент должен отобразить единственную кнопку, используя строку корневого label, и выполнить POST-запрос к той же конечной точке URL действия, что и первоначальный GET-запрос.

    • Если указаны какие-либо 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 Ответа #

Следующий пример предоставляет одно действие "root", которое ожидается для предоставления пользователю одной кнопки с меткой "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
          }
        ]
      }
    ]
  }
}

Запрос GET #

Клиент должен сделать HTTP-запрос POST JSON URL действия с телом приложения:

{
  "account": "<account>"
}
  • account - значение должно быть публичным ключом в base58-кодированном аккаунте, который может подписать транзакцию.

Клиент должен сделать запрос с заголовком Accept-Encoding header, а приложение должно ответить заголовком Content-Encoding для сжатия HTTP.

Во время выполнения запроса клиент должен отобразить домен URL действия. Если был сделан GET-запрос, клиент также должен отобразить заголовок и вывести изображение иконки из GET-ответа.

POST Ответ #

Конечная точка URL Действия (например, приложение или бэкэнд сервера) должна ответить JSON-ответом HTTP OK (с корректной полезной нагрузкой в теле) или соответствующей 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 должен содержать в себя тело полезной нагрузки из:

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 - значение должно быть сериализованной транзакции. Кошелек должен base64-декодировать транзакцию и десериализовать ее.

  • 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

Приложение может ответить частично или полностью подписанной транзакцией. Кошелек должен подтвердить транзакцию как недоверенную.

POST Ответ - Транзакция #

Если транзакция signatures пуста:

  • Кошелек должен игнорироватьfeePayer в транзакции и установить feePayer на счет в запросе.
  • Кошелек должен игнорировать recentBlockhash в транзакции и установить recentBlockhash на последний блокчейн..
  • Клиент должен сериализовать и десериализовать транзакцию перед ее подписанием. Это обеспечивает последовательное упорядочивание ключей аккаунтов в качестве обходного пути для решения этой проблемы.

Если транзакция была подписана частично:

  • Кошелек не должен устанавливать значения feePayer и recentBlockhash.
  • Кошелек должен проверять подписи, и если какая-либо из них недействительна, кошелек должен отклонить транзакцию как ошибочную.

Кошелек должен подписывать транзакцию только с 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 позволяет приложению информировать клиентов о том, какие URL-адреса веб-сайтов поддерживают Solana Actions, и предоставлять сопоставление, которое можно использовать для выполнения GET requestsк серверу API Actions.

Cross-Origin headers are required

Ответ файла actions.json должен также возвращать допустимые заголовки Cross-Origin для запросов 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 для *.

Правила #

Поле правил позволяет приложению сопоставить набор относительных маршрутных путей веб-сайта с набором других путей.

Тип: Array ActionRuleObject.

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.

    • Пример: /api/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.

  • Пример: /api/exact-path
  • Пример: https://api.example.com/v1/donate/*
  • Например: /api/category/*/item/*
  • Пример: /api/swap/**

Правила - Параметры запросов #

Параметры запроса из исходного URL всегда сохраняются и добавляются к сопоставленному URL.

Правила - Соответствие пути #

В следующей таблице описывается синтаксис для шаблонов пути соответствия:

ОператорСовпадения
*Сегмент одного пути, не включающий разделитель контуров / символов.
**Соответствует нулю или более символов, включая любой разделитель пути / символы между несколькими сегментами пути. Если другие операторы включены, то "**" оператор должен быть последним оператором.
?Шаблон не поддерживается.

Примеры Правил #

Следующий пример демонстрирует правило точного соответствия запросам на карту запросов в /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/*"
    }
  ]
}

В следующем примере используется подстановочное сопоставление путей для идемпотентного правила, чтобы сопоставить запросы к любому пути (включая подкаталоги) под /api/actions/ из вашего корня сайта к самому себе:

Info

Правила Idempotent позволяют морским клиентам более легко определить, поддерживает ли данный путь запросы Action API без необходимости префикса с помощью solana-action: URI или выполнения дополнительного тестирования ответов.

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

Идентификатор Действия #

Конечные точки действия могут включать идентификатор действия в транзакции, возвращаемые в POST-ответе для подписи пользователем. Это позволяет индексаторам и аналитическим платформам легко и достоверно относить активность на цепи к конкретному поставщику действий (т. е. сервису).

Идентификатор действия - это пара ключей, используемая для подписи специально отформатированного сообщения, которое включается в транзакцию с помощью инструкции Memo. Это сообщение-идентификатор может быть достоверно отнесено к определенному идентификатору действия и, следовательно, отнести транзакции к определенному Поставщику Действий.

Пара ключей не требуется для подписания самой транзакции. Это позволяет кошелькам и приложениям улучшить доставку транзакций, когда на транзакции, возвращаемой пользователю, нет других подписей (см. транзакцию POST-ответа).

Если по условиям использования Поставщика Действий его бэкэнд-сервисы должны предварительно подписать транзакцию до того, как это сделает пользователь, им следует использовать эту пару ключей в качестве идентификатора действия. Это позволит включить в транзакцию на одну учетную запись меньше, уменьшив общий размер транзакции на 32 байта.

Сообщение идентификатора действия #

Сообщение идентификатора действия - это отдельная строка UTF-8 с двоеточием, включаемая в транзакцию с помощью одной инструкции SPL Memo.

protocol:identity:reference:signature
  • protocol - значение используемого протокола (установите значение solana-action на в схеме URL выше)
  • identity - значение должно быть адресом открытого ключа с кодировкой base58-кодировки
  • reference - значение должно быть 32-байтовым массивом base58. Это могут быть открытые ключи, на кривой или вне кривой, и могут соответствовать или не соответствовать учетными записями на Solana.
  • signature - подпись, созданная из клавиши Action Identity с кодировкой, подписывающей только значение reference.

Значение reference должно использоваться только один раз и в одной транзакции. Для цель привязки транзакций к Поставщику Действий, только первое использование значения reference считается действительным.

Транзакции могут иметь несколько инструкций по примечаниям. При выполнении [getSignaturesForAddress](https://solana. om/docs/rpc/http/getsignaturesforaddress), результаты поля memo будут возвращать каждое сообщение инструкций как одну строку с каждой отделенной точкой с запятой.

Никакие другие данные не должны быть включены в инструкцию Memo Identifier Message.

identity и reference должны быть включены в качестве только для чтения, неподписавшего [keys](https://solana-labs.github.io/solana-web3. s/classes/TransactionInstruction.html#keys) в транзакции инструкции, не являющейся инструкцией Memo .

В инструкции Identifier Message Memo должна быть указана нулевая учетная запись. Если какие-либо учетные записи предоставлены, программа Memo требует наличия учетных записей для действительных подписчиков . Для определения действий это ограничивает гибкость, а может ухудшить качество работы пользователя. Поэтому он считается антипаттерном, и его следует избегать.

Действие Проверка личности #

Любая транзакция, включающая в себя учётную запись identity, может быть проверяемым связанным с оператором в многоэтапном процессе:

  1. Получить все транзакции для данного identity.
  2. Разберите и проверьте строку мемо каждой транзакции, чтобы убедиться, что подпись действительна для сохраненной ссылки.
  3. Верифицировать конкретную транзакцию - первое вхождение reference в цепочку:
    • Если эта транзакция встречается впервые, транзакция считается проверенной и может быть надежно приписана Поставщику Действий.
    • Если эта транзакция не является первой, она считается недействительной и, следовательно, не может быть приписана Поставщику Действий.

Поскольку Solana индексирует транзакции по ключам аккаунта, getSignaturesForAddress Метод RPC может быть использован для определения всех транзакций, включая identity аккаунт.

Ответ этого метода RPC включает все данные Memo в поле memo. Если несколько инструкций для Memo были использованы в транзакции, каждое сообщение будет включено в это поле memo и должно быть обработано соответствующим образом верификатором для получения Verification Message.

Эти транзакции сначала должны быть признаны НЕВЕРИФИЦИРОВАННЫЙ. Это вызвано тем, что не требуется подписывать транзакцию, которая позволяет транзакции включить эту учетную запись в качестве неподписавшего. Потенциально искусственное Завышение показателей атрибуции и использования.

Сообщение проверка личности следует проверить, чтобы убедиться в том, что signature был создан с помощью identity подписи reference. Если проверка подписи не удается, транзакция считается недействительной и должна быть передана к Поставщику Действий.

Если проверка подписи прошла успешно, верификатор должен убедиться, что транзакция является первым в цепочке из ссылки. Если это не так, транзакция считается недействительной.