Actions und Blinks
Solana Actions sind spezifikationskonforme APIs, die Transaktionen auf der Solana Blockchain zurückgeben. Diese Transaktionen können in verschiedenen Kontexten angezeigt, signiert und mit QR-Codes, Buttons, Widgets und Webseiten über das Internet versendet werden. Actions vereinfachen es Entwicklern, die verschiedenen Dinge, die man im Solana-Ökosystem tun kann, direkt in ihre eigene Umgebung zu integrieren. Dies ermöglicht es, Blockchain-Transaktionen durchzuführen, ohne eine andere App oder Webseite aufrufen zu müssen.
Blockchain Links – oder Blinks – verwandeln jede Solana Action in einen teilbaren, metadatenreichen Link. Blinks ermöglichen es Clients, die ‚Actions‘ verstehen (wie Browser-Erweiterungen für Wallets und Bots), zusätzliche Funktionen für den Benutzer anzuzeigen. Ein Blink würde zum Beispiel auf einer Website direkt die Vorschau einer Transaktion in einer Wallet anzeigen, ohne dass der Benutzer zu einer dezentralisierten App wechseln muss. In Discord könnte ein Bot einen Blink um ein Set aus interaktiven Buttons erweitern. Auf diese Weise wird die Möglichkeit der On-Chain-Interaktion auf jede Web-Oberfläche ausgedehnt, die eine URL anzeigen kann.
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
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:
- ensure your application has a valid actions.json file at the root of your domain
- ensure your application responds with the
required Cross-Origin headers on all Action endpoints,
including the
actions.json
file - test and debug your blinks/actions using the Blinks Inspector
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 #
Die Solana Actions-Spezifikation verwendet eine Reihe von Standard-APIs, um signierbare Transaktionen (und letztendlich signierbare Nachrichten) direkt von einer Anwendung an den Benutzer zu übermitteln. Sie sind auf öffentlich zugänglichen URLs gehostet, sodass jeder Client über deren URL interagieren kann.
Du kannst Actions als einen API-Endpunkt betrachten, der Metadaten und Inhalte zurückgibt, die der Benutzer mit seinem Blockchain-Wallet signieren soll (Transaktionen oder Authentifizierungsnachrichten).
Die Actions-API besteht aus einfachen GET
und POST
Anfragen an den
URL-Endpunkt von Actions und der Verarbeitung von Antworten, die dem
Actions-Interface entsprechen.
- Die
GET
-Anfrage liefert Metadaten, die dem Client menschenlesbare Informationen darüber bereitstellen, welche Actions unter dieser URL verfügbar sind, sowie eine optionale Liste der zugehörigen Actions. - the POST request returns a signable transaction or message that the client then prompts the user's wallet to sign and execute on the blockchain or in another offchain service.
Ausführung und Lebenszyklus von Actions #
In der Praxis ähnelt die Interaktion mit Actions stark der Interaktion mit einer typischen REST-API:
- Ein Client sendet eine initiale
GET
-Anfrage an eine Actions-URL, um Metadaten über die verfügbaren Actions zu erhalten - Der Endpunkt sendet eine Antwort zurück, die Metadaten über den Endpunkt (z.B. den Titel der Anwendung und das Icon) sowie eine Liste der verfügbaren Actions enthält
- Die Client-Anwendung (z.B. eine mobile Wallet, ein Chatbot oder eine Webseite) zeigt eine Benutzeroberfläche an, damit der Nutzer eine der Actions ausführen kann
- Nachdem der Nutzer eine Action ausgewählt hat (durch Klicken auf einen
Button), sendet der Client eine
POST
-Anfrage an den Endpunkt, um die Transaktion zum Signieren zu erhalten - Das Wallet erleichtert dem Benutzer das Signieren der Transaktion und sendet diese schließlich zur Bestätigung an die Blockchain
Solana Actions Execution and Lifecycle
Beim Empfang von Transaktionen über eine Actions-URL sollten die Clients deren Übermittlung an die Blockchain verarbeiten und den Statuslebenszyklus verwalten.
Actions unterstützen auch eine gewisse Form der Invalidierung vor der
Ausführung. Die GET
und POST
- Anfragen können auch Metadaten zurückgeben,
die anzeigen, ob eine Action ausgeführt werden kann (z.B. mit dem disabled
Feld).
Wenn zum Beispiel ein Action-Endpunkt die Abstimmung über einen
DAO-Governance-Vorschlag erleichtern soll, dessen Abstimmungsfenster bereits
geschlossen ist, könnte die initiale GET
-Anfrage eine
Fehlermeldung wie "Diese Abstimmung ist nicht mehr gültig" zurückgeben und die
"Ja" und "Nein"-Buttons als deaktiviert anzeigen.
Blinks #
Blinks (Blockchain Links) sind Client-Anwendungen, die die Action-APIs überprüfen und Benutzeroberflächen für die Interaktion und Ausführung von Actions erstellen.
Client-Anwendungen, die Blinks unterstützen, erkennen Action-kompatible URLs, analysieren sie und ermöglichen es Nutzern, mit ihnen in standardisierten Benutzeroberflächen zu interagieren.
Jede Client-Anwendung, die eine Actions-API vollständig inspiziert, um eine umfassende Benutzeroberfläche dafür zu erstellen, ist ein Blink. Daher sind nicht alle Clients, die Actions APIs nutzen, auch Blinks.
Blink-URL Spezifikation #
Eine Blink-URL beschreibt eine Client-Anwendung, die es einem Benutzer ermöglicht, den vollständigen Lebenszyklus der Ausführung einer Action abzuschließen, einschließlich der Signatur mit seiner Wallet.
https://example.domain/?action=<action_url>
Um zu einem Blink zu werden, muss jede Client-Anwendung:
-
Die Blink-URL muss einen Abfrageparameter
action
enthalten, dessen Wert eine URL-codierte Aktions-URL ist. Dieser Wert muss URL-kodiert sein, um nicht mit anderen Protokollparametern in Konflikt zu geraten. -
Die Client-Anwendung muss den Query-Parameter
Action
URL-dekodieren und den bereitgestellten Action-API-Link prüfen (siehe Action-URL-Schema). -
Der Client muss eine umfassende Benutzeroberfläche rendern, die es einem Nutzer ermöglicht, den vollständigen Lebenszyklus der Ausführung einer Action abzuschließen, einschließlich der Signatur mit seiner Wallet.
Nicht alle Blink-Client-Anwendungen (z.B. Websites oder dApps) werden alle Aktionen unterstützen. Anwendungsentwickler können auswählen, welche Actions sie innerhalb ihrer Blink-Schnittstellen unterstützen möchten.
Das folgende Beispiel zeigt eine gültige Blink-URL mit einem action
-Wert von
solana-action:https://actions.alice.com/donate
, der URL-kodiert ist:
https://example.domain/?action=solana-action%3Ahttps%3A%2F%2Factions.alice.com%2Fdonate
Detecting Actions via Blinks #
Blinks können auf mindestens drei Arten mit Actions verknüpft werden:
-
Teilen einer expliziten Action-URL:
solana-action:https://actions.alice.com/donate
In diesem Fall können nur unterstützte Clients den Blink darstellen. Es wird weder eine alternative Linkvorschau geben noch eine Webseite, die außerhalb des nicht unterstützenden Clients besucht werden kann.
-
Das Teilen eines Links zu einer Website, die über eine
actions.json
Datei im Rootverzeichnis der Website mit einer Actions-API verknüpft ist.Zum Beispiel ordnet die Datei
https://alice.com/actions.json
die Website-URLhttps://alice.com/donate
der API-URLhttps://actions.alice.com/donate
zu. Benutzer können über die Website-URL an Alice spenden, während die API-URL die entsprechenden Aktionen für das Spenden bereitstellt. -
Einbetten einer Actions-URL in eine „Zwischenseite“-URL, die versteht, wie man Aktionen analysiert.
https://example.domain/?action=<action_url>
Clients, die Blinks unterstützen, sollten in der Lage sein, jedes der oben genannten Formate zu übernehmen und eine Benutzeroberfläche korrekt darzustellen, um die Ausführung der Aktion direkt im Client zu ermöglichen.
Für Clients, die Blinks nicht unterstützen, sollte es eine zugrunde liegende Website geben (wodurch der Browser zum universellen Fallback wird).
Wenn ein Benutzer in einem Client auf eine Stelle tippt, die weder ein Actions-Button noch ein Texteingabefeld ist, sollte er zur zugrunde liegenden Webseite weitergeleitet werden.
Blink Testing and Verification #
While Solana Actions and blinks are a permissionless protocol/specification, client applications and wallets are still required to ultimately facilitate users to sign the transaction.
Use the Blinks Inspector tool to inspect, debug, and test your blinks and actions directly in your browser. You can view the GET and POST response payloads, response headers, and test all inputs to each of your linked Actions.
Each client application or wallets may have different requirements on which Action endpoints their clients will automatically unfurl and immediately display to their users on social media platforms.
For example, some clients may operate on an "allow list" approach that may require verification prior to their client unfurling an Action for users such as Dialect's Actions Registry (detailed below).
All blinks will still render and allow for signing on Dialect's dial.to blinks Interstitial site, with their registry status displayed in the blink.
Dialect's Actions Registry #
As a public good for the Solana ecosystem, Dialect maintains a public registry — together with the help of Solana Foundation and other community members — of blockchain links that have are from pre-verified from known sources. As of launch, only Actions that have been registered in the Dialect registry will unfurl in the Twitter feed when posted.
Client applications and wallets can freely choose to use this public registry or another solution to help ensure user security and safety. If not verified through the Dialect registry, the blockchain link will not be touched by the blink client, and will be rendered as a typical URL.
Developers can apply to be verified by Dialect here: dial.to/register
Spezifikation #
Die Solana Actions-Spezifikation besteht aus wichtigen Abschnitten, die Teil eines Anfrage-/Antwort-Interaktionsflusses sind:
- Solana Action URL-Schema stellt eine Actions-URL bereit
- OPTIONS response to an Action URL to pass CORS requirements
GET
-Anfrage an eine Actions-URLGET
-Antwort vom ServerPOST
-Anfrage an eine Actions-URLPOST
-Antwort vom Server
Jede dieser Anfragen wird vom Action-Client (z.B. Wallet-App, Browser-Erweiterung, dApp, Website usw.) gestellt, um spezifische Metadaten für umfangreiche Benutzeroberflächen zu sammeln und die Benutzereingabe an die Actions-API zu erleichtern.
Jede der Antworten wird von einer Anwendung (z. B. Website, Server-Backend usw.) erstellt und an den Action Client zurückgegeben. Letztendlich wird eine signierbare Transaktion oder Nachricht für eine Wallet bereitgestellt, um den Benutzer zur Genehmigung, Signierung und zum Senden an die Blockchain aufzufordern.
The types and interfaces declared within this readme files are often the simplified version of the types to aid in readability.
For better type safety and improved developer experience, the
@solana/actions-spec
package contains more complex type definitions. You can
find the
source code for them here.
URL-Schema #
Eine Solana Action URL beschreibt eine interaktive Anfrage für eine signierbare
Solana-Transaktion oder -Nachricht unter Verwendung des
solana-action
-Protokolls.
Die Anfrage ist interaktiv, da die Parameter in der URL vom Client verwendet werden, um eine Reihe von standardisierten HTTP-Anfragen zu stellen, um eine signierbare Transaktion oder Nachricht für den Benutzer zu erstellen, die dieser mit seiner Wallet signieren kann.
solana-action:<link>
-
Ein einzelnes
link
-Feld ist als Pfadname erforderlich. Der Wert muss eine bedingt URL-kodierte absolute HTTPS-URL sein. -
Wenn die URL Abfrageparameter enthält, muss sie URL-kodiert sein. Die URL-Kodierung des Werts verhindert Konflikte mit jeglichen Actions-Protokoll-Parametern, die über die Protokollspezifikation hinzugefügt werden können.
-
Falls die URL keine Abfrageparameter enthält, sollte sie nicht URL-kodiert sein. Dadurch entsteht eine kürzere URL und ein besser lesbarer QR-Code.
In beiden Fällen müssen Clients den Wert URL-dekodieren. Dies hat keine Auswirkungen, wenn der Wert nicht URL-kodiert ist. Wenn der dekodierte Wert keine absolute HTTPS-URL ist, muss die Wallet ihn als fehlerhaft ablehnen.
OPTIONS response #
In order to allow Cross-Origin Resource Sharing
(CORS) within Actions
clients (including blinks), all Action endpoints should respond to HTTP requests
for the OPTIONS
method with valid headers that will allow clients to pass CORS
checks for all subsequent requests from their same origin domain.
An Actions client may perform
"preflight"
requests to the Action URL endpoint in order check if the subsequent GET request
to the Action URL will pass all CORS checks. These CORS preflight checks are
made using the OPTIONS
HTTP method and should respond with all required HTTP
headers that will allow Action clients (like blinks) to properly make all
subsequent requests from their origin domain.
At a minimum, the required HTTP headers include:
Access-Control-Allow-Origin
with a value of*
- this ensures all Action clients can safely pass CORS checks in order to make all required requests
Access-Control-Allow-Methods
with a value ofGET,POST,PUT,OPTIONS
- ensures all required HTTP request methods are supported for Actions
Access-Control-Allow-Headers
with a minimum value ofContent-Type, Authorization, Content-Encoding, Accept-Encoding
For simplicity, developers should consider returning the same response and
headers to OPTIONS
requests as their GET
response.
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.
GET Anfrage #
Der Action Client (z.B. Wallet, Browser-Erweiterung, etc.) sollte eine HTTP
GET
JSON-Anfrage an den URL-Endpunkt der Action senden.
- Die Anfrage sollte weder die Wallet noch den Benutzer identifizieren.
- Der Client sollte die Anfrage mit einem
Accept-Encoding
-Header stellen. - Der Client sollte die Domain der URL anzeigen, während die Anfrage gestellt wird.
GET Antwort (GET Response) #
Der URL-Endpunkt der Action (z.B. Anwendung oder Server-Backend) sollte mit
einer HTTP OK
JSON-Antwort (mit einer gültigen Payload im Body) oder einem
entsprechenden HTTP-Fehler antworten.
-
Der Client muss HTTP Client-Fehler und Server-Fehler behandeln sowie Antworten umleiten.
-
Der Endpunkt sollte mit einem
Content-Encoding
-Header für die HTTP-Komprimierung antworten. -
Der Endpunkt sollte mit einem
Content-Type
-Header vonapplication/json
antworten. -
The client should not cache the response except as instructed by HTTP caching response headers.
-
The client should display the
title
and render theicon
image to user.
Error responses (i.e. HTTP 4xx and 5xx status codes) should return a JSON
response body following ActionError
to present a helpful error message to
users. See Action Errors.
GET Response Body #
Eine GET
-Antwort mit einem HTTP-Statuscode OK
sollte einen JSON Body-Payload
enthalten, die der folgenden Schnittstellenspezifikation entspricht:
export type ActionType = "action" | "completed";
export type ActionGetResponse = Action<"action">;
export interface Action<T extends ActionType> {
/** type of Action to present to the user */
type: T;
/** image url that represents the source of the action request */
icon: string;
/** describes the source of the action request */
title: string;
/** brief summary of the action to be performed */
description: string;
/** button text rendered to the user */
label: string;
/** UI state for the button being rendered to the user */
disabled?: boolean;
links?: {
/** list of related Actions a user could perform */
actions: LinkedAction[];
};
/** non-fatal error message to be displayed to the user */
error?: ActionError;
}
-
type
- The type of action being given to the user. Defaults toaction
. The initialActionGetResponse
is required to have a type ofaction
.action
- Standard action that will allow the user to interact with any of theLinkedActions
completed
- Used to declare the "completed" state within action chaining.
-
icon
- Der Wert muss eine absolute HTTP- oder HTTPS-URL eines Icon-Bildes sein. Die Datei muss ein SVG-, PNG- oder WebP-Bild sein, andernfalls muss der Client/die Wallet sie als malformed ablehnen. -
title
- Der Wert muss ein UTF-8-String sein, der die Quelle der Action-Anfrage darstellt. Zum Beispiel könnte dies der Name einer Marke, eines Geschäfts, einer Anwendung oder einer Person sein, die die Anfrage stellt. -
description
- Der Wert muss ein UTF-8-String sein, der Informationen über die Action liefert. Diese Informationen sollten dem Benutzer angezeigt werden. -
label
- Der Wert muss ein UTF-8-String sein, der auf einem Button für den Benutzer zum Anklicken angezeigt wird. Alle Labels sollten nicht länger als 5 Wörter sein und mit einem Verb beginnen, um die gewünschte Handlung des Benutzers zu verdeutlichen. Zum Beispiel "Mint NFT", "Stimme mit Ja" oder "Stake 1 SOL". -
disabled
- Der Wert muss ein boolescher Wert sein (true/false), um den deaktivierten Zustand des angezeigten Buttons (mit demlabel
-Text) darzustellen. Falls kein Wert angegeben wird, solltedisabled
standardmäßig auffalse
gesetzt werden (d. h. standardmäßig aktiviert sein). Zum Beispiel, wenn der Action-Endpunkt für eine Governance-Abstimmung ist, die bereits geschlossen wurde, wirddisabled=true
gesetzt und das Label könnte "Abstimmung beendet" sein. -
error
- Ein optionaler Fehlerhinweis für nicht schwerwiegende Fehler. Falls vorhanden, sollte der Client diesen dem Benutzer anzeigen. If set, it should not prevent the client from interpreting the action or displaying it to the user (see Action Errors). For example, the error can be used together withdisabled
to display a reason like business constraints, authorization, the state, or an error of external resource. -
links.actions
- Ein optionales Array verwandter Actions für den Endpunkt. Benutzern sollte eine Benutzeroberfläche für jede der aufgelisteten Aktionen angezeigt werden, wobei erwartet wird, dass sie nur eine Aktion ausführen. Zum Beispiel könnte ein Action-Endpunkt für eine Governance-Abstimmung drei Optionen für den Benutzer zurückgeben: "Stimme mit Ja", "Stimme mit Nein" und "Enthalten".-
If no
links.actions
is provided, the client should render a single button using the rootlabel
string and make the POST request to the same action URL endpoint as the initial GET request. -
If any
links.actions
are provided, the client should only render buttons and input fields based on the items listed in thelinks.actions
field. The client should not render a button for the contents of the rootlabel
.
-
export interface LinkedAction {
/** URL endpoint for an action */
href: string;
/** button text rendered to the user */
label: string;
/**
* Parameters to accept user input within an action
* @see {ActionParameter}
* @see {ActionParameterSelectable}
*/
parameters?: Array<TypedActionParameter>;
}
The ActionParameter
allows declaring what input the Action API is requesting
from the user:
/**
* Parameter to accept user input within an action
* note: for ease of reading, this is a simplified type of the actual
*/
export interface ActionParameter {
/** input field type */
type?: ActionParameterType;
/** parameter name in url */
name: string;
/** placeholder text for the user input field */
label?: string;
/** declare if this field is required (defaults to `false`) */
required?: boolean;
/** regular expression pattern to validate user input client side */
pattern?: string;
/** human-readable description of the `type` and/or `pattern`, represents a caption and error, if value doesn't match */
patternDescription?: string;
/** the minimum value allowed based on the `type` */
min?: string | number;
/** the maximum value allowed based on the `type` */
max?: string | number;
}
The pattern
should be a string equivalent of a valid regular expression. This
regular expression pattern should by used by blink-clients to validate user
input before before making the POST request. If the pattern
is not a valid
regular expression, it should be ignored by clients.
The patternDescription
is a human readable description of the expected input
requests from the user. If pattern
is provided, the patternDescription
is
required to be provided.
The min
and max
values allows the input to set a lower and/or upper bounds
of the input requested from the user (i.e. min/max number and or min/max
character length), and should be used for client side validation. For input
type
s of date
or datetime-local
, these values should be a string dates.
For other string based input type
s, the values should be numbers representing
their min/max character length.
If the user input value is not considered valid per the pattern
, the user
should receive a client side error message indicating the input field is not
valid and displayed the patternDescription
string.
The type
field allows the Action API to declare more specific user input
fields, providing better client side validation and improving the user
experience. In many cases, this type will resemble the standard
HTML input element.
The ActionParameterType
can be simplified to the following type:
/**
* Input field type to present to the user
* @default `text`
*/
export type ActionParameterType =
| "text"
| "email"
| "url"
| "number"
| "date"
| "datetime-local"
| "checkbox"
| "radio"
| "textarea"
| "select";
Each of the type
values should normally result in a user input field that
resembles a standard HTML input
element of the corresponding type
(i.e.
<input type="email" />
) to provide better client side validation and user
experience:
text
- equivalent of HTML “text” input elementemail
- equivalent of HTML “email” input elementurl
- equivalent of HTML “url” input elementnumber
- equivalent of HTML “number” input elementdate
- equivalent of HTML “date” input elementdatetime-local
- equivalent of HTML “datetime-local” input elementcheckbox
- equivalent to a grouping of standard HTML “checkbox” input elements. The Action API should returnoptions
as detailed below. The user should be able to select multiple of the provided checkbox options.radio
- equivalent to a grouping of standard HTML “radio” input elements. The Action API should returnoptions
as detailed below. The user should be able to select only one of the provided radio options.- Other HTML input type equivalents not specified above (
hidden
,button
,submit
,file
, etc) are not supported at this time.
In addition to the elements resembling HTML input types above, the following user input elements are also supported:
textarea
- equivalent of HTML textarea element. Allowing the user provide multi-line input.select
- equivalent of HTML select element, allowing the user to experience a “dropdown” style field. The Action API should returnoptions
as detailed below.
When type
is set as select
, checkbox
, or radio
then the Action API
should include an array of options
that each provide a label
and value
at
a minimum. Each option may also have a selected
value to inform the
blink-client which of the options should be selected by default for the user
(see checkbox
and radio
for differences).
This ActionParameterSelectable
can be simplified to the following type
definition:
/**
* note: for ease of reading, this is a simplified type of the actual
*/
interface ActionParameterSelectable extends ActionParameter {
options: Array<{
/** displayed UI label of this selectable option */
label: string;
/** value of this selectable option */
value: string;
/** whether or not this option should be selected by default */
selected?: boolean;
}>;
}
If no type
is set or an unknown/unsupported value is set, blink-clients should
default to text
and render a simple text input.
The Action API is still responsible to validate and sanitize all data from the user input parameters, enforcing any “required” user input as necessary.
For platforms other that HTML/web based ones (like native mobile), the equivalent native user input component should be used to achieve the equivalent experience and client side validation as the HTML/web input types described above.
Beispiel einer GET-Antwort #
Das folgende Antwortbeispiel liefert eine einzelne "Root"-Action, die dem Benutzer als einzelner Button mit der Beschriftung "Zugangstoken anfordern" präsentiert werden soll:
{
"title": "HackerHouse Events",
"icon": "<url-to-image>",
"description": "Claim your Hackerhouse access token.",
"label": "Claim Access Token" // button text
}
Die folgende Beispielantwort enthält 3 verknüpfte Action-Links, die es dem Benutzer erlauben, auf eine von 3 Schaltflächen zu klicken, um ihre Stimme für einen DAO-Vorschlag abzugeben:
{
"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"
}
]
}
}
Beispiel einer GET-Antwort mit Parametern #
Die folgende Beispielantwort zeigt, wie man Texteingaben des Nutzers (über
parameters
) entgegennimmt und diese Eingabe in den finalen
POST
-Anfrage-Endpunkt (über das href
-Feld innerhalb einer LinkedAction
)
einbindet:
Die folgende Beispielantwort stellt dem Nutzer 3 verknüpfte Actions zum Staken von SOL zur Verfügung: einen Button mit der Bezeichnung "1 SOL staken", einen weiteren Button mit der Bezeichnung "5 SOL staken" und ein Texteingabefeld, in das der Nutzer einen bestimmten "Betrag" eingeben kann, der an die Actions-API gesendet wird:
{
"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
}
]
}
]
}
}
Die folgende Beispielantwort bietet dem Benutzer ein einzelnes Eingabefeld zur
Eingabe eines Betrags
, der mit der POST
-Anfrage gesendet wird (entweder als
Abfrageparameter oder als Unterpfad):
{
"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-Anfrage #
Der Client muss eine HTTP POST
JSON-Anfrage an die Actions-URL mit folgendem
Body-Payload senden:
{
"account": "<account>"
}
account
- Der Wert muss der base58-kodierte öffentliche Schlüssel (public key) eines Accounts sein, der die Transaktion signieren kann.
The client should make the request with an Accept-Encoding header and the application may respond with a Content-Encoding header for HTTP compression.
Der Client sollte die Domain der Actions-URL anzeigen, während die Anfrage
gestellt wird. Wenn eine GET
-Anfrage gestellt wurde, sollte der Client auch
den title
und das icon
-Bild von dieser GET
-Antwort anzeigen.
POST-Antwort #
Der POST
-Endpunkt der Action sollte mit einer HTTP OK
JSON-Antwort (mit
einem gültigen Payload im Body) oder einem entsprechenden HTTP-Fehler antworten.
- Der Client muss HTTP Client-Fehler und Server-Fehler behandeln sowie Antworten umleiten.
- Der Endpunkt sollte mit einem
Content-Type
-Header vonapplication/json
antworten.
Error responses (i.e. HTTP 4xx and 5xx status codes) should return a JSON
response body following ActionError
to present a helpful error message to
users. See Action Errors.
POST Response Body #
Eine POST
Antwort mit einer HTTP OK
JSON-Antwort sollte folgenden
Body-Payload enthalten:
/**
* 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
- The value must be a base64-encoded serialized transaction. The client must base64-decode the transaction and deserialize it. -
message
- Der Wert muss ein UTF-8-String sein, der die Art der Transaktion beschreibt, die in der Antwort enthalten ist. The client should display this value to the user. Zum Beispiel könnte dies der Name eines gekauften Artikels, ein auf einen Kauf angewendeter Rabatt oder eine Dankesnachricht sein. -
links.next
- An optional value use to "chain" multiple Actions together in series. After the includedtransaction
has been confirmed on-chain, the client can fetch and render the next action. See Action Chaining for more details. -
Der Client und die Anwendung sollten zusätzliche Felder im Body der Anfrage und im Body der Antwort zulassen, die durch zukünftige Aktualisierungen der Spezifikation hinzugefügt werden können.
Die Anwendung kann mit einer teilweise oder vollständig signierten Transaktion antworten. The client and wallet must validate the transaction as untrusted.
POST-Antwort - Transaktion #
If the transaction
signatures
are empty or the transaction has NOT been partially signed:
- The client must ignore the
feePayer
in the transaction and set thefeePayer
to theaccount
in the request. - The client must ignore the
recentBlockhash
in the transaction and set therecentBlockhash
to the latest blockhash. - Der Client muss die Transaktion vor dem Signieren serialisieren und deserialisieren. Dies gewährleistet eine einheitliche Reihenfolge der Kontoschlüssel (account keys) und dient als Workaround für dieses Problem.
If the transaction has been partially signed:
- The client must NOT alter the
feePayer
orrecentBlockhash
as this would invalidate any existing signatures. - The client must verify existing signatures, and if any are invalid, the client must reject the transaction as malformed.
The client must only sign the transaction with the account
in the request, and
must do so only if a signature for the account
in the request is expected.
If any signature except a signature for the account
in the request is
expected, the client must reject the transaction as malicious.
Action Errors #
Actions APIs should return errors using ActionError
in order to present
helpful error messages to the user. Depending on the context, this error could
be fatal or non-fatal.
export interface ActionError {
/** simple error message to be displayed to the user */
message: string;
}
When an Actions API responds with an HTTP error status code (i.e. 4xx and 5xx),
the response body should be a JSON payload following ActionError
. The error is
considered fatal and the included message
should be presented to the user.
For API responses that support the optional error
attribute (like
ActionGetResponse
), the error is considered non-fatal and the
included message
should be presented to the user.
Action Chaining #
Solana Actions can be "chained" together in a successive series. After an Action's transaction is confirmed on-chain, the next action can be obtained and presented to the user.
Action chaining allows developers to build more complex and dynamic experiences within blinks, including:
- providing multiple transactions (and eventually sign message) to a user
- customized action metadata based on the user's wallet address
- refreshing the blink metadata after a successful transaction
- receive an API callback with the transaction signature for additional validation and logic on the Action API server
- customized "success" messages by updating the displayed metadata (e.g. a new image and description)
To chain multiple actions together, in any ActionPostResponse
include a
links.next
of either:
PostNextActionLink
- POST request link with a same origin callback url to receive thesignature
and user'saccount
in the body. This callback url should respond with aNextAction
.InlineNextActionLink
- Inline metadata for the next action to be presented to the user immediately after the transaction has confirmed. No callback will be made.
export type NextActionLink = PostNextActionLink | InlineNextActionLink;
/** @see {NextActionPostRequest} */
export interface PostNextActionLink {
/** Indicates the type of the link. */
type: "post";
/** Relative or same origin URL to which the POST request should be made. */
href: string;
}
/**
* Represents an inline next action embedded within the current context.
*/
export interface InlineNextActionLink {
/** Indicates the type of the link. */
type: "inline";
/** The next action to be performed */
action: NextAction;
}
NextAction #
After the ActionPostResponse
included transaction
is signed by the user and
confirmed on-chain, the blink client should either:
- execute the callback request to fetch and display the
NextAction
, or - if a
NextAction
is already provided vialinks.next
, the blink client should update the displayed metadata and make no callback request
If the callback url is not the same origin as the initial POST request, no callback request should be made. Blink clients should display an error notifying the user.
/** The next action to be performed */
export type NextAction = Action<"action"> | CompletedAction;
/** The completed action, used to declare the "completed" state within action chaining. */
export type CompletedAction = Omit<Action<"completed">, "links">;
Based on the type
, the next action should be presented to the user via blink
clients in one of the following ways:
-
action
- (default) A standard action that will allow the user to see the included Action metadata, interact with the providedLinkedActions
, and continue to chain any following actions. -
completed
- The terminal state of an action chain that can update the blink UI with the included Action metadata, but will not allow the user to execute further actions.
If no links.next
is not provided, blink clients should assume the current
action is final action in the chain, presenting their "completed" UI state after
the transaction is confirmed.
actions.json #
Der Zweck der Datei actions.json
besteht darin, einer
Anwendung zu ermöglichen, Clients über die Website-URLs zu informieren, die
Solana Actions unterstützen. Außerdem wird ein Mapping zur Verfügung gestellt,
um GET
-Anfragen an einen Actions-API-Server zu senden.
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.
Die Datei actions.json
sollte im Stammverzeichnis der Domain gespeichert und
allgemein zugänglich sein.
Wenn deine Webanwendung beispielsweise unter my-site.com
bereitgestellt wird,
sollte die Datei actions.json
unter https://my-site.com/actions.json
erreichbar sein. This file should also be Cross-Origin accessible via any
browser by having a Access-Control-Allow-Origin
header value of *
.
Regeln (Rules) #
Das Feld rules
erlaubt der Anwendung, eine Reihe relativer Routenpfade einer
Webseite einer Reihe anderer Pfade zuzuordnen.
Typ: Array
von 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
- Ein Muster, das jedem eingehenden Pfadnamen entspricht. -
apiPath
- Ein Zielort, der als absoluter Pfadname oder externe URL definiert ist.
Rules - pathPattern #
Ein Muster, das jedem eingehenden Pfadnamen entspricht. Es kann ein absoluter oder relativer Pfad sein und unterstützt die folgenden Formate:
-
Exakte Übereinstimmung: Stimmt genau mit dem URL-Pfad überein.
- Beispiel:
/exact-path
- Beispiel:
https://website.com/exact-path
- Beispiel:
-
Platzhalter-Übereinstimmung (Wildcard Match): Verwendet Platzhalter, um eine beliebige Abfolge von Zeichen im URL-Pfad abzugleichen. Dabei können einzelne Segmente (mit
*
) oder mehrere Segmente (mit**
) abgeglichen werden. (siehe Path Matching weiter unten).- Beispiel:
/trade/*
stimmt mit/trade/123
und/trade/abc
überein und erfasst nur das erste Segment hinter/trade/
. - Beispiel:
/category/*/item/**
stimmt mit/category/123/item/456
und/category/abc/item/def
überein. - Beispiel:
/api/actions/trade/*/confirm
stimmt mit/api/actions/trade/123/confirm
überein.
- Beispiel:
Rules - apiPath #
Der Zielpfad für die Action-Anfrage. Er kann als absoluter Pfadname oder als externe URL angegeben werden.
- Beispiel:
/api/exact-path
- Beispiel:
https://api.example.com/v1/donate/*
- Beispiel:
/api/category/*/item/*
- Example:
/api/swap/**
Rules – Abfrageparameter (Query-Parameter) #
Abfrageparameter aus der ursprünglichen URL werden immer beibehalten und an die zugeordnete URL angehängt.
Rules - Pfadabgleich (Path Matching) #
Die folgende Tabelle zeigt die Syntax für Pfadmusterabgleiche (path matching patterns):
Operator | Treffer |
---|---|
* | Ein einzelnes Pfadsegment, ohne die umgebenden Trennzeichen / . |
** | Stimmt mit keinem oder mehreren Zeichen überein, einschließlich aller Pfadtrennzeichen / zwischen mehreren Pfadsegmenten. Wenn andere Operatoren eingebunden sind, muss der ** Operator der letzte Operator sein. |
? | Nicht unterstütztes Muster. |
Regeln Beispiele #
Das folgende Beispiel zeigt eine exakte Übereinstimmungsregel, um Anfragen an
/buy
vom Rootverzeichnis deiner Website auf den exakten Pfad /api/buy
relativ zum Rootverzeichnis deiner Website zuzuordnen:
{
"rules": [
{
"pathPattern": "/buy",
"apiPath": "/api/buy"
}
]
}
The following example uses wildcard path matching to map requests to any path
(excluding subdirectories) under /actions/
from your site's root to a
corresponding path under /api/actions/
relative to your site's root:
{
"rules": [
{
"pathPattern": "/actions/*",
"apiPath": "/api/actions/*"
}
]
}
The following example uses wildcard path matching to map requests to any path
(excluding subdirectories) under /donate/
from your site's root to a
corresponding absolute path https://api.dialect.com/api/v1/donate/
on an
external site:
{
"rules": [
{
"pathPattern": "/donate/*",
"apiPath": "https://api.dialect.com/api/v1/donate/*"
}
]
}
Das folgende Beispiel verwendet Musterbasierten Pfadabgleich für eine
idempotente Regel, um Anfragen an beliebige Pfade (einschließlich
Unterverzeichnisse) unter /api/actions/
vom Rootverzeichnis Ihrer Website auf
sich selbst abzubilden:
Idempotente Regeln ermöglichen es Blink Clients, einfacher zu bestimmen, ob
ein bestimmter Pfad Action API-Anfragen unterstützt, ohne dass dieser mit dem
solana-action
: URI vorangestellt werden muss oder zusätzliche Antworttests
durchgeführt werden müssen.
{
"rules": [
{
"pathPattern": "/api/actions/**",
"apiPath": "/api/actions/**"
}
]
}
Action Identity #
Action-Endpunkte können in den Transaktionen, die in ihrer
POST
-Antwort zum Signieren an den Benutzer zurückgegeben
werden, eine Aktions-Identität (Action Identity) einfügen. Dadurch können
Indexer und Analyseplattformen On-Chain-Aktivitäten einfach und nachprüfbar
einem bestimmten Action-Anbieter (d.h. Dienst) zuordnen.
Die Action Identity ist ein Schlüsselpaar, das verwendet wird, um eine speziell formatierte Nachricht zu signieren, die mittels einer Memo-Anweisung in die Transaktion eingefügt wird. Diese Identifizierungsnachricht (Identifier Message) kann nachweislich einer bestimmten Action Identity zugeordnet werden und somit Transaktionen einem bestimmten Action Provider zuschreiben.
Das Schlüsselpaar muss nicht für die Signierung der Transaktion selbst verwendet werden. Dies ermöglicht es Wallets und Anwendungen, die Zustellbarkeit von Transaktionen zu verbessern, wenn keine anderen Signaturen in der an einen Benutzer zurückgegebenen Transaktion vorhanden sind (siehe POST Antwort Transaktion).
Falls der Anwendungsfall eines Action Providers erfordert, dass seine Backend-Dienste die Transaktion vorab signieren, bevor der Benutzer dies tut, sollten sie dieses Schlüsselpaar als ihre Action Identity verwenden. Dadurch kann ein Account weniger in die Transaktion aufgenommen werden, was die Gesamtgröße der Transaktion um 32 Bytes reduziert.
Action Identifier Message #
Die Action Identifier Message ist eine durch Doppelpunkte getrennte UTF-8-Zeichenkette, die mithilfe einer einzigen SPL Memo-Anweisung in eine Transaktion aufgenommen wird.
protocol:identity:reference:signature
protokoll
- Der Wert des verwendeten Protokolls (gemäß dem URL-Schema oben aufsolana-action
gesetzt)identity
- Der Wert muss die Base58-kodierte öffentliche Schlüsseladresse des Action Identity Schlüsselpaares seinreference
- Der Wert muss ein Base58-kodiertes 32-Byte-Array sein. Dies können öffentliche Schlüssel sein oder auch nicht, auf oder außerhalb der Kurve, und sie können mit Accounts auf Solana übereinstimmen oder auch nicht.signature
- Base58-kodierte Signatur, die vom Action Identity-Schlüsselpaar erstellt wurde, wobei nur derreference
-Wert signiert wird.
Der reference
-Wert darf nur einmal und in einer einzigen Transaktion verwendet
werden. Für die Zuordnung von Transaktionen zu einem Action Provider wird nur
die erste Verwendung des reference
-Werts als gültig betrachtet.
Transaktionen können mehrere Memo-Anweisungen enthalten. Bei der Ausführung
einer
getSignaturesForAddress
-Abfrage
wird das memo
-Feld in den Ergebnissen die Nachricht jeder Memo-Anweisung als
einen einzelnen String zurückgeben, wobei die Nachrichten durch ein Semikolon
getrennt sind.
Keine weiteren Daten sollten in der Memo-Anweisung der Identifier Message (Identifizierungsnachricht) enthalten sein.
The identity
and the reference
should be included as read-only, non-signer
keys
in the transaction on an instruction that is NOT the Identifier Message Memo
instruction.
Die Identifier Message Memo-Anweisung muss ohne bereitgestellte Accounts erfolgen. Wenn Accounts bereitgestellt werden, erfordert das Memo-Programm, dass diese Konten gültige Signierer sind. Für den Zweck der Action-Identifizierung schränkt dies die Flexibilität ein und kann die Benutzererfahrung beeinträchtigen. Daher wird dies als Antimuster betrachtet und muss vermieden werden.
Action Identity Verifizierung #
Jede Transaktion, die den identity
-Account einschließt, kann in einem
mehrstufigen Prozess nachweislich mit dem Action Provider in Verbindung gebracht
werden:
- Alle Transaktionen für eine gegebene
identity
abrufen. - Analysiere und verifiziere jede Transaktions-Memo-Zeichenfolge, um
sicherzustellen, dass die
signature
für die gespeichertereference
gültig ist. - Verifiziere, dass die spezifische Transaktion das erste Vorkommen der
reference
auf der Blockchain ist:- Wenn es sich bei dieser Transaktion um das erste Vorkommen handelt, gilt die Transaktion als verifiziert und kann sicher dem Action Provider zugeordnet werden.
- Wenn diese Transaktion NICHT das erste Ereignis ist, gilt sie als ungültig und wird daher nicht dem Action Provider zugeordnet.
Weil Solana-Validatoren Transaktionen nach den Account-Schlüsseln indizieren,
kann die RPC-Methode
getSignaturesForAddress
verwendet werden, um alle Transaktionen zu finden, die das identity
Konto
beinhalten.
Die Antwort dieser RPC-Methode enthält alle Memo-Daten im Feld memo
. Wenn
mehrere Memo-Anweisungen in der Transaktion verwendet wurden, wird jede
Memo-Nachricht in diesem memo
-Feld enthalten sein und muss entsprechend vom
Verifizierer analysiert werden, um die Identitätsverifizierungsnachricht zu
erhalten.
Diese Transaktionen sollten zunächst als UNVERIFIZIERT betrachtet werden.
Dies liegt daran, dass die identity
nicht verpflichtet ist, die Transaktion zu
signieren, was es jeder Transaktion ermöglicht, dieses Konto als Nicht-Signierer
einzubinden. Potenziell künstliche Erhöhung der Zuordnungs- und Nutzungszahlen.
Die Identitätsprüfungsnachricht sollte überprüft werden, um sicherzustellen,
dass die signature
von der identity
durch Signieren der reference
erstellt
wurde. Falls diese Signaturprüfung fehlschlägt, ist die Transaktion ungültig und
sollte dem Action Provider nicht zugerechnet werden.
Wenn die Verifizierung der Signatur erfolgreich ist, sollte der Verifizierer
sicherstellen, dass diese Transaktion das erste Auftreten der reference
in der
Blockchain ist. Ist dies nicht der Fall, wird die Transaktion als ungültig
betrachtet.