NOVO: Helius adquire a Light Protocol
Como obter os detentores de um token na Solana
Blog/Desenvolvimento

Como obter os detentores de um token na Solana

Engenheiro de Experiência do DesenvolvedorOwen Venter no XOwen Venter no LinkedIn
5 min de leitura

Neste guia, veremos como obter todos os detentores de um token fungível, como USDC. Isso pode ser útil quando você quer monitorar os detentores de um token ou recompensá-los com um airdrop.

Visão geral

Primeiro, vamos entender como os tokens, especialmente os tokens não fungíveis, funcionam na Solana. Quando um desenvolvedor cria um token, ele usa o programa de tokens para criar uma conta de mint. Essa conta de mint armazena informações sobre um token específico, como nome, endereço e imagem. Depois que a conta de mint é criada, o token pode ser emitido e armazenado em uma conta de token. Uma conta de token armazena informações sobre um token específico pertencente a um endereço específico. Isso inclui detalhes como o endereço de mint, o endereço do proprietário e a quantidade desse token na conta. Por exemplo, um endereço que possui USDC (um token SPL) terá uma conta de token para USDC.

Agora que entendemos como os tokens e as contas de token funcionam, podemos descobrir todos os detentores de um determinado token. Cada carteira que possui um token específico terá uma conta de token para ele. Isso significa que o token estará associado às contas de token de todas as carteiras que o possuem. É assim que identificaremos todos os detentores. Se encontrarmos uma forma de obter todas as contas de token associadas a um token e, em seguida, os proprietários dessas contas, teremos uma lista de todos os detentores! 

Método getTokenAccounts

Felizmente, o método getTokenAccounts da API da Helius permite fazer exatamente isso. Podemos incluir o endereço de mint de qualquer token nos parâmetros da chamada à API e receber uma lista de todas as contas de token criadas para ele. Além disso, a API também retorna o proprietário de cada conta de token. Esse proprietário é o que normalmente chamamos de detentor do token. Um detalhe importante é que uma conta pode ter várias contas de token para o mesmo token. Isso não é um grande problema. Basta implementar uma lógica para lidar com contas de token que compartilham o mesmo proprietário. 

Implementação

Agora, vamos analisar o código para ver como fazer isso na prática. Você precisará de uma chave de API da Helius para acompanhar. É possível obter uma gratuitamente acessando seu painel da Helius e criando uma conta. Para começar, precisamos criar um arquivo JavaScript chamado getTokenHolders.js. Podemos adicionar nossa URL da Helius e importar a biblioteca fs para salvar os resultados em um arquivo JSON.

Código
const url = `https://mainnet.helius-rpc.com/?api-key=`;
const fs = require("fs");

Em seguida, criaremos um método para buscar todas as contas de token associadas ao token específico. Podemos começar criando um método chamado findHolders, que usará o método getTokenAccounts para obter os dados necessários. Você pode saber mais sobre o método getTokenAccounts aqui.

É importante observar que cada chamada à API pode retornar no máximo 1.000 contas de token. A maioria dos grandes tokens da Solana tem mais de 100.000 contas de token. Para contornar essa limitação, usaremos paginação para percorrer todas as contas de token e continuar fazendo chamadas à API até buscar os dados de todas as contas de token existentes.

No método, incluiremos o mint do token nos parâmetros da chamada getTokenAccounts. Ao percorrer todas as contas de token, adicionaremos cada proprietário único a uma lista. Quando a execução do método terminar, salvaremos essa lista em um arquivo JSON contendo todos os detentores do token.

Código
const findHolders = async () => {
  // Pagination logic
  let page = 1;
 	// allOwners will store all the addresses that hold the token
  let allOwners = new Set();

  while (true) {
    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        jsonrpc: "2.0",
        method: "getTokenAccounts",
        id: "helius-test",
        params: {
          page: page,
          limit: 1000,
          displayOptions: {},
					//mint address for the token we are interested in
          mint: "CKfatsPMUf8SkiURsDXs7eK6GWb4Jsd6UDbs7twMCWxo",
        },
      }),
    });

		// Check if any error in the response
      if (!response.ok) {
        console.log(
          `Error: ${response.status}, ${response.statusText}`
        );
        break;
      }

    const data = await response.json();
  	// Pagination logic.
    if (!data.result || data.result.token_accounts.length === 0) {
      console.log(`No more results. Total pages: ${page - 1}`);
      break;
    }
    console.log(`Processing results from page ${page}`);
 		// Adding unique owners to a list of token owners.
    data.result.token_accounts.forEach((account) =>
      allOwners.add(account.owner)
    );
    page++;
  }

  fs.writeFileSync(
    "output.json",
    JSON.stringify(Array.from(allOwners), null, 2)
  );
};

‍No exemplo acima, o método getTokenAccounts é chamado várias vezes durante a paginação por todas as contas de token. A resposta da API fornecerá os seguintes dados para cada conta de token: 

Código
{
"address": "CVMR1nbxTcQ7Jpa1p137t5TyKFii3Y7Vazt9fFct3tk9",
"mint": "SHDWyBxihqiCj6YekG2GUr7wqKLeLAMK1gHZck9pL6y",
"owner": "CckxW6C1CjsxYcXSiDbk7NYfPLhfqAm3kSB5LEZunnSE",
"amount": 100000000,
"delegated_amount": 0,
"frozen": false
},

Extraímos o proprietário dessas contas de token e o adicionamos à nossa lista. Se quiséssemos, também poderíamos armazenar a quantidade do token mantida em cada conta de token para identificar os maiores detentores. 

Depois disso, basta chamar o método:

Código
findHolders();

O código completo do nosso arquivo getTokenHolders.js deve ficar assim:

Código
const url = `https://mainnet.helius-rpc.com/?api-key=`;
const fs = require("fs");

const findHolders = async () => {
  let page = 1;
  let allOwners = new Set();

  while (true) {
    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        jsonrpc: "2.0",
        method: "getTokenAccounts",
        id: "helius-test",
        params: {
          page: page,
          limit: 1000,
          displayOptions: {},
          mint: "DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263",
        },
      }),
    });

		// Check if any error in the response
      if (!response.ok) {
        console.log(
          `Error: ${response.status}, ${response.statusText}`
        );
        break;
      }

    const data = await response.json();

    if (!data.result || data.result.token_accounts.length === 0) {
      console.log(`No more results. Total pages: ${page - 1}`);

      break;
    }
    console.log(`Processing results from page ${page}`);
    data.result.token_accounts.forEach((account) =>
      allOwners.add(account.owner)
    );
    page++;
  }

  fs.writeFileSync(
    "output.json",
    JSON.stringify(Array.from(allOwners), null, 2)
  );
};

findHolders();

Saída

A saída do nosso código será uma lista de todos os detentores, semelhante a esta:

Código
[
  "111An9SVxuPpgjnuXW9Ub7hcVmZpYNrYZF4edsGwJEW",
  "11Mmng3DoMsq2Roq8LBcqdz6d4kw9oSD8oka9Pwfbj",
  "112uNfcC8iwX9P2TkRdJKyPatg6a4GNcr9NC5mTc2z3",
  "113uswn5HNgEfBUKfK4gVBmd2GpZYbxd1N6h1uUWReg",
  "11CyvpdYTqFmCVWbJJeKFNX8F8RSjNSYW5VVUi8eX4P",
  "11MANeaiHEy9S9pRQNu3nqKa2gpajzX2wrRJqWrf8dQ",
…
]

Você pode testar por conta própria usando nosso exemplo no Replit.

Conclusão

Para concluir este guia, abordamos com sucesso o processo de identificação dos detentores de tokens da Solana usando a API getTokenAccounts da Helius. Este passo a passo oferece o conhecimento necessário para interagir diretamente com a comunidade do seu token, seja para airdrops, análises ou outras interações. Se tiver alguma dúvida, fale conosco pelo Twitter ou pelo Discord. ‍

Assine a Helius

Acompanhe as novidades mais recentes do desenvolvimento Solana e receba atualizações quando publicarmos

Imagem ampliada