Web3 e Blockchain: conceitos básicos para desenvolvedores web

1. Do Web2 ao Web3: Mudança de Paradigma

1.1. O que é Web3: descentralização, propriedade de dados e ausência de intermediários

Web3 representa a terceira geração da internet, onde o controle dos dados e a propriedade digital retornam aos usuários. Diferente do Web2, onde gigantes como Google e Facebook centralizam dados e lucram com eles, o Web3 utiliza blockchain para eliminar intermediários. Desenvolvedores web agora criam aplicações onde o usuário realmente possui seus ativos digitais, sejam tokens, NFTs ou identidades.

1.2. Diferenças fundamentais entre arquitetura cliente-servidor (Web2) e rede peer-to-peer (Web3)

No Web2, um servidor central armazena dados e processa requisições. Exemplo clássico:

// Web2: Requisição a uma API REST
fetch('https://api.exemplo.com/usuarios/123')
  .then(res => res.json())
  .then(console.log)

No Web3, não há servidor central. Os dados residem em milhares de nós distribuídos. A comunicação ocorre diretamente com a blockchain:

// Web3: Chamada a um contrato inteligente
const provider = new ethers.providers.Web3Provider(window.ethereum)
const contract = new ethers.Contract(enderecoContrato, abi, provider)
const dados = await contract.obterDados(123)

1.3. Papel do desenvolvedor web: de consumidor de APIs REST para interação com contratos inteligentes

O desenvolvedor web tradicional consome APIs REST ou GraphQL. No Web3, ele interage com contratos inteligentes — programas imutáveis na blockchain. A lógica de negócio migra do backend para o contrato, e o frontend se torna a interface para essa lógica descentralizada.

2. Fundamentos de Blockchain para Desenvolvedores

2.1. O que é um blockchain: blocos, hashes, cadeia imutável e consenso

Um blockchain é um livro-razão digital onde cada bloco contém transações e um hash do bloco anterior, formando uma cadeia imutável. O consenso (Proof of Work ou Proof of Stake) valida novos blocos sem necessidade de autoridade central.

Bloco 1:
  Hash: 0x4f3a...
  Hash anterior: 0x0000...
  Transações: [tx1, tx2]

Bloco 2:
  Hash: 0x9b2c...
  Hash anterior: 0x4f3a...
  Transações: [tx3, tx4]

2.2. Contratos inteligentes: código autoexecutável na blockchain

Contratos inteligentes são programas que rodam na blockchain. Exemplo em Solidity:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Contador {
    uint256 public valor;

    function incrementar() public {
        valor += 1;
    }
}

2.3. Endereços, chaves públicas/privadas e carteiras

Assim como sessões e tokens JWT autenticam usuários no Web2, no Web3 a autenticação ocorre via criptografia de chave pública/privada. O endereço Ethereum (ex: 0x123...) é derivado da chave pública. A carteira (MetaMask, WalletConnect) gerencia essas chaves e assina transações.

3. Ferramentas e Ambiente de Desenvolvimento Web3

3.1. Provedores de nó: Infura, Alchemy e conexão com redes

Provedores como Infura e Alchemy oferecem acesso a nós Ethereum sem necessidade de rodar um nó próprio:

const provider = new ethers.providers.InfuraProvider('sepolia', 'SUA_API_KEY')

3.2. Bibliotecas essenciais: Ethers.js e Web3.js

Ethers.js é a biblioteca mais moderna para interagir com Ethereum:

// Provider: conexão com a blockchain
// Signer: quem assina transações (carteira)
// Contract: interface para contratos inteligentes

const provider = new ethers.providers.Web3Provider(window.ethereum)
const signer = provider.getSigner()
const contract = new ethers.Contract(endereco, abi, signer)

3.3. Wallets para navegador: MetaMask

MetaMask injeta window.ethereum no navegador. Para conectar:

async function conectarCarteira() {
  if (window.ethereum) {
    const contas = await window.ethereum.request({ 
      method: 'eth_requestAccounts' 
    })
    return contas[0]
  }
}

4. Interagindo com Contratos Inteligentes a partir do Frontend

4.1. Lendo dados da blockchain: chamadas call

Chamadas call são gratuitas e apenas leem dados:

const saldo = await contract.balanceOf(enderecoUsuario)
console.log(`Saldo: ${ethers.utils.formatEther(saldo)} ETH`)

4.2. Escrevendo dados: transações send

Transações send modificam o estado e custam gas:

const tx = await contract.transfer(enderecoDestino, ethers.utils.parseEther("0.1"))
await tx.wait() // Aguarda confirmação
console.log(`Transação confirmada: ${tx.hash}`)

4.3. Eventos e logs: escutando mudanças em tempo real

Contratos emitem eventos que o frontend pode escutar:

contract.on("Transfer", (from, to, value) => {
  console.log(`Transferência: ${from} -> ${to}: ${value}`)
})

5. Autenticação Descentralizada e Identidade Digital

5.1. Login com carteira (Sign-in with Ethereum — EIP-4361)

Em vez de senha, o usuário assina uma mensagem:

const mensagem = `Bem-vindo ao DApp!
Nonce: ${nonce}
Endereço: ${endereco}`

const assinatura = await signer.signMessage(mensagem)
// Enviar mensagem + assinatura para backend verificar

5.2. Recuperação de endereço e nonce para evitar replay attacks

O backend verifica a assinatura e recupera o endereço:

const enderecoRecuperado = ethers.utils.verifyMessage(mensagem, assinatura)
if (enderecoRecuperado === endereco) {
  // Autenticado!
}

5.3. Diferenças práticas: session storage vs. chave pública como identificador

No Web2, usamos session storage para tokens JWT. No Web3, o identificador é o endereço público da carteira. Não há logout tradicional — a sessão dura enquanto o usuário mantiver a assinatura válida.

6. Armazenamento Descentralizado e Oráculos

6.1. IPFS e Filecoin: armazenamento de metadados e arquivos grandes

IPFS armazena arquivos de forma distribuída. Combinado com contratos:

// Upload para IPFS via Pinata ou Infura
const resultado = await ipfs.add(arquivo)
const hashIPFS = resultado.path // Ex: QmX...
// Armazenar hash no contrato
await contract.definirImagemPerfil(hashIPFS)

Oráculos conectam blockchain a dados externos:

// Contrato solicita preço ETH/USD via Chainlink
uint256 preco = await priceFeed.latestRoundData()

6.3. Combinação prática: frontend web + IPFS para imagens + contrato para ownership

// Frontend: exibe NFT armazenado no IPFS
const hash = await contract.obterTokenURI(tokenId)
const metadata = await fetch(`https://ipfs.io/ipfs/${hash}`)
const imagem = metadata.image // URL IPFS da imagem

7. Segurança, Custos e Boas Práticas para Devs Web

7.1. Gas e estimativas de custo

Cada transação custa gas, pago em ETH. Estimar custo:

const estimativa = await contract.estimateGas.transfer(endereco, valor)
console.log(`Gas estimado: ${estimativa.toString()}`)

7.2. Riscos comuns

  • Reentrância: ataques que chamam o contrato repetidamente
  • Front-running: bots que veem transações pendentes e as antecipam
  • Validação: sempre validar no contrato, nunca apenas no frontend

7.3. Debugging e testes: Hardhat, Ganache

Hardhat permite simular blockchain local:

// hardhat.config.js
module.exports = {
  networks: {
    hardhat: {
      chainId: 31337
    }
  }
}
// Teste local: npx hardhat node

Referências