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 запит і повертає транзакцію, яку користувач може підписати
Info

Перегляньте цей відеоурок про те, як створити Solana Action за допомогою SDK @solana/actions.

Ви також можете знайти вихідний код для Action, який виконує нативний переказ SOL, тут, а також кілька інших прикладів Action у цьому репозиторії.

Під час розгортання ваших Solana Action у продакшн:

Якщо ви шукаєте натхнення для створення Action та blink, перегляньте репозиторій Awesome Blinks, де можна знатий творіння спільноти та навіть ідеї для нових blink.

Actions #

Специфікація Solana Actions використовує набір стандартних API для надання транзакцій, які можна підписати (а згодом і повідомлень, що також можна підписати), безпосередньо від додатка до користувача. Вони розміщуються за загальнодоступними URL-адресами й відповідно доступні для будь-якого клієнта за своїм URL.

Info

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

API Actions полягає у здійсненні простих GET та POST запитів до Action URL ендпоінту й обробці відповідей, що відповідають інтерфейсу Actions.

  1. GET запит повертає метадані, які надають клієнту читабельну інформацію про те, які дії доступні за цією URL-адресою, а також необов'язковий список пов'язаних дій.
  2. POST запит повертає транзакцію або повідомлення для підпису, після чого клієнт пропонує користувачеві підписати його за допомогою гаманця та виконати їх у блокчейні або в іншій off-chain службі.

Виконання та життєвий цикл Action #

На практиці взаємодія з Actions дуже схожа на взаємодію зі звичайним REST API:

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

Виконання Solana Actions та життєвий циклВиконання 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 (blockchain links) - це клієнтські додатки, які аналізують Action API та створюють користувацькі інтерфейси для взаємодії та виконання Actions.

Клієнтські додатки, які підтримують blink, просто виявляють сумісні Action URL, розбирають їх і дозволяють користувачам взаємодіяти з ними у стандартизованих користувацьких інтерфейсах.

Info

Будь-який клієнтський додаток, який повністю аналізує Actions API для побудови повного інтерфейсу для нього, є blink. Тому не всі клієнти, який використовує Actions API, є blink.

URL blink описує клієнтський додаток, яка дозволяє користувачеві завершити повний цикл виконання Action, включаючи підпис з їх гаманцем.

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

Для того щоб будь-яка клієнтська програма могла використовувати blink:

  • Blink URL повинна містити параметр запиту action, значення якого буде URL закодованим для Action URL. Це значення повинно бути закодовано, щоб уникнути конфліктів з іншими параметрами протоколу.

  • Клієнтський додаток повинний декодувати URL параметр запиту action і інтроспектувати надане посилання Action API (див. Action URL scheme).

  • Клієнт повинен відображати користувацький інтерфейс, який дозволяє завершити весь життєвий цикл виконання Action, включаючи підпис з їх гаманця.

Info

Не всі клієнтські 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

Blink можуть бути пов'язані з Actions принаймні трьома способами:

  1. Поширення за допомогою явного Action URL: solana-action:https://actions.alice.com/donate

    У цьому випадку лише підтримувані клієнти можуть відтворювати blink. Не буде доступно жодного альтернативного попереднього перегляду посилання або сайту, який можна було б відвідати за межами непідтримуваного клієнта.

  2. Поширення посилання на вебсайт, який пов'язаний з Actions API за допомогою actions.json файлуу кореневій директорії домену вебсайту.

    Наприклад, https://alice.com/actions.json відображає посилання https://alice.com/donate на веб-сайті, де користувачі можуть здійснити пожертвування на користь Alice, на API URL https://actions.alice.com/donate\`, де знаходяться Actions для здійснення пожертвування Alice.

  3. Вбудовування Action URL в "проміжний" URL веб-сайту, який розуміє, як парсити Actions.

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

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

Для клієнтів, які не підтримують blink, повинен бути доступний базовий вебсайт (що робить браузер універсальним резервом).

Якщо користувач натискає на будь-яке місце в клієнтській програмі, крім кнопки дії або поля введення тексту, його повинно перенаправити на базовий сайт.

Хоча Solana Actions та blinks є протоколом/специфікацією без права доступу, клієнтські додатки та гаманці все одно повинні забезпечувати користувачам можливість підписувати транзакції.

Кожен з цих клієнтських додатків або гаманців може мати різні вимоги щодо того, які Action ендпоінт їхні клієнти будуть автоматично розгортати та відображати своїм користувачам на платформах соціальних мереж.

Наприклад, деякі клієнти можуть працювати за принципом "дозволеного списку", що може вимагати перевірки перед тим, як їхній клієнт розгорне 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 складається з ключових розділів, які є частиною процесу взаємодії запит/відповідь:

Кожен із цих запитів робиться Action клієнтом (наприклад, додатком гаманця, браузерним розширенням, dApp, вебсайтом тощо), щоб зібрати специфічні метадані для багатих користувацьких інтерфейсів і для полегшення введення користувача в Actions API.

Кожна з відповідей формується додатком (наприклад, вебсайтом, серверною частиною, тощо) і повертається клієнту Action. Зрештою, надаючи транзакцію або повідомлення для підпису, щоб гаманець запропонував користувачу підтвердити, підписати та відправити у блокчейн.

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.

Cross-Origin headers for actions.json

Відповідь файлу 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-помилкою.

Тіло відповіді GET запиту #

Відповідь на GET запит з HTTP OK JSON повинна містити тіло з вмістом, що відповідає специфікації інтерфейсу:

ActionGetResponse
export interface ActionGetResponse {
  /** 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;
}
  • 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 - Опційне вказівне поле для відображення не критичних помилок. Якщо воно присутнє, клієнт повинен відображати його користувачу. Якщо воно встановлене, воно не повинно заважати клієнту інтерпретувати дію або відображати її користувачу. Наприклад, помилку можна використовувати разом із параметром disabled для відображення причин, таких як бізнес-обмеження, авторизація, стан чи помилка зовнішнього ресурсу.

ActionError
export interface ActionError {
  /** non-fatal error message to be displayed to the user */
  message: string;
}
  • links.actions - Опціональний масив пов'язаних дій для ендпоінта. Користувачам повинно відображатися інтерфейсне вікно для кожної з перелічених дій і очікувати, що вони виконають лише одну. Наприклад, ендпоінт дії голосування в управлінні може повертати три варіанти для користувача: "Vote Yes", "Vote No" і "Abstain from Vote".

    • Якщо не надано 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;
  /** Parameter to accept user input within an action */
  parameters?: [ActionParameter];
}
 
/** Parameter to accept user input within an action */
export interface ActionParameter {
  /** 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;
}

Приклад 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-помилкою.

Тіло POST відповіді #

Відповідь на POST запит з HTTP OK JSON повинна містити тіло з вмістом:

ActionPostResponse
export interface ActionPostResponse {
  /** base64 encoded serialized transaction */
  transaction: string;
  /** describes the nature of the transaction */
  message?: string;
}
  • transaction - Значення повинно бути закодованою у форматі base64 серіалізованої транзакції. Клієнт повинен декодувати транзакцію з base64 і провести її [десеріалізацію] (https://solana-labs.github.io/solana-web3.js/classes/Transaction.html#from).

  • message - Значення повинно бути рядком UTF-8, який описує характер транзакції, включеної в відповідь. Клієнт повинен відображати це значення користувачеві. Наприклад, це може бути назва товару, що придбана, знижка на покупку або подяка.

  • Клієнт та додаток повинні дозволяти додаткові поля у тілі запиту та тілі відповіді, які можуть бути додані у майбутніх оновленнях специфікації.

Info

Додаток може відповісти частково або повністю підписаною транзакцією. Клієнт і гаманець повинні позначити транзакцію як ненадійну.

POST Відповідь - Транзакція #

Якщо підписи транзакції порожні або транзакція не була частково підписана:

  • Клієнт повинен ігнорувати feePayer у транзакції і встановити feePayer на обліковий запис у запиті.
  • Клієнт повинен ігнорувати recentBlockhash у транзакції і встановити recentBlockhash на останній блокхеш.
  • Клієнт повинен серіалізувати та десеріалізувати транзакцію перед її підписанням. Це забезпечує послідовний порядок ключів облікових записів, як обхідне рішення для цієї проблеми.

Якщо транзакцію було частково підписано:

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

Клієнт повинен підписувати транзакцію лише з обліковим записом у запиті і робити це тільки в тому випадку, якщо очікується підпис для облікового запису у запиті.

Якщо очікується будь-який підпис, крім підпису для облікового запису у запиті, клієнт повинен відхилити транзакцію як зловмисну.

actions.json #

Мета файлу actions.json file полягає в тому, щоб додаток міг вказати клієнтам, які веб-сайти підтримують Solana Action і надавати відображення, яке можна використовувати для виконання GET запитів до сервера Actions API.

Cross-Origin headers are required

Відповідь файлу 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.

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' відносно кореня вашого сайту:

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

Ідемпотентні правила дозволяють blink клієнтам легше визначити, чи підтримує заданий шлях запити Action API, без необхідності додавання префікса solana-action: URI або виконання додаткового тестування відповідей.

actions.json
{
  "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, закодованою у форматі base58
  • reference - Значення повинно бути масивом із 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 у багатокроковому процесі:

  1. Отримайте всі транзакції для даного identity.
  2. Проаналізуйте та перевірте рядок memo кожної транзакції, переконуючись, що підпис signature є дійсним для збереженого значення reference.
  3. Перевірте, що конкретна транзакція є першим випадком 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 на ланцюжку. Якщо це не так, транзакцію вважають недійсною.