Actions et Blinks

Les Actions Solana sont des API conformes aux spécifications qui retournent des transactions sur la blockchain Solana pour être prévisualisées, signées et envoyées via un certain nombre de contextes différents tels que les QR codes, les boutons + widgets et les sites Internet. Les Actions permettent aux développeurs d'intégrer facilement dans leur environnement les choses qu'il est possible de faire dans l'écosystème Solana, ce qui leur permet d'effectuer des transactions blockchain sans avoir à naviguer vers une autre application ou une autre page web.

Les liens blockchain – ou blinks – transforment toute Action Solana en un lien partageable et contenant des métadonnées. Les blinks permettent aux clients sensibles aux Actions (portefeuilles de navigateur, robots) d'afficher des fonctionnalités supplémentaires pour l'utilisateur. Par exemple, sur un site web, un blink peut immédiatement déclencher une prévisualisation de la transaction dans un portefeuille sans passer par une application décentralisée ou encore sur Discord où un robot peut étendre le blink en un ensemble de boutons interactif. La possibilité d'interagir avec la chaîne est ainsi étendue à toute interface web capable d'afficher une URL.

Get Started #

To quickly get started with creating custom Solana Actions:

npm install @solana/actions
  • install the Solana Actions SDK in your application
  • build an API endpoint for the GET request that returns the metadata about your Action
  • create an API endpoint that accepts the POST request and returns the signable transaction for the user
Info

Checkout this video tutorial on how to build a Solana Action using the @solana/actions SDK.

You can also find the source code for an Action that performs a native SOL transfer here and several other example Actions in this repo.

When deploying your custom Solana Actions to production:

If you are looking for inspiration around building Actions and blinks, checkout the Awesome Blinks repository for some community creations and even ideas for new ones.

Actions #

La spécification des Actions Solana utilise un ensemble d'API standard pour retourner des transactions pouvant être signées (et éventuellement des messages pouvant être signés) à partir d'une application directement à un utilisateur. Ils sont hébergés sur des URL accessibles au public et sont donc accessibles par leur URL à tout client qui souhaite interagir avec eux.

Info

Vous pouvez considérer les Actions comme un point de terminaison de l'API qui retournera des métadonnées et quelque chose qu'un utilisateur pourra signer (une transaction ou un message d'authentification) avec son portefeuille blockchain.

L'API Actions consiste à effectuer de simples requêtes GET et POST à l'adresse URL d'une Action et à traiter les réponses conformément à l'interface Actions.

  1. la requête GET retourne des métadonnées qui fournissent au client des informations lisibles par l'homme sur les actions disponibles à cette URL, ainsi qu'une liste facultative d'actions associées.
  2. la requête POST retourne une transaction ou un message pouvant être signé que le client demande ensuite au portefeuille de l'utilisateur de signer et d'exécuter sur la blockchain ou sur un autre service hors chaîne.

Exécution et Cycle de vie des Actions #

En pratique, l'interaction avec les Actions ressemble beaucoup à l'interaction avec une API REST classique :

  • un client fait une requête GET initiale à une URL d'Action afin d'obtenir les métadonnées sur les actions disponibles
  • le point de terminaison retourne une réponse qui contient les métadonnées relatives au point de terminaison (comme le titre et l'icône de l'application) et une liste des actions disponibles pour ce point de terminaison
  • l'application client (comme un portefeuille mobile, un chat bot ou un site web) affiche une interface utilisateur permettant à l'utilisateur d'effectuer l'une des actions
  • après que l'utilisateur a sélectionné une action (en cliquant sur un bouton), le client envoie une requête POST au point de terminaison afin d'obtenir la transaction à faire signer par l'utilisateur
  • le portefeuille permet à l'utilisateur de signer la transaction et envoie finalement la transaction à la blockchain pour confirmation

Solana Actions Execution and LifecycleSolana Actions Execution and Lifecycle

Lorsqu'ils reçoivent des transactions d'une URL d'Actions, les clients doivent se charger de la soumission de ces transactions à la blockchain et gérer le cycle de vie de leur état.

Les Actions supportent également un certain niveau d'invalidation avant l'exécution. Les requêtes GET et POST peuvent retourner des métadonnées indiquant si l'action peut être réalisée (comme avec le champ disabled).

Par exemple, s'il existe un point de terminaison Action qui permet de voter sur une proposition de gouvernance d'une DAO dont la fenêtre de vote est fermée, la requête GET initiale peut retourner le message d'erreur "Cette proposition n'est plus soumise au vote" et les boutons "Voter Oui" et "Voter Non" comme étant "désactivés".

Les Blinks (liens blockchain) sont des applications client qui analysent les API d'Action et construisent des interfaces utilisateur permettant d'interagir avec les Actions et de les exécuter.

Les applications client qui prennent en charge les blinks ne font que détecter les URL compatibles avec les Actions, les analyser et permettre aux utilisateurs d'interagir avec eux au moyen d'interfaces utilisateur standardisées.

Info

Toute application client qui analyse en profondeur une API d'Actions pour en construire une interface complète est un blink. Par conséquent, tous les clients qui utilisent des API d'Actions ne sont pas forcément des blinks.

Une URL blink décrit une application client qui permet à un utilisateur d'effectuer le cycle de vie complet de l'exécution d'une Action, y compris la signature avec son portefeuille.

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

Pour qu'une application client devienne un blink :

  • L'URL blink doit contenir un paramètre de requête action dont la valeur est une URL d'Action encodée. Cette valeur doit être encodée pour ne pas entrer en conflit avec d'autres paramètres du protocole.

  • L'application client doit décoder le paramètre de requête action et analyser le lien de l'API Action fourni (voir schéma d'URL d'Action).

  • Le client doit afficher une interface utilisateur riche qui permet à un utilisateur d'effectuer le cycle de vie complet de l'exécution d'une Action, y compris la signature avec son portefeuille.

Info

Toutes les applications client blink (ex. sites Web ou dApps) ne prendront pas en charge toutes les Actions. En effet, les développeurs d'applications peuvent choisir les Actions qu'ils souhaitent prendre en charge dans leurs interfaces blink.

L'exemple suivant montre une URL blink valide avec une valeur action égale à solana-action:https://actions.alice.com/donate qui est encodée dans l'URL :

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

Les blinks peuvent être liés à des Actions d'au moins 3 façons :

  1. Partage d'une URL d'Action explicite : solana-action:https://actions.alice.com/donate

    Dans ce cas, seuls les clients pris en charge peuvent rendre le blink. Il n'y aura pas de prévisualisation de lien de remplacement, ni de site pouvant être visité en dehors du client non supporté.

  2. Partage d'un lien vers un site web lié à une API Actions via un fichier actions.json présent à la racine du domaine du site web.

    Par exemple, https://alice.com/actions.json associe https://alice.com/donate, URL d'un site web où les utilisateurs peuvent faire un don à Alice, à l'URL de l'API https://actions.alice.com/donate, où sont hébergées les Actions permettant de faire un don à Alice.

  3. Intégration d'une URL d'Action dans l'URL d'un site "interstitiel" qui comprend comment analyser les Actions.

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

Les clients qui prennent en charge les blinks doivent être en mesure d'accepter l'un des formats ci-dessus et d'afficher correctement une interface pour faciliter l'exécution de l'action directement dans le client.

Pour les clients qui ne prennent pas en charge les blinks, il doit y avoir un site web sous-jacent (le navigateur devenant ainsi la solution de remplacement universelle).

Si un utilisateur appuie sur un élément du client qui n'est pas un bouton d'action ou un champ de saisie de texte, il doit être redirigé vers le site sous-jacent.

Bien que les Actions Solana et les blinks soient un protocole/une spécification ne nécessitant pas de permission (permissionless), les applications client et les portefeuilles sont toujours nécessaires pour faciliter la signature des transactions par les utilisateurs.

Chacune de ces applications client ou portefeuilles peut avoir des exigences différentes concernant les points de terminaison d'Action que leurs clients déploieront automatiquement et afficheront immédiatement à leurs utilisateurs sur les plateformes de médias sociaux.

Par exemple, certains clients peuvent fonctionner selon une approche de "liste d'autorisation" qui peut nécessiter une vérification avant que le client ne déploie une Action pour des utilisateurs tel que le Registre d'Actions de Dialect (détaillé ci-dessous).

Tous les blinks seront toujours affichés et permettront de signer sur le site interstitiel de blinks dial.to de Dialect avec leur statut d'enregistrement affiché dans le blink.

Registre d'Actions de Dialect #

En tant que bien public pour l'écosystème Solana, Dialect maintient un registre public - avec l'aide de la Fondation Solana et d'autres membres de la communauté - des liens blockchain qui ont été pré-vérifiés à partir de sources connues. Dès le lancement, seules les Actions enregistrées dans le registre de Dialect se déploieront dans le fil Twitter lorsqu'elles seront publiées.

Les applications client et les portefeuilles peuvent librement choisir d'utiliser ce registre public ou une autre solution pour garantir la sécurité des utilisateurs. S'il n'est pas vérifié par le registre Dialect, le lien blockchain ne sera pas touché par le client blink et sera rendu comme une URL classique.

Les développeurs peuvent demander à être vérifiés par Dialect ici : dial.to/register

Spécification #

La spécification des Actions Solana consiste en des sections clés qui font partie d'un flux d'interaction de requête/réponse :

Chacune de ces requêtes est effectuée par le client d'Action (par exemple application de portefeuille, extension de navigateur, dApp, site web, etc.) afin de recueillir des métadonnées spécifiques pour les interfaces utilisateur enrichies et pour faciliter la saisie de l'utilisateur dans l'API d'Actions.

Chacune des réponses est élaborée par une application (site web, serveur backend, etc.) et renvoyée au client d'Action. Finalement, elle fournit une transaction ou un message pouvant être signé par un portefeuille et invite l'utilisateur à l'approuver, le ou la signer et à l'envoyer à la blockchain.

Schéma d'URL #

Une URL d'Action Solana décrit une requête interactive pour une transaction ou un message Solana pouvant être signé, en utilisant le protocole solana-action.

La requête est interactive car les paramètres de l'URL sont utilisés par un client pour effectuer une série de requêtes HTTP standardisées afin de composer une transaction ou un message pouvant être signé par l'utilisateur à l'aide de son portefeuille.

solana-action:<link>
  • Un seul champ link est requis comme chemin d'accès. La valeur doit être une URL HTTPS absolue encodée de manière conditionnelle.

  • Si l'URL contient des paramètres de requête, elle doit être encodée. L'encodage de la valeur permet d'éviter tout conflit avec les paramètres du protocole Actions qui peuvent être ajoutés via la spécification du protocole.

  • Si l'URL ne contient pas de paramètres de requête, elle ne doit pas être encodée. Il en résulte une URL plus courte et un QR code moins dense.

Dans les deux cas, les clients doivent décoder la valeur. Cela n'a aucun effet si la valeur n'est pas encodée. Si la valeur décodée n'est pas une URL HTTPS absolue, le portefeuille doit la rejeter comme étant malformée.

Réponse OPTIONS #

Afin de permettre le Cross-Origin Resource Sharing (CORS) dans les clients Actions (y compris les blinks), tous les points de terminaison Action doivent répondre aux requêtes HTTP par la méthode OPTIONS avec des en-têtes valides ce qui permettra aux clients de passer les contrôles CORS pour toutes les requêtes ultérieures provenant du même domaine d'origine.

Un client Actions peut effectuer des demandes de "contrôle préalable" au point de terminaison de l'URL d'Action afin de vérifier si la demande GET ultérieure à l'URL d'Action passera toutes les vérifications CORS. Ces contrôles préalables CORS sont effectués à l'aide de la méthode HTTP OPTIONS et doivent répondre avec tous les en-têtes HTTP nécessaires pour permettre aux clients Action (comme les blinks) d'effectuer correctement toutes les requêtes ultérieures à partir de leur domaine d'origine.

Au minimum, les en-têtes HTTP requis sont les suivants :

  • Access-Control-Allow-Origin avec une valeur de *
    • cela permet de s'assurer que tous les clients Action peuvent passer les contrôles CORS en toute sécurité afin d'effectuer toutes les requêtes nécessaires
  • Access-Control-Allow-Methods avec une valeur de GET,POST,PUT,OPTIONS
    • cela permet de s'assurer que toutes les méthodes de requête HTTP requises sont prises en charge par les Actions
  • Access-Control-Allow-Headers avec une valeur minimum de Content-Type, Authorization, Content-Encoding, Accept-Encoding

Pour des raisons de simplicité, les développeurs devraient envisager de retourner la même réponse et les mêmes en-têtes aux requêtes OPTIONS que leur réponse GET.

Cross-Origin headers for actions.json

The actions.json file response must also return valid Cross-Origin headers for GET and OPTIONS requests, specifically the Access-Control-Allow-Origin header value of *.

See actions.json below for more details.

Requête GET #

Le client d'Action (par exemple portefeuille, extension de navigateur, etc.) doit effectuer une requête JSON HTTP GET au point de terminaison de l'URL d'Action.

  • La requête ne doit pas identifier le portefeuille ou l'utilisateur.
  • Le client doit faire la requête avec un en-tête Accept-Encoding.
  • Le client doit afficher le domaine de l'URL lors de la requête.

Réponse GET #

Le point de terminaison de l'URL d'Action (par exemple application ou serveur backend) doit répondre par une réponse JSON HTTP OK (avec une charge utile valide dans le corps) ou par une erreur HTTP appropriée.

Corps de la réponse GET #

Une réponse GET avec une réponse JSON HTTP OK doit inclure dans le corps une charge utile conforme à la spécification de l'interface :

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 - La valeur doit être une URL HTTP ou HTTPS absolue d'une image d'icône. Le fichier doit être une image SVG, PNG ou WebP, sinon le client/le portefeuille doit le rejeter comme étant malformé.

  • title - La valeur doit être une chaîne UTF-8 qui représente la source de la requête d'action. Il peut s'agir, par exemple, du nom d'une marque, d'un magasin, d'une application ou de la personne qui fait la requête.

  • description - La valeur doit être une chaîne UTF-8 qui fournit des informations sur l'action. La description doit être affichée à l'utilisateur.

  • label - La valeur doit être une chaîne UTF-8 qui sera affichée sur un bouton sur lequel l'utilisateur pourra cliquer. Toutes les étiquettes (labels) ne doivent pas dépasser 5 mots et doivent commencer par un verbe pour renforcer l'action que vous voulez que l'utilisateur fasse. Par exemple, "Mint NFT", "Votez Oui" ou "Staker 1 SOL".

  • disabled - La valeur doit être un booléen pour représenter l'état désactivé du bouton affiché (qui affiche la chaîne label). Si aucune valeur n'est fournie, la valeur par défaut de disabled est false (c'est-à-dire activée par défaut). Par exemple, si le point de terminaison de l'action concerne un vote de gouvernance qui a été clôturé, définissez disabled=true et le label pourrait être "Vote Clôturé".

  • error - Une indication d'erreur facultative pour les erreurs non fatales. Si l'indication est présente, le client doit l'afficher à l'utilisateur. Si défini, cela ne doit pas empêcher le client d'interpréter l'action ou de l'afficher à l'utilisateur. Par exemple, l'erreur peut être utilisée avec disabled pour afficher une raison comme des contraintes commerciales, une autorisation, un état ou une erreur de ressource externe.

ActionError
export interface ActionError {
  /** non-fatal error message to be displayed to the user */
  message: string;
}
  • links.actions - Un tableau optionnel d'actions associées au point de terminaison. Une interface utilisateur doit présenter aux utilisateurs chacune des actions listées et il doit leur être demandé de n'en effectuer qu'une seule. Par exemple, un point de terminaison d'action de vote de gouvernance peut renvoyer trois options à l'utilisateur : "Voter Oui", "Voter Non" et "S'abstenir de Voter".

    • Si aucun links.actions n'est fourni, le client doit afficher un seul bouton en utilisant la chaîne label de la racine et envoyer une requête POST au même point de terminaison de l'URL d'action que la requête GET initiale.

    • Si des links.actions sont fournis, le client ne doit afficher les boutons et les champs de saisie qu'en fonction des éléments listés dans le champ links.actions. Le client ne doit donc pas afficher de bouton pour le contenu du label de la racine.

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;
}

Exemple de réponse GET #

L'exemple de réponse suivant fournit une action "root" unique qui doit être présentée à l'utilisateur sous la forme d'un bouton unique intitulé "Claim Access Token" (Réclamer un Jeton d'Accès) :

{
  "title": "HackerHouse Events",
  "icon": "<url-to-image>",
  "description": "Claim your Hackerhouse access token.",
  "label": "Claim Access Token" // button text
}

L'exemple de réponse suivant fournit 3 liens d'action associée qui permettent à l'utilisateur de cliquer sur l'un des 3 boutons pour voter lors d'une proposition de 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"
      }
    ]
  }
}

Exemple de réponse GET avec Paramètres #

Les exemples de réponse suivants montrent comment accepter une saisie de texte de la part de l'utilisateur (via des parameters (paramètres)) et inclure cette saisie dans le point de terminaison de la requête POST finale (via le champ href d'une LinkedAction) :

L'exemple de réponse suivant fournit à l'utilisateur 3 actions associées pour staker des SOL : un bouton libellé "Staker 1 SOL", un autre bouton libellé "Staker 5 SOL" et un champ de saisie de texte qui permet à l'utilisateur d'entrer une valeur spécifique de "amount" (montant) qui sera envoyée à l'API d'Action :

{
  "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
          }
        ]
      }
    ]
  }
}

L'exemple de réponse suivant fournit un champ de saisie unique permettant à l'utilisateur d'entrer un amount (montant) qui est envoyé avec la requête POST (soit en tant que paramètre de requête, soit en tant que sous-chemin) :

{
  "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
          }
        ]
      }
    ]
  }
}

Requête POST #

Le client doit faire une requête JSON HTTP POST à l'URL de l'action avec dans le corps une charge utile contenant :

{
  "account": "<account>"
}
  • account - La valeur doit être la clé publique encodée en base58 d'un compte qui peut signer la transaction.

Le client doit faire la requête avec un en-tête Accept-Encoding et l'application peut répondre avec un en-tête Content-Encoding pour la compression HTTP.

Le client doit afficher le domaine de l'URL de l'action lorsque la requête est effectuée. Si une requête GET a été faite, le client doit également afficher le title et afficher l'image icon de cette réponse GET.

Réponse POST #

Le point de terminaison POST de l'Action doit répondre par une réponse JSON HTTP OK (avec une charge utile valide dans le corps) ou par une erreur HTTP appropriée.

Corps de la réponse POST #

Une réponse POST avec une réponse JSON HTTP OK doit inclure dans le corps de la charge utile :

ActionPostResponse
export interface ActionPostResponse {
  /** base64 encoded serialized transaction */
  transaction: string;
  /** describes the nature of the transaction */
  message?: string;
}
  • transaction - La valeur doit être une transaction sérialisée encodée en base64. Le client doit décoder la transaction en base64 et la désérialiser.

  • message - La valeur doit être une chaîne UTF-8 décrivant la nature de la transaction incluse dans la réponse. Le client doit afficher cette valeur à l'utilisateur. Il peut s'agir, par exemple, du nom d'un article acheté, d'une réduction appliquée lors d'un achat ou d'une note de remerciement.

  • Le client et l'application doivent autoriser des champs supplémentaires dans le corps de la requête et dans le corps de la réponse qui pourront être ajoutés par de futures mises à jour de la spécification.

Info

L'application peut répondre par une transaction partiellement ou totalement signée. Le client et le portefeuille doivent valider la transaction comme étant non fiable.

Réponse POST - Transaction #

Si les signatures de la transaction sont vides ou si la transaction n'a PAS été partiellement signée :

  • Le client doit ignorer feePayer présent dans la transaction et fixer feePayer à la valeur du account indiquée dans la requête.
  • Le client doit ignorer recentBlockhash présent dans la transaction et fixer recentBlockhash à la valeur du dernier blockhash.
  • Le client doit sérialiser et désérialiser la transaction avant de la signer. Cela permet d'assurer un ordre cohérent des clés de compte et constitue une solution de contournement à ce problème.

Si la transaction a été partiellement signée :

  • Le client ne doit PAS modifier feePayer ou recentBlockhash car cela invaliderait les signatures existantes.
  • Le client doit vérifier les signatures existantes, et si l'une d'entre elles n'est pas valide, il doit rejeter la transaction comme étant malformée.

Le client ne doit signer la transaction qu'avec le account indiqué dans la requête, et ne doit le faire que si une signature pour le account indiqué dans la requête est attendue.

Si une signature autre que celle du account présent dans la requête est attendue, le client doit rejeter la transaction comme étant malveillante.

actions.json #

L'objectif du fichier actions.json est de permettre à une application d'indiquer aux clients quelles URL de sites web prennent en charge les Actions Solana et de fournir un mappage qui peut être utilisé pour effectuer des requêtes GET à un serveur API d'Actions.

Cross-Origin headers are required

The actions.json file response must also return valid Cross-Origin headers for GET and OPTIONS requests, specifically the Access-Control-Allow-Origin header value of *.

See OPTIONS response above for more details.

Le fichier actions.json doit être stocké et universellement accessible à la racine du domaine.

Par exemple, si votre application web est déployée à l'adresse my-site.com alors le fichier actions.json doit être accessible à l'adresse https://my-site.com/actions.json. This file should also be Cross-Origin accessible via any browser by having a Access-Control-Allow-Origin header value of *.

Règles #

Le champ rules (règles) permet à l'application de mapper un ensemble de chemins d'accès relatifs d'un site web à un ensemble d'autres chemins d'accès.

Type: Array de 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 - Un modèle qui correspond à chaque chemin d'accès entrant.

  • apiPath - Une destination définie comme un chemin d'accès absolu ou une URL externe.

Règles - pathPattern #

Un modèle qui correspond à chaque chemin d'accès entrant. Il peut s'agir d'un chemin absolu ou relatif et prend en charge les formats suivants :

  • Exact Match (Correspondance Exacte) : Correspond au chemin d'accès exact de l'URL.

    • Exemple : /exact-path
    • Exemple : https://website.com/exact-path
  • Wildcard Match (Correspondance avec des Caractères Génériques) : Utilise des caractères génériques pour correspondre à n'importe quelle séquence de caractères dans le chemin d'accès de l'URL. Il peut s'agir d'un seul segment (en utilisant *) ou de plusieurs segments (en utilisant **). (voir Correspondance des Chemins ci-dessous).

    • Exemple : /trade/* correspondra à /trade/123 et à /trade/abc, capturant seulement le premier segment après /trade/.
    • Exemple : /category/*/item/** correspondra à /category/123/item/456 et à /category/abc/item/def.
    • Exemple : /api/actions/trade/*/confirm correspondra à /api/actions/trade/123/confirm.

Règles - apiPath #

Le chemin de destination de la requête d'action. Il peut être défini comme un nom de chemin absolu ou une URL externe.

  • Exemple : /api/exact-path
  • Exemple : https://api.example.com/v1/donate/*
  • Exemple : /api/category/*/item/*
  • Exemple : /api/swap/**

Règles - Paramètres de Requête #

Les paramètres de requête de l'URL d'origine sont toujours conservés et ajoutés à l'URL mappée.

Règles - Correspondance des Chemins #

Le tableau suivant présente la syntaxe des modèles de correspondance de chemin :

OpérateurCorrespondance
*Un seul segment de chemin sans inclure le séparateur de chemin / caractères environnant.
**Correspond à zéro ou plusieurs caractères, y compris tout séparateur de chemin / caractères entre plusieurs segments de chemin. Si d'autres opérateurs sont inclus, l'opérateur ** doit être le dernier opérateur.
?Modèle non pris en charge.

Exemples de règles #

L'exemple suivant montre une règle de correspondance exacte pour mapper les requêtes /buy depuis la racine de votre site au chemin exact /api/buy relatif à la racine de votre site :

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

L'exemple suivant utilise la correspondance des chemins d'accès avec des caractères génériques pour faire correspondre les requêtes à n'importe quel chemin d'accès (en excluant les sous-répertoires) sous /actions/ depuis la racine de votre site à un chemin d'accès correspondant sous /api/actions/ relatif à la racine de votre site :

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

L'exemple suivant utilise la correspondance des chemins d'accès avec des caractères génériques pour faire correspondre les requêtes à n'importe quel chemin d'accès (en excluant les sous-répertoires) sous /donate/ depuis la racine de votre site à un chemin d'accès absolu correspondant, https://api.dialect.com/api/v1/donate/\`, sur un site externe :

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

L'exemple suivant utilise la correspondance des chemins d'accès avec des caractères génériques pour une règle idempotente pour faire correspondre les requêtes à n'importe quel chemin d'accès (y compris les sous-répertoires) sous /api/actions/ de la racine de votre site à lui-même :

Info

Les règles idempotentes permettent aux clients blink de déterminer plus facilement si un chemin donné prend en charge les requêtes de l'API Action sans avoir à être préfixé par l'URI solana-action: ou à effectuer des tests de réponse supplémentaires.

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

Identité d'Action #

Les points de terminaison d'Action peuvent inclure une Action Identity (Identité d'Action) dans les transactions qui sont retournées dans leur réponse POST que l'utilisateur doit signer. Cela permet aux indexeurs et aux plateformes d'analyse d'attribuer facilement et de manière vérifiable l'activité sur la chaîne à un Action Provider (Fournisseur d'Action) en particulier (c'est-à-dire un service).

L'Identité d'Action est une paire de clés utilisée pour signer un message spécifiquement formaté qui est inclus dans la transaction à l'aide d'une instruction Memo. Ce Identifier Message (Message d'Identification) peut être attribué de manière vérifiable à une Identité d'Action en particulier, et donc attribuer des transactions à un Fournisseur d'Action en particulier.

La paire de clés n'est pas nécessaire pour signer la transaction. Cela permet aux portefeuilles et aux applications d'améliorer la délivrabilité des transactions lorsqu'aucune autre signature ne figure dans la transaction retournée à l'utilisateur (voir Réponse POST - Transaction).

Si le cas d'utilisation d'un Fournisseur d'Action nécessite que ses services backend pré-signent la transaction avant l'utilisateur, il doit utiliser cette paire de clés comme Identité d'Action. Cela permettra d'inclure un compte de moins dans la transaction, réduisant la taille totale de la transaction de 32 octets.

Message d'Identification d'Action #

Le Message d'Identification d'Action est une chaîne UTF-8 séparée par deux points, incluse dans une transaction à l'aide d'une seule instruction SPL Memo.

protocol:identity:reference:signature
  • protocol - La valeur du protocole utilisé (fixé à solana-action selon le Schéma d'URL ci-dessus)
  • identity - La valeur doit être l'adresse de la clé publique encodée en base58 de la paire de clés de l'Identité d'Action
  • reference - La valeur doit être un tableau de 32 octets encodé en base58. Il peut s'agir ou non de clés publiques, sur ou en dehors de la courbe, et correspondre ou non à des comptes sur Solana.
  • signature - signature encodée en base58 créée à partir de la paire de clés de l'Identité d'Action et signant uniquement la valeur reference.

La valeur reference ne doit être utilisée qu'une seule fois et dans une seule transaction. Afin d'associer des transactions à un Fournisseur d'Actions, seule la première utilisation de la valeur reference est considérée comme valide.

Les transactions peuvent avoir plusieurs instructions Mémo. Lors de l'exécution d'un getSignaturesForAddress, le champ memo résultant retournera le message de chaque instruction memo sous la forme d'une chaîne unique, chaque instruction étant séparée par un point-virgule.

Aucune autre donnée ne doit être incluse dans l'instruction Memo du Message d'Identification.

L'identity et la reference doivent être incluses en tant que clés en lecture seule et non signataires dans la transaction sur une instruction qui n'est PAS l'instruction Memo du Message d'Identification.

L'instruction Memo du Message d'Identification doit avoir aucun compte fourni. Si des comptes sont fournis, le programme Memo exige que ces comptes soient des signataires valides. Pour identifier les actions, cela limite la flexibilité et peut dégrader l'expérience utilisateur. C'est pourquoi il est considéré comme un anti-modèle et doit être évité.

Vérification de l'Identité d'Action #

Toute transaction qui inclut le compte identity peut être associée de manière vérifiable au Fournisseur d'Actions grâce à un processus en plusieurs étapes :

  1. Obtenir toutes les transactions pour une identity donnée.
  2. Analyser et vérifier la chaîne mémo de chaque transaction, en s'assurant que la signature est valide pour la reference stockée.
  3. Vérifier que la transaction en question est la première occurrence sur la chaine de la reference :
    • Si cette transaction est la première occurrence, la transaction est considérée comme vérifiée et peut être attribuée en toute sécurité au Fournisseur d'Actions.
    • Si cette transaction n'est PAS la première occurrence, elle est considérée comme invalide et n'est donc pas attribuée au Fournisseur d'Actions.

Comme les validateurs Solana indexent les transactions selon les clés de compte, la méthode RPC getSignaturesForAddress peut être utilisée pour localiser toutes les transactions incluant le compte identity.

La réponse de cette méthode RPC inclut toutes les données Memo dans le champ memo. Si plusieurs instructions Memo ont été utilisées dans la transaction, chaque message memo sera inclus dans le champ memo et devra être analysé en conséquence par le vérificateur afin d'obtenir le Identity Verification Message (Message de Vérification d'Identité).

Ces transactions doivent être initialement considérées comme NON VÉRIFIÉES. Cela est dû au fait que l'identity n'est pas requise pour signer la transaction, ce qui permet à toute transaction d'inclure ce compte en tant que non-signataire. Cela peut ainsi potentiellement gonfler artificiellement le nombre d'attributions et d'utilisations.

Le Message de Vérification d'Identité doit être vérifié pour s'assurer que la signature a été créée par l'identity qui signe la reference. Si la vérification de la signature échoue, la transaction n'est pas valide et doit être attribuée au Fournisseur d'Action.

Si la vérification de la signature réussie, le vérificateur doit s'assurer que cette transaction est la première occurrence sur la chaîne de la reference. Si ce n'est pas le cas, la transaction est considérée comme invalide.