Actions en Blinks

Solana Actions zijn specificatie-conforme API's die transacties op de Solana-blockchain retourneren om te bekijken, te ondertekenen en te verzenden in verschillende contexten, waaronder QR-codes, knoppen + widgets en websites op het internet. Actions maken het voor ontwikkelaars eenvoudig om de mogelijkheden van het Solana-ecosysteem direct in jouw omgeving te integreren, zodat je blockchaintransacties kunt uitvoeren zonder naar een andere app of webpagina te hoeven navigeren.

Blockchain-links – oftewel blinks – maken van elke Solana Action een deelbare, metadata-rijke link. Blinks stellen Action-bewuste clients (browserextensie-wallets, bots) in staat om extra functionaliteit voor de gebruiker weer te geven. Op een website kan een blink direct een transactievoorvertoning in een wallet activeren zonder naar een gedecentraliseerde app te gaan; in Discord kan een bot de blink uitbreiden tot een interactieve reeks knoppen. Dit verplaatst de mogelijkheid om onchain te interageren naar elk weboppervlak dat een URL kan weergeven.

Aan de slag

Om snel aan de slag te gaan met het maken van aangepaste Solana Actions:

npm install @solana/actions
  • installeer de Solana Actions SDK in jouw applicatie
  • bouw een API-eindpunt voor het GET-verzoek dat de metadata over jouw Action retourneert
  • maak een API-eindpunt dat het POST-verzoek accepteert en de ondertekenabare transactie voor de gebruiker retourneert

Bekijk deze videotutorial over hoe je een Solana Action bouwt met behulp van de @solana/actions SDK.

Je kunt ook de broncode voor een Action vinden die een native SOL-overdracht uitvoert, en verschillende andere voorbeeldacties in deze repo.

Bij het implementeren van jouw aangepaste Solana Actions naar productie:

Als je op zoek bent naar inspiratie voor het bouwen van Actions en blinks, bekijk dan de Awesome Blinks-repository voor een aantal creaties van de community en zelfs ideeën voor nieuwe.

Actions

De Solana Actions-specificatie maakt gebruik van een set standaard-API's om ondertekenabare transacties (en uiteindelijk ondertekenabare berichten) rechtstreeks van een applicatie naar een gebruiker te leveren. Ze worden gehost op openbaar toegankelijke URL's en zijn daarom via hun URL toegankelijk voor elke client.

Je kunt Actions zien als een API-eindpunt dat metadata retourneert en iets wat een gebruiker moet ondertekenen (een transactie of een authenticatiebericht) met hun blockchain-wallet.

De Actions API bestaat uit eenvoudige GET- en POST-verzoeken aan de URL-eindpunt van een Action en het verwerken van de antwoorden die voldoen aan de Actions-interface.

  1. het GET-verzoek retourneert metadata die de client leesbare informatie geeft over welke actions beschikbaar zijn op deze URL, en een optionele lijst van gerelateerde actions.
  2. het POST-verzoek retourneert een ondertekenabare transactie of bericht dat de client vervolgens aan de wallet van de gebruiker aanbiedt om te ondertekenen en uit te voeren op de blockchain of in een andere offchain-service.

Uitvoering en levenscyclus van Actions

In de praktijk lijkt het werken met Actions sterk op het werken met een typische REST API:

  • een client doet het initiële GET-verzoek aan een Action URL om metadata op te halen over de beschikbare Actions
  • het eindpunt retourneert een antwoord dat metadata bevat over het eindpunt (zoals de titel en het pictogram van de applicatie) en een overzicht van de beschikbare actions voor dit eindpunt
  • de clientapplicatie (zoals een mobiele wallet, chatbot of website) toont een gebruikersinterface waarmee de gebruiker een van de actions kan uitvoeren
  • nadat de gebruiker een action selecteert (door op een knop te klikken), doet de client een POST-verzoek aan het eindpunt om de transactie te verkrijgen die de gebruiker moet ondertekenen
  • de wallet faciliteert het ondertekenen van de transactie door de gebruiker en stuurt de transactie uiteindelijk naar de blockchain ter bevestiging

Uitvoering en levenscyclus van Solana ActionsUitvoering en levenscyclus van Solana Actions

Bij het ontvangen van transacties van een Actions URL moeten clients de indiening van deze transacties op de blockchain afhandelen en hun toestandslevenscyclus beheren.

Actions ondersteunen ook een bepaalde mate van ongeldigverklaring vóór uitvoering. Het GET- en POST-verzoek kunnen metadata retourneren die aangeeft of de action uitgevoerd kan worden (zoals met het disabled-veld).

Als er bijvoorbeeld een Action-eindpunt is dat stemming op een DAO-governancevoorstel faciliteert waarvan het stemvenster is gesloten, kan het initiële GET-verzoek de foutmelding "Dit voorstel staat niet meer open voor stemming" retourneren en de knoppen "Stem Ja" en "Stem Nee" als "uitgeschakeld" weergeven.

Blinks (blockchain-links) zijn clientapplicaties die Action API's analyseren en gebruikersinterfaces opbouwen voor het interageren met en uitvoeren van Actions.

Clientapplicaties die blinks ondersteunen, detecteren eenvoudig Action-compatibele URL's, verwerken deze en stellen gebruikers in staat ermee te interageren via gestandaardiseerde gebruikersinterfaces.

Elke clientapplicatie die een Actions API volledig analyseert om een complete interface daarvoor te bouwen, is een blink. Daarom zijn niet alle clients die Actions API's gebruiken, blinks.

Een blink URL beschrijft een clientapplicatie waarmee een gebruiker de volledige levenscyclus van het uitvoeren van een Action kan voltooien, inclusief ondertekening met hun wallet.

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

Om van een clientapplicatie een blink te maken:

  • De blink URL moet een queryparameter action bevatten waarvan de waarde een URL-gecodeerde Action URL is. Deze waarde moet URL-gecodeerd zijn om conflicten met andere protocolparameters te voorkomen.

  • De clientapplicatie moet de queryparameter action URL-decoderen en de opgegeven Action API-link analyseren (zie Action URL-schema).

  • De client moet een rijke gebruikersinterface weergeven waarmee de gebruiker de volledige levenscyclus van het uitvoeren van een Action kan voltooien, inclusief ondertekening met hun wallet.

Niet alle blink-clientapplicaties (bijv. websites of dApps) ondersteunen alle Actions. Applicatieontwikkelaars kunnen kiezen welke Actions ze willen ondersteunen binnen hun blink-interfaces.

Het volgende voorbeeld toont een geldige blink URL met een action-waarde van solana-action:https://actions.alice.com/donate die URL-gecodeerd is:

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

Blinks kunnen op ten minste 3 manieren aan Actions worden gekoppeld:

  1. Een expliciete Action URL delen: solana-action:https://actions.alice.com/donate

    In dit geval kunnen alleen ondersteunde clients de blink weergeven. Er is geen fallback-linkvoorvertoning of site die buiten de niet-ondersteunende client bezocht kan worden.

  2. Een link delen naar een website die via een actions.json-bestand op de domeinroot van de website aan een Actions API is gekoppeld.

    Zo wijst https://alice.com/actions.json bijvoorbeeld https://alice.com/donate, een website-URL waar gebruikers aan Alice kunnen doneren, toe aan de API URL https://actions.alice.com/donate, waar Actions voor doneren aan Alice worden gehost.

  3. Een Action URL insluiten in een "tussenliggende" site-URL die begrijpt hoe Actions verwerkt moeten worden.

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

Clients die blinks ondersteunen, moeten elk van de bovenstaande formaten kunnen verwerken en correct een interface weergeven om het uitvoeren van de action direct in de client te faciliteren.

Voor clients die geen blinks ondersteunen, moet er een onderliggende website zijn (waardoor de browser de universele fallback wordt).

Als een gebruiker ergens op een client tikt dat geen actieknop of tekstinvoerveld is, moeten ze naar de onderliggende site worden geleid.

Hoewel Solana Actions en blinks een rechtenvrij protocol/specificatie zijn, moeten clientapplicaties en wallets uiteindelijk faciliteren dat gebruikers de transactie ondertekenen.

Gebruik de Blinks Inspector-tool om jouw blinks en actions direct in jouw browser te inspecteren, debuggen en testen. Je kunt de GET- en POST-antwoordpayloads, antwoordheaders bekijken en alle invoer voor elk van jouw gekoppelde Actions testen.

Elke clientapplicatie of wallet kan andere vereisten hebben ten aanzien van welke Action-eindpunten automatisch worden uitgevouwen en direct aan hun gebruikers worden weergegeven op sociale mediaplatforms.

Sommige clients kunnen bijvoorbeeld werken met een "allowlist"-aanpak waarbij verificatie vereist is voordat hun client een Action voor gebruikers uitvouwt, zoals het Actions Registry van Dialect (hieronder beschreven).

Alle blinks worden nog steeds weergegeven en maken ondertekening mogelijk op de dial.to blinks-tussenliggende site van Dialect, met hun registerstatus weergegeven in de blink.

Het Actions Registry van Dialect

Als publiek goed voor het Solana-ecosysteem onderhoudt Dialect een openbaar register — samen met de hulp van Solana Foundation en andere communityleden — van blockchain-links die afkomstig zijn van vooraf geverifieerde bronnen. Vanaf de lancering zullen alleen Actions die zijn geregistreerd in het Dialect-register worden uitgevouwen in de Twitter-feed wanneer ze worden geplaatst.

Clientapplicaties en wallets kunnen vrijelijk kiezen om dit openbare register of een andere oplossing te gebruiken om de veiligheid van gebruikers te waarborgen. Als niet geverifieerd via het Dialect-register, wordt de blockchain-link niet verwerkt door de blink-client en wordt deze weergegeven als een gewone URL.

Ontwikkelaars kunnen zich hier aanmelden voor verificatie door Dialect: dial.to/register

Specificatie

De Solana Actions-specificatie bestaat uit belangrijke secties die deel uitmaken van een verzoek/antwoord-interactiestroom:

Elk van deze verzoeken wordt gedaan door de Action-client (bijv. wallet-app, browserextensie, dApp, website, enz.) om specifieke metadata te verzamelen voor uitgebreide gebruikersinterfaces en om gebruikersinvoer voor de Actions API te faciliteren.

Elk van de antwoorden wordt samengesteld door een applicatie (bijv. website, server-backend, enz.) en teruggestuurd naar de Action-client. Uiteindelijk wordt hiermee een ondertekенbare transactie of bericht aangeboden waarmee een wallet de gebruiker vraagt om goed te keuren, te ondertekenen en naar de blockchain te verzenden.

De typen en interfaces die in dit readme-bestand zijn gedeclareerd, zijn vaak de vereenvoudigde versie van de typen om de leesbaarheid te verbeteren.

Voor betere type-veiligheid en een verbeterde ontwikkelaarservaring bevat het pakket @solana/actions-spec meer complexe typedefinities. U kunt de broncode hier vinden.

URL-schema

Een Solana Action-URL beschrijft een interactief verzoek voor een ondertekенbare Solana-transactie of -bericht met behulp van het solana-action-protocol.

Het verzoek is interactief omdat de parameters in de URL door een client worden gebruikt om een reeks gestandaardiseerde HTTP-verzoeken te doen om een ondertekенbare transactie of bericht samen te stellen voor de gebruiker om te ondertekenen met zijn wallet.

solana-action:<link>
  • Een enkel link-veld is vereist als padnaam. De waarde moet een voorwaardelijk URL-gecodeerde absolute HTTPS-URL zijn.

  • Als de URL queryparameters bevat, moet deze URL-gecodeerd zijn. Het URL-coderen van de waarde voorkomt conflicten met eventuele Actions-protocolparameters, die mogelijk worden toegevoegd via de protocolspecificatie.

  • Als de URL geen queryparameters bevat, hoeft deze niet URL-gecodeerd te zijn. Dit levert een kortere URL en een minder dichte QR-code op.

In beide gevallen moeten clients de waarde URL-decoderen. Dit heeft geen effect als de waarde niet URL-gecodeerd is. Als de gedecodeerde waarde geen absolute HTTPS-URL is, moet de wallet deze afwijzen als ongeldig.

OPTIONS-antwoord

Om Cross-Origin Resource Sharing (CORS) binnen Action-clients (inclusief blinks) mogelijk te maken, moeten alle Action-eindpunten reageren op HTTP-verzoeken voor de OPTIONS-methode met geldige headers die clients in staat stellen CORS-controles te doorstaan voor alle volgende verzoeken vanaf hetzelfde brondomein.

Een Action-client kan "preflight"-verzoeken sturen naar het Action-URL-eindpunt om te controleren of het volgende GET-verzoek naar de Action-URL alle CORS-controles doorstaat. Deze CORS-preflight-controles worden uitgevoerd met de HTTP-methode OPTIONS en moeten reageren met alle vereiste HTTP-headers die Action-clients (zoals blinks) in staat stellen alle volgende verzoeken correct te doen vanaf hun brondomein.

De minimaal vereiste HTTP-headers zijn:

  • Access-Control-Allow-Origin met een waarde van *
    • dit zorgt ervoor dat alle Action-clients veilig CORS-controles kunnen doorstaan om alle vereiste verzoeken te kunnen doen
  • Access-Control-Allow-Methods met een waarde van GET,POST,PUT,OPTIONS
    • zorgt ervoor dat alle vereiste HTTP-verzoekmethoden worden ondersteund voor Actions
  • Access-Control-Allow-Headers met een minimumwaarde van Content-Type, Authorization, Content-Encoding, Accept-Encoding

Voor de eenvoud kunnen ontwikkelaars overwegen hetzelfde antwoord en dezelfde headers terug te sturen op OPTIONS-verzoeken als hun GET-antwoord.

Cross-Origin-headers voor actions.json

Het bestandsantwoord actions.json moet ook geldige Cross-Origin-headers retourneren voor GET- en OPTIONS-verzoeken, met name de headerwaarde Access-Control-Allow-Origin van *.

Zie actions.json hieronder voor meer details.

GET-verzoek

De Action-client (bijv. wallet, browserextensie, enz.) moet een HTTP GET JSON-verzoek sturen naar het URL-eindpunt van de Action.

  • Het verzoek mag de wallet of de gebruiker niet identificeren.
  • De client moet het verzoek doen met een Accept-Encoding-header.
  • De client moet het domein van de URL weergeven terwijl het verzoek wordt gedaan.

GET-antwoord

Het URL-eindpunt van de Action (bijv. applicatie of server-backend) moet reageren met een HTTP OK JSON-antwoord (met een geldige payload in de body) of een passende HTTP-fout.

Foutantwoorden (d.w.z. HTTP 4xx- en 5xx-statuscodes) moeten een JSON-antwoordbody retourneren volgens ActionError om een nuttige foutmelding aan gebruikers te tonen. Zie Action-fouten.

GET-antwoordbody

Een GET-antwoord met een HTTP OK JSON-antwoord moet een body-payload bevatten die de interfacespecificatie volgt:

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 - Het type actie dat aan de gebruiker wordt gegeven. Standaard ingesteld op action. De initiële ActionGetResponse moet een type van action hebben.

    • action - Standaardactie waarmee de gebruiker kan communiceren met elk van de LinkedActions
    • completed - Wordt gebruikt om de "voltooide" status binnen actieketening te declareren.
  • icon - De waarde moet een absolute HTTP- of HTTPS-URL zijn van een icoонafbeelding. Het bestand moet een SVG-, PNG- of WebP-afbeelding zijn, anders moet de client/wallet het afwijzen als ongeldig.

  • title - De waarde moet een UTF-8-tekenreeks zijn die de bron van het actieverzoek vertegenwoordigt. Dit kan bijvoorbeeld de naam zijn van een merk, winkel, applicatie of persoon die het verzoek doet.

  • description - De waarde moet een UTF-8-tekenreeks zijn die informatie over de actie verstrekt. De beschrijving moet aan de gebruiker worden weergegeven.

  • label - De waarde moet een UTF-8-tekenreeks zijn die wordt weergegeven op een knop waarop de gebruiker kan klikken. Alle labels mogen niet meer dan 5 woorden bevatten en moeten beginnen met een werkwoord om de actie die de gebruiker moet ondernemen te verduidelijken. Bijvoorbeeld: "Mint NFT", "Stem ja" of "Stake 1 SOL".

  • disabled - De waarde moet een boolean zijn die de uitgeschakelde status van de weergegeven knop (die de label-tekenreeks toont) vertegenwoordigt. Als er geen waarde is opgegeven, moet disabled standaard false zijn (d.w.z. standaard ingeschakeld). Als het actie-eindpunt bijvoorbeeld voor een bestuursstemming is die is gesloten, stel dan disabled=true in en het label kan "Stemming gesloten" zijn.

  • error - Een optionele foutindicatie voor niet-fatale fouten. Indien aanwezig, moet de client deze aan de gebruiker tonen. Indien ingesteld, mag dit de client niet verhinderen de actie te interpreteren of aan de gebruiker te tonen (zie Action-fouten). De fout kan bijvoorbeeld samen met disabled worden gebruikt om een reden weer te geven zoals zakelijke beperkingen, autorisatie, de status of een fout van een externe resource.

  • links.actions - Een optionele array van gerelateerde acties voor het eindpunt. Gebruikers moeten een UI te zien krijgen voor elk van de vermelde acties en worden verwacht er slechts één uit te voeren. Een eindpunt voor een bestuursstemactie kan bijvoorbeeld drie opties aan de gebruiker retourneren: "Stem ja", "Stem nee" en "Onthouding van stemming".

    • Als er geen links.actions is opgegeven, moet de client één knop weergeven met de root-label-tekenreeks en het POST-verzoek doen naar hetzelfde actie-URL-eindpunt als het initiële GET-verzoek.

    • Als er links.actions zijn opgegeven, moet de client alleen knoppen en invoervelden weergeven op basis van de items in het veld links.actions. De client mag geen knop weergeven voor de inhoud van het root-label.

LinkedAction
export interface LinkedAction {
/** Type of action to be performed by user */
type: LinkedActionType;
/** 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>;
}

De ActionParameter maakt het mogelijk te declareren welke invoer de Actions API van de gebruiker opvraagt:

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

Het pattern moet een tekenreeks zijn die equivalent is aan een geldig regulier expressie. Dit reguliere-expressiepatroon moet door blink-clients worden gebruikt om gebruikersinvoer te valideren voordat het POST-verzoek wordt gedaan. Als het pattern geen geldige reguliere expressie is, moet het door clients worden genegeerd.

De patternDescription is een voor mensen leesbare beschrijving van de verwachte invoerverzoeken van de gebruiker. Als pattern is opgegeven, is het verplicht om ook patternDescription op te geven.

De waarden min en max stellen de invoer in staat een onder- en/of bovengrens in te stellen voor de invoer die van de gebruiker wordt gevraagd (d.w.z. min/max-getal en/of min/max-tekenlength), en moeten worden gebruikt voor validatie aan de clientzijde. Voor invoertypes van date of datetime-local moeten deze waarden datumtekenreeksen zijn. Voor andere op tekenreeksen gebaseerde invoertypes moeten de waarden getallen zijn die de min/max-tekenlengte vertegenwoordigen.

Als de gebruikersinvoerwaarde niet geldig wordt geacht volgens het pattern, moet de gebruiker een foutmelding aan de clientzijde ontvangen die aangeeft dat het invoerveld ongeldig is, en moet de patternDescription-tekenreeks worden weergegeven.

Het veld type stelt de Actions API in staat meer specifieke gebruikersinvoervelden te declareren, wat betere validatie aan de clientzijde biedt en de gebruikerservaring verbetert. In veel gevallen zal dit type lijken op het standaard HTML-invoerelement.

De ActionParameterType kan worden vereenvoudigd tot het volgende 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";

Elk van de type-waarden moet normaal gesproken resulteren in een gebruikersinvoerveld dat lijkt op een standaard HTML-input-element van het bijbehorende type (d.w.z. <input type="email" />) om betere validatie aan de clientzijde en een betere gebruikerservaring te bieden:

  • text - equivalent van het HTML "text"-invoerelement
  • email - equivalent van het HTML "email"-invoerelement
  • url - equivalent van het HTML "url"-invoerelement
  • number - equivalent van het HTML "number"-invoerelement
  • date - equivalent van het HTML "date"-invoerelement
  • datetime-local - equivalent van het HTML "datetime-local"-invoerelement
  • checkbox - equivalent van een groepering van standaard HTML "checkbox"-invoerelementen. De Actions API moet options retourneren zoals hieronder beschreven. De gebruiker moet meerdere van de aangeboden selectievakopties kunnen selecteren.
  • radio - equivalent van een groepering van standaard HTML "radio"-invoerelementen. De Actions API moet options retourneren zoals hieronder beschreven. De gebruiker moet slechts één van de aangeboden radio-opties kunnen selecteren.
  • Andere HTML-invoertypeequivalenten die hierboven niet zijn opgegeven (hidden, button, submit, file, enz.) worden momenteel niet ondersteund.

Naast de elementen die lijken op de bovenstaande HTML-invoertypen, worden ook de volgende gebruikersinvoerelementen ondersteund:

  • textarea - equivalent van het HTML textarea-element. Hiermee kan de gebruiker invoer op meerdere regels opgeven.
  • select - equivalent van het HTML select-element, waarmee de gebruiker een "dropdown"-stijlveld kan gebruiken. De Action API moet options retourneren zoals hieronder beschreven.

Wanneer type is ingesteld op select, checkbox of radio, moet de Action API een array van options bevatten, waarbij elke optie minimaal een label en een value biedt. Elke optie kan ook een selected-waarde hebben om de blink-client te informeren welke optie standaard voor de gebruiker geselecteerd moet worden (zie checkbox en radio voor de verschillen).

Deze ActionParameterSelectable kan worden vereenvoudigd tot de volgende typedefinitie:

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

Als er geen type is ingesteld of een onbekende/niet-ondersteunde waarde is ingesteld, moeten blink-clients standaard text gebruiken en een eenvoudig tekstinvoerveld weergeven.

De Action API blijft verantwoordelijk voor het valideren en opschonen van alle gegevens uit de gebruikersinvoerparameters, waarbij eventuele "verplichte" gebruikersinvoer naar behoefte wordt afgedwongen.

Voor andere platforms dan HTML/webgebaseerde platforms (zoals native mobiel) moet het equivalente native gebruikersinvoercomponent worden gebruikt om dezelfde ervaring en clientsidevalidatie te bereiken als de hierboven beschreven HTML/web-invoertypen.

Voorbeeld GET-respons

Het volgende voorbeeldantwoord biedt één enkele "root"-actie die naar verwachting aan de gebruiker wordt gepresenteerd als één knop met het label "Claim Access Token":

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

Het volgende voorbeeldantwoord biedt 3 gerelateerde actielinks waarmee de gebruiker op één van de 3 knoppen kan klikken om zijn stem uit te brengen voor een DAO-voorstel:

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

Voorbeeld GET-respons met parameters

Het volgende voorbeeldantwoord laat zien hoe tekstinvoer van de gebruiker kan worden ontvangen (via parameters) en opgenomen in het uiteindelijke POST-verzoekeindpunt (via het veld href in een LinkedAction):

Het volgende voorbeeldantwoord biedt de gebruiker 3 gekoppelde acties om SOL te staken: een knop met het label "Stake 1 SOL", een andere knop met het label "Stake 5 SOL", en een tekstinvoerveld waarmee de gebruiker een specifieke "amount"-waarde kan invoeren die naar de Action API wordt verzonden:

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

Het volgende voorbeeldantwoord biedt één invoerveld waarmee de gebruiker een amount kan invoeren die wordt meegestuurd met het POST-verzoek (als queryparameter of als subpad):

{
"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-verzoek

De client moet een HTTP POST JSON-verzoek sturen naar de actie-URL met de volgende bodyinhoud:

{
"account": "<account>"
}
  • account - De waarde moet de base58-gecodeerde publieke sleutel zijn van een account dat de transactie mag ondertekenen.

De client moet het verzoek uitvoeren met een Accept-Encoding header en de applicatie mag reageren met een Content-Encoding header voor HTTP-compressie.

De client moet het domein van de actie-URL weergeven terwijl het verzoek wordt uitgevoerd. Als er een GET-verzoek is gedaan, moet de client ook de title weergeven en de icon-afbeelding renderen uit die GET-respons.

POST-respons

Het POST-eindpunt van de actie moet reageren met een HTTP OK JSON-respons (met een geldige payload in de body) of een passende HTTP-fout.

Foutreacties (d.w.z. HTTP 4xx- en 5xx-statuscodes) moeten een JSON-responsebody retourneren die ActionError volgt om een nuttige foutmelding aan gebruikers te tonen. Zie Action Errors.

POST-responsbody

Een POST-respons met een HTTP OK JSON-respons moet een bodyinhoud bevatten van:

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 - De waarde moet een base64-gecodeerde geserialiseerde transactie zijn. De client moet de transactie base64-decoderen en deserialiseren.

  • message - De waarde moet een UTF-8-tekenreeks zijn die de aard van de transactie in de respons beschrijft. De client moet deze waarde aan de gebruiker tonen. Dit kan bijvoorbeeld de naam zijn van een item dat wordt gekocht, een korting op een aankoop of een bedankbericht.

  • links.next - Een optionele waarde om meerdere acties achter elkaar te "koppelen". Nadat de bijgevoegde transaction onchain is bevestigd, kan de client de volgende actie ophalen en weergeven. Zie Action Chaining voor meer details.

  • De client en de applicatie moeten aanvullende velden in de verzoekbody en responsebody toestaan, die mogelijk worden toegevoegd door toekomstige specificatie-updates.

De applicatie kan reageren met een gedeeltelijk of volledig ondertekende transactie. De client en wallet moeten de transactie als niet-vertrouwd valideren.

POST-respons - Transactie

Als de transactie signatures leeg zijn of de transactie NIET gedeeltelijk is ondertekend:

  • De client moet de feePayer in de transactie negeren en de feePayer instellen op het account in het verzoek.
  • De client moet de recentBlockhash in de transactie negeren en de recentBlockhash instellen op de meest recente blockhash.
  • De client moet de transactie serialiseren en deserialiseren voordat deze wordt ondertekend. Dit zorgt voor consistente volgorde van de accountsleutels, als tijdelijke oplossing voor dit probleem.

Als de transactie gedeeltelijk is ondertekend:

  • De client mag de feePayer of recentBlockhash NIET wijzigen, omdat dit bestaande handtekeningen ongeldig zou maken.
  • De client moet bestaande handtekeningen verifiëren, en als een of meer ongeldig zijn, moet de client de transactie afwijzen als ongeldig gevormd.

De client mag de transactie alleen ondertekenen met het account in het verzoek, en mag dat alleen doen als een handtekening voor het account in het verzoek wordt verwacht.

Als een andere handtekening dan die voor het account in het verzoek wordt verwacht, moet de client de transactie afwijzen als kwaadaardig.

Actiefouten

Actions API's moeten fouten retourneren via ActionError om nuttige foutmeldingen aan de gebruiker te presenteren. Afhankelijk van de context kan deze fout fataal of niet-fataal zijn.

ActionError
export interface ActionError {
/** simple error message to be displayed to the user */
message: string;
}

Wanneer een Actions API reageert met een HTTP-foutstatuscode (d.w.z. 4xx en 5xx), moet de responsebody een JSON-payload zijn die ActionError volgt. De fout wordt als fataal beschouwd en het bijgevoegde message moet aan de gebruiker worden getoond.

Voor API-reacties die het optionele error-attribuut ondersteunen (zoals ActionGetResponse), wordt de fout als niet-fataal beschouwd en moet het bijgevoegde message aan de gebruiker worden getoond.

Actiekoppeling

Solana Actions kunnen achter elkaar worden "gekoppeld". Nadat de transactie van een actie onchain is bevestigd, kan de volgende actie worden opgehaald en aan de gebruiker worden gepresenteerd.

Actiekoppeling stelt ontwikkelaars in staat om complexere en dynamischere ervaringen binnen blinks te bouwen, waaronder:

  • het aanbieden van meerdere transacties (en uiteindelijk berichtondertekening) aan een gebruiker
  • aangepaste actiemetadata op basis van het walletadres van de gebruiker
  • de blink-metadata vernieuwen na een succesvolle transactie
  • een API-callback ontvangen met de transactiehandtekening voor aanvullende validatie en logica op de Action API-server
  • aangepaste "succes"-berichten door de weergegeven metadata bij te werken (bijv. een nieuwe afbeelding en beschrijving)

Om meerdere acties aan elkaar te koppelen, neem in elke ActionPostResponse een links.next op van het type:

  • PostNextActionLink - POST-verzoeklink met een callback-url van dezelfde oorsprong om de signature en het account van de gebruiker in de body te ontvangen. Deze callback-url moet reageren met een NextAction.
  • InlineNextActionLink - Inline metadata voor de volgende actie die direct na bevestiging van de transactie aan de gebruiker wordt gepresenteerd. Er wordt geen callback uitgevoerd.
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

Nadat de transaction uit de ActionPostResponse door de gebruiker is ondertekend en onchain is bevestigd, moet de blink-client:

  • het callbackverzoek uitvoeren om de NextAction op te halen en weer te geven, of
  • als een NextAction al beschikbaar is via links.next, moet de blink-client de weergegeven metadata bijwerken en geen callbackverzoek doen

Als de callback-url niet dezelfde oorsprong heeft als het eerste POST-verzoek, mag er geen callbackverzoek worden gedaan. Blink-clients moeten een foutmelding weergeven om de gebruiker te informeren.

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

Op basis van het type moet de volgende actie via blink-clients op een van de volgende manieren aan de gebruiker worden gepresenteerd:

  • action - (standaard) Een standaardactie waarmee de gebruiker de bijgevoegde actiemetadata kan bekijken, kan communiceren met de opgegeven LinkedActions, en verdere acties kan koppelen.

  • completed - De eindstatus van een actieketen die de blink-UI kan bijwerken met de bijgevoegde actiemetadata, maar de gebruiker niet toestaat verdere acties uit te voeren.

Als links.next niet is opgegeven, moeten blink-clients aannemen dat de huidige actie de laatste actie in de keten is en hun "voltooid"-UI-status weergeven nadat de transactie is bevestigd.

actions.json

Het doel van het actions.json-bestand stelt een applicatie in staat clients te instrueren welke website-URL's Solana Actions ondersteunen en biedt een mapping die kan worden gebruikt voor het uitvoeren van GET-verzoeken naar een Actions API-server.

Cross-Origin headers zijn vereist

Het antwoord van het actions.json-bestand moet ook geldige Cross-Origin headers retourneren voor GET- en OPTIONS-verzoeken, met name de Access-Control-Allow-Origin-headerwaarde van *.

Zie OPTIONS-respons hierboven voor meer details.

Het actions.json-bestand moet worden opgeslagen en universeel toegankelijk zijn in de hoofdmap van het domein.

Als uw webapplicatie bijvoorbeeld is geïmplementeerd op my-site.com, moet het actions.json-bestand toegankelijk zijn via https://my-site.com/actions.json. Dit bestand moet ook Cross-Origin toegankelijk zijn via elke browser door een Access-Control-Allow-Origin-headerwaarde van * in te stellen.

Regels

Het veld rules stelt de applicatie in staat een set relatieve routepaden van een website te koppelen aan een set andere paden.

Type: Array van 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 - Een patroon dat overeenkomt met elk inkomend padnaam.

  • apiPath - Een bestemmingslocatie gedefinieerd als een absoluut padnaam of externe URL.

Regels - pathPattern

Een patroon dat overeenkomt met elk inkomend padnaam. Het kan een absoluut of relatief pad zijn en ondersteunt de volgende formaten:

  • Exacte Overeenkomst: Komt overeen met het exacte URL-pad.

    • Voorbeeld: /exact-path
    • Voorbeeld: https://website.com/exact-path
  • Jokerteken Overeenkomst: Gebruikt jokertekens om een willekeurige reeks tekens in het URL-pad te matchen. Dit kan enkelvoudige segmenten (met *) of meerdere segmenten (met **) matchen. (zie Padmatching hieronder).

    • Voorbeeld: /trade/* komt overeen met /trade/123 en /trade/abc, waarbij alleen het eerste segment na /trade/ wordt vastgelegd.
    • Voorbeeld: /category/*/item/** komt overeen met /category/123/item/456 en /category/abc/item/def.
    • Voorbeeld: /api/actions/trade/*/confirm komt overeen met /api/actions/trade/123/confirm.

Regels - apiPath

Het doelpad voor het actieverzoek. Het kan worden gedefinieerd als een absoluut padnaam of een externe URL.

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

Regels - Queryparameters

Queryparameters van de oorspronkelijke URL worden altijd bewaard en toegevoegd aan de gekoppelde URL.

Regels - Padmatching

De volgende tabel beschrijft de syntaxis voor padmatchingpatronen:

OperatorKomt overeen met
*Een enkel padsegment, zonder de omringende scheidingstekens /.
**Komt overeen met nul of meer tekens, inclusief scheidingstekens / tussen meerdere padsegmenten. Als andere operators zijn opgenomen, moet de **-operator de laatste operator zijn.
?Niet-ondersteund patroon.

Regelvoorbeelden

Het volgende voorbeeld toont een exacte-overeenkomstregel om verzoeken naar /buy vanaf de hoofdmap van uw site toe te wijzen aan het exacte pad /api/buy relatief aan de hoofdmap van uw site:

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

Het volgende voorbeeld gebruikt jokerteken-padmatching om verzoeken naar elk pad (exclusief submappen) onder /actions/ vanaf de hoofdmap van uw site toe te wijzen aan een corresponderend pad onder /api/actions/ relatief aan de hoofdmap van uw site:

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

Het volgende voorbeeld gebruikt jokerteken-padmatching om verzoeken naar elk pad (exclusief submappen) onder /donate/ vanaf de hoofdmap van uw site toe te wijzen aan het corresponderende absolute pad https://api.dialect.com/api/v1/donate/ op een externe site:

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

Het volgende voorbeeld gebruikt jokerteken-padmatching voor een idempotente regel om verzoeken naar elk pad (inclusief submappen) onder /api/actions/ vanaf de hoofdmap van uw site naar zichzelf toe te wijzen:

Idempotente regels stellen blink-clients in staat gemakkelijker te bepalen of een gegeven pad Action API-verzoeken ondersteunt, zonder vooraf te hoeven worden voorzien van het solana-action: URI of aanvullende responstest uit te voeren.

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

Actie-identiteit

Actie-eindpunten kunnen een Actie-identiteit opnemen in de transacties die worden geretourneerd in hun POST-respons voor ondertekening door de gebruiker. Dit maakt het voor indexeerders en analyseplatformen eenvoudig en verifieerbaar mogelijk om onchain-activiteit toe te schrijven aan een specifieke Actieaanbieder (d.w.z. dienst) op een verifieerbare manier.

De Actie-identiteit is een keypair dat wordt gebruikt om een speciaal opgemaakt bericht te ondertekenen dat via een Memo-instructie in de transactie wordt opgenomen. Dit Identificatiebericht kan verifieerbaar worden toegeschreven aan een specifieke Actie-identiteit, en daarmee transacties aan een specifieke Actieaanbieder koppelen.

Het keypair hoeft de transactie zelf niet te ondertekenen. Dit stelt wallets en applicaties in staat de bezorging van transacties te verbeteren wanneer er geen andere handtekeningen op de aan de gebruiker geretourneerde transactie staan (zie POST-responstransactie).

Als de gebruikssituatie van een Actieaanbieder vereist dat hun backend-diensten de transactie vooraf ondertekenen vóór de gebruiker, dienen zij dit keypair te gebruiken als hun Actie-identiteit. Hierdoor hoeft er één account minder te worden opgenomen in de transactie, waardoor de totale transactiegrootte met 32 bytes wordt verkleind.

Actie-identificatiebericht

Het Actie-identificatiebericht is een met dubbele punten gescheiden UTF-8-tekenreeks die via een enkel SPL Memo-instructie in een transactie wordt opgenomen.

protocol:identity:reference:signature
  • protocol - De waarde van het gebruikte protocol (ingesteld op solana-action conform het URL-schema hierboven)
  • identity - De waarde moet het base58-gecodeerde openbare-sleuteladres zijn van het Actie-identiteit keypair
  • reference - De waarde moet een base58-gecodeerde 32-byte array zijn. Dit kunnen al dan niet publieke sleutels zijn, op of buiten de curve, en kunnen al dan niet overeenkomen met accounts op Solana.
  • signature - base58-gecodeerde handtekening aangemaakt door het Actie-identiteit keypair dat alleen de reference-waarde ondertekent.

De reference-waarde mag slechts eenmaal en in één enkele transactie worden gebruikt. Voor het doel van het koppelen van transacties aan een Actieaanbieder wordt alleen het eerste gebruik van de reference-waarde als geldig beschouwd.

Transacties kunnen meerdere Memo-instructies bevatten. Bij het uitvoeren van getSignaturesForAddress zal het memo-veld in de resultaten het bericht van elke Memo-instructie retourneren als één tekenreeks, waarbij elke instructie wordt gescheiden door een puntkomma.

Er mogen geen andere gegevens worden opgenomen in de Memo-instructie van het Identificatiebericht.

De identity en de reference dienen te worden opgenomen als alleen-lezen, niet-ondertekenende sleutels in de transactie op een instructie die NIET de Memo-instructie van het Identificatiebericht is.

De Memo-instructie van het Identificatiebericht moet nul accounts bevatten. Als er accounts worden opgegeven, vereist het Memo-programma dat deze accounts geldige ondertekenaars zijn. Voor de doeleinden van het identificeren van acties beperkt dit de flexibiliteit en kan dit de gebruikerservaring verslechteren. Daarom wordt dit beschouwd als een anti-patroon en must worden vermeden.

Verificatie van Actie-identiteit

Elke transactie die het identity-account bevat, kan verifieerbaar worden gekoppeld aan de Actieaanbieder via een meerstapsproces:

  1. Haal alle transacties op voor een gegeven identity.
  2. Parseer en verifieer de memo-tekenreeks van elke transactie, en zorg dat de signature geldig is voor de opgeslagen reference.
  3. Verifieer dat de specifieke transactie de eerste onchain-aanwezigheid is van de reference onchain:
    • Als deze transactie de eerste aanwezigheid is, wordt de transactie als geverifieerd beschouwd en kan deze veilig worden toegeschreven aan de Actieaanbieder.
    • Als deze transactie NIET de eerste aanwezigheid is, wordt deze als ongeldig beschouwd en daher niet toegeschreven aan de Actieaanbieder.

Omdat Solana validators transacties indexeren op basis van accountsleutels, kan de getSignaturesForAddress RPC-methode worden gebruikt om alle transacties met het identity-account te vinden.

De respons van deze RPC-methode bevat alle Memo-gegevens in het memo-veld. Als meer dan één Memo-instructie is gebruikt in de transactie, wordt elk memo-bericht opgenomen in dit memo-veld en moet het door de verificateur dienovereenkomstig worden geparseerd om het Identiteitsverificatiebericht te verkrijgen.

Deze transacties dienen aanvankelijk als NIET-GEVERIFIEERD te worden beschouwd. Dit komt doordat de identity niet verplicht is de transactie te ondertekenen, waardoor elke transactie dit account als niet-ondertekenaar kan opnemen. Dit kan de attributie- en gebruikstellingen kunstmatig verhogen.

Het Identiteitsverificatiebericht moet worden gecontroleerd om te bevestigen dat de signature is aangemaakt door de identity die de reference ondertekent. Als deze handtekeningverificatie mislukt, is de transactie ongeldig en mag deze niet worden toegeschreven aan de Actieaanbieder.

Als de handtekeningverificatie succesvol is, dient de verificateur te controleren of deze transactie de eerste onchain-aanwezigheid van de reference is. Als dat niet het geval is, wordt de transactie als ongeldig beschouwd.

Is this page helpful?

© 2026 Solana Foundation. Alle rechten voorbehouden.