Historique des transactions TON : lt, hash et nœud d'archive
Comment fonctionne l'historique des transactions TON : logical time (lt), hash et pointeur de dernière transaction. Lecture via MCP et rôle du nœud d'archive.
Vous travaillez de nuit et, à 3 h 47, un message tombe : un utilisateur a payé sa commande en TON, et le bot ne l'a pas comptabilisée. Vous ouvrez l'explorateur — l'argent est bien là, le virement entrant est visible. Le problème n'est donc pas dans la blockchain, mais dans la façon dont votre service lit l'historique des transactions. Et c'est là que vous découvrez que, sur TON, cet historique n'est pas du tout organisé comme vous en avez l'habitude avec Ethereum.
Le monitoring des paiements sur TON paraît trompeusement simple : on interroge le solde et on réagit au changement. En pratique, tout s'écroule. Deux paiements du même montant dans la même minute — y en a-t-il eu un ou deux ? L'utilisateur a payé en USDT, et le solde GRAM n'a pas bougé d'un poil. Il vous faut un relevé sur six mois, et le liteserver ne renvoie que les dernières transactions sans un mot sur le reste.
Si vous branchez un agent IA sur TON ou si vous écrivez un backend qui rapproche des paiements, entrons dans le concret : ce qu'est l'historique des transactions TON, à quoi sert la paire lt + hash, pourquoi la profondeur bute sur le nœud d'archive et comment lire tout cela depuis un agent via MCP.
Ce qu'est l'historique des transactions dans TON et pourquoi un agent en a besoin
Dans TON, chaque compte — wallet, contrat, jetton-wallet — possède sa propre chaîne de transactions. Chaque transaction est le résultat du traitement d'un message entrant : réception de GRAM, transfert de jeton, appel d'une méthode de contrat. Pour un agent (Claude, Cursor, n'importe quel client MCP) qui encaisse des paiements ou rapproche des comptes, l'historique est la seule source fiable : le solde dit « combien maintenant », l'historique dit « quoi exactement et quand, de qui et pour quel montant ».
Les tâches très concrètes pour lesquelles un agent a besoin de l'historique :
- confirmer la bonne réception d'un paiement (« vérifie si un virement est arrivé sur cette adresse dans la dernière heure ») ;
- constituer un relevé de wallet ;
- retrouver une transaction précise à partir de son identifiant ;
- rapprocher les jetons entrants (USDT par exemple) du montant attendu.
Le problème, c'est que « donne-moi les transactions n° 100 à 120 » ne marche pas sur TON. Il n'existe pas ici de numérotation globale et continue des blocs qui permettrait de « donner la transaction numéro N ». L'ordre est établi autrement — par le temps logique.
Le temps logique (lt) : pourquoi TON n'a pas de numérotation de blocs classique
Sur Ethereum, tout est simple : il y a le bloc n° 19 000 000, et dedans les transactions dans l'ordre. Un compteur global unique, monotone croissant, et tout le monde se réfère au même numéro.
TON est un système multi-thread : masterchain, workchains, shards qui se scindent et fusionnent selon la charge. Il n'existe tout simplement pas ici de « numéro de bloc » unique permettant d'ordonner linéairement tous les événements du réseau. À la place, TON utilise le temps logique (lt, logical time) — un compteur monotone croissant avec lequel le réseau ordonne les événements, les messages et les transactions. Il garantit ceci : si l'événement A a influencé l'événement B, alors lt(A) < lt(B).
D'où une conséquence pratique : la position d'une transaction est définie non par un numéro de bloc, mais par la paire (lt, hash). Le lt se charge de l'ordre (qui vient avant), le hash de l'identification univoque de la transaction. Pris séparément, ils sont inutiles pour une requête ciblée : des objets différents peuvent avoir des lt voisins, et le hash seul ne dit pas au liteserver par où commencer la lecture.
Hash de transaction et paire lt + hash : le pointeur de dernière transaction d'un compte
Le hash d'une transaction est son empreinte cryptographique ; sur TON, il arrive en base64 ou en hex. Le lt dit « quand dans l'ordre », le hash « laquelle exactement », parce que, sur une même tranche de lt, une ambiguïté reste théoriquement possible et que, sans le hash, le liteserver ne renverra pas la transaction. À retenir fermement : la paire (lt, hash) est indissociable. Le lt seul ou le hash seul ne suffisent pas.
Où trouver le point de départ ? L'état du compte conserve un pointeur vers la toute dernière transaction — last_transaction_id, c'est-à-dire cette même paire lt + hash (champs last_trans_lt / last_trans_hash). C'est la « tête » de la liste, celle par laquelle commence le parcours de l'historique vers l'arrière.
Dans l'outillage MCP de TONNode, c'est get_account_state qui s'en charge — il renvoie le statut du compte, ses flags et le pointeur vers la dernière transaction.
Comment get_transactions parcourt l'historique : lt + hash et la chaîne prev_trans
Voici le point clé, celui qui rend possible le feuilletage de l'historique. Chaque transaction contient, en plus de ses propres lt et hash, deux champs : prev_trans_lt et prev_trans_hash — la référence vers la transaction précédente du même compte. Les transactions forment donc une liste simplement chaînée qui remonte le temps ; la tête, c'est le last_transaction_id issu de l'état.
get_transactions accepte :
account— l'adresse du compte ;- les
ltethashde départ — le point à partir duquel lire ; count— la taille du lot.
Il renvoie un lot de transactions en allant vers l'arrière depuis le point indiqué. La logique du parcours page par page :
- Prendre
last_trans_lt/last_trans_hashdepuisget_account_state— c'est la tête. - Appeler
get_transactions(account, lt, hash, count)— récupérer un lot. - Sur la dernière transaction du lot, relever
prev_trans_ltetprev_trans_hash. - Rappeler
get_transactionsavec cette paire — c'est la page suivante. - Répéter jusqu'à ce que
prev_trans_lttombe à 0 (le début de vie du compte) ou jusqu'à atteindre la profondeur voulue.
Voilà comment fonctionne la pagination sur TON : non pas « page 2 », mais « continue à partir de cette paire (lt, hash) ».
Blocs récents contre historique profond : à quoi sert un nœud d'archive
C'est là que la plupart des développeurs trébuchent. Un liteserver ordinaire renvoie les blocs récents et l'historique récent d'un compte : il conserve une fenêtre d'état limitée — un certain nombre de blocs récents — et, à mesure que le réseau grossit, les anciennes données en sont évacuées. Remontez la chaîne prev_trans suffisamment loin et, à un moment, le liteserver cessera tout simplement de renvoyer des transactions : elles ne sont physiquement plus dans sa fenêtre. Le paiement de tout à l'heure, vous le verrez ; la transaction d'il y a six mois, non.
Ce n'est pas un bug, c'est un choix de conception : garder le parcours complet de chaque compte depuis le bloc de genèse coûte cher. L'historique profond est conservé par un nœud d'archive — un nœud qui ne purge pas les anciens blocs et garde l'état complet du réseau sur toute son histoire.
Conclusion pratique :
- détection de paiement, relevé récent, « est-ce arrivé dans la dernière heure » — un liteserver ordinaire suffit ;
- audit complet d'un wallet depuis le tout premier jour — il faut un nœud d'archive.
Autre source de douleur : les liteservers publics de la config globale de TON. Ils sont partagés et limités : sous charge, ils répondent souvent not ready ou partent en timeout ADNL, et l'historique profond n'y est pas non plus. Si vous êtes justement tombé sur un not ready, c'est le symptôme d'un liteserver partagé surchargé — l'analyse se trouve dans la note pourquoi le liteserver répond not ready et comment le réparer.
Soyons honnêtes sur TONNode : le nœud d'archive est dans la roadmap et en cours de synchronisation — je ne vous promets pas la profondeur d'archive comme fonctionnalité déjà disponible. Aujourd'hui, il s'agit de lire l'historique récent via un endpoint maîtrisé, sans la loterie des liteservers publics. Pour l'archive complète depuis le bloc de genèse, attendez une annonce dédiée.
Comment lire l'historique TON avec un agent IA via MCP
TONNode est un serveur MCP hébergé pour TON, exactement 16 outils, et get_transactions fait partie du bloc lecture. MCP (Model Context Protocol) est le standard par lequel l'agent appelle les outils lui-même, sans que vous ayez à assembler des requêtes ADNL à la main. Pas besoin d'installer de SDK, de monter un liteserver ni de décortiquer du TL-B — l'agent appelle l'outil directement.
Connexion locale gratuite
L'ensemble complet des outils de lecture, config publique, paquet @tonnode/mcp — open source, MIT :
{
"mcpServers": {
"ton": {
"command": "npx",
"args": ["-y", "@tonnode/mcp"]
}
}
}
Le paquet fonctionne sur le protocole ADNL natif de TON, sans couche HTTP intermédiaire.
Endpoint hébergé avec votre propre clé
Pour un débit garanti, prenez l'endpoint hébergé avec votre propre clé :
{
"mcpServers": {
"ton": {
"type": "http",
"url": "https://mcp.tonnode.io/mcp",
"headers": { "Authorization": "Bearer tn_live_…" }
}
}
}
Pour lire l'historique, vous utiliserez :
get_account_state— le point de départ du parcours (last_trans_lt/last_trans_hash), le statut et les flags du compte ;get_transactions— les transactions elles-mêmes, page par page, par paire(lt, hash);parse_address— conversion hors ligne des adresses entreEQ/UQ/raw;get_jetton_infoetget_jetton_balance— pour l'historique des jetons.
Pratique : détecter un paiement et parcourir l'historique page par page
Montons un scénario type — « le paiement est-il arrivé, et pour quel montant ».
Le prompt pour l'agent
Via l'outil
ton, prendsget_account_statepourEQC…myshop, puisget_transactionsà partir de seslast_trans_lt/last_trans_hash, count 20. Trouve un virement entrant de 5 GRAM sur les 10 dernières minutes. Convertis les adresses des expéditeurs en EQ viaparse_addressavant de comparer. S'il faut remonter plus loin dans l'historique, prends lesprev_trans_lt/prev_trans_hashde la dernière transaction et répèteget_transactions.
L'agent ira chercher lui-même la tête de la chaîne, feuillettera le lot et vérifiera les montants.
Pseudo-code du parcours paginé
Le même parcours en pseudo-code (les appels sont les outils MCP que l'agent déclenche) :
state = get_account_state(account)
lt = state.last_trans_lt
hash = state.last_trans_hash
while lt != 0:
batch = get_transactions(account, lt, hash, count=20)
for tx in batch:
if matches_expected_payment(tx): # message entrant avec le montant/commentaire attendu
return tx
last = batch[-1]
lt = last.prev_trans_lt
hash = last.prev_trans_hash # sans hash, impossible de demander la page suivante
Les détails qui économisent des heures de debug
- Dans les champs des transactions, les adresses arrivent sous forme raw (
0:abcd…). Avant de comparer l'expéditeur ou le destinataire à l'adresseEQ…dont vous avez l'habitude, ramenez les deux au même format viaparse_address— sinon la comparaison de chaînes échouera alors qu'il s'agit de la même adresse. Plus de détails sur les formats : EQ, UQ et raw dans les adresses TON. - Les paiements en USDT ne sont pas visibles sur la chaîne du wallet GRAM. Les jetons vivent sur un jetton-wallet distinct, dont l'adresse se calcule on-chain (
get_jetton_balancele fait pour vous et renvoie le solde courant). Pour l'historique des jetons, parcourez les transactions du jetton-wallet, pas celles du wallet principal. - Reconvertissez les montants raw via les decimals. Les montants de jetons arrivent en unités minimales : pour transformer
5000000en 5 USDT lisibles par un humain, prenezdecimalsdepuisget_jetton_info— pour l'USDT c'est 6, pour la plupart des jetons 9. Une confusion, et vous vous trompez d'un facteur 1000. L'analyse complète : comment détecter un paiement USDT entrant sur TON. - Dédupliquez par
(lt, hash), pas par montant. Deux paiements identiques ne se distinguent que par la paire lt + hash — c'est précisément la clé d'idempotence.
Si, au-delà de l'historique, l'agent doit interroger l'état courant d'un contrat, c'est run_get_method qui s'en charge — comment appeler des get-méthodes sans SDK, c'est montré dans la lecture de TON sans SDK via une get-méthode.
En bref
- Sur TON, il n'y a pas de numéros de blocs comme sur Ethereum — la position d'une transaction est donnée par la paire
(lt, hash): lt pour l'ordre, hash pour l'identification, et les deux sont obligatoires ensemble. - Les transactions d'un compte forment une liste chaînée via
prev_trans_lt/prev_trans_hash; vous feuilletez vers l'arrière en partant dulast_transaction_idfourni parget_account_state. - Un liteserver ordinaire renvoie l'historique récent ; la profondeur complète, c'est l'affaire d'un nœud d'archive.
- Pour les jetons, n'oubliez ni les decimals de
get_jetton_info(USDT = 6) ni les adresses raw, qu'il faut faire passer parparse_address.
Pas envie de vous battre avec des liteservers publics qui répondent not ready ? get_transactions est disponible d'emblée sur le plan gratuit Hobby — 60 requêtes/min, pour toujours, sans carte bancaire, la clé est délivrée dès la connexion.
Branchez la lecture de l'historique TON en une minute → tonnode.io/dashboard?plan=hobby
Et pour ce que sait faire un agent sur TON au-delà de la lecture de l'historique — les 16 outils sur la page des outils TONNode.
Donnez à votre agent l'accès à TON
16 outils MCP : lecture, swaps non-custodial, cross-chain et wallets. Forfait gratuit — 60 req/min, sans carte.