🇵🇹
DAO Lunes Labs - PT
  • 👋Seja Bem-vindo a DAO Lunes Labs
  • Overview
    • 🚪Introdução
    • 🚀Manifesto DAO Lunes Labs
    • 🍕Tokenomics
    • 👑Proposta de Valor
    • 🧑‍🚀Comunidade e Participação
    • 🗺️Roadmap
    • 💼Compromisso com Ética e Responsabilidade
    • 👾Programa de Bug Bounty: Lunes Security Initiative (LSI)
  • Developers
    • 💽Para Nodes
      • 🥾Instalar Node
        • 🏗️Rust toolchain
        • 🐧Linux
    • 🖥️Para Desenvolvedores
      • 📑Smart Contract Ink! 4.x
        • ✨Configuração
          • 📐Criando um projeto com ink!
          • 🖥️Compile Seu Contrato
          • ⛓️Executar um nó Lunes
          • ⬆️Implante seu contrato
          • 🔛Chame Seu Contrato
          • 🛠️Solução de problemas
        • 🪄Fundamentos
          • 👾Modelo de Contrato
          • 👨‍🚀Armazenando Valores
          • 🔭Lendo Valores do Armazenamento
          • 🦸‍♂️Alterando os Valores de Armazenamento
          • 🎡Eventos
          • 👨‍🔧Seletores
          • 🪶Definições de Trait
          • 🗣️Chamadas entre Contratos (Cross-Contract Calls)
          • 🦸Contratos Atualizáveis
          • 🤺Funções do Ambiente
          • 🏟️Tipos de Ambiente de Cadeia
          • 💠Metadados
          • 🧪Testes de Contrato
          • 🕵️‍♂️Depuração de Contratos
          • 🔬Verificação de Contrato
        • 🎙️Macros e Atributos
          • 📇#[ink::contract]
          • 👽#[ink(anonymous)]
          • 👷#[ink(constructor)]
          • 📏#[ink(default)]
          • 🎢#[ink(event)]
          • 🛩️#[ink(impl)]
          • 📧#[ink(message)]
          • 👨‍💼#[ink(namespace = "…")]
          • 💸#[ink(payable)]
          • ⚡#[ink(selector = S:u32)]
          • 💽#[ink(storage)]
          • 💣#[ink(topic)]
          • ⛓️#[ink::chain_extension]
        • 💽Storege & Data Structires
          • Working with Mapping
          • Storage Layout
          • Custom Data Structures
          • Metadata Format
        • 👾Frontend Development
          • Getting Started
          • Connect Wallet
          • Hooks
            • All Hooks
            • Contracts
              • useCall
              • useCallSubscription
              • useContract
              • useDryRun
              • useEventSubscription
              • useEvents
              • useTx
              • useTxPaymentInfo
            • Wallets
              • useWallet
              • useAllWallets
              • useInstalledWallets
              • useUninstalledWallets
            • API
              • useApi
              • useBalance
              • useBlockHeader
          • Configuration
          • useink / core
            • Contracts
              • Call
              • decodeCallResult
              • decodeError
              • getRegistryError
              • toAbiMessage
          • useink / chains
            • Getting Started
            • Chain Configurations
            • ChainId
          • useink / notifications
            • Getting Started
            • Configuration
            • useNotifications
            • toNotificationLevel
          • useink / utils
            • Getting Started
            • Pick Helpers
            • tx Helpers
            • Types
        • 💡Examples
          • 📔Smart Contracts
          • 📱Dapps
        • 🛠️Tools
          • 🖌️OpenBrush
      • 📒Smart Contract - EVM
        • Create ERC-20 Ink Token!
      • 💰Desenvolvendo uma Wallet Lunes
        • 👾Transações de Tokens PSP22
    • 🎨Para Designers
      • 🖌️Brand Lunes
Powered by GitBook
On this page
  • Criação de Carteiras, Simulação de Taxas e Transações de Tokens
  • Sumário da Seção de Transações de Tokens
  • 10. Introdução ao PSP22 e Contratos de Tokens na Lunes
  • 11. Função getQueryToken: Simulação de Transações no Contrato
  • 12. Função sendTXToken: Execução de Transações no Contrato
  • 13. Função transferToken: Transferência Simplificada de Tokens
  • 14. Detalhes Técnicos e Boas Práticas
  • 15. Exemplo Completo de Código
  • 16. Possíveis Melhorias
  • Conclusão

Was this helpful?

  1. Developers
  2. Para Desenvolvedores
  3. Desenvolvendo uma Wallet Lunes

Transações de Tokens PSP22

Criação de Carteiras, Simulação de Taxas e Transações de Tokens

A Lunes é uma solochain desenvolvida com o framework Substrate, operando de forma independente, mas utilizando ferramentas e padrões comuns ao ecossistema Substrate. Esta documentação já abordou a criação de carteiras, simulação de taxas e transações básicas na rede Lunes. Agora, expandimos para incluir transações de tokens baseadas no padrão PSP22, que é o equivalente ao ERC-20 para blockchains Substrate, permitindo a interação com contratos inteligentes de tokens na rede Lunes.

Sumário da Seção de Transações de Tokens

  1. Introdução ao PSP22 e Contratos de Tokens na Lunes

  2. Função getQueryToken: Simulação de Transações no Contrato

  3. Função sendTXToken: Execução de Transações no Contrato

  4. Função transferToken: Transferência Simplificada de Tokens

  5. Detalhes Técnicos e Boas Práticas

  6. Exemplo Completo de Código

  7. Possíveis Melhorias


10. Introdução ao PSP22 e Contratos de Tokens na Lunes

O padrão PSP22 é uma especificação para tokens fungíveis no ecossistema Substrate, inspirada no ERC-20 do Ethereum. Ele define métodos como transfer, balanceOf, approve, entre outros, permitindo a criação e manipulação de tokens em blockchains como a Lunes. Esta seção documenta como interagir com um contrato PSP22 na rede Lunes, utilizando a biblioteca @polkadot/api para consultar e executar transações de tokens.

Pré-requisitos

  • Contrato PSP22 implantado: Você precisa do endereço do contrato e do arquivo ABI (Application Binary Interface) correspondente.

  • Dependências: Certifique-se de ter instalado @polkadot/api e @polkadot/api-contract:

    npm install @polkadot/api @polkadot/api-contract
  • Endpoints: Use os mesmos endpoints da Lunes mencionados anteriormente (ex.: wss://ws-test.lunes.io para testnet).


11. Função getQueryToken: Simulação de Transações no Contrato

Objetivo

A função getQueryToken realiza uma consulta (simulação) ao contrato PSP22 para verificar os resultados de uma transação sem executá-la na blockchain. Isso é útil para estimar custos (gas e taxas) e validar parâmetros antes de enviar a transação real.

Código

const { ContractPromise } = require('@polkadot/api-contract');

async function getQueryToken(address, router, param, api, apiReady, account) {
  if (!api || !apiReady || !account) {
    throw new Error("API não inicializada ou conta inválida.");
  }

  const contract = new ContractPromise(api, ABI_psp22, address);

  const gasLimit = api.registry.createType('WeightV2', {
    refTime: 1000000000n,
    proofSize: 100000n,
  });

  const { storageDeposit, result, gasRequired, output } = await contract.query[router](
    account.address,
    { gasLimit, storageDepositLimit: null },
    ...Object.values(param)
  );

  if (result.isErr) {
    const dispatchError = api.registry.findMetaError(result.asErr.asModule);
    const error = dispatchError.docs.length ? dispatchError.docs.concat().toString() : dispatchError.name;
    throw new Error(error);
  }

  return { contract, gasRequired, storageDeposit, output };
}

Passos Detalhados

  1. Validação Inicial:

    • Verifica se a API está inicializada (apiReady), se o objeto api existe e se há uma conta válida (account).

    • Caso contrário, lança um erro para evitar execuções inválidas.

  2. Criação do Contrato:

    • Usa ContractPromise para instanciar o contrato com o endereço (address) e o ABI (ABI_psp22).

    • O ABI define a interface do contrato (métodos, parâmetros, etc.).

  3. Simulação da Chamada:

    • O método contract.query[router] simula a execução do método especificado (ex.: transfer).

    • Parâmetros:

      • account.address: Endereço da conta que realiza a consulta.

      • { gasLimit, storageDepositLimit: null }: Define limites de gás e depósito de armazenamento.

      • ...Object.values(param): Passa os parâmetros do método (ex.: { to: "endereço", value: "100" }).

    • Retorna:

      • gasRequired: Quantidade de gás estimada.

      • storageDeposit: Taxa de armazenamento (se aplicável).

      • result: Resultado da simulação.

      • output: Saída do método, se bem-sucedido.

  4. Tratamento de Erros:

    • Se result.isErr, extrai o erro do registro da API e lança uma exceção detalhada.

  5. Retorno:

    • Retorna um objeto com o contrato, gás necessário e outros dados para uso na transação real.


12. Função sendTXToken: Execução de Transações no Contrato

Objetivo

A função sendTXToken executa a transação real no contrato PSP22, utilizando os dados obtidos pela simulação em getQueryToken.

Código

async function sendTXToken(address, router, param, api, apiReady, account) {
  const contracts = await getQueryToken(address, router, param, api, apiReady, account);

  return new Promise((resolve, reject) => {
    contracts.contract.tx[router](
      {
        gasLimit: contracts.gasRequired,
        storageDepositLimit: null,
      },
      ...Object.values(param)
    ).signAndSend(account, (res) => {
      if (res.status.isInBlock) {
        console.log(`Transação incluída no bloco: ${res.status.asInBlock.toString()}`);
      } else if (res.status.isFinalized) {
        console.log(`Transação finalizada com hash: ${res.txHash.toString()}`);
        resolve(res.txHash.toString());
      }
      if (res.isError) {
        reject(new Error("Erro na execução da transação"));
      }
    });
  });
}

Passos Detalhados

  1. Obter Dados da Simulação:

    • Chama getQueryToken para obter o contrato e o gasRequired.

  2. Envio da Transação:

    • Usa contract.tx[router] para preparar a transação real.

    • Configura gasLimit com o valor retornado pela simulação.

    • Assina e envia a transação com signAndSend, usando a conta fornecida (account).

  3. Monitoramento:

    • isInBlock: A transação foi incluída em um bloco.

    • isFinalized: A transação foi finalizada e é irreversível.

    • isError: Indica falha na execução, rejeitando a promessa com um erro.

  4. Retorno:

    • Resolve com o hash da transação quando finalizada.


13. Função transferToken: Transferência Simplificada de Tokens

Objetivo

A função transferToken simplifica a transferência de tokens PSP22 para um endereço específico.

Código

async function transferToken(value, to, api, apiReady, account) {
  const contractAddress = import.meta.env.VITE_CONTRACT_TOKEN;
  await sendTXToken(
    contractAddress,
    "psp22::transfer",
    { to, value: value.toString(), data: "" },
    api,
    apiReady,
    account
  );
}

Passos Detalhados

  1. Parâmetros:

    • value: Quantidade de tokens a transferir (em Unis).

    • to: Endereço de destino.

    • api, apiReady, account: Dependências necessárias para a transação.

  2. Chamada ao sendTXToken:

    • Usa o endereço do contrato armazenado em VITE_CONTRACT_TOKEN.

    • Chama o método psp22::transfer com os parâmetros { to, value, data }.

  3. Execução:

    • A função delega a execução para sendTXToken, que lida com a simulação e envio.


14. Detalhes Técnicos e Boas Práticas

PSP22

  • O padrão PSP22 define métodos como:

    • transfer(to, value, data): Transfere tokens.

    • balanceOf(account): Consulta o saldo de uma conta.

    • approve(spender, value): Autoriza um gasto.

Gas e Storage Deposit

  • GasRequired: Estimativa de gás necessária para a transação, obtida na simulação.

  • StorageDeposit: Taxa para armazenar dados no contrato, geralmente nula para transferências simples.

Segurança

  • Verifique sempre apiReady e a validade de account antes de executar operações.

  • Use variáveis de ambiente (ex.: VITE_CONTRACT_TOKEN) para evitar expor endereços sensíveis no código.

Endpoints

  • Para transações de tokens, utilize os mesmos endpoints da Lunes (ex.: wss://ws.lunes.com para mainnet).


15. Exemplo Completo de Código

Aqui está um exemplo completo que conecta à rede Lunes, cria uma carteira e transfere tokens PSP22:

const { ApiPromise, WsProvider } = require('@polkadot/api');
const { ContractPromise } = require('@polkadot/api-contract');
const { Keyring } = require('@polkadot/api');
const { mnemonicGenerate } = require('@polkadot/util-crypto');

// Substitua pelo ABI do seu contrato PSP22
const ABI_psp22 = require('./path/to/psp22_abi.json');

async function main() {
  // Conectar à rede de teste
  const provider = new WsProvider('wss://ws-test.lunes.io');
  const api = await ApiPromise.create({ provider });
  const apiReady = true;

  // Criar uma nova carteira
  const keyring = new Keyring({ type: 'sr25519' });
  const newSeed = mnemonicGenerate();
  const account = keyring.addFromUri(newSeed);
  console.log('Nova Seed Phrase:', newSeed);
  console.log('Endereço da carteira:', account.address);

  // Função getQueryToken
  async function getQueryToken(address, router, param) {
    if (!api || !apiReady || !account) throw new Error("API ou conta inválida");
    const contract = new ContractPromise(api, ABI_psp22, address);
    const gasLimit = api.registry.createType('WeightV2', { refTime: 1000000000n, proofSize: 100000n });
    const { storageDeposit, result, gasRequired, output } = await contract.query[router](
      account.address,
      { gasLimit, storageDepositLimit: null },
      ...Object.values(param)
    );
    if (result.isErr) {
      const dispatchError = api.registry.findMetaError(result.asErr.asModule);
      throw new Error(dispatchError.docs.length ? dispatchError.docs.concat().toString() : dispatchError.name);
    }
    return { contract, gasRequired, storageDeposit, output };
  }

  // Função sendTXToken
  async function sendTXToken(address, router, param) {
    const contracts = await getQueryToken(address, router, param);
    return new Promise((resolve, reject) => {
      contracts.contract.tx[router](
        { gasLimit: contracts.gasRequired, storageDepositLimit: null },
        ...Object.values(param)
      ).signAndSend(account, (res) => {
        if (res.status.isInBlock) console.log(`Incluída no bloco: ${res.status.asInBlock.toString()}`);
        else if (res.status.isFinalized) resolve(res.txHash.toString());
        if (res.isError) reject(new Error("Erro na transação"));
      });
    });
  }

  // Função transferToken
  async function transferToken(value, to) {
    const contractAddress = "ENDEREÇO_DO_CONTRATO_PSP22"; // Substitua pelo endereço real
    await sendTXToken(
      contractAddress,
      "psp22::transfer",
      { to, value: value.toString(), data: "" }
    );
  }

  // Transferir 100 tokens
  try {
    await transferToken(100, "endereco_destino_lunes_aqui");
    console.log("Transferência concluída!");
  } catch (error) {
    console.error("Erro ao transferir tokens:", error.message);
  }

  // Desconectar
  await api.disconnect();
}

main().catch(console.error);

Notas:

  • Substitua "ENDEREÇO_DO_CONTRATO_PSP22" pelo endereço real do contrato.

  • Ajuste o caminho do ABI_psp22 para o arquivo correto.


16. Possíveis Melhorias

  1. Validação de Parâmetros:

    • Adicione verificação para garantir que to seja um endereço válido:

      if (!api.isValidAddress(to)) throw new Error("Endereço de destino inválido");
  2. Estado de Carregamento:

    • Implemente um mecanismo de feedback (ex.: setLoading) para desabilitar botões durante a transação:

      setLoading(true);
      await transferToken(value, to);
      setLoading(false);
  3. Mensagens de Erro Amigáveis:

    • Melhore o feedback ao usuário:

      if (error.message.includes("1010")) {
        throw new Error("Saldo insuficiente para completar a transação.");
      }

Conclusão

Esta seção expande a documentação da rede Lunes para incluir transações de tokens PSP22, oferecendo um guia completo para simular, executar e simplificar transferências de tokens. Com exemplos práticos e boas práticas, os desenvolvedores podem integrar contratos inteligentes à suas aplicações na Lunes de forma eficiente e segura.

Last updated 3 months ago

Was this helpful?

🖥️
💰
👾