Skip to content

Transferência de Tokens Sol Entre Contas - Ledger

Transferência de Tokens Sol Entre Contas - Ledger

Introdução

Nesta seção, vamos orientá-lo através da criação de um aplicativo. Este aplicativo criará uma transação que será assinada com a Ledger Nano antes de enviá-la para a blockchain. O objetivo do aplicativo é transferir sol (tokens) da sua conta Solana na sua Ledger para outra conta.

Pré-requisitos

Antes de iniciar, certifique-se de ter cumprido os pré requisitos.

Instale o aplicativo Solana Nano

Primeiro, você precisa instalar o aplicativo Solana Nano da Ledger Live, conforme indicado nos pré requisitos da Ethereum.

Implementação do tutorial

Nesta implementação, estaremos construindo uma aplicação web com uma linguagem javascript bem simples que usa o protocolo USB de um pacote Ledger para se comunicar com a ledger.

Inicialização do projeto

É hora de implementar o aplicativo e testá-lo. Primeiro, abra um terminal e crie uma nova pasta. Para este tutorial, a pasta terá o nome “e2e-sol-tutorial”. Execute:

mkdir e2e-sol-tutorial
cd e2e-sol-tutorial

Em seguida, inicialize o projeto executando o seguinte:

npm init

Responda às perguntas exibidas ou, por padrão, pressione enter. Não há incidência na execução.

Execute:

touch index.html
touch index.js
touch style.css
mkdir assets

Coloque este logotipo na pasta de ativos.

Sua pasta de trabalho deve ficar assim. 1 Fig. 2: Pasta do Aplicativo

Implementação de código

index.html

Em index.html, copie e cole o seguinte código:

<!DOCTYPE html>
<html>
  <head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
    <link rel="stylesheet" href="style.css">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script>
    <script type="module" src="index.js"></script>
  </head>

  <body class="m-5">
    <div class="d-flex flex-column justify-content-center m-5 align-items-center">
      <p>Clique no botão abaixo para conectar sua Carteira Ledger</p>
      <div class="d-flex flex-row w-100 justify-content-around">
        <button class="btn btn-primary w-25" data-bs-toggle="modal" data-bs-target="#WalletModal">Conecte sua carteira</button>
        <button class="btn btn-primary w-25" id="get-information">Obter informações</button>
      </div>
    </div>
    <div class="d-flex flex-row">
      <div id="app" class="w-50">
        <form class="row g-3">
          <div class="col-md-12">
            <label for="wallet" class="form-label">Chave Pública da Carteira</label>
            <input type="text" class="form-control" id="wallet" disabled>
          </div>
          <div class="col-md-12">
            <label for="recipient" class="form-label" disabled>Saldo</label>
            <input type="text" class="form-control" id="balance">
          </div>
          <div class="col-md-12">
            <label for="recipient" class="form-label">Beneficiário</label>
            <input type="text" class="form-control" id="recipient">
          </div>
          <div class="col-md-6">
            <label for="gasPrice" class="form-label">Preço do gas</label>
            <input type="text" class="form-control" id="gasPrice" disabled>
          </div>
          <div class="col-md-6">
            <label for="value" class="form-label">Valor</label>
            <input type="text" class="form-control" id="value" >
          </div>
          <div class="col-12">
            <button type="button" id="tx-transfer" class="btn btn-primary">Criar Transação</button>
          </div>
        </form>
      </div>
      <div class="w-50 d-flex flex-column">
            <p class="url">Solana explorer:</p>
            <a id="url" href="" target="_blank"></a>
      </div>
    </div>

    <!-- Modal -->
    <div class="modal fade" id="WalletModal" tabindex="-1" aria-labelledby="WalletModalLabel" aria-hidden="true">
      <div class="modal-dialog">
        <div class="modal-content">
          <div class="modal-header">
            <h5 class="modal-title" id="WalletModalLabel">Escolha a sua carteira</h5>
            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
          </div>
          <div class="modal-body d-flex justify-content-center">
            <button id="connect-ledger" class="rounded-3 align-self-center" data-bs-dismiss="modal">
              <img src="./assets/ledger-logo.jpg" class="card-img-top" alt="Ledger">
            </button>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

index.js

Em index.js, copie e cole o seguinte código:

import * as SolanaWeb3 de '@solana/web3.js';
import TransportWebUSB de "@ledgerhq/hw-transport-webusb";
import Solana de "@ledgerhq/hw-app-solana";
import { listen } de "@ledgerhq/logs";
import bs58 de "bs58";

//Provedor Infuria para a rede devnet Solana
const connection = new SolanaWeb3.Connection(SolanaWeb3.clusterApiUrl('devnet'),"confirmed");

let transport;
let _sol;
let addressWallet;
let recipient = SolanaWeb3.Keypair.generate().publicKey;
let value = 0.1;
let gasPrice;

//verificar todos os erros cometidos pelo Transport
listen(log => console.log(log));

document.getElementById("connect-ledger").onclick = async function () {
    //Conectando-se a Ledger Nano com protocolo USB
    transport = await TransportWebUSB.create();
}

document.getElementById("get-information").onclick = async function () {
    //Obter uma instância Solana e a chave pública da conta Ledger Nano solana
    _sol = new Solana(transport);
    const { address } = await _sol.getAddress("44'/501'/0'");
    addressWallet = new SolanaWeb3.PublicKey(bs58.encode(address));

    //Obtenha algumas propriedades do provedor
    const balance = await connection.getBalance(addressWallet);
    gasPrice = SolanaWeb3.LAMPORTS_PER_SOL / 100;

    //Preencher as entradas com o valor padrão
    document.getElementById("wallet").value = bs58.encode(address);
    document.getElementById("balance").value = balance/ SolanaWeb3.LAMPORTS_PER_SOL;
    document.getElementById("gasPrice").value = parseInt(gasPrice) + " wei";
    document.getElementById("value").value = value;
    document.getElementById("recipient").value = recipient.toBase58();
}


document.getElementById("tx-transfer").onclick = async function () {
    //Obtendo informações a partir das entradas
    recipient = new SolanaWeb3.PublicKey(document.getElementById("recipient").value);
    value = document.getElementById("value").value;

    //Construir transação com as informações coletadas
    try {
        const recentBlockhash = await connection.getRecentBlockhash();
        const transaction = new SolanaWeb3.Transaction({ feePayer: addressWallet, recentBlockhash: recentBlockhash.blockhash}).add(
            SolanaWeb3.SystemProgram.transfer({
                fromPubkey: addressWallet,
                toPubkey: recipient,
                lamports: SolanaWeb3.LAMPORTS_PER_SOL * value,
            }),
        );


        //Serializando a transação para passá-la à Ledger Nano para assinatura
        const unsignedTx = transaction.serializeMessage();

        //Assine com a Ledger Nano (Assine o que você vê)
        const { signature } = await _sol.signTransaction("44'/501'/0'", unsignedTx);
        transaction.addSignature(addressWallet,signature);

        //Serialize a mesma transação de antes, mas adicione a assinatura nela
        const signedTx = transaction.serialize();


        //Enviando a transação para a blockchain
        const hash = await connection.sendRawTransaction(signedTx, {preflightCommitment:"confirmed", skipPreflight: false});

        //Exibir a URL do explorador Solana na tela
        const url = "https://explorer.solana.com/tx/" + hash +"?cluster=devnet";
        document.getElementById("url").innerHTML = url;
        document.getElementById("url").href = url;
    } catch (error) {
        console.log(error);
    }
}

style.css

Em style.css copie e cole o seguinte código:

.modal-content{
    width: 300px;
    height: 400px;
}

#conectar ledger{
    width: 17rem;
    height: 9rem;
    background-color: white;
    border: none;
}

#conectar ledger:hover{
    background-color: #EDEFF3;
}

.modal-body{
    background-color: #F7F9FD;
}

#url,.url{
    text-align: center;
    margin-top: 160px;
    color: green;
}

Instalação de dependências

Instale os pacotes

Execute:

npm install --save-dev parcel
npm install --save @ledgerhq/hw-app-solana
npm install --save @ledgerhq/hw-transport-webusb
npm install --save @ledgerhq/logs
npm install --save @solana/web3.js
npm install --save bs58

Pacotes e o que eles fazem

parcel É uma ferramenta de compilação que o ajudará a empacotar seu aplicativo para executá-lo no navegador.

@ledgerhq/hw-app-solana Ele irá ajudá-lo a pedir a sua Ledger Nano para acessar o aplicativo solana na Ledger Nano.

@ledgerhq/hw-transport-webusb Ele fornece todos os métodos para interagir com sua Ledger com uma conexão USB.

@ledgerhq/logs Ele fornece o registro de todos os erros de sua conexão com seu dispositivo Ledger que podem aparecer durante o desenvolvimento.

@solana/web3.js Ele fornece todos os métodos para interagir com a blockchain solana.

bs58 Ele fornece todos os métodos para calcular a codificação de base 58.

Modificar Package.json

Modifique a 5ª linha: "main": "index.js"=> "source": "index.html" E certifique-se de ter esta linha nos scripts:

 "scripts": {
    "start": "parcel"
  },

Adicione isto no final do script:

 "alias": {
    "@ledgerhq/devices": "@ledgerhq/devices/lib-es"
  }

Seu arquivo deve ficar assim:

{
    "name": "e2e-sol-tutorial",
    "version": "1.0.0",
    "description": "",
    "source": "index.html",
    "scripts": {
        "start": "parcel"
    },
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "parcel": "^2.3.2"
    },
    "dependencies": {
        "@ledgerhq/hw-app-solana": "^6.26.0",
        "@ledgerhq/hw-transport-webusb": "^6.24.1",
        "@ledgerhq/logs": "^6.10.0",
        "@solana/web3.js": "^1.36.0",
        "bs58": "^5.0.0"
    },
    "alias": {
        "@ledgerhq/devices": "@ledgerhq/devices/lib-es"
    }
}

Teste do tutorial

Inicie o servidor de desenvolvimento

Agora que a configuração foi concluída, o aplicativo deve ser criado para ser exibido. Inicie o servidor de desenvolvimento:

npm run start

Agora o aplicativo está funcionando. Abra o Chrome e vá para localhost:1234, ele exibirá:

2 Fig. 3: Aplicativo rodando no navegador

Conecte o seu dispositivo Ledger

Antes de clicar no texto, conecte sua Ledger à porta USB, desbloqueie-a e execute o aplicativo solana. As etapas são descritas abaixo.

3 Fig. 4: Digite o código PIN da Ledger

4 Fig. 5: Execute o aplicativo Solana na Ledger Nano

5 Fig. 6: O aplicativo Solana está sendo executado na Ledger Nano

Conecte sua Ledger ao aplicativo

Agora você pode clicar no botão “Connect your Wallet” e uma janela modal será aberta. Clique no logotipo da Ledger.

6 Fig. 7: Escolha da Carteira Agora escolha a Ledger Nano para conectar ao navegador.

7 Fig. 8: Conecte a Ledger Nano

Após conectar a Nano, clique em “Get Information”. Se tudo correr bem, os campos de entrada serão preenchidos com dados. A entrada em cinza não deve ser alterada e é extraída diretamente da blockchain ou do seu aplicativo Ledger Nano.

8 Fig. 9: Aplicação após conectar a Ledger Nano

Envie o token Sol para sua conta solana Ledger Nano

Para enviar alguns tokens sol na rede Devnet, você pode ir a um dos sites de faucet solana ou fazê-lo com a interface de linha de comando da solana:

Faucet Solana Solana CLI

Se você procura a maneira mais fácil e rápida, use o Faucet Solana. Se você preferir usar a CLI da Solana, leia esta documentação para instalá-la antes de começar a enviar Sol.

A Devnet da Solana não é visível na Ledger Live, você pode verificar a transação passada no Solana Explorer.

Opção n°1 - Faucet Solana Vá para o site Faucet Solana coloque sua chave pública da carteira (exibida no aplicativo web) na entrada e clique em “Devnet”

9 Fig. 1: Faucet Solana

Opção nº 2 - Solana CLI

Vá para o site Solana CLI, existem etapas para adicionar alguns tokens sol à sua conta.

solana airdrop 1 <ENDEREÇO_DA_CONTA_DE_DESTINO> --url https://api.devnet.solana.com

Por exemplo

solana airdrop 1 72tCcW6F4gRWJLCXf3RGejNDZBwUvWCfxHTdxoLGV4ht --url [https://api.devnet.solana.com](https://api.devnet.solana.com)

Criar uma transação para transferir sol

Agora que as entradas estão preenchidas com dados, é hora de transferir alguns tokens sol da sua conta solana da Ledger para outra conta (você pode manter a conta padrão no arquivo “index.js”).

Portanto, clique em “Create Transaction” para criar a transação que será assinada pela sua Ledger antes de enviá-la para a blockchain.

10 Fig. 10: Aplicativo após conectar a Ledger Nano

Quando a transação prosseguir e finalizar, uma URL será exibida na tela. Esta URL é um link para o Solana Explorer para revisar a transação.

Lá você pode encontrar todas as informações sobre a transação que você enviou anteriormente.

11Fig. 11: URL de informações da transação

Se você for no Solana Explorer, poderá ver as informações de sua transação.

12 Fig. 12: Resultado no Solana Explorer após o envio da transação

13 Fig. 13: Resultado no Solana Explorer após o envio da transação

Parabéns, você construiu com sucesso seu primeiro aplicativo de transferência conectado à Ledger!!!


Este artigo foi publicado no Portal do desenvolvedor Ledger. Traduzido por Marcelo Panegali.