Ethers.js

Já vimos como é possível interagir com o Ethereum utilizando JSON-RPC. No entanto, existem bibliotecas que facilitam essa interação, pois permitem incluir chamadas diretamente no código das aplicações com instruções que utilizam JSON-RPC por trás.

Uma das bibliotecas mais conhecidas Ă© o ethers.js, que Ă© escrito em JavaScript. Assim como ela, existem outras em JavaScript (Web3.js) e em outras linguagens como Python (Web3py).

No nosso caso, utilizaremos o ethers.js, pois Ă© o mais utilizado atualmente.

Realizando chamadas JSON-RPC com ethers.js

Vamos ver como começar a utilizar o ethers.js. Lembre-se de que, como executaremos código JavaScript, precisamos ter o node.js e o npm instalados (veja os pré-requisitos deste módulo).

Posicione-se no repositório do seu projeto antes de iniciar a instalação.

  1. Instalar o ethers.js:

    npm init
    npm install ethers

    Certifique-se de que os componentes associados à instalação foram criados no seu diretório:

    • Um diretĂłrio node_modules/ que contĂ©m todos os mĂłdulos instalados, incluindo a pasta ethers.

    • Um arquivo package-lock.json que descreve as versões exatas das dependĂŞncias instaladas.

    • Seu arquivo package.json deve conter o ethers na seção de dependĂŞncias.

  2. Obter uma URL de acesso ao Ethereum de um provedor de serviços de acesso a nós:

    No nosso caso, utilizaremos o Alchemy. Utilize a URL que obteve na seção anterior, que tem a seguinte estrutura: “https://eth-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_PROJECT_ID”.

  3. Escrever um script para se conectar e fazer chamadas JSON-RPC:

    Crie um arquivo index.js no VS Code e adicione o seguinte cĂłdigo:

    const { ethers } = require("ethers");
    
    // Substitua pela sua URL do Alchemy
    const alchemyUrl = '<https://eth-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_PROJECT_ID>';
    
    // Crie um provedor usando a URL do Alchemy
    const provider = new ethers.JsonRpcProvider(alchemyUrl);
    
    // Obtenha o nĂşmero do bloco atual
    async function getBlockNumber() {
      try {
        const blockNumber = await provider.getBlockNumber();
        console.log("NĂşmero de bloque actual:", blockNumber);
      } catch (e) {
        console.error("Error al obtener el nĂşmero de bloque", e);
      }
    }
    
    getBlockNumber();

    Neste primeiro script, obtemos o nĂşmero do Ăşltimo bloco criado no Ethereum.

    Detalhando a estrutura deste script:

    • Importamos a biblioteca ethers.js.

    • Definimos que nos conectaremos via HTTPS com um provedor de serviço de nĂłs como o Alchemy e especificamos a URL para a conexĂŁo.

    • Criamos um novo JsonRpcProvider utilizando a URL do Alchemy. Um provedor no ethers.js Ă© um objeto que se conecta a um nĂł do Ethereum e permite realizar diversas chamadas Ă  blockchain, como obter o nĂşmero do bloco atual, enviar transações, etc.

    • Definimos uma função assĂ­ncrona chamada getBlockNumber. Dentro da função, usamos await provider.getBlockNumber() para obter o nĂşmero do bloco atual da blockchain. A palavra-chave await faz com que a função espere atĂ© que a promessa seja resolvida e retorna o resultado. Se a chamada for bem-sucedida, o nĂşmero do bloco Ă© impresso no console. Se houver um erro durante a chamada, ele Ă© capturado no bloco catch e uma mensagem de erro Ă© impressa no console.

    • Executamos a função getBlockNumber.

    <aside> ⚠️ Este script usa a versão 6 do ethers.js. Se você estiver utilizando uma versão anterior, é muito provável que obtenha um erro.</aside>

  4. Executar o Script:

    bashCopiar cĂłdigo
    node index.js
  5. Escrever um script para obter o saldo de uma conta:

    Execute este cĂłdigo utilizando o node.js para obter o saldo de uma conta.

    javascriptCopiar cĂłdigo
    const { ethers } = require("ethers");
    
    // Substitua pela sua URL do Alchemy
    const alchemyUrl = '<https://eth-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_PROJECT_ID>';
    
    // Crie um provedor usando a URL do Alchemy
    const provider = new ethers.JsonRpcProvider(alchemyUrl);
    
    // Indique a conta que se quer conhecer o saldo
    const address = "0x742d35Cc6634C0532925a3b844Bc454e4438f44e";
    
    // Obtenha o saldo da conta
    async function getBalance() {
      try {
        const balance = await provider.getBalance(address);
        console.log("Saldo de la cuenta:", ethers.formatEther(balance), "ETH");
      } catch (e) {
        console.error("Error al obtener el saldo de la cuenta", e);
      }
    }
    
    getBalance();

    <aside> 👨🏻‍💻 Desafio: Utilizando este código, modifique o endereço para obter o saldo da conta pública de Vitalik.

    </aside>

O archivo .env

Quando precisarmos fazer uma chamada à blockchain que envolva realizar uma escrita, será necessário assinar as transações e, para isso, é preciso utilizar a chave privada da nossa carteira. Não podemos expor nossa chave privada ou, em geral, qualquer informação sensível. Qual é a solução? Utilizar uma combinação de um arquivo .env (lido como "dot i-en-vi") e um arquivo .gitignore.

Um .env é um arquivo de texto que contém pares chave-valor, onde cada par representa uma variável de ambiente. Esses arquivos são utilizados para configurar aplicações de forma que a configuração específica do ambiente (por exemplo, desenvolvimento, teste, produção) possa ser mantida fora do código-fonte e carregada dinamicamente conforme necessário.

Por que utilizar um arquivo .env?

  • Segurança: Manter chaves de API e outras credenciais fora do cĂłdigo-fonte ajuda a prevenir sua exposição acidental.

  • Flexibilidade: Permite alterar configurações facilmente sem modificar o cĂłdigo.

  • Portabilidade: Facilita a configuração do ambiente em diferentes máquinas e ambientes (desenvolvimento, testes, produção).

Passos para utilizar um arquivo .env em um programa JavaScript:

1. Instalar o dotenv

Primeiro, você precisa instalar a biblioteca dotenv, que carrega as variáveis de ambiente de um arquivo .env para process.env.

npm install dotenv

2. Criar um archivo .env

Na raiz do seu projeto, crie um arquivo chamado .env. Este arquivo conterá suas variáveis de ambiente. Por exemplo:

ALCHEMY_URL=https://eth-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_PROJECT_ID
API_KEY=your_api_key
PORT=3000

3. Carregar variáveis de ambiente na sua aplicação

No seu arquivo principal JavaScript (por exemplo, index.js), carregue as variáveis de ambiente usando o dotenv e sentenças do tipo process.env.VARIABLE_NAME para incorporar os valores das variáveis do arquivo .env à sua aplicação.

// Importar dotenv
require('dotenv').config();

// Acessando variáveis ​​de ambiente
const alchemyUrl = process.env.ALCHEMY_URL;
const apiKey = process.env.API_KEY;
const port = process.env.PORT;

console.log(`Alchemy URL: ${alchemyUrl}`);
console.log(`API Key: ${apiKey}`);
console.log(`Port: ${port}`);

4. Utilizar as variáveis de ambiente no seu código

Você pode utilizar essas variáveis de ambiente na sua aplicação. Por exemplo, nosso script para obter o número do bloco atual utilizando um arquivo .env seria o seguinte:

const { ethers } = require('ethers');
require('dotenv').config();

const alchemyUrl = process.env.ALCHEMY_URL;
const provider = new ethers.JsonRpcProvider(alchemyUrl);

async function getBlockNumber() {
  try {
    const blockNumber = await provider.getBlockNumber();
    console.log('NĂşmero de bloque actual:', blockNumber);
  } catch (e) {
    console.error('Error al obtener el nĂşmero de bloque', e);
  }
}

getBlockNumber();

5. Usar um arquivo .gitignore

Certifique-se de adicionar seu arquivo .env ao arquivo .gitignore para que ele nĂŁo seja enviado ao seu repositĂłrio Git e suas credenciais nĂŁo sejam expostas acidentalmente.

.env
node_modules

E a estrutura do seu repositĂłrio deve ser semelhante a esta:

mi-proyecto/
├── .env
├── .gitignore
├── index.js
└── package.json

Com esses passos, sua aplicação pode usar variáveis de ambiente definidas em um arquivo .env, mantendo a configuração flexível e segura.

Fazer uma chamada de escrita em Sepolia

Agora vamos ver como devemos proceder para executar uma transação que implica uma alteração na blockchain.

Neste exemplo, faremos a transferĂŞncia de ETH de uma conta para outra dentro da rede Sepolia. Para isso, precisamos ter o seguinte:

  • Uma URL de acesso Ă  Sepolia no formato: https://eth-sepolia.g.alchemy.com/v2/TU_ACCESO (vocĂŞ deve obtĂŞ-la de forma semelhante Ă  da mainnet em um serviço como o Alchemy).

  • A chave privada da wallet de origem dos fundos.

  • O endereço de destino dos fundos.

  • Incluir os dados da URL de acesso e da chave privada no arquivo .env.

const { ethers } = require('ethers');
require('dotenv').config();

// URL do provedor Sepolia do arquivo .env
const sepoliaUrl = process.env.SEPOLIA_URL;

// Crie um provedor usando a URL da Sepolia
const provider = new ethers.JsonRpcProvider(sepoliaUrl);

// Carregue a carteira a partir de uma chave privada
const privateKey = process.env.PRIVATE_KEY;
const wallet = new ethers.Wallet(privateKey, provider);

async function sendTransaction() {
  const tx = {
    to: 'TARGET_ADDRESS', // Endereço de destino que você deve especificar
    value: ethers.parseEther('0.1'), // quantidade a enviar em ETH
    gasLimit: 21000,
    // gasPrice: opcional, você pode deixar o fornecedor determinar o preço apropriado
  };

  try {
    const txResponse = await wallet.sendTransaction(tx);
    console.log('TransacciĂłn enviada:', txResponse.hash);

    // Aguarde a validação da transação
    const receipt = await txResponse.wait();
    console.log('Transação validada:', receipt);
  } catch (e) {
    console.error('Error ao enviar a transação', e);
  }
}

sendTransaction();

Chamadas mais usadas no ethers.js

Provedores (providers)

  1. Criação de um provedor

    const provider = new ethers.JsonRpcProvider(url);
  2. Obter o nĂşmero do bloco atual

    const blockNumber = await provider.getBlockNumber();
  3. Obter o saldo de um endereço

    const balance = await provider.getBalance(address);
  4. Obter informações de um bloco

    const block = await provider.getBlock(blockNumber);
  5. Obter o histórico de transações de um endereço

    const history = await provider.getHistory(address);
  6. Obter o preço do gás

    const gasPrice = await provider.getGasPrice();
  7. Obter uma transação

    const tx = await provider.getTransaction(transactionHash);
  8. Obter o status de uma transação

    const txReceipt = await provider.getTransactionReceipt(txHash);

Wallets

  1. Criar uma carteira aleatĂłria

    const wallet = ethers.Wallet.createRandom();
    console.log("Address:", wallet.address);//para ver a conta
    console.log("Private Key:", wallet.privateKey); //para ver a chave privada
  2. Carregar uma carteira a partir de uma chave privada

    const wallet = new ethers.Wallet(privateKey);
  3. Conectar uma carteira a um provedor

    const connectedWallet = wallet.connect(provider);
  4. Assinar uma mensagem

    const signedMessage = await wallet.signMessage(message);
  5. Enviar uma transação

    const txResponse = await wallet.sendTransaction(transaction);

Utilitários

  1. Converter Ether para Wei

    const weiAmount = ethers.parseEther("1.0");
  2. Converter Wei para Ether

    const etherAmount = ethers.formatEther(weiAmount);
  3. Calcular o hash de uma mensagem

    const messageHash = ethers.hashMessage(message);
  4. Obter o endereço de um contrato a partir de seu bytecode

    const contractAddress = ethers.getContractAddress(transaction);

Contratos

  1. Conectar a um contrato

    const contract = new ethers.Contract(contractAddress, abi, provider);
  2. Chamar uma função somente leitura

    const result = await contract.someReadOnlyFunction();
  3. Enviar uma transação para uma função de escrita

    const txResponse = await contract.someWriteFunction(params, { gasLimit, gasPrice });
  4. Ouvir eventos de um contrato

    contract.on("EventName", (param1, param2, event) => {
      console.log(param1, param2, event);
    });

Last updated