L’ABI d’un contrat Ethereum est une description d’interface qui aide les applications à encoder les appels de fonctions et à interpréter les données renvoyées. ABI signifie Application Binary Interface, ou interface binaire d’application. Sa description JSON contient notamment les noms des fonctions, les types de leurs paramètres et les types de leurs valeurs de retour. Évaluer l’implémentation demande des éléments supplémentaires.
Pour comprendre son rôle, il faut distinguer ce que l’interface déclare, la manière dont ses données sont représentées et ce que le programme exécutable fait effectivement. Cette distinction évite de prendre des noms familiers ou un résultat lisible pour une preuve de sécurité.
ABI, code source et bytecode : trois rôles distincts
La documentation Ethereum sur la compilation présente l’ABI JSON comme une description du contrat déployé et de ses fonctions. Elle explique aussi que la machine virtuelle Ethereum, ou EVM, a besoin de bytecode pour exécuter un contrat.
Le code source intervient en amont. Dans l’exemple Multiply7 de la documentation JSON-RPC d’Ethereum, un contrat écrit en Solidity est compilé en bytecode destiné à l’EVM. Cet exemple illustre la compilation ; il ne vérifie pas le code source d’un autre déploiement.
À partir de ces rôles documentés, on peut distinguer trois représentations :
- Le code source : le programme fourni au compilateur dans l’exemple.
- Le bytecode : la représentation exécutée par l’EVM.
- L’ABI JSON : la description d’interface utilisée pour interpréter les fonctions et leurs données typées.
Cette distinction est une déduction fondée sur leurs rôles respectifs. Posséder l’une de ces représentations ne suffit pas à établir sa correspondance avec les deux autres. Trouver un fichier ABI ne démontre donc pas, à lui seul, qu’il correspond au déploiement étudié.
Pour un cas d’interface commune, notre guide de la norme ERC-20 et de l’interface des jetons Ethereum apporte un complément. Ici, la question porte sur la description des fonctions et de leurs types, indépendamment d’une norme particulière.
Ce qu’indique la description d’une fonction
La spécification ABI de Solidity définit les champs de l’interface JSON. Pour une fonction nommée, commencez par trois éléments :
name: le nom de la fonction.inputs: la description ordonnée de ses paramètres, avec leur nom et leur type canonique.outputs: la description des paramètres de retour, au moyen d’objets semblables à ceux deinputs.
Les paramètres de type tuple utilisent également components pour décrire leurs éléments. Le tableau outputs peut être vide. Lire une ABI consiste donc à préserver une structure, pas simplement à reconnaître des mots.
Toutes les entrées ne suivent pas le modèle d’une fonction nommée. Les entrées constructor, receive et fallback n’ont ni nom ni sorties. Les entrées receive et fallback n’ont pas non plus d’entrées. Les champs attendus dépendent ainsi de la catégorie examinée.
Une sortie déclarée décrit la structure de retour attendue. Elle n’établit pas qu’une exécution a eu lieu ou qu’une valeur particulière a été obtenue. La déclaration et le résultat observé doivent rester séparés.
Comment les noms et les types déterminent le sélecteur
Pour un appel de fonction ABI ordinaire, le sélecteur est dérivé de la signature canonique de la fonction. Celle-ci associe son nom à la liste de ses types de paramètres, entre parenthèses. Le sélecteur correspond aux quatre premiers octets du hachage Keccak-256 de cette signature.
Reconnaître un nom ne suffit donc pas à comprendre cette relation. Les types des paramètres font eux aussi partie de la signature canonique. Comparer uniquement les noms laisse de côté une partie des informations utilisées pour dériver le sélecteur.
Les types de retour ont un autre rôle : ils sont exclus de cette signature, même si la description JSON complète contient les sorties. On en déduit qu’un sélecteur ne fournit pas, à lui seul, le schéma de retour. Cette conclusion repose sur la séparation documentée entre la dérivation du sélecteur et la description des sorties.
Cette relation aide à interpréter l’interface. Elle ne permet pas d’établir que l’implémentation est sûre.
Pourquoi le décodage dépend d’un schéma
L’encodage ABI suit les types des valeurs à encoder. La spécification précise que cet encodage n’est pas autodescriptif : son décodage nécessite un schéma. Dans ce contexte, le schéma fournit les types et la structure nécessaires à l’interprétation des données.
Deux questions se présentent alors. Quels types et quelle structure sont déclarés ? Sur quels éléments repose la correspondance entre cette description et les données étudiées ? Un fichier ABI fournit une description dans la mesure où il contient les entrées pertinentes ; son adéquation au déploiement reste une question distincte.
Les valeurs de retour d’une fonction sont réunies dans un tuple, puis encodées ensemble selon les règles ABI. La description des sorties compte donc pour interpréter les données renvoyées, même si leurs types ne participent pas à la dérivation du sélecteur.
Une interprétation lisible reste conditionnée par la pertinence du schéma. Puisque le décodage dépend d’une description fournie, on en déduit qu’interpréter des octets avec cette description ne vérifie pas indépendamment l’implémentation exécutable.
Exemple hypothétique : lire une interface sans inventer le résultat
Imaginons un contrat entièrement fictif, utilisé dans un exercice, avec une fonction nommée lookupRecord. Son ABI hypothétique déclare une entrée appelée recordId, de type uint256, et deux sorties : found, de type bool, et label, de type string. Cet exemple ne désigne aucun contrat déployé.
L’interface permet d’identifier le nom de la fonction, le type de l’entrée et la structure du retour en deux parties. Sa signature canonique serait lookupRecord(uint256). Les types des sorties ne figureraient pas dans cette signature servant à dériver le sélecteur.
Supposons maintenant que l’énoncé fournisse uniquement cette interface et demande quel libellé la fonction renvoie pour l’enregistrement 7. Le résultat n’est pas établi. La déclaration fournit un schéma de retour, mais l’exercice ne donne ni le comportement de l’implémentation ni un résultat d’exécution.
De même, le nom ne suffit pas à conclure que la fonction consulte une base de données particulière, applique une règle donnée ou produit une information exacte. Cette déduction concerne les limites des éléments fournis dans l’exercice. De telles conclusions demanderaient des preuves supplémentaires sur l’implémentation et les résultats.
Une liste de contrôle pour interpréter une ABI
- Identifier le document : distinguer l’interface JSON du code source et du bytecode exécutable.
- Examiner la correspondance : chercher les éléments reliant l’ABI fournie au déploiement étudié.
- Lire la catégorie d’entrée : appliquer les champs d’une fonction nommée lorsque ce modèle convient.
- Préserver la structure des entrées : relever noms, types canoniques, ordre et composants des tuples.
- Lire les sorties séparément : distinguer la structure déclarée d’un résultat observé.
- Décrire précisément le sélecteur : retenir le nom et les types d’entrée canoniques, en excluant les types de retour.
- Expliciter les hypothèses de décodage : identifier le schéma dont dépend l’interprétation.
- Limiter la conclusion : l’interprétation de l’interface ne prouve pas, à elle seule, la sécurité de l’implémentation.
Cette dernière limite découle du rôle descriptif de l’ABI, de la dépendance du décodage à un schéma et du rôle exécutable du bytecode. Elle ne constitue pas un constat d’insécurité concernant un contrat particulier. Les sources citées étayent cette explication ; leur attribution ne certifie aucun déploiement.
Contenu pédagogique préparé avec l’aide de l’IA. L’exercice fictif sert à comprendre une interface et ne recommande ni transaction réelle ni signature d’une demande dans un portefeuille.