ABI de contrato Ethereum: como interpretar a interface e seus limites

A ABI de um contrato Ethereum é uma descrição de interface que ajuda aplicações a codificar chamadas de funções e interpretar os dados retornados. ABI significa Application Binary Interface, ou interface binária de aplicação. O arquivo JSON registra informações como nomes de funções, tipos dos parâmetros e tipos de retorno. Ele descreve a interface de forma estruturada; avaliar a implementação exige evidências adicionais.

A distinção útil está entre o que a interface declara, como os dados são representados e o que o programa executável realmente faz. Entender esses papéis facilita a leitura de uma ABI sem transformar nomes familiares ou resultados legíveis em prova de segurança.

ABI, código-fonte e bytecode têm papéis diferentes

A documentação de compilação do Ethereum apresenta a ABI em JSON como uma descrição do contrato implantado e de suas funções. Também explica que a máquina virtual Ethereum, a EVM, precisa de bytecode para executar um contrato.

O código-fonte entra nessa explicação antes da execução. No exemplo Multiply7 da documentação JSON-RPC do Ethereum, um contrato escrito em Solidity é compilado em bytecode para a EVM. O exemplo demonstra essa relação de compilação; ele não verifica o código-fonte de outros contratos implantados.

A partir dessas premissas, podemos distinguir três representações:

  • Código-fonte: o programa fornecido para compilação no exemplo.
  • Bytecode: a representação executada pela EVM.
  • ABI em JSON: a descrição da interface usada para interpretar funções e seus dados tipados.

Essa distinção é uma dedução dos papéis documentados. Ter uma dessas representações, por si só, não comprova sua correspondência com as outras duas. Encontrar um arquivo de ABI, em particular, não demonstra que ele corresponde ao contrato implantado em discussão.

Para conhecer a estrutura do programa, consulte o guia sobre código, estado e funções de contratos inteligentes no Ethereum. Aqui, o foco é interpretar a descrição da interface.

O que uma entrada de função informa

A especificação de ABI do Solidity define os campos da interface em JSON. Para uma função com nome, comece por três elementos:

  • name: o nome da função.
  • inputs: a descrição ordenada dos parâmetros, com o nome e o tipo canônico de cada um.
  • outputs: a descrição dos parâmetros de retorno, em objetos semelhantes aos de inputs.

Parâmetros do tipo tupla também usam components para descrever seus campos. O array de saídas pode estar vazio. Esses detalhes importam porque a descrição de uma interface precisa preservar a estrutura dos dados, além de apresentar palavras reconhecíveis.

Nem toda entrada da ABI segue o padrão de uma função com nome. Entradas de construtor, receive e fallback não têm nome nem saídas; receive e fallback também não têm entradas. Os campos esperados dependem do tipo de entrada analisada.

Uma saída declarada informa a estrutura esperada do retorno. Ela não comprova que houve execução nem que um valor específico foi produzido. Mantenha a declaração separada da evidência de um resultado efetivo.

Como nomes e tipos se relacionam com o seletor

Em uma chamada comum de função segundo a ABI, o seletor deriva da assinatura canônica da função. Essa assinatura combina o nome com a lista dos tipos de parâmetros entre parênteses. O seletor corresponde aos quatro primeiros bytes do hash Keccak-256 dessa assinatura.

Por isso, reconhecer o nome é apenas parte da interpretação da interface. Os tipos dos parâmetros também integram a assinatura canônica. Comparar somente o nome, ignorando os tipos de entrada, deixa de fora parte da informação usada para derivar o seletor.

Os tipos de retorno têm outro papel: ficam fora da assinatura usada para derivar o seletor, embora a descrição completa em JSON inclua as saídas. Portanto, o seletor, sozinho, não fornece o esquema de retorno. Essa conclusão decorre da separação documentada entre a derivação do seletor e a descrição das saídas.

Essa relação explica um aspecto da interface. Ela não comprova que um seletor identifica uma implementação segura e não deve ser tratada como um parecer de segurança.

Por que codificar e decodificar dependem de um esquema

A codificação ABI segue os tipos dos valores codificados. A especificação esclarece que essa codificação não descreve a si mesma: para decodificá-la, é necessário um esquema. Nesse contexto, o esquema fornece os tipos e a estrutura necessários à interpretação dos dados.

Isso cria duas tarefas de leitura. Primeiro, identificar os tipos e a estrutura declarados. Depois, estabelecer por que aquela descrição é adequada aos dados analisados. Fornecer uma ABI responde à primeira tarefa na medida em que o arquivo contém a descrição relevante; sua correspondência com um contrato implantado continua sendo uma questão separada.

Os valores de retorno de uma função são reunidos em uma tupla e codificados em conjunto segundo a ABI. Assim, a descrição de outputs importa para interpretar o retorno, mesmo que seus tipos não participem da derivação do seletor.

Uma interpretação legível deve permanecer condicionada à adequação do esquema. O limite é uma dedução: como a decodificação depende de uma descrição fornecida, interpretar bytes com essa descrição não verifica, de forma independente, a implementação executável.

Exemplo hipotético de leitura de uma interface

Imagine um contrato fictício usado em uma aula, com uma função chamada lookupRecord. Sua ABI hipotética declara uma entrada chamada recordId, do tipo uint256, e duas saídas: found e label, dos tipos bool e string. É um exemplo inventado, sem contrato real ou instrução para interagir com um.

A interface permite identificar o nome da função, o tipo da entrada e a estrutura do retorno em duas partes. Sua assinatura canônica seria lookupRecord(uint256). Os tipos das saídas declaradas não apareceriam nessa assinatura usada para derivar o seletor.

Agora suponha que o exercício forneça apenas essa interface e pergunte qual texto a função retorna para o registro 7. A resposta sustentada pelas informações disponíveis é que o resultado não está estabelecido. A declaração fornece um esquema de retorno, mas o exercício não apresenta o comportamento da implementação nem um resultado de execução.

Da mesma forma, o nome não basta para concluir que a função consulta determinada base de dados, aplica uma regra específica ou produz informações corretas. Essa é uma dedução sobre os limites das evidências do exercício. Para sustentar essas conclusões, seriam necessárias informações adicionais sobre a implementação e o resultado.

Checklist para interpretar uma ABI com conclusões proporcionais

  1. Identifique o arquivo: diferencie a interface em JSON do código-fonte e do bytecode executável.
  2. Confira a correspondência: procure evidências que conectem a ABI fornecida ao contrato implantado em discussão.
  3. Leia o tipo de entrada: aplique os campos de funções com nome apenas quando forem pertinentes.
  4. Preserve a estrutura das entradas: observe nomes, tipos canônicos, ordem e componentes de tuplas, quando presentes.
  5. Examine as saídas separadamente: diferencie a estrutura declarada de retorno de um resultado observado.
  6. Seja preciso sobre o seletor: considere a assinatura canônica com nome e tipos de entrada, sem os tipos de retorno.
  7. Explicite as premissas da decodificação: identifique o esquema do qual depende a interpretação.
  8. Limite a conclusão: interpretar a interface, por si só, não comprova a segurança da implementação.

O último limite é uma dedução baseada no papel descritivo da ABI, na dependência de um esquema para decodificar e no papel executável do bytecode. Não representa uma constatação de que determinado contrato é inseguro. As fontes fundamentam a explicação; sua citação não certifica um contrato implantado.

Material educativo preparado com auxílio de IA. O exercício hipotético serve para compreender interfaces, sem recomendar o envio de transações ou a assinatura de solicitações em uma carteira.