Skip to content

address.inspect classe erc20/contract des adresses sans bytecode sur le réseau demandé (contamination cross-chain de la classification) #79

Description

@spouletmathis

Symptôme

Sur network: "gnosis", address.inspect retourne detected_roles contenant contract,
erc20, burnable, mintable et typeName: "Utility Token" pour des adresses dont
eth_getCode renvoie 0x sur Gnosis. Ces contrats existent sur Ethereum, pas sur la
chaîne demandée : la classification semble provenir d'une autre chaîne que celle passée en
paramètre.

Build testée : 5e4eb061d (2026-08-19), 83 commits après v1.25.0, compilée localement,
appels via --mcp-binary.

Cas de test

A=0xe5f7ef61443fc36ae040650aa585b0395aef77c8

# 1. vérité terrain : pas de bytecode sur Gnosis
curl -s -X POST -H 'Content-Type: application/json' \
  --data "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getCode\",\"params\":[\"$A\",\"latest\"]}" \
  https://rpc.gnosischain.com
# → {"result":"0x"}

# 2. le contrat existe bien sur Ethereum
curl -s -X POST -H 'Content-Type: application/json' \
  --data "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_getCode\",\"params\":[\"$A\",\"latest\"]}" \
  https://ethereum-rpc.publicnode.com
# → {"result":"0x608060405234801561001057600080fd5b50..."}

# 3. Alter, sur gnosis, le classe pourtant comme ERC-20
$BUILD/alter-cli mcp address.inspect --json "{\"network\":\"gnosis\",\"address\":\"$A\"}" \
  --mcp-binary $BUILD/alter-mcp --timeout 150

Le tool chain.rpc d'Alter lui-même confirme l'absence de code, sur la même session :

$BUILD/alter-cli mcp chain.rpc --json "{\"network\":\"gnosis\",\"method\":\"eth_getCode\",\"params\":[\"$A\",\"latest\"]}" \
  --mcp-binary $BUILD/alter-mcp
# → {"chain_id":100,"method":"eth_getCode","result":"0x","result_confidence":"complete"}

Donc chain.rpc et address.inspect, dans la même session et sur le même réseau, se
contredisent sur la nature de l'adresse.

Observé vs attendu

Observé  : detected_roles = ['burnable','contract','erc20','evm','mintable']
           typeName       = "Utility Token"
           result_confidence = "partial"
Attendu  : detected_roles = ['evm']   (aucun rôle de contrat sur une adresse sans code)
           typeName       = ""        ou un marqueur explicite "non déployé sur ce réseau"
Vérité terrain : eth_getCode(gnosis) = "0x" sur 2 RPC Gnosis publics indépendants
                 (rpc.gnosischain.com, gnosis-rpc.publicnode.com)

Fréquence

Systématique, pas anecdotique. Sur les 12 premières adresses du preset realtokens qui
n'ont pas de bytecode sur Gnosis : 12/12 sont classées
['burnable','contract','erc20','evm','mintable'] / Utility Token.

Contre-exemple utile pour le diagnostic : 0x0675e8F4A52eA6c845CB6427Af03616a2073538c,
également sans code sur Gnosis, est correctement classée ['evm'] seul avec
typeName: "". Le défaut n'est donc pas universel — il touche les adresses pour lesquelles
une classification existe sur une autre chaîne, ce qui oriente vers un cache ou une
résolution multi-chaînes qui ignore le network demandé.

Sur un contrat réellement déployé sur Gnosis
(0xfe17c3c0b6f38cf3bd8ba872bee7a18ab16b43fb), la classification est en revanche juste et
précise : erc3643 + Security Token + proxy, total_supply conforme au RPC direct.
Le mécanisme fonctionne bien quand l'adresse est effectivement sur la chaîne visée.

Impact usage

Ici, address.inspect sert à qualifier une adresse avant de l'intégrer au suivi de
patrimoine RealT (3916, valorisation). Un faux erc20 sur la mauvaise chaîne conduit à
inscrire une ligne qui n'existe pas sur ce réseau, puis à interroger des balances qui
renverront 0 — sans qu'aucun signal ne distingue « je ne détiens rien » de « ce token n'est
pas sur cette chaîne ».

Le result_confidence: "partial" est un signal, mais trop faible : il ne dit pas quoi
est partiel, et une valeur partial est courante sur des réponses par ailleurs correctes.

Contexte aggravant : le preset realtokens (812 adresses) est décrit comme « RealTokens sur
Ethereum et Gnosis » mais aucune de ses 812 entrées ne porte son réseau
(collection.inspect → toutes les entrées ont la seule clé address). Impossible donc de
savoir depuis le preset sur quelle chaîne interroger une adresse donnée — ce qui rend la
mauvaise réponse d'address.inspect d'autant plus piégeuse.

✅ Test d'acceptation

  1. Sur 0xe5f7ef61443fc36ae040650aa585b0395aef77c8 avec network: "gnosis" :
    detected_roles ne contient ni contract, ni erc20, ni burnable, ni mintable.
  2. typeName n'est pas "Utility Token" ; l'adresse est présentée comme non déployée sur
    la chaîne demandée (champ explicite plutôt que rôles vides muets).
  3. Si une classification issue d'une autre chaîne est retournée, elle est étiquetée par sa
    chaîne d'origine
    et ne peut pas être confondue avec la chaîne demandée.
  4. Cohérence interne : pour toute adresse, address.inspect(network=X) ne peut pas annoncer
    contract quand chain.rpc eth_getCode sur ce même X retourne 0x.
  5. Anti-régression : sur 0xfe17c3c0b6f38cf3bd8ba872bee7a18ab16b43fb (gnosis),
    la classification reste erc3643 / Security Token / proxy et
    total_supply == "1300000000000000000000".
  6. Anti-régression : 0x0675e8F4A52eA6c845CB6427Af03616a2073538c (gnosis) reste ['evm'].

Suggestion connexe

Faire porter à chaque entrée du preset realtokens son réseau (network ou chain_id)
supprimerait la cause racine côté usage : aujourd'hui, rien ne permet de savoir quelle
chaîne interroger pour une des 812 adresses, ce qui rend l'erreur de chaîne quasi
inévitable côté consommateur.

Réserves

Testé sur profil chargé, chaîne Gnosis provisionnée, collection rmm-v3, sans clé API
explorer. Je n'ai pas cherché à déterminer si la classification erronée vient d'un cache
inter-chaînes, d'un registre statique ou d'une résolution d'endpoint — seulement à établir
la contradiction observable avec chain.rpc sur la même session.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions