Somente para fins educacionais; não constitui recomendação nem aconselhamento de investimento. Investir pode causar perdas.
Resposta direta
A EIP-712 padroniza como aplicativos Ethereum descrevem, calculam o hash e solicitam assinaturas de dados estruturados tipados. Uma solicitação contém types, primaryType, domain e message; seu digest é keccak256("\x19\x01" || domainSeparator || hashStruct(message)). Isso torna a codificação determinística e permite que uma carteira compatível exiba os campos com mais clareza que um hash opaco.
Ela não torna a mensagem verdadeira, inofensiva, revogável ou protegida contra replay. O aplicativo precisa vincular a autoridade à rede e ao verificador corretos, definir cada campo sem ambiguidade, impor nonces e limites de tempo, validar o signatário certo e restringir a execução. Uma assinatura válida comprova a aprovação de um digest exato segundo uma regra de verificação; não comprova identidade, intenção informada nem a segurança do site ou contrato.
A conclusão desta revisão não prova que um ativo, transação ou sistema seja seguro.
Como funciona
1. Identifique a ação e o caminho de verificação
Determine se a solicitação autoriza login, ordem, voto, allowance de token, transferência, chamada retransmitida ou outra ação. Localize o código que reconstrói o digest e consome a assinatura. Para uma conta externamente controlada, a verificação costuma recuperar um endereço de uma assinatura ECDSA; para uma conta de contrato, pode ser necessário chamar ERC-1271 isValidSignature(hash, signature) e conferir o valor de sucesso 0x1626ba7e.
2. Fixe o domínio
Examine o tipo EIP712Domain exato e seus valores. Os campos padrão são name, version, chainId, verifyingContract e salt, mas apenas os presentes entram no hash. Confirme de forma independente a rede ativa, o código implantado e o verificador pretendido; nome, símbolo, rótulo de proxy ou endereço com checksum familiar não bastam. ERC-5267 eip712Domain() pode expor o domínio, mas o suporte é opcional e proxies ou upgrades ainda exigem análise.
3. Reconstrua o grafo de tipos
Comece em primaryType, preserve a ordem dos membros e reúna recursivamente as structs referenciadas. encodeType acrescenta suas definições ordenadas pelo nome do tipo. A EIP-712 admite inteiros de largura fixa, address, bool, de bytes1 a bytes32, bytes e string dinâmicos, arrays e structs; o padrão não define os aliases uint e int, tipos de ponto fixo nem valores cíclicos.
4. Decodifique cada valor e unidade
Relacione cada valor ao tipo declarado e ao significado no aplicativo. Confira endereços completos, unidades inteiras brutas, sinais, ordem de arrays, destinatários, spenders, ativos, quantias, taxas, limites, destinos, hashes de calldata e strings legíveis. bytes e string dinâmicos aparecem em encodeData como o hash Keccak-256 do conteúdo; arrays usam o hash das codificações concatenadas e structs aninhadas usam o próprio hashStruct.
5. Recalcule o digest de forma independente
Calcule typeHash = keccak256(encodeType(primaryType)) e depois hashStruct(message) = keccak256(typeHash || encodeData(message)). Calcule o separador de domínio da mesma forma e combine-o com os bytes de versão ERC-191 0x19 0x01. Compare frontend, biblioteca de assinatura, contrato verificador e implementação independente; JSONs visualmente iguais não comprovam codificação tipada idêntica.
6. Audite replay, tempo e controles de execução
A EIP-712 não inclui proteção contra replay. Confirme que o verificador confere o signatário pretendido, consome ou invalida o nonce correto, impõe deadline ou janelas de validade, vincula todos os parâmetros críticos e mantém o resultado pretendido se um relayer ou frontrunner enviar primeiro. A separação de domínio só impede colisões entre domínios realmente codificados; campos ausentes ou errados podem deixar caminhos de reutilização entre contratos ou redes.
7. Assine com escopo mínimo e reconcilie o resultado
Rejeite campos ocultos, tipos inexplicados, valores ilimitados, prazos distantes, contratos desconhecidos, IDs de rede divergentes, telas de blind signing ou contexto de execução incompleto. Preserve o JSON tipado exato e o digest, use uma conta de finalidade limitada quando possível e confira transação, recibo, eventos, saldos, allowances, nonces, estado da ordem e finalidade. Desconectar o site não revoga uma assinatura utilizável nem uma autoridade já criada.
Exemplos calculados
Exemplo 1: Construção do tipo e do digest
Para Order(address maker,address token,uint256 amount,uint256 nonce,uint256 deadline), typeHash é o hash Keccak-256 dessa string exata, inclusive a ordem dos campos. O hash da mensagem é keccak256(typeHash || maker || token || amount || nonce || deadline) e cada membro ocupa 32 bytes. O digest final acrescenta 0x1901, o separador de domínio e o hash da mensagem; alterar amount de 250000000 para 250000001 muda o digest e invalida a assinatura anterior.
Exemplo 2: Unidades e prazo
Uma quantia de 250 USDC com seis casas decimais é codificada como 250000000, não 250. Se o timestamp atual for 1727000000 e o prazo 1727000900, a janela será 900 seconds = 15 minutes. A exibição decimal da carteira e o relógio local servem apenas de apoio; o verificador usa o inteiro bruto e a regra de tempo on-chain escolhida.
Exemplo 3: Controle de replay
Uma ordem leva nonce 41 e preenchimento máximo de 5 ETH. Depois que o verificador marca o nonce 41 como consumido, uma segunda apresentação deve falhar mesmo que a assinatura continue criptograficamente válida. Se o contrato não consumir o nonce nem tornar a execução idempotente, a mesma assinatura pode autorizar mais 5 ETH; o separador de domínio sozinho não impede esse replay.
Exemplo 4: Validade da carteira de contrato
Uma carteira de contrato 2-de-3 aprova um digest com os signatários A, B e C configurados. As assinaturas de A e B podem fazer o ERC-1271 retornar 0x1626ba7e hoje. Se um upgrade substituir B por D, os mesmos bytes podem se tornar inválidos: a validade ERC-1271 pode depender do estado, política, tempo e chamadas externas atuais, e recuperar um endereço não decide a validade de uma conta de contrato.
Riscos
chainIderrado ou ausenteverifyingContractfalsificado ou inesperadonameouversionde domínio enganoso- Implementação proxy ou domínio alterado após upgrade
primaryTypeerrado ou tipo sombra com rótulo semelhante- Ordem de membros, dependências ou codificador incompatível
- Endereço truncado, substituído ou rotulado de modo enganoso
- Erro de casas decimais ou de inteiro com sinal versus sem sinal
- Item de array, struct aninhada ou payload
bytesoculto - Valor ilimitado, escopo amplo ou destinatário controlado pelo atacante
- Nonce ausente, antigo, compartilhado ou consumido incorretamente
- Prazo ausente, distante, com overflow ou interpretação ambígua
- Replay entre redes, contratos, contas ou ações
- Retenção, censura, front-running ou redirecionamento pelo relayer
- Maleabilidade da assinatura ou recuperação ECDSA permissiva
- Mudança de signatário, módulo, limite, estado ou código ERC-1271
- Falha de renderização, blind signing ou tipo não suportado na carteira
- JSON do frontend diferente do digest do verificador
- Revogação ou cancelamento que perde uma disputa de ordenação
- Confundir o resultado do prompt com recibo, mudança de estado ou finalidade
Equívocos comuns
Mito 1: Assinaturas EIP-712 são transações
São mensagens assinadas off-chain. Um relayer ou outro participante pode enviá-las depois a um contrato, e a transação resultante pode gastar Gas e mudar estado sem ser enviada pelo signatário.
Mito 2: Uma exibição estruturada torna a solicitação segura
Campos tipados melhoram a inspeção, mas esquemas, valores, contratos, rótulos, aninhamentos ocultos ou renderização incompleta ainda podem enganar.
Mito 3: O separador de domínio impede todo replay
Ele separa somente o domínio codificado. Replay no mesmo domínio ainda exige nonce, prazo, cancelamento, contabilidade de preenchimento ou idempotência; campos omitidos não criam limites.
Mito 4: Recuperar o endereço esperado comprova autorização
A recuperação comprova uma assinatura EOA sobre o digest, não a semântica do aplicativo. Contas de contrato exigem sua política ERC-1271, não recuperação comum.
Mito 5: Fechar a página ou desconectar a carteira cancela a assinatura
Uma assinatura copiada pode ser usada até que nonce, prazo, cancelamento, estado ou política do verificador a invalide. Confira o estado on-chain relevante, não a sessão.
Tópicos relacionados
- ID da rede
- Nonce e prazo do ERC-2612 Permit
- Risco da assinatura Permit2
- Autorização da carteira
- Assinatura da carteira
Fontes
- EIP-712: Typed structured data hashing and signing - Ethereum Improvement Proposals (acessado em: 2026-08-19)
- ERC-191: Signed Data Standard - Ethereum Improvement Proposals (acessado em: 2026-08-19)
- ERC-1271: Standard Signature Validation Method for Contracts - Ethereum Improvement Proposals (acessado em: 2026-08-19)
- ERC-2612: Permit Extension for EIP-20 Signed Approvals - Ethereum Improvement Proposals (acessado em: 2026-08-19)
- ERC-5267: Retrieval of EIP-712 domain - Ethereum Improvement Proposals (acessado em: 2026-08-19)
- EIP-2: Homestead Hard-fork Changes - Ethereum Improvement Proposals (acessado em: 2026-08-19)
- Contract ABI Specification - Solidity Documentation (acessado em: 2026-08-19)
- ERC-7730: Structured Data Clear Signing Format - Ethereum Improvement Proposals (acessado em: 2026-08-19)