Recentemente escrevi um artigo explicando tenicamente como as carteiras de criptomoedas funcionam, que você pode ler aqui.
No tutorial de hoje, eu vou ensinar como você pode criar sua própria carteira de criptomoedas, ou seja, programar uma aplicação que conecta um usuário à blockchain e dapps web3. Faremos isso utilizando a linguagem JavaScript e a biblioteca Ethers JS, com o objetivo de termos ao final dele uma aplicação console que permita as operações básicas em redes blockchain Ethereum ou que sigam o padrão EVM (+-80% do mercado de blockchain).
Se preferir, você pode assistir ao vídeo abaixo, que tem o mesmo conteúdo.
Vamos lá!
#1 – Por que criar sua própria carteira cripto?
A primeira coisa que deve vir na sua mente é: por que diabos eu iria querer criar a minha própria carteira de criptomoedas?
Essa dúvida é super normal já que existem no mercado diversas opções gratuitas e consolidadas como a MetaMask e a Brave Wallet, entre outras. Mas assim como ocorreu (e ainda ocorre, mas em menor intensidade) com os navegadores de Internet entre o final da década de 90 e início dos anos 2000, estamos no início de uma nova revolução tecnológica e com isso na etapa de surgimento das grandes aplicações de uso cotidiano nesse contexto. Não há ainda uma hegemonia de software em diversos nichos deste mercado e mesmo a MetaMask sendo a líder no setor de carteiras cripto, estamos falando de menos de 30MM de usuários mundialmente em um mercado que tem potencial para os bilhões. E isso não vale apenas para carteiras cripto, mas para diversos nichos na web3.
Não apenas isso, mas aprender como criar sua própria carteira de criptomoedas vai te ajudar também a pensar em novas e interessantes maneiras de interagir com a blockchain ao mesmo tempo que aprofunda seu entendimentos sobre este tipo de software pois apesar do nome, talvez você já tenha ouvido falar que as carteiras não são exatamente “carteiras”, certo? E acho que esse é o ponto principal deste tutorial, te ajudar a entender como esses softwares realmente funcionam, independente se você vier a criar um app como Trust Wallet ou qualquer outro.
Dito isso, nossa primeira missão é entender, tecnicamente, como funciona uma carteira de criptomoedas.
#2 – Como funciona uma carteira de criptomoedas?
Podemos resumir basicamente o funcionamento de uma carteira de criptomoedas como:
- guardar as chaves de uma conta da blokchain;
- consultar os ativos (tokens) desta conta;
- fazer transações nesta conta usando as chaves;
Quaisquer outras funcionalidades além dessas são secundárias e mudam de aplicação para aplicação como por exemplo a criação de novas contas, agenda de contatos frequentes, histórico de atividades, alertas, compra de criptomoedas e muito mais. Aliás, pensando em modelo de negócios, é justamente nessas funcionalidades adicionais é que você pode criar um negócio lucrativo e uma aplicação interessante.
Mas voltando ao que nos interessa, todas essas funcionalidades exigem que o software se comuniquem com ao menos um nó de uma blockchain, para poder consultar e escrever no livro-razão. Assim, em última instância, uma carteira de criptomoedas nada mais é do que um client de blockchain e é justamente isso que faremos neste tutorial, começando a seguir.
#3 – Configurando o Projeto
Os protocolos de comunicação com a blockchain podem ser utilizando com quaisquer tecnologias que permitam comunicação pela rede. Para este projeto optarei por utilizar a linguagem de programação JavaScript, uma das mais versáteis da atualidade, e como farei uma aplicação de console (sem interface gráfica, apenas interação via terminal) utilizarei a tecnologia Node.js que me permite usar JS em aplicações que não estejam no browser.
Caso você não possua o Node.js instalado na sua máquina, o vídeo abaixo ensina a instalar.
Com o Node.js instalado, você pode criar uma pasta no seu computador com o nome de wallet-ethers e abrindo o terminal de linha de comando do seu sistema operacional (cmd no Windows), navegue até a pasta que criou e digite o seguinte comando para inicializar o seu projeto.
1 2 3 |
npm init -y |
Com o projeto inicializado, vamos instalar as dependências que vamos precisar, ainda com o terminal aberto.
1 2 3 |
npm install ethers dotenv |
O pacote Ethers é muito utilizado para desenvolvimento de aplicações JavaScript integradas à blockchain e inclusive tem funcionalidades que facilitarão muito a nossa vida quando o assunto é criar uma carteira cripto. Já o pacote DotEnv serve para carregar variáveis/configurações de ambiente, algo que vai permitir nossa carteira se tornar mais dinâmica e poder ser usada com qualquer rede baseada em Ethereum/EVM.
Agora crie um arquivo .env na pasta do seu projeto com duas variáveis dentro.
1 2 3 4 |
BLOCKCHAIN_NODE=https://data-seed-prebsc-1-s1.binance.org:8545/ SYMBOL=BNB |
A variável BLOCKCHAIN_NODE serve para informar o endereço do nó da blockchain com o qual a sua carteira irá interagir para pegar e escrever as informações. Aqui você deverá fazer uma escolha relacionada à rede na qual a sua carteira irá operar e o exemplo que coloquei no código acima é para uso com a BSC Testnet, ou seja, o ambiente de desenvolvimento da blockchain da Binance. Caso prefira usar outra rede compatível, neste post eu apresento configurações para outras redes de teste.
Já a segunda variável tem a ver com a primeira e serve para você informar qual a moeda nativa que é usada na respectiva rede, um recurso que vai nos ajudar mais tarde para tornar a experiência melhor para o usuário.
Agora crie um arquivo index.js na raiz da sua aplicação e carregue o arquivo .env e suas respectivas variáveis da seguinte forma.
1 2 3 4 5 6 7 8 9 10 11 |
//index.js require("dotenv").config(); const SYMBOL = process.env.SYMBOL; const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) |
No final, eu apenas guardei a variável SYMBOL em uma constante de mesmo nome, pois vamos usá-las em diversos pontos. Na sequência, já adiantei o código de leitura de inputs do usuário no terminal, com o módulo nativo readline, devidamente configurado. Usaremos o readline para interagir com usuário fazendo perguntas e aguardando respostas, típico de aplicações console (se já usou algum CLI na vida, logo vai entender como eles são criados).
#4 – Criando a sua Wallet
A próxima missão é começarmos a implementar as funcionalidades da carteira. Para não misturarmos código de interação do usuário (que ficarão no index.js) com o código da carteira em si, vamos criar um segundo arquivo em nosso projeto chamado WalletService.js. Nele, vamos começar importando a biblioteca Ethers e implementaremos, uma a uma, as funções de comunicação com a blockchain usando tal biblioteca.
Com esta biblioteca carregada, vamos criar a conexão com o nó da blockchain, a nível do módulo (reaproveitaremos essa conexão em todas as funções). Também defini uma variável local myWallet que servirá para guardar o objeto de configuração da carteira, depois que inicializarmos ele.
1 2 3 4 5 6 7 8 |
//WalletService.js const { ethers } = require("ethers"); const provider = new ethers.JsonRpcProvider(process.env.BLOCKCHAIN_NODE); let myWallet = null; |
Falando nele, a primeira função que vamos criar é justamente a de criação da carteira. Nosso software de carteira permitirá tanto a criação de uma nova carteira quanto a importação de uma carteira já existente, mas vamos implementar uma coisa de cada vez.
1 2 3 4 5 6 7 8 9 10 11 |
//WalletService.js function createWallet() { myWallet = ethers.Wallet.createRandom(provider); return myWallet; } module.exports = { createWallet } |
Aqui usei a classe Wallet para criar uma nova carteira aleatoriamente, devolvendo o objeto da mesma para quem chamou a função. Não esqueça de exportar essa função ao final do módulo para que ela possa ser chamada em nosso index.js. Falando nele, vamos começar a implementar nosso menu com as opções que teremos.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
const WalletService = require("./WalletService"); let myAddress = ""; function menu() { setTimeout(() => { console.clear(); if (myAddress) console.log(`You are logged as ${myAddress}`); else console.log(`You aren't logged.`); console.log("1 - Create Wallet"); console.log("2 - Recover Wallet"); console.log("3 - Balance"); console.log("4 - Send " + SYMBOL); console.log("5 - Search tx"); rl.question("Choose your option: ", (answer) => { switch (answer) { case "1": createWallet(); break; case "2": recoverWallet(); break; case "3": getBalance(); break; case "4": sendTx(); break; case "5": searchTx(); break; default: { console.log('Wrong option!'); menu(); } } }) }, 1000) } menu(); |
Aqui eu comecei importando nosso WalletService e declarando uma variável para armazenar o endereço da carteira de quem iniciou a sessão do aplicativo (usaremos esta variável mais tarde). Depois eu declaro uma função menu que limpa o console, verifica se já temos uma carteira (imprimindo no console se houver) e depois imprime as 5 opções que teremos para o usuário, cada uma chamando uma função. Nós não temos essas funções ainda, mas logo teremos.
O principal ponto aqui é entender como o readline (variável rl) funciona: a função question exibe uma pergunta para o usuário e lê a resposta (answer) em um callback assim que ele apertar Enter. Com base nessa resposta, temos a execução da função apropriada. Esse comportamento eu coloquei dentro de um setTimeout para ter tempo do usuário entender o que está acontecendo na aplicação e por fim, chamo a impressão do menu ao final do módulo.
Se rodar o index.js você já terá o menu funcionando, mas se escolher qualquer opção terá um erro até que implemente a mesma.
Para implementar a primeira funcionalidade, crie uma função createWallet() no mesmo arquivo com o seguinte conteúdo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
//index.js function preMenu() { rl.question(`Press any key to continue...`, () => { menu(); }) } function createWallet() { console.clear(); const myWallet = WalletService.createWallet(); myAddress = myWallet.address; console.log(`Your new wallet:`); console.log(myAddress); preMenu(); } |
A createWallet() limpa o console (sempre faremos isso) e chama a função de mesmo nome que deixamos pronta na WalletService.js. O resultado é um objeto com address e privateKey, sendo que o primeir será impresso no console indicando que a nova carteira foi criada com sucesso. Por fim, chamamos uma função preMenu() que aguarda um Enter do usuário antes de reimprimir todo o menu novamente.
Experimente a aplicação do jeito que está, executando ela com “node index” e criando uma nova carteira. Claro, toda vez que rodar a aplicação do zero, terá de criar uma nova carteira, pois não temos banco de dados, isso até que a gente implemente a recuperação de carteiras.
O que faremos na segunda etapa deste tutorial, que você confere aqui!
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.