Acciones y Blinks

Solana Actions o Acciones son APIs que cumplen con especificaciones que devuelven transacciones en la cadena de bloques de Solana para ser previsualizadas, firmadas y enviadas a través de un número diverso de contextos, incluyendo códigos QR, botones + widgets y sitios web a través de Internet. Las Acciones facilitan a los desarrolladores la integración de todo lo que puedes hacer en el ecosistema de Solana directo en su entorno actual, permitiéndoles realizar transacciones en la cadena de bloques sin la necesidad de navegar a otra aplicación o página web.

Los enlaces Blockchain – o blinks – convierten cualquier Solana Action en un enlace compartible y rico en metadatos. Los Blinks permiten a los clientes compatibles con Acciones (como extensiones de billetera del navegador o bots) mostrar capacidades adicionales para el usuario. En un sitio web, un blink podría activar inmediatamente una vista previa de la transacción en una billetera sin tener que ir a una aplicación descentralizada; en Discord, un bot podría ampliar el blink en un conjunto interactivo de botones. Esto brinda la capacidad de interactuar con la cadena de bloques a cualquier superficie web capaz de mostrar una URL.

Primeros Pasos #

Para comenzar rápidamente a crear Acciones personalizadas en Solana:

npm install @solana/actions
Info

Echa un vistazo a este tutorial de cómo construir una Acción de Solana usando el SDK @solana/actions.

También puedes encontrar el código fuente para una Acción que realiza una transferencia SOL nativa y varias otras Acciones de ejemplo en este repo.

Al desplegar tus Acciones personalizadas de Solana en producción:

Si estás buscando inspiración para construir Acciones y Blinks, revisa el repositorio "Awesome Blinks" que contiene algunas creaciones de la comunidad e incluso ideas para otras nuevas.

Acciones #

La especificación de Solana Actions utiliza un conjunto de APIs estándar para entregar transacciones que pueden ser firmadas (y eventualmente mensajes firmables) desde una aplicación directamente a un usuario. Están alojadas en URLs de acceso público y, por tanto, son accesibles por su URL para que cualquier cliente pueda interactuar con ellas.

Info

Puedes pensar en Acciones como un endpoint de la API que devolverá metadatos y algo para que un usuario firme (ya sea una transacción o un mensaje de autenticación) con su billetera de la cadena de bloques.

La API de Acciones consiste en realizar solicitudes simples GET y POST al endpoint URL de una Acción y gestionar las respuestas que cumplen con la interfaz de Acciones.

  1. La solicitud GET devuelve metadatos que proporcionan información legible para el cliente sobre qué acciones están disponibles en esta URL, y una lista opcional de acciones relacionadas.
  2. La solicitud POST devuelve una transacción o mensaje que puede ser firmado. Posteriormente, el cliente solicita a la billetera del usuario que firme y ejecute esta transacción en la cadena de bloques o en otro servicio fuera de la cadena.

Ejecución y ciclo de vida de las Acciones #

En la práctica, interactuar con Acciones se parece mucho a interactuar con una API REST típica:

  • Un cliente realiza una solicitud inicial GET a la URL de una Acción para obtener metadatos sobre las Acciones disponibles
  • El endpoint devuelve una respuesta que incluye metadatos de la acción (como el título y el icono de la aplicación) y una lista de las acciones disponibles para este endpoint
  • La aplicación cliente (como una billetera móvil, un chatbot o un sitio web) muestra una interfaz de usuario para que el usuario realice una de las acciones
  • Después de que el usuario seleccione una acción (haciendo clic en un botón), el cliente realiza una solicitud POST al endpoint para obtener la transacción que el usuario debe firmar
  • La billetera facilita al usuario la firma de la transacción y, en última instancia, envía la transacción a la cadena de bloques para su confirmación

Solana Actions Execution and LifecycleSolana Actions Execution and Lifecycle

Al recibir transacciones de una URL de Acciones, los clientes deben gestionar el envío de estas transacciones a la cadena de bloques y gestionar su ciclo de vida.

Las Acciones también admiten cierto nivel de invalidación antes de la ejecución. Las peticiones GET y POST pueden devolver algunos metadatos que indiquen si la acción puede realizarse (como el campo disabled).

Por ejemplo: si hubiera una Acción que facilitara la votación de una propuesta de gobernanza de una DAO cuya ventana de votación se hubiera cerrado, la solicitud GET inicial podría devolver el mensaje de error "Esta propuesta ya no está disponible para votación" y los botones "Votar sí" y "Votar no" se mostrarían como "desactivados".

Los Blinks (enlaces de blockchain) son aplicaciones cliente que introspeccionan las API de las Acciones y construyen interfaces de usuario en torno a la interacción y ejecución de las Acciones.

Las aplicaciones cliente que admiten blinks simplemente detectan las URL compatibles con Acciones, las analizan y permiten a los usuarios interactuar con ellas en interfaces de usuario estandarizadas.

Info

Cualquier aplicación cliente que realice una introspección completa de una API de Acciones para construir una interfaz completa para ella es un blink. Por lo tanto, no todos los clientes que consumen una API de Acciones son blinks.

Una URL blink describe una aplicación cliente que permite a un usuario completar el ciclo de vida de una Acción, incluyendo la firma con su billetera.

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

Para que cualquier aplicación cliente se convierta en un blink:

  • La URL de un blink debe contener el parámetro action cuyo valor sea una URL codificada como URL de una Acción. Este valor debe ser codificado como URL para no entrar en conflicto con ningún otro parámetro del protocolo.

  • La aplicación cliente debe decodificar la URL del parámetro action e introspeccionar la API de acción correspondiente (véase URL de una Acción).

  • El cliente debe ofrecer una interfaz de usuario que permita completar el ciclo de vida de una Acción, incluida la firma con su billetera.

Info

No todas las aplicaciones cliente blink (por ejemplo: sitios web o dApps) soportarán todas las Acciones. Los desarrolladores de aplicaciones pueden elegir las Acciones que desean admitir en sus interfaces blink.

El siguiente ejemplo muestra una URL blink con el valor action de solana-action:https://actions.alice.com/donar codificado como URL:

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

Los blinks pueden ser enlazados a las Acciones en al menos 3 formas:

  1. Compartir una URL de acción explícita: solana-action:https://actions.alice.com/donar

    En este caso, solo los clientes compatibles pueden renderizar el blink. No habrá enlace de previsualización alternativa, o sitio que pueda ser visitado fuera del cliente compatible.

  2. Compartir un enlace a un sitio web vinculado a una API de Acciones a través de un archivo actions.json en la raíz del dominio del sitio web.

    Por ejemplo: https://alice.com/actions.json asigna https://alice.com/donar, la URL de un sitio web en el que los usuarios pueden donar a Alice, a la URL de la API https://actions.alice.com/donar, en la que se alojan las Acciones para donar a Alice.

  3. Incrustar una URL de Acción en la URL de un sitio “interstitial” que sepa cómo interpretar las Acciones.

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

Los clientes que admiten blinks deben ser capaces de tomar cualquiera de los formatos anteriores y renderizar una interfaz para facilitar la ejecución de la acción directamente en el cliente.

Para los clientes que no admiten blinks, debe haber un sitio web subyacente (haciendo que el navegador se convierta en la alternativa universal).

Si un usuario pulsa en cualquier parte de un cliente que no sea un botón de acción o un campo de entrada de texto debe ir al sitio web subyacente.

Mientras que las Acciones y Blinks de Solana son un protocolo/especificación que no requieren permisos, las aplicaciones cliente y las billeteras siguen siendo requeridas para facilitar a los usuarios firmar la transacción.

Cada una de estas aplicaciones cliente o billeteras pueden tener diferentes requisitos en cuanto al endpoints de Acción que desplegarán automáticamente e inmediatamente a sus usuarios en las plataformas de redes sociales.

Por ejemplo: algunos clientes pueden operar con un enfoque de "lista de permitidos" que puede requerir verificación antes de que su cliente implemente una Acción para usuarios como el Registro de Acciones de Dialect (detallado a continuación).

Todos los Blinks seguirán mostrándose y permitiendo firmar en el sitio intersticial de Dialect dial.to, con su estado de registro mostrado en el Blink.

Registro de Acciones de Dialect #

Como un bien público para el ecosistema de Solana, Dialect mantiene un registro público — junto con la ayuda de la Fundación Solana y otros miembros de la comunidad — de enlaces blockchain que tienen procedencia de fuentes conocidas previamente verificadas. A partir del lanzamiento, solo las Acciones que se hayan registrado en el registro de Dialect se desplegarán en Twitter cuando se publique.

Las aplicaciones cliente y billeteras pueden elegir libremente utilizar este registro público u otra solución para ayudar a garantizar la seguridad del usuario. Si no se verifica a través del registro de Dialect, el enlace blockchain no será tocado por el cliente Blink y se representará como una URL típica.

Los desarrolladores pueden solicitar ser verificados por Dialect aquí.

Especificación #

La especificación de Solana Actions consta de secciones clave que forman parte de un flujo de interacción solicitud/respuesta:

Cada una de estas solicitudes las realiza el Cliente de Acciones (por ejemplo: aplicación de una billetera, extensión de navegador, dApp, sitio web, etc.) para recopilar metadatos específicos para interfaces de usuario y facilitar la entrada de datos del usuario en la API de Acciones.

Cada una de las respuestas es elaborada por una aplicación (por ejemplo: sitio web, servidor backend, etc.) y devuelta al Cliente de Acciones. En última instancia, proporciona una transacción o mensaje firmable para que una billetera pida al usuario que lo apruebe, firme y se envíe a la cadena de bloques.

Esquema de URL #

Una URL de Acción de Solana describe una solicitud interactiva de una transacción o mensaje de Solana firmable mediante el protocolo solana-action.

La solicitud es interactiva porque los parámetros de la URL son utilizados por un cliente para realizar una serie de solicitudes HTTP estandarizadas para componer una transacción o mensaje firmable para que el usuario lo firme con su billetera.

solana-action:<link>
  • Se requiere un único campo link como nombre de ruta. El valor debe ser un URL HTTPS absoluto condicionalmente codificado.

  • Si la URL contiene parámetros de consulta, deben estar codificados como URL. La codificación URL del valor evita conflictos con cualquier parámetro del protocolo que puede añadirse a través de la especificación.

  • Si la URL no contiene parámetros de consulta, no debe codificarse como URL. Esto produce una URL más corta y un código QR menos denso.

En ambos casos, los clientes deben decodificar el valor. Esto no tiene ningún efecto si el valor no está codificado como URL. Si el valor decodificado no es una URL HTTPS absoluta, la billetera debe rechazarlo como malformado.

Respuesta OPTIONS #

Para permitir el Intercambio de Recursos entre Orígenes (o CORS por sus siglas en inglés) dentro de Acciones clientes (incluidos los blinks), todos los endpoints de Acción deben responder a las solicitudes HTTP para el método OPTIONS con cabeceras válidas que permitirán a los clientes pasar comprobaciones CORS para todas las solicitudes posteriores de su mismo dominio de origen.

Un cliente de Acciones puede realizar solicitudes de "verificación previa" al endpoint de la URL de Acción para verificar si la solicitud GET subsecuente a la URL de Acción pasará todas las comprobaciones de CORS. Estas verificaciones previas de CORS se realizan utilizando el método HTTP OPTIONS y deben responder con todas las cabeceras HTTP requeridas que permitirán a los clientes de Acción (como los blinks) realizar correctamente todas las solicitudes posteriores desde su dominio de origen.

Como mínimo, las cabeceras HTTP requeridas incluyen:

  • Access-Control-Allow-Origin con el valor *
    • esto garantiza que todos los clientes de Acción puedan pasar las comprobaciones CORS de forma segura para realizar todas las solicitudes requeridas
  • Access-Control-Allow-Methods con el valor GET,POST,PUT,OPTIONS
    • asegura que todos los métodos requeridos de peticiones HTTP sean compatibles con Acciones
  • Access-Control-Allow-Headers con un valor mínimo de Content Type, Authorization, Content-Encoding, Accept-Encoding

Por simplicidad, los desarrolladores deben considerar devolver la misma respuesta y cabecera a las solicitudes OPTIONS como su respuesta GET.

Cross-Origin headers for actions.json

La respuesta del archivo actions.json también debe devolver cabeceras de origen cruzado válidas para las solicitudes GET y OPTIONS, específicamente el valor de la cabecera Access-Control-Allow-Origin de *.

Consulte actions.json abajo para más detalles.

Solicitud GET #

El cliente de la Acción (por ejemplo: una billetera, extensión del navegador, etc.) debe realizar una solicitud HTTP GET JSON al endpoint URL de la Acción.

  • La solicitud no debe identificar la billetera ni al usuario.
  • El cliente debe realizar la solicitud con una cabecera Accept-Encoding.
  • El cliente debe mostrar el dominio de la URL mientras se realiza la solicitud.

Respuesta GET #

El endpoint de la URL de la Acción (por ejemplo: aplicación o servidor backend) debe responder con una respuesta HTTP OK JSON (con una información válida en el cuerpo) o un error HTTP apropiado.

Cuerpo de la respuesta GET #

Una respuesta GET con una respuesta HTTP OK JSON debe incluir un cuerpo que siga la especificación de la interfaz:

ActionGetResponse
export interface ActionGetResponse {
  /** url de la imagen que representa el origen de la solicitud de la acción */
  icon: string;
  /** describe el origen de la solicitud de la acción */
  title: string;
  /** breve resumen de la acción a realizar */
  description: string;
  /** texto del botón mostrado al usuario */
  label: string;
  /** Estado de la UI para el botón que se muestra al usuario */
  disabled?: boolean;
  links?: {
    /** lista de Acciones relacionadas que un usuario podría realizar */
    actions: LinkedAction[];
  };
  /** mensaje de error no fatal que se mostrará al usuario */
  error?: ActionError;
}
  • icon - El valor debe ser una URL HTTP o HTTPS absoluta de una imagen que representa un icono. El archivo debe ser una imagen SVG, PNG o WebP, o el cliente/billetera debe rechazarlo como malformado.

  • title - El valor debe ser una cadena de caracteres UTF-8 que represente el origen de la solicitud de la acción. Por ejemplo: podría ser el nombre de una marca, tienda, aplicación o persona que realiza la solicitud.

  • description - El valor debe ser una cadena de caracteres UTF-8 que proporcione información sobre la acción. La descripción debe mostrarse al usuario.

  • label - El valor debe ser una cadena de caracteres UTF-8 que se mostrará en un botón para que el usuario haga clic. Ninguna de las etiquetas deben superar las 5 palabras y deben comenzar con un verbo para informar al usuario de la acción a realizar. Por ejemplo: "Votar Si" o "Depositar fondos".

  • disabled - El valor debe ser booleano para representar el estado desactivado del botón renderizado (que muestra la etiqueta). Si no se proporciona ningún valor, disabled debe ser por defecto false (es decir, activado por defecto). Por ejemplo: si el endpoint de la acción es para una votación de gobernanza que se ha cerrado, establezca disabled=true y la label podría ser "Voto cerrado".

  • error - Una indicación de error opcional para errores no fatales. Si está presente, el cliente debe mostrarlo al usuario. Si se establece, no debe impedir que el cliente interprete la acción o dejar de mostrarla al usuario. Por ejemplo: el error se puede utilizar junto con disabled para mostrar razones como restricciones del negocio, autorización, el estado o un error de un recurso externo.

ActionError
export interface ActionError {
  /** mensaje de error no fatal que se mostrará al usuario */
  message: string;
}
  • links.actions - Un arreglo opcional de acciones relacionadas para el endpoint. Se debe mostrar a los usuarios una UI para cada una de las acciones enlistadas y esperar que solo una sea seleccionada para realizarse. Por ejemplo: un endpoint de acción de votación de gobernanza puede devolver tres opciones al usuario como "Votar Sí", "Votar No" y "Abstenerse de votar".

    • Si no se proporciona links.actions, el cliente debe mostrar un solo botón usando el string raíz label y realizar la solicitud POST al mismo endpoint que la solicitud GET inicial.

    • Si se proporciona algún links.actions, el cliente solo debe mostrar botones y campos de entrada basados ​​en los elementos enumerados en el campo links.actions. El cliente no debe mostrar un botón para el contenido del label raíz.

LinkedAction
export interface LinkedAction {
  /** URL para una acción */
  href: string;
  /** texto del botón mostrado al usuario */
  label: string;
  /** Parámetro para aceptar la entrada del usuario dentro de una acción */
  parameters?: [ActionParameter];
}
 
/** Parámetro para aceptar la entrada del usuario dentro de una acción */
export interface ActionParameter {
  /** nombre del parámetro en la url */
  name: string;
  /** texto para el campo de entrada del usuario */
  label?: string;
  /** declara si este campo es obligatorio (por defecto es `false`) */
  required?: boolean;
}

Ejemplo de respuesta GET #

El siguiente ejemplo de respuesta proporciona una única acción "raíz" que se espera que presente al usuario un único botón con la etiqueta "Reclamar token de acceso":

{
  "title": "Eventos HackerHouse,
  "icon": "<url-to-image>",
  "description": "Reclama tu token de acceso para la Hackerhouse.",
  "label": "Reclamar token de acceso" // texto del botón
}

El siguiente ejemplo de respuesta proporciona 3 enlaces de acción relacionados que permiten al usuario hacer clic en uno de los 3 botones para emitir su voto para una propuesta en una DAO:

{
  "title": "Plataforma Realms para DAOs",
  "icon": "<url-to-image>",
  "description": "Vota en la propuesta de gobernanza #1234 de la DAO.",
  "label": "Votar",
  "links": {
    "actions": [
      {
        "label": "Votar Si", // texto del botón
        "href": "/api/propuesta/1234/votar?respuesta=si"
      },
      {
        "label": "Votar No", // texto del botón
        "href": "/api/propuesta/1234/votar?respuesta=no"
      },
      {
        "label": "Abstenerse de votar", // texto del botón
        "href": "/api/propuesta/1234/votar?respuesta=nulo"
      }
    ]
  }
}

Ejemplo de respuesta GET con parámetros #

Los siguientes ejemplos demuestran cómo aceptar la entrada de texto del usuario (a través de parameters) e incluir esa entrada en la petición POST (a través del campo href dentro de un LinkedAction):

El siguiente ejemplo de respuesta proporciona al usuario 3 acciones vinculadas para hacer stake de SOL: un botón denominado "Stake 1 SOL", otro botón denominado "Stake 5 SOL" y un campo de entrada de texto que permite al usuario introducir un valor específico que se enviará a la API de Acciones:

{
  "title": "Stake-o-matic",
  "icon": "<url-to-image>",
  "description": "Stake SOL para ayudar a asegurar la red de Solana.",
  "label": "Stake SOL", // no se muestra ya que `links.actions` existe
  "links": {
    "actions": [
      {
        "label": "Stake 1 SOL", // texto del boton
        "href": "/api/stake?amount=1"
        // no hay `parameters` por lo que no es campo de texto
      },
      {
        "label": "Stake 5 SOL", // button text
        "href": "/api/stake?amount=5"
        // no hay `parameters` por lo que no es campo de texto
      },
      {
        "label": "Stake", // texto del boton
        "href": "/api/stake?amount={amount}",
        "parameters": [
          {
            "name": "cantidad", // nombre del campo
            "label": "cantidad en SOL" // placeholder del campo de texto
          }
        ]
      }
    ]
  }
}

El siguiente ejemplo de respuesta proporciona un único campo de entrada para que el usuario introduzca un monto que se envía con la solicitud POST (como parámetro de consulta o puede utilizarse una sub-ruta):

{
  "icon": "<url-to-image>",
  "label": "Donar SOL",
  "title": "Dona a la Caridad",
  "description": "Apoya a esta fundación por medio de donaciones en SOL.",
  "links": {
    "actions": [
      {
        "label": "Donar", // texto del botón
        "href": "/api/donar/{monto}", // o /api/donar?monto={monto}
        "parameters": [
          // {monto} campo de entrada
          {
            "name": "monto", // nombre del campo de la entrada
            "label": "Monto en SOL" // placeholder de la entrada de texto
          }
        ]
      }
    ]
  }
}

Solicitud POST #

El cliente debe hacer una petición HTTP POST JSON a la URL de la acción con un body de:

{
  "account": "<account>"
}
  • account - El valor debe ser la clave pública codificada en base58 de una cuenta que pueda firmar la transacción.

El cliente debe realizar la solicitud con una cabecera Accept-Encoding y la aplicación puede responder con una cabecera Content-Encoding para la compresión HTTP.

El cliente debe mostrar el dominio de la URL de la acción mientras se realiza la solicitud. Si se ha realizado una petición GET, el cliente también debe mostrar el title y renderizar la imagen icon de esa respuesta GET.

Respuesta POST #

El endpoint POST de la Acción debe responder con una respuesta JSON HTTP OK (con un payload válido en el cuerpo) o un error HTTP apropiado.

Cuerpo de la respuesta POST #

Una respuesta POST con una respuesta HTTP OK JSON debe incluir un cuerpo de:

ActionPostResponse
export interface ActionPostResponse {
  /** transacción serializada codificada en base64 */
  transaction: string;
  /** describe la naturaleza de la transacción */
  message?: string;
}
  • transaction - El valor debe ser una transacción serializada codificada en base64. El cliente debe decodificar en base64 la transacción y deserializarla.

  • message - El valor debe ser una cadena de caracteres UTF-8 que describa la naturaleza de la transacción incluida en la respuesta. El cliente debe mostrar este valor al usuario. Por ejemplo: puede ser el nombre de un artículo que se compra, un descuento aplicado a una compra o una nota de agradecimiento.

  • El cliente y la aplicación deben permitir campos adicionales en el cuerpo de la solicitud y en el cuerpo de la respuesta, que pueden ser añadidos por futuras actualizaciones de la especificación.

Info

La aplicación puede responder con una transacción parcial o totalmente firmada. El cliente y la billetera deben validar la transacción como no confiable.

Respuesta POST - Transacción #

Si las signatures de la transacción están vacías o la transacción NO se ha firmado parcialmente:

  • El cliente debe ignorar el feePayer en la transacción y establecer el feePayer del account en la solicitud.
  • El cliente debe ignorar el recentBlockhash en la transacción y establecer el recentBlockhash con el último blockhash.
  • El cliente debe serializar y deserializar la transacción antes de firmarla. Esto garantiza un orden coherente de las cuentas, como solución para este problema.

Si la transacción ha sido parcialmente firmada:

  • El cliente NO debe modificar el feePayer o el recentBlockhash ya que esto invalidaría cualquier firma existente.
  • El cliente debe verificar las firmas existentes y, si alguna no es válida, el cliente debe rechazar la transacción como mal formada.

El cliente sólo debe firmar la transacción con el account en la solicitud, y debe hacerlo sólo si se espera una firma para ese account en la solicitud.

Si se espera alguna firma excepto la firma del account en la solicitud, el cliente debe rechazar la transacción como maliciosa.

actions.json #

El propósito del archivo actions.json es permitirle a una aplicación indicar a los clientes qué URL de sitios web admiten Acciones de Solana y proporcionar una asignación que pueda utilizarse para realizar solicitudes GET a un servidor de API de Acciones.

Cross-Origin headers are required

La respuesta del archivo actions.json también debe devolver cabeceras de Origen Cruzado válidas para las solicitudes GET y OPTIONS, específicamente el valor de la cabecera Access-Control-Allow-Origin de *.

Vea Respuesta OPTIONS arriba para más detalles.

El archivo actions.json debe almacenarse y ser accesible universalmente en la raíz del dominio.

Por ejemplo: si su aplicación web se despliega en mi-sitio.com, el archivo actions.json debe estar accesible en https://mi-sitio.com/actions.json. Este archivo también debe ser accesible desde orígenes cruzados a través de cualquier navegador teniendo un valor de cabecera Access-Control-Allow-Origin de *.

Reglas #

El campo rules (reglas) permite a la aplicación asignar un conjunto de rutas relativas de un sitio web a un conjunto de otras rutas.

Type: Array de ActionRuleObject.

ActionRuleObject
interface ActionRuleObject {
  /** ruta relativa (preferida) o absoluta para realizar la asignación de reglas  */
  pathPattern: string;
  /** ruta relativa (preferida) o absoluta que admita solicitudes de acción */
  apiPath: string;
}
  • pathPattern - Un patrón que coincide con cada nombre de ruta entrante.

  • apiPath - Un destino de ubicación definido como una ruta absoluta o una URL externa.

Reglas - pathPattern #

Un patrón que coincide con cada nombre de ruta entrante. Puede ser una ruta absoluta o relativa y admite los siguientes formatos:

  • Coincidencia Exacta: Coincide con la ruta URL exacta.

    • Ejemplo: /exact-path
    • Ejemplo: https://website.com/exact-path
  • Coincidencia por Comodín: Utiliza comodines para hacer coincidir cualquier secuencia de caracteres en la ruta URL. Puede coincidir con segmentos individuales (utilizando *) o múltiples (utilizando **). (Véase Coincidencia de Rutas más abajo).

    • Ejemplo: /intercambiar/* coincidirá con /intercambiar/123 y /intercambiar/abc, capturando sólo el primer segmento después de /intercambiar/.
    • Ejemplo: /categoria/*/objeto/** coincidirá con /categoria/123/objeto/456 y /categoria/abc/objeto/def.
    • Ejemplo: /api/actions/intercambiar/*/confirmar coincidirá con /api/actions/intercambiar/123/confirmar.

Reglas - apiPath #

La ruta de destino de la acción solicitada. Puede definirse como una ruta absoluta o una URL externa.

  • Ejemplo: /api/categoria/*/objeto/*
  • Ejemplo: https://api.ejemplo.com/v1/donar/*
  • Ejemplo: /api/categoria/*/objeto/*
  • Ejemplo: /api/swap/**

Reglas - Parámetros de Consulta #

Los Parámetros de Consulta de la URL original siempre se conservan y se añaden a la URL asignada.

Reglas - Coincidencia de Rutas #

La siguiente tabla muestra la sintaxis de los patrones de coincidencia de ruta:

OperadorCoincidencias
*Un único segmento de ruta, sin incluir los caracteres / separadores de ruta.
**Coincide con cero o más caracteres, incluido cualquier separador de ruta / entre varios segmentos de ruta. Si se incluyen otros operadores, el operador ** debe ser el último.
?Patrón no soportado.

Ejemplos de reglas #

El siguiente ejemplo muestra una regla de coincidencia exacta para asignar solicitudes a /comprar desde la raíz de su sitio a la ruta exacta /api/comprar relativa a la raíz de su sitio:

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

El siguiente ejemplo utiliza la coincidencia de rutas con comodines para asignar solicitudes a cualquier ruta (excluyendo subdirectorios) en /actions/ desde la raíz de su sitio a una ruta correspondiente en /api/actions/ relativa a la raíz de su sitio:

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

El siguiente ejemplo utiliza una coincidencia de rutas con comodines para asignar solicitudes a cualquier ruta (excluyendo subdirectorios) en /donate/ desde la raíz de su sitio a una ruta absoluta correspondiente https://api.dialect.com/api/v1/donate/ en un sitio externo:

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

El siguiente ejemplo utiliza la coincidencia de rutas con comodines para una regla idempotente que asigna solicitudes a cualquier ruta (incluidos los subdirectorios) en /api/actions/ desde la raíz de su sitio hasta sí mismo:

Info

Las reglas idempotentes permiten a los clientes Blink determinar fácilmente si una ruta admite solicitudes de API de Acción sin tener que tener el prefijo solana-action: ni realizar pruebas adicionales.

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

Identidad de la Acción #

La transacción retornada en la respuesta del POST puede incluir una Identidad. Esto permite a los indexadores y plataformas de análisis saber fácilmente y con veracidad qué Proveedor de Acciones (es decir, un servicio) originó la actividad.

La Identidad de la Acción es un par de llaves que se utiliza para firmar un mensaje que tiene un formato especial y se incluye en la transacción mediante una instrucción Memo. Este Mensaje Identificador garantiza la veracidad de la Identidad de la Acción y, por lo tanto, permite atribuir transacciones a un Proveedor de Acciones específico.

No se requiere que el par de llaves firme la transacción en sí. Esto permite que las billeteras y aplicaciones mejoren la capacidad de entrega de las transacciones cuando no hay otras firmas en la transacción devuelta al usuario (consulte transacción de respuesta POST).

Si el caso de uso de un Proveedor de Acciones requiere que su servicio firme previamente la transacción antes de que lo haga el usuario, deben usar este par de llaves como su Identidad de Acción. Esto permitirá incluir una cuenta menos en la transacción, lo que reducirá el tamaño total de las transacciones en 32 bytes.

Mensaje de Identificación de la Acción #

El Mensaje de Identificación de la Acción es una cadena de caracteres UTF-8 separada por dos puntos incluida en una transacción mediante una única instrucción SPL Memo.

protocol:identity:reference:signature
  • protocol: el valor del protocolo que se utiliza (establecido como solana-action según el esquema URL anterior)
  • identity: el valor debe ser la dirección de llave pública codificada en base58 del par de llaves de la Identidad de la Acción
  • reference: el valor debe ser un arreglo de 32 bytes codificado en base58. Estas pueden ser o no llaves públicas, dentro o fuera de la curva, y pueden corresponder o no con cuentas de Solana.
  • signature: firma codificada en base58 creada a partir del par de llaves de la Identidad de la Acción que firma solo el valor de reference.

El valor de reference debe usarse solo una vez y en una sola transacción. A los efectos de asociar transacciones con un Proveedor de Acciones, solo se considera válido el primer uso del valor de reference.

Las transacciones pueden tener múltiples instrucciones Memo. Al realizar un getSignaturesForAddress, el campo memo de los resultados devolverá un mensaje que incluye todos los memos, cada uno separado por punto y coma.

No se deben incluir otros datos en la instrucción Memo del Mensaje de Identificación.

La identity y la reference deben incluirse como claves de solo lectura y sin firma en la transacción, en una instrucción que NO es la instrucción Memo de Mensaje de Identificación.

La instrucción Memo del Mensaje de Identificación no debe tener ninguna cuenta. Si se proporciona alguna cuenta, el programa Memo requiere que todas esas cuentas provean una firma válida. A los efectos de identificar acciones, esto restringe la flexibilidad y puede degradar la experiencia del usuario. Por lo tanto, se considera un antipatrón y debe evitarse.

Verificación de identidad de la Acción #

Cualquier transacción que incluya la cuenta identity se puede asociar de manera verificable con el Proveedor de Acciones en un proceso de varios pasos:

  1. Obtenga todas las transacciones para una identity determinada.
  2. Analice y verifique la cadena de caracteres del memo de cada transacción, asegurando que signature es una firma válida para la reference.
  3. Verifique que la transacción sea la primera ocurrencia de reference en la cadena de bloques:
    • Si esta transacción es la primera ocurrencia, la transacción se considera verificada y puede atribuirse de manera segura al Proveedor de Acciones.
    • Si esta transacción NO es la primera ocurrencia, se considera inválida y, por lo tanto, no se atribuye al Proveedor de Acciones.

Debido a que los validadores de Solana indexan las transacciones según las llaves de las cuentas, se puede utilizar el método RPC getSignaturesForAddress para obtener todas las transacciones que incluyen la cuenta que corresponde a identity.

La respuesta de este método del RPC incluye toda la información del campo memo. Si se utilizaron varias instrucciones Memo en la transacción, cada mensaje memo se incluirá en este campo memo y el verificador deberá analizarlo para obtener el Mensaje de Verificación de Identidad.

Estas transacciones deben considerarse inicialmente NO VERIFICADAS. Esto se debe a que no se requiere la identity para firmar la transacción, lo que permite que cualquier transacción incluya esta cuenta sin su firma. Potencialmente inflando de manera artificial el consumo de recursos.

Se debe verificar el Mensaje de Verificación de Identidad para garantizar que la signature fue creada por la identity que firma la reference. Si la verificación de la firma falla, la transacción es inválida y debe atribuirse al Proveedor de Acciones.

Si la verificación de la firma es exitosa, el verificador debe asegurarse de que esta transacción sea la primera aparición reference en la cadena de bloques. Si no es así, la transacción se considera inválida.