Communitygithub.com

flutter-dart-code-review

Lista de verificação de revisão de código Flutter/Dart independente de biblioteca, cobrindo práticas recomendadas de widgets, padrões de gerenciamento de estado (BLoC, Riverpod, Provider, GetX, MobX, Signals), expressões idiomáticas Dart, desempenho, acessibilidade, segurança e arquitetura limpa. Use ao revisar código Flutter ou Dart, independentemente da biblioteca de gerenciamento de estado que o projeto utiliza.

O que é flutter-dart-code-review?

Esta skill fornece uma lista de verificação abrangente e independente de bibliotecas para revisão de código Flutter/Dart. Ela é útil para desenvolvedores e revisores que desejam garantir que o código siga as melhores práticas da indústria, cobrindo desde saúde geral do projeto, segurança de tipos e expressões idiomáticas do Dart, até decomposição de widgets, gerenciamento de estado (qualquer solução: BLoC, Riverpod, Provider, GetX, MobX, Signals), desempenho, testes, acessibilidade, design responsivo e segurança. A skill é baseada no SKILL.md, que atua como um guia de melhores práticas com checklists para cada tópico, ajudando a padronizar revisões e evitar erros comuns. Ela é projetada para ser usada com qualquer assistente de IA que suporte skills, como Claude Code, Cursor ou Codex, fornecendo um conjunto de regras claras para revisão de código Flutter/Dart.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/flutter-dart-code-review

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Práticas Recomendadas de Revisão de Código Flutter/Dart

Lista de verificação abrangente e independente de bibliotecas para revisar aplicativos Flutter/Dart. Esses princípios se aplicam independentemente da solução de gerenciamento de estado, biblioteca de roteamento ou estrutura de injeção de dependência usada.


1. Saúde Geral do Projeto

  • O projeto segue uma estrutura de pastas consistente (primeiro recurso ou primeira camada)
  • Separação adequada de responsabilidades: UI, lógica de negócios, camadas de dados
  • Nenhuma lógica de negócios em widgets; widgets são puramente de apresentação
  • pubspec.yaml está limpo — sem dependências não utilizadas, versões fixadas adequadamente
  • analysis_options.yaml inclui um conjunto de lints estrito com configurações de analisador estritas ativadas
  • Nenhuma declaração print() no código de produção — use dart:developer log() ou um pacote de logging
  • Arquivos gerados (.g.dart, .freezed.dart, .gr.dart) estão atualizados ou no .gitignore
  • Código específico de plataforma isolado atrás de abstrações

2. Armadilhas da Linguagem Dart

  • Dinâmico implícito: Anotações de tipo ausentes levando a dynamic — ative strict-casts, strict-inference, strict-raw-types
  • Mau uso da segurança de nulo: Uso excessivo de ! (operador de explosão) em vez de verificações de nulo adequadas ou correspondência de padrões do Dart 3 (if (value case var v?))
  • Falhas de promoção de tipo: Usar this.field onde a promoção de variável local funcionaria
  • Capturar muito amplamente: catch (e) sem cláusula on; sempre especifique os tipos de exceção
  • Capturar Error: Subtipos de Error indicam bugs e não devem ser capturados
  • async não utilizado: Funções marcadas como async que nunca usam await — sobrecarga desnecessária
  • Uso excessivo de late: late usado onde anulável ou inicialização de construtor seria mais seguro; adia erros para o tempo de execução
  • Concatenação de strings em loops: Use StringBuffer em vez de + para construção iterativa de strings
  • Estado mutável em contextos const: Campos em classes de construtor const não devem ser mutáveis
  • Ignorar valores de retorno de Future: Use await ou chame explicitamente unawaited() para sinalizar intenção
  • var onde final funciona: Prefira final para variáveis locais e const para constantes de tempo de compilação
  • Importações relativas: Use importações package: para consistência
  • Coleções mutáveis expostas: APIs públicas devem retornar visualizações não modificáveis, não List/Map brutos
  • Correspondência de padrões do Dart 3 ausente: Prefira expressões switch e if-case em vez de verificações is verbosas e casting manual
  • Classes descartáveis para múltiplos retornos: Use registros Dart 3 (String, int) em vez de DTOs de uso único
  • print() no código de produção: Use dart:developer log() ou o pacote de logging do projeto; print() não tem níveis de log e não pode ser filtrado

3. Práticas Recomendadas de Widget

Decomposição de widget:

  • Nenhum widget único com um método build() excedendo ~80-100 linhas
  • Widgets divididos por encapsulamento E por como eles mudam (limites de reconstrução)
  • Métodos auxiliares privados _build*() que retornam widgets são extraídos para classes de widget separadas (permite reutilização de elemento, propagação const e otimizações do framework)
  • Widgets sem estado preferidos em vez de com estado onde nenhum estado local mutável é necessário
  • Widgets extraídos estão em arquivos separados quando reutilizáveis

Uso de const:

  • Construtores const usados sempre que possível — evita reconstruções desnecessárias
  • Literais const para coleções que não mudam (const [], const {})
  • Construtor é declarado const quando todos os campos são finais

Uso de chave:

  • ValueKey usado em listas/grades para preservar o estado em reordenações
  • GlobalKey usado com moderação — apenas quando acessar o estado na árvore for realmente necessário
  • UniqueKey evitado em build() — força a reconstrução a cada quadro
  • ObjectKey usado quando a identidade é baseada em um objeto de dados em vez de um único valor

Temas & sistema de design:

  • As cores vêm de Theme.of(context).colorScheme — sem Colors.red ou valores hexadecimais codificados
  • Os estilos de texto vêm de Theme.of(context).textTheme — sem TextStyle embutido com tamanhos de fonte brutos
  • Compatibilidade com modo escuro verificada — sem suposições sobre fundo claro
  • Espaçamento e dimensionamento usam tokens de design consistentes ou constantes, não números mágicos

Complexidade do método build:

  • Nenhuma chamada de rede, E/S de arquivo ou computação pesada em build()
  • Nenhum Future.then() ou trabalho async em build()
  • Nenhuma criação de assinatura (.listen()) em build()
  • setState() localizado na menor subárvore possível

4. Gerenciamento de Estado (Independente de Biblioteca)

Esses princípios se aplicam a todas as soluções de gerenciamento de estado do Flutter (BLoC, Riverpod, Provider, GetX, MobX, Signals, ValueNotifier, etc.).

Arquitetura:

  • A lógica de negócios vive fora da camada de widget — em um componente de gerenciamento de estado (BLoC, Notifier, Controller, Store, ViewModel, etc.)
  • Os gerenciadores de estado recebem dependências via injeção, não as construindo internamente
  • Uma camada de serviço ou repositório abstrai fontes de dados — widgets e gerenciadores de estado não devem chamar APIs ou bancos de dados diretamente
  • Os gerenciadores de estado têm uma única responsabilidade — nenhum gerenciador "deus" lidando com preocupações não relacionadas
  • As dependências entre componentes seguem as convenções da solução:
    • Em Riverpod: provedores dependendo de provedores via ref.watch é esperado — sinalize apenas cadeias circulares ou excessivamente emaranhadas
    • Em BLoC: blocs não devem depender diretamente de outros blocs — prefira repositórios compartilhados ou coordenação na camada de apresentação
    • Em outras soluções: siga as convenções documentadas para comunicação entre componentes

Imutabilidade & igualdade de valor (para soluções de estado imutável: BLoC, Riverpod, Redux):

  • Os objetos de estado são imutáveis — novas instâncias criadas via copyWith() ou construtores, nunca mutadas no local
  • As classes de estado implementam == e hashCode adequadamente (todos os campos incluídos na comparação)
  • O mecanismo é consistente em todo o projeto — override manual, Equatable, freezed, registros Dart ou outros
  • Coleções dentro de objetos de estado não são expostas como List/Map brutos mutáveis

Disciplina de reatividade (para soluções de mutação reativa: MobX, GetX, Signals):

  • O estado é mutado apenas através da API reativa da solução (@action no MobX, .value em signals, .obs no GetX) — a mutação direta de campo ignora o rastreamento de alterações
  • Valores derivados usam o mecanismo computado da solução em vez de serem armazenados redundantemente
  • Reações e descartadores são limpos adequadamente (ReactionDisposer no MobX, limpeza de efeito no Signals)

Design da forma do estado:

  • Estados mutuamente exclusivos usam tipos selados, variantes de união ou o tipo de estado assíncrono embutido da solução (por exemplo, AsyncValue do Riverpod) — não sinalizadores booleanos (isLoading, isError, hasData)
  • Cada operação assíncrona modela carregamento, sucesso e erro como estados distintos
  • Todas as variantes de estado são tratadas exaustivamente na UI — nenhum caso ignorado silenciosamente
  • Estados de erro carregam informações de erro para exibição; estados de carregamento não carregam dados obsoletos
  • Dados anuláveis não são usados como indicador de carregamento — os estados são explícitos
// RUIM — sopa de sinalizadores booleanos permite estados impossíveis
class UserState {
  bool isLoading = false;
  bool hasError = false; // isLoading && hasError é representável!
  User? user;
}

// BOM (abordagem imutável) — tipos selados tornam estados impossíveis não representáveis
sealed class UserState {}
class UserInitial extends UserState {}
class UserLoading extends UserState {}
class UserLoaded extends UserState {
  final User user;
  const UserLoaded(this.user);
}
class UserError extends UserState {
  final String message;
  const UserError(this.message);
}

// BOM (abordagem reativa) — enum observável + dados, mutações via API de reatividade
// enum UserStatus { initial, loading, loaded, error }
// Use o observable/signal da sua solução para encapsular status e dados separadamente

Otimização de reconstrução:

  • Widgets consumidores de estado (Builder, Consumer, Observer, Obx, Watch, etc.) com escopo o mais estreito possível
  • Seletores usados para reconstruir apenas quando campos específicos mudam — não em cada emissão de estado
  • Widgets const usados para interromper a propagação de reconstrução na árvore
  • Estado computado/derivado é calculado reativamente, não armazenado redundantemente

Assinaturas & descarte:

  • Todas as assinaturas manuais (.listen()) são canceladas em dispose() / close()
  • Stream controllers são fechados quando não são mais necessários
  • Timers são cancelados no ciclo de vida de descarte
  • O ciclo de vida gerenciado pelo framework é preferido em vez de assinatura manual (construtores declarativos em vez de .listen())
  • Verificação mounted antes de setState em callbacks assíncronos
  • BuildContext não usado após await sem verificar context.mounted (Flutter 3.7+) — context obsoleto causa travamentos
  • Nenhuma navegação, diálogos ou mensagens de scaffold após lacunas assíncronas sem verificar se o widget ainda está montado
  • BuildContext nunca armazenado em singletons, gerenciadores de estado ou campos estáticos

Estado local vs. global:

  • Estado de UI efêmero (caixa de seleção, controle deslizante, animação) usa estado local (setState, ValueNotifier)
  • O estado compartilhado é elevado apenas o mais alto necessário — não globalizado demais
  • O estado com escopo de recurso é descartado adequadamente quando o recurso não está mais ativo

5. Desempenho

Reconstruções desnecessárias:

  • setState() não chamado no nível do widget raiz — localize as alterações de estado
  • Widgets const usados para interromper a propagação de reconstrução
  • RepaintBoundary usado em torno de subárvores complexas que repintam independentemente
  • Parâmetro filho de AnimatedBuilder usado para subárvores independentes da animação

Operações caras em build():

  • Nenhuma ordenação, filtragem ou mapeamento de grandes coleções em build() — compute na camada de gerenciamento de estado
  • Nenhuma compilação de regex em build()
  • O uso de MediaQuery.of(context) é específico (por exemplo, MediaQuery.sizeOf(context))

Otimização de imagem:

  • Imagens de rede usam cache (qualquer solução de cache apropriada para o projeto)
  • Resolução de imagem apropriada para o dispositivo de destino (sem carregar imagens 4K para miniaturas)
  • Image.asset com cacheWidth/cacheHeight para decodificar no tamanho de exibição
  • Widgets de espaço reservado e de erro fornecidos para imagens de rede

Carregamento preguiçoso:

  • ListView.builder / GridView.builder usado em vez de ListView(children: [...]) para listas grandes ou dinâmicas (construtores concretos são adequados para listas pequenas e estáticas)
  • Paginação implementada para grandes conjuntos de dados
  • Carregamento adiado (deferred as) usado para bibliotecas pesadas em compilações web

Outros:

  • Widget Opacity evitado em animações — use AnimatedOpacity ou FadeTransition
  • Recorte evitado em animações — pré-recorte imagens
  • operator == não sobrescrito em widgets — use construtores const em vez disso
  • Widgets de dimensão intrínseca (IntrinsicHeight, IntrinsicWidth) usados com moderação (passo de layout extra)

6. Testes

Tipos de teste e expectativas:

  • Testes unitários: Cobrem toda a lógica de negócios (gerenciadores de estado, repositórios, funções utilitárias)
  • Testes de widget: Cobrem comportamento de widget individual, interações e saída visual
  • Testes de integração: Cobrem fluxos de usuário críticos de ponta a ponta
  • Testes dourados: Comparações perfeitas de pixel para componentes de UI críticos para o design

Metas de cobertura:

  • Buscar 80%+ de cobertura de linha na lógica de negócios
  • Todas as transições de estado têm testes correspondentes (carregamento → sucesso, carregamento → erro, repetição, etc.)
  • Casos de borda testados: estados vazios, estados de erro, estados de carregamento, valores de contorno

Isolamento de teste:

  • Dependências externas (clientes de API, bancos de dados, serviços) são simuladas ou falsificadas
  • Cada arquivo de teste testa exatamente uma classe/unidade
  • Os testes verificam o comportamento, não detalhes de implementação
  • Stubs definem apenas o comportamento necessário para cada teste (stubbing mínimo)
  • Nenhum estado mutável compartilhado entre casos de teste

Qualidade do teste de widget:

  • pumpWidget e pump usados corretamente para operações assíncronas
  • find.byType, find.text, find.byKey usados apropriadamente
  • Nenhum teste instável dependendo de tempo — use pumpAndSettle ou pump(Duration) explícito
  • Testes executados em CI e falhas bloqueiam merges

7. Acessibilidade

Widgets semânticos:

  • Widget Semantics usado para fornecer rótulos de leitor de tela onde os rótulos automáticos são insuficientes
  • ExcludeSemantics usado para elementos puramente decorativos
  • MergeSemantics usado para combinar widgets relacionados em um único elemento acessível
  • Imagens têm a propriedade semanticLabel definida

Suporte a leitor de tela:

  • Todos os elementos interativos são focalizáveis e têm descrições significativas
  • A ordem de foco é lógica (segue a ordem de leitura visual)

Acessibilidade visual:

  • Relação de contraste >= 4.5:1 para texto contra fundo
  • Alvos tocáveis têm pelo menos 48x48 pixels
  • A cor não é o único indicador de estado (use ícones/texto junto)
  • O texto escala com as configurações de tamanho da fonte do sistema

Acessibilidade de interação:

  • Nenhum callback onPressed sem operação — todo botão faz algo ou está desabilitado
  • Campos de erro sugerem correções
  • O contexto não muda inesperadamente enquanto o usuário está inserindo dados

8. Preocupações Específicas de Plataforma

Diferenças iOS/Android:

  • Widgets adaptativos de plataforma usados onde apropriado
  • Navegação de volta tratada corretamente (botão voltar Android, gesto de deslizar para voltar iOS)
  • Barra de status e área segura tratadas via widget SafeArea
  • Permissões específicas de plataforma declaradas em AndroidManifest.xml e Info.plist

Design responsivo:

  • LayoutBuilder ou MediaQuery usado para layouts responsivos
  • Pontos de interrupção definidos consistentemente (telefone, tablet, desktop)
  • O texto não transborda em telas pequenas — use Flexible, Expanded, FittedBox
  • Orientação paisagem testada ou explicitamente bloqueada
  • Específico para web: interações de mouse/teclado suportadas, estados de hover presentes

9. Segurança

Armazenamento seguro:

  • Dados confidenciais (tokens, senhas, chaves de API) armazenados em armazenamento seguro do dispositivo (flutter_secure_storage)
  • Nenhum segredo codificado no código — segredos injetados via variáveis de ambiente ou serviços de configuração
  • Chaves de API de terceiros nunca armazenadas em repositórios de código (use git-crypt ou semelhante para arquivos de configuração)
  • SharedPreferences não usado para dados confidenciais

Comunicação de rede:

  • Todas as chamadas de API usam HTTPS com certificados SSL/TLS válidos
  • Certificados SSL/TLS fixados (pinados) em aplicativos de produção para prevenir ataques MITM
  • Nenhum cabeçalho de autorização exposto em logs ou mensagens de erro

Validação de entrada:

  • Todas as entradas do usuário são validadas e sanitizadas antes do uso
  • Nenhuma injeção de código ou SQL possível através de entradas do usuário
  • Validação de entrada do lado do servidor também presente para chamadas de API

Outros:

  • Verificações de integridade de deep links realizadas
  • Nenhuma comunicação insegura com plataformas nativas (canais de método seguros)
  • Dependências de terceiros atualizadas para evitar vulnerabilidades conhecidas

10. Gerenciamento de Dependências

Dependências de pacotes:

  • Nenhuma dependência não utilizada em pubspec.yaml
  • Dependências são fixadas com intervalo ou trava (lock) para builds reproduzíveis
  • Dependências são atualizadas regularmente para versões compatíveis
  • Dependências depreciadas ou com vulnerabilidades conhecidas são evitadas ou substituídas

Dependências de desenvolvimento:

  • Dependências de desenvolvimento (testes, linting) não são incluídas na compilação de produção
  • Builders de código (freezed, json_serializable) são especificados como dependências de desenvolvimento

Dependências transitivas:

  • Nenhuma dependência transitiva indesejada é arrastada (use dependency_overrides com moderação)
  • A árvore de dependências é verificada por pacotes duplicados ou conflitantes

11. Tratamento de Erros e Logging

Tratamento de erros:

  • Toda operação assíncrona tem tratamento de erro (try/catch em torno de await ou tratamento de erro em streams)
  • Erros não são engolidos — cada erro é registrado ou exibido ao usuário
  • Erros são mapeados para mensagens amigáveis ao usuário antes da exibição
  • Erros inesperados são capturados em um nível superior (por exemplo, em um gerenciador de estado global)

Logging:

  • Logging estruturado usado (em vez de print)
  • Níveis de log apropriados: debug, info, warn, error
  • Logging não expõe informações confidenciais do usuário
  • Logging é configurável por ambiente (desenvolvimento, homologação, produção)

12. Roteamento e Navegação

Roteamento declarativo:

  • Roteamento declarativo preferido (Navigator 2.0 ou bibliotecas de terceiros como go_router)
  • Navegação baseada em URL usada para web e deep links
  • Roteamento profundo (nested routing) implementado corretamente

Navegação segura:

  • Nenhuma navegação executada após o contexto ser destruído (verifique context.mounted)
  • Argumentos de rota são tipados e validados
  • Nenhuma navegação ocorre em callbacks de build ou initState sem verificação de montagem

13. Otimizações de Compilação

Compilação para web:

  • Estruturas de árvore de renderização otimizadas para web (canvas vs DOM)
  • Imagens otimizadas para web (WebP, carregamento preguiçoso)
  • Divisão de código usada para bibliotecas grandes
  • Pacotes JavaScript otimizados em tamanho (tree shaking, minificação)

Compilação para mobile:

  • Binários otimizados para tamanho (remover código morto, minimizar ativos não utilizados)
  • Ativos (imagens, fontes, arquivos) são compactados para o tamanho mínimo
  • Estratégias de cache de ativos implementadas

14. Configuração e Ambiente

Variáveis de ambiente:

  • Configurações específicas de ambiente (API URLs, chaves) são injetadas via variáveis de ambiente ou serviços de configuração
  • Nenhuma configuração codificada no código
  • Diferentes ambientes (desenvolvimento, homologação, produção) têm configurações separadas

Configuração de build:

  • Utilizar flavors de build para diferentes ambientes
  • Nomes de aplicativos, ícones e nomes de pacotes diferem entre ambientes para evitar conflitos

15. Documentação e Comentários

Documentação de código:

  • Comentários de documentação (///) presentes para APIs públicas
  • Comentários explicam o "porquê", não apenas o "o quê" (código já mostra o quê)
  • Nenhum comentário desatualizado ou enganoso
  • README do projeto explica como configurar, construir e testar

Resumo

Esta lista de verificação é projetada para ser usada durante revisões de código para garantir qualidade, consistência e aderência às melhores práticas em aplicativos Flutter/Dart. Adapte-a às necessidades específicas do seu projeto eliminando ou adicionando itens conforme apropriado.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Habilidades Relacionadas