Exemplo de dApp Wagmi
Introdução
O CrossFi dApp Example é uma aplicação Next.js mínima construída com wagmi v2 e viem v2 que demonstra interações centrais de EVM na CrossFi Chain. Este exemplo serve como ponto de partida prático para desenvolvedores que desejam construir aplicações descentralizadas na rede CrossFi compatível com EVM.
A aplicação demonstra:
- Conexão de carteira: Conecte o MetaMask à CrossFi Testnet e Mainnet
- Informação da conta: Exibir o endereço da carteira conectada e o saldo de XFI
- Transferências nativas: Enviar tokens XFI para qualquer endereço
- Assinatura de mensagens: Assine mensagens arbitrárias usando
signMessage
Repositório no GitHub: https://github.com/crossfichain/dapp-example
Quando usar este exemplo
Este exemplo é útil para:
- Início rápido: obtenha uma dApp funcional em minutos para entender a integração da CrossFi EVM
- Validação de RPC: Testar os endpoints RPC da CrossFi Testnet/Mainnet e a conectividade da rede
- Fundação da integração: Use como modelo para construir dApps mais complexos
- Aprendendo wagmi: Entenda como usar hooks do wagmi com a CrossFi Chain
- Testes de desenvolvimento: Protótipo rápido para testar interações da carteira e transações
Pré-requisitos
Antes de executar este exemplo, certifique-se de ter:
- Node.js 18+ instalado no seu sistema
- Gerenciador de pacotes yarn (ou npm/pnpm)
- Extensão de navegador MetaMask (ou outra carteira compatível com Web3)
- Tokens XFI de teste na CrossFi Testnet (para testes de transações)
Para obter tokens XFI de teste, você pode:
- Usar o faucet da CrossFi Testnet (ver os recursos oficiais da CrossFi)
- Solicitar tokens da comunidade
Instalação e Execução
Clone o repositório e instale as dependências:
git clone https://github.com/crossfichain/dapp-example.git
c d dapp-example
yarn
Inicie o servidor de desenvolvimento:
yarn dev
A aplicação ficará disponível em http://localhost:3000.
Comandos opcionais
yarn build # Build para produção
yarn start # Executar build de produção
Visão geral do projeto
Tecnologias
- Next.js 16 - Framework React com App Router
- React 19 - Biblioteca de UI
- TypeScript - Desenvolvimento com tipagem estática
- wagmi v2 - Hooks do React para Ethereum
- viem v2 - Biblioteca TypeScript para Ethereum
- Material-UI (MUI) - Biblioteca de componentes de UI
- notistack - Sistema de notificações
Projeto Estrutura
app/
components/
Header.tsx # Conexão e estado da carteira
AccountWidget.tsx # Exibir endereço e saldo
NetworkSwitcher.tsx # Alternar entre Testnet/Mainnet
SendTxWidget.tsx # Enviar transações XFI
SignMessageWidget.tsx # Assinar mensagens
connector/
index.tsx # Configuração wagmi
lib/
theme.ts # Configuração de tema MUI
layout.tsx # Layout do app com provedores
page.tsx # Componente da página principal
Funções dos Componentes
- Header: Gerencia a conexão/desconexão da carteira usando o conector MetaMask e exibe o status da conexão
- AccountWidget: Exibe o endereço da carteira conectada e o saldo de XFI usando hooks do wagmi
- NetworkSwitcher: Permite aos usuários alternar entre CrossFi Testnet (ID da cadeia 4157) e Mainnet (ID da cadeia 4158)
- SendTxWidget: Gerencia transferências nativas de tokens XFI com acompanhamento de transação
- SignMessageWidget: Demonstra a funcionalidade de assinatura de mensagens
Configuração de Rede
A aplicação suporta tanto a CrossFi Testnet quanto a Mainnet. A configuração da rede é definida em app/connector/index.tsx:
export const CHAIN_CONFIG = {
testnet: {
chanId: 4157,
name: 'CrossFi Testnet',
rpcUrls: 'https://rpc.testnet.ms',
nativeCurrency: {
name: 'XFI',
symbol: 'XFI',
decimals: 18,
},
},
mainnet: {
chanId: 4158,
name: 'CrossFi Mainnet',
rpcUrls: 'https://rpc.mainnet.ms',
nativeCurrency: {
name: 'XFI',
symbol: 'XFI',
decimals: 18,
},
},
};
export const wagmiConfig = createConfig({
chains: [
{
id: CHAIN_CONFIG.testnet.chanId,
name: CHAIN_CONFIG.testnet.name,
rpcUrls: {
default: { http: [CHAIN_CONFIG.testnet.rpcUrls] },
},
nativeCurrency: CHAIN_CONFIG.testnet.nativeCurrency,
},
{
id: CHAIN_CONFIG.mainnet.chanId,
name: CHAIN_CONFIG.mainnet.name,
rpcUrls: {
default: { http: [CHAIN_CONFIG.mainnet.rpcUrls] },
},
nativeCurrency: CHAIN_CONFIG.mainnet.nativeCurrency,
},
],
connectors: [metaMask()],
ssr: true,
transports: {
[CHAIN_CONFIG.testnet.chanId]: http(CHAIN_CONFIG.testnet.rpcUrls),
[CHAIN_CONFIG.mainnet.chanId]: http(CHAIN_CONFIG.mainnet.rpcUrls),
},
});
Pontos-chave de Configuração
- IDs de Cadeia: Testnet usa
4157, Mainnet usa4158 - RPC URLs: Conexões HTTP diretas aos endpoints RPC CrossFi
- Moeda Nativa: XFI com 18 decimais em ambas as redes
- Conector: MetaMask está configurado como o conector da carteira
- Suporte SSR: renderização do lado do servidor está habilitada para Next.js
As URLs de exploradores de blocos não estão configuradas neste exemplo. Você pode adicioná-las como melhoria opcional se exploradores oficiais da CrossFi estiverem disponíveis.
Conectando uma Carteira
O componente Header gerencia a conexão da carteira usando os hooks useConnect, useAccount e useDisconnect do wagmi:
import { useAccount, useConnect, useDisconnect } from 'wagmi';
import { metaMask } from 'wagmi/connectors';
export function Header() {
const { address, isConnected, chain } = useAccount();
const { connect, isPending } = useConnect();
const { disconnect } = useDisconnect();
return (
// UI renders based on connection state
{!isConnected ? (
<Button onClick={() => connect({ connector: metaMask() })} disabled={isPending}>
{isPending ? 'Connecting...' : 'Connect Wallet'}
</Button>
) : (
<Box>
<Typography>{address?.slice(0, 6)}...{address?.slice(-4)}</Typography>
<Typography>{chain?.name}</Typography>
<Button onClick={() => disconnect()}>Disconnect</Button>
</Box>
)}
);
}
Fluxo de Conexão
- O usuário clica no botão "Conectar Carteira"
- A janela pop-up do MetaMask aparece solicitando permissão
- O usuário aprova a conexão
- Atualizações de UI para mostrar:
- Endereço da carteira encurtado (ex.,
0x1234...5678) - Nome da rede atual
- Botão "Disconnect"
- Endereço da carteira encurtado (ex.,
- Enquanto estiver conectando, o botão exibe o estado "Connecting..."
Troca de Rede
O componente NetworkSwitcher permite aos usuários alternar entre CrossFi Testnet e Mainnet:
import { useSwitchChain } from 'wagmi';
export function NetworkSwitcher() {
const { chain } = useAccount();
const { switchChain } = useSwitchChain();
return (
<TextField
select
value={chain?.id || ''}
onChange={e => switchChain({ chanId: Number(e.target.value) })}
>
{Object.values(CHAIN_CONFIG).map(net => (
<MenuItem key={net.chanId} value={net.chanId}>
{net.name}
</MenuItem>
))}
</TextField>
);
}
O hook useSwitchChain aciona uma solicitação de troca de rede pelo MetaMask quando o usuário seleciona uma rede diferente no menu suspenso.
Visualizando Conta e Saldo
O componente AccountWidget exibe o endereço da carteira conectada e o saldo de XFI:
import { useAccount, useBalance } from 'wagmi';
export function AccountWidget() {
const { address, isConnecting } = useAccount();
const { data, isLoading } = useBalance({ address });
return (
<Card>
<CardContent>
<Typography variant="h6">Address</Typography>
{isConnecting ? <Typography>Loading...</Typography> : <Typography>{address}</Typography>}
<Typography variant="h6">Balance</Typography>
{isLoading ? (
<Typography>Loading...</Typography>
) : (
<Typography>{data ? `${data.formatted} ${data.symbol}` : 'No Data'}</Typography>
)}
</CardContent>
</Card>
);
}
Como funciona
useAccount: Fornece o endereço da carteira conectada atualmenteuseBalance: Busca o saldo de XFI para o endereço conectado a partir do endpoint RPC- Atualizações automáticas: O saldo é atualizado automaticamente quando a rede ou a conta muda
- Exibição formatada: O saldo é formatado com as casas decimais corretas e exibe o símbolo da moeda (XFI)
Enviando Transações XFI
O componente SendTxWidget demonstra como enviar transferências nativas de XFI:
import { useSendTransaction, useWaitForTransactionReceipt } from 'wagmi';
import { isAddress, parseEther } from 'viem';
export function SendTxWidget() {
const { sendTransaction, data, isPending, isError, error } = useSendTransaction();
const { data: receipt, isLoading } = useWaitForTransactionReceipt({ hash: data });
const [recipient, setRecipient] = useState('');
const [amount, setAmount] = useState('');
const handleSend = async () => {
if (!isAddress(recipient)) {
enqueueSnackbar('Please fill correct recipient', { variant: 'warning' });
return;
}
sendTransaction({
to: recipient as Address,
value: parseEther(amount),
});
enqueueSnackbar('Transaction sent', { variant: 'success' });
};
// Display transaction receipt when available
{receipt && (
<>
<Typography>Transaction hash: {receipt.transactionHash}</Typography>
<Typography>Block: {receipt.blockNumber}</Typography>
</>
)}
}
Fluxo de Transação
- Entrada do Usuário: O usuário insere o endereço do destinatário e o valor em XFI
- Validação: O endereço é validado usando
isAddress()do viem - Conversão de Valor: O valor é convertido de XFI para wei usando
parseEther() - Enviar Transação:
sendTransaction()é chamado com destinatário e valor - Confirmação do MetaMask: O usuário confirma a transação no MetaMask
- Aguardar Recibo:
useWaitForTransactionReceiptmonitora o status da transação - Exibir Resultado: O hash da transação e o número do bloco são exibidos quando minerado
Principais Recursos
- Validação de Endereço: Garante que o endereço do destinatário seja válido antes de enviar
- Conversão de valores: Converte automaticamente valores legíveis para wei
- Rastreamento de transação: Exibe o hash da transação imediatamente e o número do bloco após a mineração
- Tratamento de erros: Exibe notificações de erro se a transação falhar
- Estados de carregamento: Exibe indicadores de carregamento durante o processamento da transação
Este exemplo demonstra apenas transferências nativas de XFI. Não inclui transferências de tokens ERC-20 nem interações com contratos inteligentes. Isso exigiria ABI de contrato adicional e hooks wagmi diferentes.
Assinando uma Mensagem
O componente SignMessageWidget demonstra a assinatura de mensagens usando a chave privada da carteira:
import { useSignMessage } from 'wagmi';
export function SignMessageWidget() {
const [message, setMessage] = useState('');
const [signature, setSignature] = useState('');
const { signMessageAsync, isPending } = useSignMessage();
const handleSign = async () => {
try {
const sig = await signMessageAsync({ message });
setSignature(sig);
} catch (error) {
console.error(error);
}
};
return (
<Card>
<CardContent>
<Typography variant="h6">Sign Message</Typography>
<TextField
label="Message"
value={message}
onChange={e => setMessage(e.target.value)}
/>
<Button onClick={handleSign} disabled={isPending}>
{isPending ? 'Signing...' : 'Sign'}
</Button>
{signature && (
<Box>
<Typography variant="body2">Signature:</Typography>
<Typography variant="caption">{signature}</Typography>
</Box>
)}
</CardContent>
</Card>
);
}
Como funciona a assinatura de mensagens
- O usuário insere uma mensagem de texto arbitrária
- O usuário clica no botão "Sign"
- A janela pop-up do MetaMask pede ao usuário para assinar a mensagem
- O usuário aprova a solicitação de assinatura
- A assinatura é exibida na interface (uma string hex começando com
0x)
Limitações Atuais
Este exemplo demonstra apenas signMessage (assinatura pessoal). O seguinte não está incluído neste exemplo:
- Assinatura de dados tipados EIP-712 (
signTypedData) - assinatura de dados estruturados - Verificação de assinatura - verificação on-chain ou off-chain
- Recuperação de mensagem - recuperando o endereço do signatário a partir de uma assinatura
Esses recursos adicionais de assinatura podem ser implementados em exemplos separados ou adicionados a este projeto como melhorias.
Executando o Exemplo
Siga estes passos para executar a dApp localmente:
- Clonar o repositório:
git clone https://github.com/crossfichain/dapp-example.git
c dapp-example
2. **Instalar dependências**:
```bash
yarn
-
Iniciar servidor de desenvolvimento:
yarn dev -
Abrir no navegador: Navegue para
http://localhost:3000 -
Configurar MetaMask:
- Se CrossFi Testnet não estiver no seu MetaMask, a dApp solicitará que você a adicione
- Alternativamente, você pode adicionar a rede manualmente usando o guia de configuração de rede
-
Obter XFI de teste:
- Obtenha tokens XFI de teste do faucet da CrossFi Testnet
- Verifique os canais oficiais da CrossFi para links de faucet
-
Teste os recursos:
- Clique em "Connect Wallet" e aprove a conexão do MetaMask
- Visualize seu endereço e saldo no Account Widget
- Alternar entre Testnet e Mainnet usando o Network Switcher
- Envie uma pequena quantidade de XFI para outro endereço usando o widget Send Transaction
- Assine uma mensagem de teste usando o widget Sign Message
Limitações e próximos passos
O que este exemplo inclui
✅ Conector MetaMask via wagmi
✅ Transferências nativas de XFI (enviar/receber tokens XFI)
✅ Assinatura de mensagens (signMessage)
✅ Troca de Rede entre Testnet e Mainnet
✅ Exibição de saldo e informações da conta
O que não está incluído
As seguintes funções não estão implementadas neste exemplo e podem ser adicionadas em futuras iterações:
❌ Web3Modal - interface de conexão multi-wallet
❌ WalletConnect - suporte para carteira móvel
❌ Dados tipados EIP-712 - signTypedData para assinaturas estruturadas
❌ Verificação de assinatura - verificação on-chain ou off-chain
❌ Interações com contratos inteligentes - leitura de ou escrita em contratos implantados
❌ Transferências ERC-20 - envio de tokens diferentes de XFI nativo
❌ Estimativa de gás - cálculo de custos de transação
❌ Integração com exploradores de blocos - links para ver transações no explorer
Possíveis melhorias
Versões futuras ou guias separados poderiam incluir:
- Suporte para múltiplos conectores de carteira (WalletConnect, Coinbase Wallet, etc.)
- Exemplos de implantação e interação com contratos inteligentes
- Operações de tokens ERC-20, ERC-721 e ERC-1155
- Integração com recursos específicos da CrossFi (se houver)
- Tratamento de erros pronto para produção e feedback ao usuário
- Histórico de transações e exibição de recibos
- Otimização de preço de gás
Conclusão
O CrossFi dApp Example fornece uma base sólida para construir aplicações descentralizadas na CrossFi EVM. Ele demonstra as interações essenciais necessárias para a maioria das dApps: conexão da carteira, verificação de saldo, transações e assinatura de mensagens.
Use este exemplo como ponto de partida e estenda-o com recursos adicionais conforme necessário para o seu caso de uso específico. Para tópicos mais avançados, explore outras seções da documentação da CrossFi.
Recursos