Recentemente escrevi um artigo explicando tecnicamente 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 Bitcoin JS, com o objetivo de termos ao final dele uma aplicação console que permita as operações básicas em redes blockchain Bitcoin ou que sigam o padrão da mesma.
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 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-btcjs 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 bip32 bip39 bitcoinjs-lib tiny-secp256k1 |
O pacote BitcoinJS-lib é muito utilizado para desenvolvimento de aplicações JavaScript integradas à blockchain do BTC. Já os pacote BIP32 e BIP39 são bibliotecas que implementam aspectos de geração de chaves no padrão das carteiras do BTC (BIP significa Bitcoin Improvement Proposal, o equivalente aos EIP do ecossistema Ethereum).
Agora crie um arquivo index.js na raiz da sua aplicação e carregue o módulo readline.
1 2 3 4 5 6 7 8 |
//index.js const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) |
O código de leitura de inputs do usuário no terminal exige 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 as bibliotecas que vamos precisar e implementaremos, uma a uma, as funções de comunicação com a blockchain usando tal biblioteca.
Com estas bibliotecas carregadas, vamos guardar em constantes as configurações de rede (NETWORK) e o caminho de derivação de carteiras (PATH). Estas duas informações estão apontadas neste exemplo para Testnet do BTC, mas você pode apontar para produção se quiser, seguindo as instruções nos comentários. 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 9 10 11 12 13 14 |
//WalletService.js const BIP32Factory = require("bip32"); const ecc = require("tiny-secp256k1"); const bip32 = BIP32Factory.default(ecc); const bip39 = require("bip39"); const bitcoin = require("bitcoinjs-lib"); const NETWORK = bitcoin.networks.testnet;//ou mainnet const PATH = "m/49'/1'/0'/0";//o /1 indica testnet, ou /0 para mainnet 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 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
//WalletService.js function createWallet() { let mnemonic = bip39.generateMnemonic(); const seed = bip39.mnemonicToSeedSync(mnemonic); let root = bip32.fromSeed(seed, NETWORK); let account = root.derivePath(PATH); let node = account.derive(0).derive(0); let address = bitcoin.payments.p2pkh({ pubkey: node.publicKey, network: NETWORK }).address; myWallet = { address, privateKey: node.toWIF() } return myWallet; } module.exports = { createWallet } |
Aqui usei a função bip39.generateMnemonic para criar uma frase mnemônica aleatória e com ela gerar a seed de carteiras. Com a seed e a informação da rede, conseguimos criar a raiz (root) de derivação que por sua vez irá derivar em uma conta da qual pegaremos o endereço e a chave privada nas linhas seguintes, guardando estas duas informações em um objeto. 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 BTC"); 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": sendBtc(); 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, aguarde!
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.