Actions e Blinks

Solana Actions são APIs que seguem especificações e retornam transações na blockchain da Solana para serem visualizadas, assinadas e enviadas em diversos contextos, incluindo QR codes, botões, widgets e sites na internet. Actions facilitam a vida dos desenvolvedores ao permitir que eles integrem as funcionalidades do ecossistema Solana diretamente em seus ambientes, possibilitando a realização de transações blockchain sem precisar sair do aplicativo ou página atual.

Links de blockchain – ou blinks – transformam qualquer Solana Action em um link compartilhável e rico em metadados. Blinks permitem que clients que entendem Actions (como carteiras de extensão de navegador e bots) exibam capacidades adicionais para o usuário. Em um site, um blink pode imediatamente acionar uma pré-visualização de transação em uma carteira sem ir para um aplicativo descentralizado; no Discord, um bot pode expandir o blink em um conjunto interativo de botões. Isso leva a capacidade de interação on-chain para qualquer superfície web capaz de exibir uma URL.

Get Started #

To quickly get started with creating custom Solana Actions:

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

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

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

When deploying your custom Solana Actions to production:

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

Action #

A especificação Solana Actions usa um conjunto de APIs padrão para entregar transações assináveis (e eventualmente mensagens assináveis) de um aplicativo diretamente para um usuário. Elas são hospedadas em URLs acessíveis publicamente e, portanto, acessíveis por qualquer client via URL para interação.

Info

Você pode pensar em Actions como um endpoint de API que retornará metadados e algo para o usuário assinar (uma transação ou uma mensagem de autenticação) com sua carteira blockchain.

A API Actions consiste em fazer requisições simples GET e POST para o endpoint da URL de uma Action e tratar as respostas que seguem a interface de Actions.

  1. A requisição GET retorna metadados que fornecem informações legíveis para o client sobre quais ações estão disponíveis nessa URL, e uma lista opcional de ações relacionadas.
  2. A requisição POST retorna uma transação ou mensagem assinável que o client então solicita à carteira do usuário para assinar e executar na blockchain ou em outro serviço off-chain.

Execução e Ciclo de Vida de uma Action #

Na prática, interagir com Actions é bem parecido com interagir com uma API REST típica:

  • um client faz a requisição inicial GET para uma URL Action, para obter metadados sobre as Actions disponíveis
  • o endpoint retorna uma resposta que inclui metadados sobre o endpoint (como o título e o ícone do aplicativo) e uma lista das ações disponíveis para esse endpoint
  • o aplicativo client (como uma carteira móvel, bot de chat ou site) exibe uma interface para o usuário realizar uma das ações
  • depois que o usuário seleciona uma ação (clicando em um botão), o client faz uma requisição POST para o endpoint obter a transação que o usuário deve assinar
  • a carteira facilita a assinatura da transação pelo usuário e, finalmente, envia a transação para a blockchain para confirmação

Execução e Ciclo de Vida da Solana ActionsExecução e Ciclo de Vida da Solana Actions

Ao receber transações de uma URL de Actions, os clients devem gerenciar o envio dessas transações para a blockchain e gerenciar seu ciclo de vida de estado.

Actions também suportam algum nível de invalidação antes da execução. As requisições GET e POST podem retornar alguns metadados que informam se a ação pode ser realizada (como com o campo disabled).

Por exemplo, se houver um endpoint de Action que facilita a votação em uma proposta de governança de DAO cujo período de votação já encerrou, a requisição GET inicial pode retornar a mensagem de erro "Esta proposta não está mais aberta para votação" e os botões "Votar Sim" e "Votar Não" como "desabilitados".

Blinks (links de blockchain) são aplicações client que inspecionam APIs de Action e constroem interfaces de usuário para interagir e executar Actions.

Aplicações client que suportam blinks simplesmente detectam URLs compatíveis com Actions, as interpretam e permitem que os usuários interajam com elas em interfaces de usuário padronizadas.

Info

Qualquer aplicação client que inspecione completamente uma API de Actions para construir uma interface completa para ela é um blink. Portanto, nem todos os clients que consomem APIs Actions são blinks.

Uma URL de blink descreve uma aplicação client que permite ao usuário completar todo o ciclo de vida da execução de uma Action, incluindo assinar com sua carteira.

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

Para qualquer aplicação client se tornar um blink:

  • A URL blink deve conter um parâmetro de consulta action cujo valor é uma URL de Action codificada (URL da ação](#url-scheme). Este valor deve ser URL-encoded para não conflitar com outros parâmetros de protocolo.

  • A aplicação client deve URL-decode o parâmetro de consulta action e analisar o link da API Action fornecido (veja esquema de URL Action).

  • O client deve renderizar uma interface de usuário rica que permita ao usuário completar o ciclo completo de execução de uma Action(#action-execution-and-lifecycle), incluindo a assinatura com sua carteira.

Info

Nem todas as aplicações client de blink (por exemplo, sites ou dApps) suportarão todas as Actions. Os desenvolvedores de aplicativos podem escolher quais Actions desejam suportar dentro de suas interfaces de blink.

O exemplo a seguir demonstra uma URL de blink válida com um valor action de solana-action:https://actions.alice.com/donate que está codificado na URL:

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

Blinks podem ser vinculados aos Actions de pelo menos 3 maneiras:

  1. Compartilhando uma URL Action explícita: solana-action:https://actions.alice.com/donate

    Nesse caso, apenas clients compatíveis podem renderizar o blink. Não haverá uma pré-visualização do link ou um site que possa ser visitado fora do client não compatível.

  2. Compartilhando um link para um site que esteja vinculado a uma API de Actions por meio de um arquivo actions.json file na raiz do domínio do site.

    Por exemplo, https://alice.com/actions.json mapeia https://alice.com/donate, uma URL de site onde os usuários podem doar para Alice, para a URL da API https://actions.alice.com/donate, onde Actions para doações a Alice estão hospedadas.

  3. Incorporando uma URL de Action em uma URL de site "intermediário" que entende como analisar Actions.

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

Clients que suportam blinks devem ser capazes de usar qualquer um dos formatos acima e renderizar corretamente uma interface para facilitar a execução da ação diretamente no client.

Para clients que não suportam blinks, deve haver um site subjacente (fazendo com que o navegador se torne a solução universal).

Se um usuário tocar em qualquer lugar do client que não seja um botão de ação ou campo de entrada de texto, ele deve ser levado ao site subjacente.

Embora Solana Actions e blinks sejam um protocolo/especificação sem permissões, aplicações client e carteiras ainda são necessárias para facilitar a assinatura da transação pelos usuários.

Cada uma dessas aplicações client ou carteiras pode ter diferentes requisitos sobre quais endpoints de Action seus clients irão expandir automaticamente e exibir imediatamente para seus usuários nas plataformas de mídia social.

Por exemplo, alguns clients podem operar com uma abordagem de "lista de permissão" que pode exigir verificação antes de seus clients expandirem uma Action para os usuários, como o Registro de Actions da Dialect (detalhado abaixo).

Todos os blinks ainda serão renderizados e permitirão a assinatura no dial.to site intersticial de blinks da Dialect, com seu status de registro exibido no blink.

Registro de Actions da Dialect #

Como um bem público para o ecossistema Solana, a Dialect mantém um registro público — juntamente com a ajuda da Solana Foundation e outros membros da comunidade — de links de blockchain que foram pré-verificados de fontes conhecidas. Desde o lançamento, apenas Actions registradas no registro da Dialect serão expandidas no feed do Twitter quando postadas.

Aplicações client e carteiras podem escolher livremente usar esse registro público ou outra solução para ajudar a garantir a segurança e a proteção dos usuários. Se não for verificado pelo registro da Dialect, o link de blockchain não será tocado pelo client blink e será renderizado como uma URL típica.

Os desenvolvedores podem se inscrever para serem verificados pela Dialect aqui: dial.to/register

Especificação #

A especificação do Solana Actions é composta por seções principais que fazem parte do fluxo de interação de requisição/resposta:

Cada uma dessas requisições é feita pelo Action client (por exemplo, aplicativo de carteira, extensão de navegador, dApp, site, etc) para coletar metadados específicos e facilitar a interação do usuário com a API de Actions.

Cada uma das respostas é elaborada por uma aplicação (por exemplo, site, backend de servidor, etc) e retornada ao Action client. O objetivo final é fornecer uma transação ou mensagem assinável para que a carteira do usuário solicite a aprovação, assinatura e envio para a blockchain.

Esquema da URL #

Uma URL de Action da Solana descreve uma requisição interativa para uma transação ou mensagem assinável da Solana usando o protocolo solana-action.

A requisição é interativa porque os parâmetros na URL são usados por um client para fazer uma série de requisições HTTP padronizadas para compor uma transação ou mensagem assinável para o usuário assinar com sua carteira.

solana-action:<link>
  • Um único campo de link é necessário como o caminho. O valor deve ser uma URL HTTPS absoluta condicionalmente codificada na URL-encoded.

  • Se a URL contiver parâmetros de consulta, ela deve ser codificada. Codificar a URL evita conflitos com quaisquer parâmetros de protocolo de Actions, que podem ser adicionados via especificação de protocolo.

  • Se a URL não contiver parâmetros de consulta, ela não deve ser codificada. Isso produz uma URL mais curta e um código QR menos denso.

Em ambos os casos, os clients devem decodificar o valor da URL-decode. Isso não tem efeito se o valor não estiver como URL codificado. Se o valor decodificado não for uma URL HTTPS absoluta, a carteira deve rejeitá-lo como malformado.

Resposta OPTIONS #

Para permitir o Cross-Origin Resource Sharing (CORS) dentro dos clients de Actions (incluindo blinks), todos os endpoints de Action devem responder a requisições HTTP para o método OPTIONS com cabeçalhos válidos que permitirão que os clients passem nas verificações de CORS para todas as requisições subsequentes do mesmo domínio de origem.

Um client de Actions pode realizar requisições de "preflight" para o endpoint da URL de Action a fim de verificar se a requisição GET subsequente para a URL de Action passará em todas as verificações de CORS. Essas verificações de preflight CORS são feitas usando o método HTTP OPTIONS e devem responder com todos os cabeçalhos HTTP necessários que permitirão que os clients de Actions (como blinks) façam adequadamente todas as requisições subsequentes do seu domínio de origem.

No mínimo, os cabeçalhos HTTP necessários incluem:

  • Access-Control-Allow-Origin com um valor de *
    • isso garante que todos os clients de Actions possam passar nas verificações de CORS para fazer todas as requisições necessárias
  • Access-Control-Allow-Methods com um valor de GET,POST,PUT,OPTIONS
    • garante que todos os métodos de requisição HTTP necessários sejam suportados para Actions
  • Access-Control-Allow-Headers com um valor mínimo de Content-Type, Authorization, Content-Encoding, Accept-Encoding

Para simplicidade, os desenvolvedores devem considerar retornar a mesma resposta e cabeçalhos para as requisições OPTIONS que para as respostas GET response.

Cross-Origin headers for actions.json

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

See actions.json below for more details.

Requisição GET #

O Action client (por exemplo, carteira, extensão de navegador, etc) deve fazer uma requisição HTTP GET JSON para o endpoint da URL da Action.

  • A requisição não deve identificar a carteira ou o usuário.
  • O client deve fazer a requisição com um cabeçalho Accept-Encoding.
  • O client deve exibir o domínio da URL enquanto a requisição está sendo feita.

Resposta GET #

O endpoint da URL da Action (por exemplo, aplicação ou backend de servidor) deve responder com uma resposta HTTP OK JSON (com um payload válido no corpo) ou um erro HTTP apropriado.

Corpo da Resposta GET #

Uma resposta GET com uma resposta HTTP OK JSON deve incluir um payload no corpo que siga a especificação da interface:

ActionGetResponse
export interface ActionGetResponse {
  /** URL da imagem que representa a origem da solicitação de ação */
  icon: string;
  /** descreve a origem da solicitação de ação */
  title: string;
  /** resumo breve da ação a ser realizada */
  description: string;
  /** texto do botão renderizado para o usuário */
  label: string;
  /** estado da UI para o botão sendo renderizado para o usuário */
  disabled?: boolean;
  links?: {
    /** lista de Actions relacionadas que um usuário pode realizar */
    actions: LinkedAction[];
  };
  /** mensagem de erro não fatal a ser exibida para o usuário */
  error?: ActionError;
}
  • icon- O valor deve ser uma URL HTTP ou HTTPS absoluta de uma imagem de ícone. O arquivo deve ser uma imagem SVG, PNG ou WebP, ou o client/carteira deve rejeitá-lo como malformado.

  • title- O valor deve ser uma string UTF-8 que representa a origem da requisição de ação. Por exemplo, isso pode ser o nome de uma marca, loja, aplicativo ou pessoa que está fazendo a solicitação.

  • description - O valor deve ser uma string UTF-8 que fornece informações sobre a ação. A descrição deve ser exibida para o usuário.

  • label - O valor deve ser uma string UTF-8 que será renderizada em um botão para o usuário clicar. Todos os rótulos não devem exceder frases de 5 palavras e devem começar com um verbo para solidificar a ação que você deseja que o usuário realize. Por exemplo, "Mint NFT", "Vote Yes" ou "Stake 1 SOL".

  • disabled - O valor deve ser booleano para representar o estado desabilitado do botão renderizado (que exibe o string label). Se nenhum valor for fornecido, disabled deve ser padrão como false (ou seja, habilitado por padrão). Por exemplo, se o endpoint de ação for para uma votação de governança que foi encerrada, defina disabled=true e o label pode ser "Vote Closed".

  • error - Uma indicação opcional de erro não fatal. Se presente, o client deve exibi-la para o usuário. Se definido, não deve impedir o client de interpretar a ação ou exibi-la para o usuário. Por exemplo, o erro pode ser usado junto com disabled para exibir um motivo, como restrições comerciais, autorização, estado ou um erro de recurso externo.

ActionError
export interface ActionError {
  /** mensagem de erro não fatal a ser exibida para o usuário */
  message: string;
}
  • links.actions - Um array opcional de ações relacionadas para o endpoint. Os usuários devem ver a UI para cada uma das ações listadas e devem realizar apenas uma. Por exemplo, um endpoint de ação de votação de governança pode retornar três opções para o usuário: "Vote Yes", "Vote No" e "Abstain from Vote".

    • Se nenhum links.actions for fornecido, o client deve renderizar um único botão usando a string label raiz e fazer a requisição POST para o mesmo endpoint de URL de ação que a requisição GET inicial.

    • Se quaisquer links.actions forem fornecidos, o client deve renderizar apenas botões e campos de entrada baseados nos itens listados no campo links.actions. O client não deve renderizar um botão para o conteúdo do label raiz.

LinkedAction
export interface LinkedAction {
  /** endpoint de URL para uma ação */
  href: string;
  /** texto do botão renderizado para o usuário */
  label: string;
  /** Parâmetro para aceitar a entrada do usuário dentro de uma ação */
  parameters?: [ActionParameter];
}
 
/** Parâmetro para aceitar a entrada do usuário dentro de uma ação */
export interface ActionParameter {
  /** nome do parâmetro na url */
  name: string;
  /** texto do placeholder para o campo de entrada do usuário */
  label?: string;
  /** declarar se este campo é obrigatório (padrão é `false`) */
  required?: boolean;
}

Exemplo de Resposta GET #

A resposta de exemplo a seguir fornece uma única ação "root" que deve ser apresentada ao usuário como um único botão com o rótulo "Claim Access Token":

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

A resposta de exemplo a seguir fornece 3 links de ações relacionadas que permitem ao usuário clicar em um dos 3 botões para votar em uma proposta de DAO:

{
  "title": "Realms DAO Platform",
  "icon": "<url-to-image>",
  "description": "Vote nas propostas de governança DAO #1234.",
  "label": "Vote",
  "links": {
    "actions": [
      {
        "label": "Vote Yes", // texto do botão
        "href": "/api/proposal/1234/vote?choice=yes"
      },
      {
        "label": "Vote No", // texto do botão
        "href": "/api/proposal/1234/vote?choice=no"
      },
      {
        "label": "Abstain from Vote", // texto do botão
        "href": "/api/proposal/1234/vote?choice=abstain"
      }
    ]
  }
}

Exemplo de Resposta GET com Parâmetros #

A resposta de exemplo a seguir demonstra como aceitar entrada de texto do usuário (via parâmetros) e incluir essa entrada no endpoint da requisição POST final (via o campo href dentro de um LinkedAction):

A resposta de exemplo a seguir fornece ao usuário 3 ações vinculadas para fazer stake de SOL: um botão rotulado "Stake 1 SOL", outro botão rotulado "Stake 5 SOL" e um campo de entrada de texto que permite ao usuário inserir um valor específico "amount" que será enviado para a API Action:

{
  "title": "Stake-o-matic",
  "icon": "<url-to-image>",
  "description": "Stake SOL para ajudar manter a rede da Solana segura",
  "label": "Stake SOL", // não exibido, pois `links.actions` são fornecidos
  "links": {
    "actions": [
      {
        "label": "Stake 1 SOL", // texto do botão
        "href": "/api/stake?amount=1"
        // sem `parameters`, portanto, não é um campo de entrada de texto
      },
      {
        "label": "Stake 5 SOL", // texto do botão
        "href": "/api/stake?amount=5"
        // sem `parameters`, portanto, não é um campo de entrada de texto
      },
      {
        "label": "Stake", // texto do botão
        "href": "/api/stake?amount={amount}",
        "parameters": [
          {
            "name": "amount", // nome do campo
            "label": "Quantidade de SOL" // texto de placeholder
          }
        ]
      }
    ]
  }
}

A resposta de exemplo a seguir fornece um único campo de entrada para o usuário inserir um amount que é enviado com a requisição POST (podendo ser usado como um parâmetro de consulta ou um subcaminho):

{
  "icon": "<url-to-image>",
  "label": "Donate SOL",
  "title": "Doe para a GoodCause Charity",
  "description": "Ajude a apoiar esta instituição de caridade doando SOL.",
  "links": {
    "actions": [
      {
        "label": "Donate", // texto do botão
        "href": "/api/donate/{amount}", // ou /api/donate?amount={amount}
        "parameters": [
          // campo de entrada {amount}
          {
            "name": "amount", // nome do campo de entrada
            "label": "Quantidade de SOL" // texto do placeholder
          }
        ]
      }
    ]
  }
}

Requisição POST #

O client deve fazer uma requisição HTTP POST JSON para a URL da ação com um payload no corpo de:

{
  "account": "<account>"
}
  • account - O valor deve ser a chave pública codificada em base58 de uma conta que pode assinar a transação.

O client deve fazer a requisição com um cabeçalho Accept-Encoding header e a aplicação pode responder com um cabeçalho Content-Encoding header para compressão HTTP.

O client deve exibir o domínio da URL da ação enquanto a requisição está sendo feita. Se uma requisição GET foi feita, o client também deve exibir o title e renderizar a imagem do icon dessa resposta GET.

Resposta POST #

O endpoint POST da Action deve responder com uma resposta HTTP OK JSON (com um payload válido no corpo) ou um erro HTTP apropriado.

Corpo da Resposta POST #

Uma resposta POST com uma resposta HTTP OK JSON deve incluir um payload no corpo de:

ActionPostResponse
export interface ActionPostResponse {
  /** transação serializada e codificada em base64 */
  transaction: string;
  /** descreve a natureza da transação */
  message?: string;
}
  • transaction - O valor deve ser uma transação transação serializada codificada em base64. O client deve decodificar a transação de base64 e desserializá-la.

  • message - O valor deve ser uma string UTF-8 que descreve a natureza da transação incluída na resposta. O client deve exibir esse valor para o usuário. Por exemplo, pode ser o nome de um item sendo comprado, um desconto aplicado a uma compra ou uma nota de agradecimento.

  • O client e a aplicação devem permitir campos adicionais no corpo da requisição e no corpo da resposta, que podem ser adicionados por atualizações futuras da especificação.

Info

A aplicação pode responder com uma transação parcialmente ou totalmente assinada. O client e a carteira devem validar a transação como não confiável.

Resposta POST - Transação #

Se as assinaturas na transação estiverem vazias ou a transação NÃO tiver sido parcialmente assinada:

  • O client deve ignorar o feePayer na transação e definir o feePayer como a account na requisição.
  • O client deve ignorar o recentBlockhash na transação e definir o recentBlockhash como o último blockhash.
  • O client deve serializar e desserializar a transação antes de assiná-la. Isso garante a ordenação consistente das chaves de conta, como uma solução para este problema.

Se a transação foi parcialmente assinada:

  • O client NÃO deve alterar o feePayer ou o recentBlockhash, pois isso invalidaria quaisquer assinaturas existentes.
  • O client deve verificar as assinaturas existentes e, se alguma for inválida, o client deve rejeitar a transação como malformada.

O client deve assinar a transação apenas com a account na requisição, e deve fazê-lo apenas se uma assinatura para a account na requisição for esperada.

Se qualquer assinatura, exceto uma assinatura para a account na requisição, for esperada, o client deve rejeitar a transação como maliciosa.

actions.json #

O propósito do arquivo actions.json permite que uma aplicação instrua clients sobre quais URLs de site suportam Solana Actions e forneça um mapeamento que pode ser usado para realizar requisições GET para um servidor de API de Actions.

Cross-Origin headers are required

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

See OPTIONS response above for more details.

O arquivo actions.json deve ser armazenado e acessível universalmente na raiz do domínio.

Por exemplo, se sua aplicação web estiver implantada em my-site.com, então o arquivo actions.json deve ser acessível em https://my-site.com/actions.json. This file should also be Cross-Origin accessible via any browser by having a Access-Control-Allow-Origin header value of *.

Regras #

O campo rules permite que a aplicação mapeie um conjunto de caminhos relativos de rota de um site para um conjunto de outros caminhos.

Tipo: Array de ActionRuleObject.

ActionRuleObject
interface ActionRuleObject {
  /** caminho relativo (preferido) ou absoluto para realizar o mapeamento de regra */
  pathPattern: string;
  /** caminho relativo (preferido) ou absoluto que suporta requisições action */
  apiPath: string;
}
  • pathPattern - Um padrão que corresponde a cada caminho de entrada.

  • apiPath - Um destino definido como um caminho absoluto ou URL externa.

Regras - pathPattern #

Um padrão que corresponde a cada caminho de entrada. Pode ser um caminho absoluto ou relativo e suporta os seguintes formatos:

  • Correspondência Exata: Corresponde exatamente ao caminho da URL.

    • Exemplo: /exact-path
    • Exemplo: https://website.com/exact-path
  • Correspondência Coringa: Usa curingas para corresponder a qualquer sequência de caracteres no caminho da URL. Isso pode corresponder a segmentos únicos (usando *) ou múltiplos segmentos (usando **). (veja Correspondência de Caminhos abaixo).

    • Exemplo: /trade/* corresponderá a /trade/123 e /trade/abc, capturando apenas o primeiro segmento após /trade/.
    • Exemplo: /category/*/item/** corresponderá a /category/123/item/456 e /category/abc/item/def.
    • Exemplo: /api/actions/trade/*/confirm corresponderá a /api/actions/trade/123/confirm.

Regras - apiPath #

O caminho de destino para a requisição action. Pode ser definido como um caminho absoluto ou uma URL externa.

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

Regras - Parâmetros de Consulta #

Os parâmetros de consulta da URL original são sempre preservados e anexados à URL mapeada.

Regras - Correspondência de Caminho #

A tabela a seguir descreve a sintaxe para padrões de correspondência de caminho:

OperadorCorresponde
*Um único segmento de caminho, não incluindo o caractere separador de caminho circundante /.
**```

Corresponde a zero ou mais caracteres, incluindo qualquer caractere separador de caminho / entre múltiplos segmentos de caminho. Se outros operadores estiverem incluídos, o operador ** deve ser o último operador.

| `?`      | Padrão não suportado.                                                                                                                                                                                          |
 
### Exemplos de Regras
 
O exemplo a seguir demonstra uma regra de correspondência exata para mapear requisições para `/buy` da raiz do seu site para o caminho exato `/api/buy` relativo à raiz do seu site:
 
```json filename="actions.json"
{
  "rules": [
    {
      "pathPattern": "/buy",
      "apiPath": "/api/buy"
    }
  ]
}

O exemplo a seguir usa correspondência de caminho coringa para mapear requisições para qualquer caminho (excluindo subdiretórios) sob /actions/ da raiz do seu site para um caminho correspondente sob /api/actions/relativo à raiz do seu site:

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

O exemplo a seguir usa correspondência de caminho coringa para mapear requisições para qualquer caminho (excluindo subdiretórios) sob /donate/ da raiz do seu site para um caminho absoluto correspondente https://api.dialect.com/api/v1/donate/ em um site externo:

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

O exemplo a seguir usa correspondência de caminho com coringa para uma regra idempotente para mapear requisições para qualquer caminho (incluindo subdiretórios) sob /api/actions/ da raiz do seu site para ele mesmo:

Info

Regras idempotentes permitem que clients de blink determinem mais facilmente se um determinado caminho suporta requisições de API action sem precisar ser prefixado com o URI solana-action:ou realizar testes de resposta adicionais.

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

Identidade do Action #

Os endpoints de Action podem incluir uma Identidade de Ação nas transações que são retornadas na resposta POST para o usuário assinar. Isso permite que indexadores e plataformas de análise atribuam facilmente e de maneira verificável a atividade on-chain a um Provedor de Ação específico (ou seja, serviço) de forma verificável.

A Identidade da Action é um par de chaves usado para assinar uma mensagem formatada especialmente que é incluída na transação usando uma instrução de Memo. Essa Identifier Message pode ser atribuída de forma verificável a uma Identidade da Ação específica, e, portanto, atribuir transações a um Provedor de Ação específico.

O par de chaves não é necessário para assinar a própria transação. Isso permite que carteiras e aplicativos melhorem a entregabilidade das transações quando nenhuma outra assinatura está na transação retornada para um usuário (veja transação de resposta POST).

Se o caso de uso de um Provedor de Ação exigir que seus serviços de backend pré-assinem a transação antes do usuário, eles devem usar este par de chaves como sua Identidade de Ação. Isso permitirá que uma conta a menos seja incluída na transação, reduzindo o tamanho total das transações em 32 bytes.

Mensagem de Identificação de Ação #

A Mensagem de Identificação de Ação é uma string UTF-8 separada por dois pontos incluída em uma transação usando uma única instrução SPL Memo.

protocol:identity:reference:signature
  • protocol - O valor do protocolo sendo usado (definido como solana-action conforme o Esquema de URL acima)
  • identity- O valor deve ser o endereço da chave pública codificado em base58 do par de chaves da Identidade de Ação
  • reference - O valor deve ser uma array de 32 bytes codificado em base58. Isso pode ou não ser chaves públicas, on ou off the curve, e pode ou não corresponder a contas na Solana.
  • signature - assinatura codificada em base58 criada a partir do par de chaves da Identidade de Ação assinando apenas o valor reference.

O valor reference deve ser usado apenas uma vez e em uma única transação. Para o propósito de associar transações a um Provedor de Ação, apenas o primeiro uso do valor reference é considerado válido.

As transações podem ter múltiplas instruções Memo. Ao realizar um getSignaturesForAddress, o campo memo dos resultados retornará a mensagem de cada instrução memo como uma única string com cada uma separada por ponto e vírgula.

Nenhum outro dado deve ser incluído na instrução Memo da Mensagem de Identificação.

A identity e a reference devem ser incluídas como chaves de leitura apenas, keys não assinantes na transação em uma instrução que NÃO seja a instrução Memo da Mensagem de Identificação.

A instrução Memo da Mensagem de Identificação deve ter zero contas fornecidas. Se quaisquer contas forem fornecidas, o programa Memo exige que essas contas sejam assinantes válidos. Para fins de identificação de ações, isso restringe a flexibilidade e pode degradar a experiência do usuário. Portanto, é considerado um anti-padrão e deve ser evitado.

Verificação de Identidade do Action #

Qualquer transação que inclua a conta identity pode ser associada verificadamente ao Provedor do Action em um processo de múltiplas etapas:

  1. Obtenha todas as transações para uma determinada identity.
  2. Analise e verifique a string de memo de cada transação, garantindo que a signature é válida para o reference armazenado.
  3. Verifique se a transação específica é a primeira ocorrência on-chain do reference:
    • Se esta transação for a primeira ocorrência, a transação é considerada verificada e pode ser atribuída com segurança ao Provedor do Action.
    • Se esta transação NÃO for a primeira ocorrência, ela é considerada inválida e, portanto, não atribuída ao Provedor do Action.

Como os validadores da Solana indexam as transações pelas chaves das contas, o método RPC getSignaturesForAddress pode ser usado para localizar todas as transações que incluem a conta identity.

A resposta deste método RPC inclui todos os dados do Memo no campo memo. Se várias instruções de Memo foram usadas na transação, cada mensagem de memo será incluída neste campo memo e deve ser analisada adequadamente pelo verificador para obter a Mensagem de Verificação de Identidade.

Essas transações devem ser inicialmente consideradas NÃO VERIFICADAS. Isso ocorre porque a identity não é obrigatória para assinar a transação, o que permite que qualquer transação inclua essa conta como não-signatária. Potencialmente inflando artificialmente os contadores de atribuição e uso.

A Mensagem de Verificação de Identidade deve ser verificada para garantir que a signature foi criada pela identity assinando o reference. Se essa verificação de assinatura falhar, a transação é inválida e não deve ser atribuída ao Provedor do Action.

Se a verificação da assinatura for bem-sucedida, o verificador deve garantir que esta transação seja a primeira ocorrência on-chain do reference. Se não for, a transação é considerada inválida.