
Mobile Wallet Adapter
Se você já construiu dApps Solana com wallet-adapter, conhece o procedimento: o usuário clica em Conectar, a extensão do navegador aparece, o usuário aprova. Simples. Mas tente isso em um celular e você descobrirá que tudo o que você sabe sobre conexões de carteira está errado.
Não existem extensões de navegador no mobile. Usuários não navegam dentro de navegadores dApp das carteiras. O modelo familiar de popup não se traduz para apps nativos. O Mobile Wallet Adapter existe porque o modelo web fundamentalmente não funciona em celulares.
Por que o Mobile é Diferente
Na web, extensões de carteira se injetam no contexto JavaScript do navegador. Seu dApp as descobre, solicita uma conexão, e a extensão cuida da assinatura. A carteira vive dentro do mesmo processo do navegador que seu dApp.
Sistemas operacionais mobile não funcionam assim. iOS e Android isolam apps uns dos outros por segurança. Seu dApp não pode acessar a memória de outro app, chamar suas funções ou compartilhar um contexto JavaScript. Cada app é uma fortaleza.
Esse isolamento cria um problema fundamental: como seu dApp pede a um app de carteira para assinar algo quando eles não podem se comunicar diretamente?
A resposta é o Mobile Wallet Adapter, um protocolo que estabelece canais de comunicação criptografados entre apps usando o sistema de mensagens inter-app do sistema operacional, combinado com conexões WebSocket locais.
Vantagens principais
UX Nativa: Usuários permanecem em seus apps de carteira familiares em vez de experiências de navegador embarcadas
Segurança Aprimorada: Chaves privadas nunca saem do app da carteira, nem temporariamente
Compatibilidade Universal: Uma implementação funciona com qualquer carteira compatível com MWA (Phantom, Solflare, e outras)
O Modelo de Sessão
O wallet-adapter web mantém uma conexão persistente. Você conecta uma vez, depois assina transações quando necessário durante a sessão. A carteira lembra que você está conectado.
O MWA funciona de forma diferente. Cada interação é uma sessão atômica que abre, realiza operações e fecha. Pense nisso como fazer uma ligação telefônica versus ter uma conexão de chat sempre ativa.
Fluxo do wallet-adapter web:
Connect → [persistent connection] → Sign → Sign → Sign → DisconnectFluxo do Mobile Wallet Adapter:
Open Session → Authorize → Sign (uma ou mais) → Close Session
Open Session → Authorize → Sign (uma ou mais) → Close Session
...repetir para cada interaçãoToda vez que seu app precisa da carteira, ele abre uma nova sessão. Dentro dessa sessão, você pode autorizar (ou re-autorizar com um token em cache) e solicitar múltiplas assinaturas. Quando a sessão fecha, a carteira pode retornar ao segundo plano.
Isso pode parecer ineficiente, mas na verdade é elegante:
Sem conexões obsoletas: Você nunca precisa lidar com "carteira desconectou inesperadamente"
Intenção clara do usuário: Cada sessão é uma ação explícita do usuário
Eficiente em bateria: Sem WebSocket persistente consumindo energia
A Função transact
Todo o SDK do MWA gira em torno de uma função: transact(). Tudo acontece dentro de seu callback.
import { transact, Web3MobileWallet } from '@solana-mobile/mobile-wallet-adapter-protocol-web3js';
await transact(async (wallet: Web3MobileWallet) => {
// Sessão agora está ABERTA
// App da carteira está em primeiro plano
// Usuário pode ver as solicitações do seu dApp
const { accounts } = await wallet.authorize({
identity: APP_IDENTITY,
chain: 'solana:devnet',
});
// Você agora tem a chave pública do usuário
// Solicitar assinaturas, enviar transações, etc.
}); // Sessão FECHA quando o callback completaQuando você chama transact():
Seu app gera um keypair efêmero e cria uma URI de associação
O SO inicia o app da carteira via essa URI
A carteira inicia um servidor WebSocket local
Seu app conecta e realiza um handshake criptografado
Seu callback executa com acesso total à carteira
Quando seu callback retorna (ou lança erro), a sessão termina
O app da carteira vem para o primeiro plano durante este processo. O usuário vê a identidade do seu app e pode aprovar ou rejeitar solicitações. Quando termina, retornam ao seu app.
Autorização vs Conexão
Na web, "conectar" uma carteira significa que a carteira concorda em compartilhar sua chave pública com seu dApp. Assinar é uma operação separada.
O MWA combina esses conceitos de forma diferente. O método authorize tanto estabelece confiança QUANTO recupera contas:
const authResult = await wallet.authorize({
identity: {
name: 'Meu dApp Solana',
uri: 'https://mydapp.com',
icon: 'favicon.ico',
},
chain: 'solana:devnet',
});
// authResult contém:
// - accounts: endereços da carteira do usuário
// - auth_token: salve isso para re-autorização silenciosa
// - wallet_uri_base: para conexões diretas futurasO objeto identity é crucial. Carteiras exibem esta informação aos usuários para que saibam qual app está solicitando acesso. No Android, carteiras podem verificar criptograficamente que a solicitação veio realmente do app que reivindica essa identidade, não de um impostor malicioso.
Re-autorização silenciosa
Ninguém quer aprovar conexões de carteira repetidamente. O MWA resolve isso com auth tokens:
// Primeira vez: usuário vê diálogo de aprovação
const result = await wallet.authorize({
identity: APP_IDENTITY,
chain: 'solana:devnet',
});
// Salvar o token
await AsyncStorage.setItem('auth_token', result.auth_token);
// Sessões posteriores: incluir o token
const cachedToken = await AsyncStorage.getItem('auth_token');
await transact(async (wallet) => {
const result = await wallet.authorize({
identity: APP_IDENTITY,
chain: 'solana:devnet',
auth_token: cachedToken, // Pular aprovação se válido
});
// Se o token for válido, nenhum prompt do usuário é necessário
});Auth tokens são strings opacas; seu formato é específico da carteira. Seu app apenas armazena e os passa. Se um token expirar ou se tornar inválido, a carteira solicitará uma nova autorização.
Assinando Transações
Uma vez autorizado dentro de uma sessão, você pode solicitar assinaturas. O MWA fornece duas abordagens:
signAndSendTransactions (Recomendado)
A carteira assina E transmite a transação. Este é o método preferido porque:
A carteira cuida da seleção do endpoint RPC
Melhor lógica de retry
Menos round-trips de rede do seu app
await transact(async (wallet) => {
const { accounts } = await wallet.authorize({
identity: APP_IDENTITY,
chain: 'solana:devnet',
});
const fromPubkey = new PublicKey(toByteArray(accounts[0].address));
// Construir sua transação
const tx = new VersionedTransaction(/* ... */);
// Carteira assina e envia para a rede
const signatures = await wallet.signAndSendTransactions({
transactions: [tx],
});
console.log('Assinatura da transação:', signatures[0]);
});signTransactions
Se você precisa da transação assinada de volta (para simulação, envio personalizado ou assinatura multi-parte), use este método:
const signedTxs = await wallet.signTransactions({
transactions: [tx1, tx2],
});
// signedTxs estão assinadas mas NÃO enviadas
// Seu app deve enviá-las para a rede
await connection.sendTransaction(signedTxs[0]);O que Esperar
Este curso ensina você a construir dApps React Native prontos para produção com Mobile Wallet Adapter. Ao final, você terá:
Um entendimento completo do protocolo MWA e ciclo de vida de sessão
Um projeto React Native funcionando com polyfills e dependências adequadas
Um AuthorizationProvider para gerenciar estado da carteira em todo seu app
Padrões de tratamento de erros para cada modo de falha
Um app capstone que envia tokens entre carteiras
Pré-requisitos
Conhecimento básico de React e TypeScript
Familiaridade com conceitos Solana (transações, contas, chaves públicas)
Experiência com
@solana/web3.jsé útil mas não obrigatóriaUm dispositivo Android com uma carteira Solana instalada (Phantom ou Solflare recomendados)
Nota: Embora emuladores funcionem para desenvolvimento básico de UI, testar MWA requer um dispositivo real com um app de carteira instalado.
Estrutura do Curso
Vamos começar entendendo exatamente o que acontece quando seu app abre aquela conexão de carteira.