
Note du développeur : La naissance du Hook Aggregator
TechFlow SélectionTechFlow Sélection

Note du développeur : La naissance du Hook Aggregator
Cet article explore l'origine et le mécanisme de fonctionnement du Aggregator Hook, ainsi que son impact profond sur Uniswap et l'écosystème plus large des DEX.
Rédaction : Attens & Bruce
Édition : Lisa, DODO Research
Ceci (Aggregator Hook) est une excellente chose pour les autres DEX : ajouter quelques lignes de code permet d'accéder à un « super agrégateur », pourquoi s'en priver ? C'est bien sûr aussi une excellente chose pour Uniswap, qui peut ainsi intégrer en douceur et sans coût la liquidité des autres DEX pour son propre usage.
— Attens, DODO DEV Leader
Le lancement d'Uniswap V4 a rapidement déclenché une tempête parmi les développeurs : la structure Hook apporte une grande extensibilité aux contrats de pool traditionnels, rigides et standardisés. L'interface du Hook d'Uniswap V4 couvre presque tout le cycle de vie des interactions entre le pool et les fonds, offrant un terrain fertile aux « tempêtes d'idées » des développeurs. Des cas relativement simples comme le TWAMM Hook, introduisant une protection via oracle pondéré temporellement, au LimitOrder Hook illustrant un potentiel encore plus grand, ou même au Hook de trading inter-chaînes né lors d'un hackathon, tous ces Hooks poussent comme des champignons après la pluie.
En tant qu'acteurs de Defi, nous ne pouvions pas rester passifs. Lors de l'événement ETH Global en novembre, nous avons proposé une nouvelle conception de Hook, et avons eu la chance de remporter le prix « Best of Use Hook ». En raison de sa forte polyvalence, pouvant être intégré comme composant logiciel dans divers contrats de pools de liquidité, nous l'avons nommé : Aggregator Hook.
L'Aggregator Hook vise à jouer le rôle de « pont », permettant à la liquidité existante sur le marché de se connecter directement aux pools d'Uniswap V4 ; tout en gérant dynamiquement les fonds selon le principe du « juste-à-temps », en injectant la liquidité avant l'échange et en la retirant après, minimisant ainsi l'impact sur le pool d'origine. Cette intégration permet aux fournisseurs de liquidité (LPs) de gérer leurs fonds avec une facilité inédite, profitant à la fois de l'architecture robuste d'Uniswap et de la liquidité élargie provenant de l'écosystème global des DEX.
Cet article explore l'origine, le mécanisme opérationnel de l'Aggregator Hook, ainsi que ses profondes implications pour Uniswap et l'écosystème DEX plus largement.
I. Naissance de l'Aggregator Hook
À l'origine, cette idée venait d'un besoin simple : nous avions un pool DODO V3 très efficace en termes de cotation, pouvions-nous transférer ce système entier vers Uni V4 via un Hook ?
En étudiant le LimitOrderHook, nous avons eu une révélation : le Hook peut héberger une partie des fonds. Une découverte anodine, mais qui a ouvert la porte du terrier du lapin. Le fait que « le Hook soit un contrat autonome » combiné à « le Hook peut héberger des fonds » nous a conduit à nous demander : le Hook lui-même pourrait-il être un pool ? Et si maintenant nous disposions d'un contrat – qui pourrait être un pool d'un autre DEX, ou avoir une autre logique (par exemple un pool de financement participatif ou un système de dépôt de garantie), satisfaisant toutefois les exigences d'Uniswap V4 concernant les contrats Hook, et possédant les fonctions correspondantes – alors ce contrat pourrait aussi être un Hook.
Nous avons donc abouti à l'idée initiale : Aggregator Hook est un Hook centré sur le pool, à la fois un pool DODO V3 et un Hook Uni V4. Nous devions migrer notre système de cotation dans les fonctions associées au Hook, utilisant le JIT pour que les utilisateurs obtiennent sur Uni V4 exactement la même cotation que sur DODO V3. La solution initiale semblait naturelle : nous connaissions les limites haute et basse du prix de chaque jeton, ainsi que la quantité disponible à la vente ; convertir les bornes de prix en ticks, remplir la liquidité selon la quantité disponible, puis exécuter l’échange. Parfait — jusqu’à ce que… nous rencontrions un écart de prix considérable.
Nous avons testé de nombreuses combinaisons de tickSpacing et de frais, ainsi que différentes configurations de ticks correspondant aux bornes de prix. Même dans le meilleur des cas, l'écart atteignait 0,2 % par rapport à la cotation native de DODO V3, suffisant pour nuire à l'expérience utilisateur. Clairement, cela résultait des différences algorithmiques entre DODO V3 et Uni V4. Pour résoudre cet écart, deux portes s’ouvraient devant nous :
-
La porte principale : tenir pleinement compte des différences algorithmiques entre Uni V4 et DODO V3 afin de trouver une formule de re-mappage de liquidité
-
La porte de derrière : utiliser fromAmount pour obtenir un prix depuis DODO V3, puis fixer directement les paramètres de remplissage de liquidité à partir de ce prix, supprimant ainsi l'écart
Après une brève tentative, nous avons choisi sans hésiter la porte de derrière ! Bien que nous soyons convaincus que la première option, si elle menait à une solution analytique, produirait certainement un petit article élégant, malheureusement nous ne sommes pas mathématiciens. L'inconvénient de la deuxième solution est évident : elle entraîne forcément une consommation supplémentaire de gaz, du fait de l'appel supplémentaire pour la cotation. Mais ses avantages sont tout aussi clairs : la fonction qui fournit le prix à partir de fromAmount n’est pas exclusive à DODO V3. Tous les pools Dex disposent d'une fonction similaire — getAmountsOut, get_dy, querySellTokens… Peu importe le nom, il existe toujours un moyen d'obtenir un prix depuis le contrat. Ainsi, ce composant Hook peut non seulement être utilisé dans un pool DODO V3, mais aussi être intégré dans n’importe quel pool Dex, voire même dans un solveur indépendant. Tout contrat doté de liquidité et capable de fournir une cotation, en ajoutant simplement ce bout de code Hook, peut devenir simultanément un Hook, et former avec le Hook-Pool un pool Uni V4 valide. Dans ce cas idéal, le routage d'Uni V4 pourrait non seulement atteindre les pools Uni V4 traditionnels, mais aussi nos « trick pools » innovants.
Nous étions enthousiasmés — c’est une excellente chose pour les autres Dex : ajouter un peu de code pour accéder à un « super agrégateur », pourquoi s’en priver ? C’est aussi excellent pour Uniswap : il peut absorber en douceur et sans coût la liquidité des autres Dex pour son propre usage.
Bien sûr, cette vision ambitieuse dépend de l'algorithme de routage final d'Uni V4 et de la manière dont il gère la priorité de ces pools. C’est un autre sujet, peut-être ferons-nous un autre article sur l’algorithme de routage d’Uni V4. Mais en raison de la spécificité des Hooks, on peut affirmer avec certitude que quel que soit l’algorithme retenu, il devra prendre en compte l’impact des Hooks, car les opérations dans les Hooks influencent directement le prix final perçu par l’utilisateur.
Nous espérons que vous vous souvenez encore de l’hypothèse fondamentale de notre vision : nous obtenons un prix, puis trouvons une méthode de remplissage de liquidité dans Uni V4 capable de projeter ce prix, de sorte que l’utilisateur obtienne le même prix via Uni V4 qu’en échangeant directement via le Hook-Pool.
Finalement, nous y sommes arrivés. C’est pourquoi nous l’appelons officiellement « Aggregator Hook ».
II. Flux opérationnel de l'Aggregator Hook
Lorsqu’on examine la mise en œuvre concrète de l'Aggregator Hook, on découvre que la magie n’est en réalité qu’une pièce subtilement cachée dans la manche du prestidigitateur :
-
L'utilisateur lance un appel swap
-
Déclenchement du beforeSwapHook, qui exécute trois actions :
-
Retrait de toute la liquidité restante dans le pool (Chut ! C’est le point clé.)
-
Utilisation du fromAmount de l'utilisateur pour obtenir le prix natif de l’échange sur le Hook-Pool
-
Calcul des paramètres de modifyPosition à partir du prix d’échange, puis remplissage de liquidité
-
Fin de l'appel swap
-
Le routeur externe traite les transferts entrant et sortant de l'utilisateur
Comme illustré ci-dessous :

Lorsque l'ordre de transaction de l'utilisateur approche, le hook BeforeSwap est activé, et les fournisseurs de liquidité (LPs) injectent de la liquidité dans le pool Uniswap V4. Cette liquidité accrue s'adapte à l'ordre imminent, favorisant son exécution réussie. Cependant, plutôt que de retirer cette liquidité à la fin de l'échange, on la laisse temporairement dans le pool. Elle fait alors partie intégrante du cycle complet de la première transaction.
L'innovation réside dans le traitement des transactions suivantes. Avant le démarrage de la prochaine transaction, le hook BeforeSwap est à nouveau déclenché. Sa première tâche consiste à retirer toute liquidité excédentaire laissée par la transaction précédente.
Une fois la liquidité résiduelle retirée, les LPs répètent l'étape initiale : ils analysent les besoins de la nouvelle transaction et ajoutent une quantité précise de liquidité dans deux intervalles de prix. Ce remplissage minutieux garantit non seulement une utilisation optimisée de la liquidité, mais aussi un positionnement d'une efficacité maximale, réduisant ainsi le glissement et améliorant l'exécution globale des transactions dans l'écosystème Uniswap.
III. Analyse du mécanisme et du code
La partie la plus captivante doit être gardée pour la fin.
Quand retirer la liquidité
Tout d'abord, expliquons pourquoi nous devons retirer la liquidité, basé sur deux considérations :
-
Dans ce Hook, le Hook-Pool est l'entité principale, et la liquidité devrait être concentrée autant que possible dans le Hook-Pool.
-
Le calcul du re-mappage des prix est plus simple lorsque le pool n’a pas de liquidité excédentaire.
Dans JIT, la pratique habituelle consiste à injecter de la liquidité avant le swap de l'utilisateur, puis à la retirer après. Nous pensions initialement la même chose : ajouter la liquidité dans beforeSwapHook, la retirer dans afterSwapHook, une logique fluide — mais les Hooks réservent souvent des surprises. Observons la structure actuelle du testRouter d'Uni V4 :



Voyez-vous ? Ce qui bloque notre grand projet, c’est que l’échange réel de jetons entre l’utilisateur et le poolManager n’a lieu qu’après la fin de manager.swap. Cela signifie que afterSwapHook ne se produit pas vraiment « après l’échange », donc nous ne pouvons pas y retirer la liquidité. La fonction removeLiquidity perd sa position idéale, nous laissant désorientés, avec cet acteur abandonné debout, seul et maladroit, après l’appel swap dans les tests, comme un clown. À court d’options, nous envisagions d’exploiter hookData dans la fonction swap, voire de modifier testRouter ; c’est alors que l’un des créateurs de la pomme d’or, @ken d’Uni, et leur développeur @saucepoint, nous ont donné un conseil crucial : retirer la liquidité au début de la transaction suivante.
Cette solution est clairement optimale pour nous. Premièrement, elle nécessite des modifications minimes du code, et il ne nous restait alors que 7 heures avant la présentation du hackathon. Deuxièmement, elle ne dépend plus du comportement imprévisible de testRouter pour automatiser le retrait de liquidité : il suffit d’attendre un peu, jusqu’à ce que le prochain utilisateur arrive, et les fonds seront remboursés comme prévu.
Bien entendu, le propriétaire du Hook-Pool peut retirer la liquidité d’Uni V4 à tout moment, sans attendre le prochain utilisateur. La fonction remove ci-dessous est publique :


Par ailleurs, pour protéger les fonds, nous utilisons le hook beforeModifyPosition pour vérifier que l’expéditeur du message modifiant la liquidité est autorisé.

Comment remplir la liquidité
Les formules de calcul d'Uni V4 sont identiques à celles d'Uni V3, bien que le pool d'Uni V4 soit désormais une bibliothèque. Nous considérons uniquement le remplissage unidirectionnel de liquidité dans un intervalle de tick très petit, par exemple entre tick -46874 et tick -46873, afin de minimiser la consommation liée aux changements de tick. En lisant le code et les articles d'analyse pertinents, on peut utiliser l'algorithme d'Uni pour obtenir la formule suivante.

Code correspondant :

Mais ce n’est pas terminé. En observant la répartition de liquidité dans Uni V3/V4, on remarque :

Après avoir rempli la liquidité, seule la moitié de l’intervalle de prix permet réellement d’exécuter notre transaction unidirectionnelle. Si nous vendons token0 contre token1, l’intervalle de tick sélectionné est [tickLower, tickUpper], correspondant à [priceLower, priceUpper]. Pendant l’échange, le prix devrait baisser vers le prix cible, mais ce prix cible ne doit pas descendre en dessous de (priceLower + priceUpper) / 2. S’il descend en dessous, cela se traduit par un price_next dépassant la limite inférieure, nécessitant une correction de tickLower. Une correction similaire est requise à l’autre extrémité. Exemple :

Ce correctif correspond au code suivant :

Équilibre des prix
Jusqu’ici, nous avons tenu toutes nos promesses. Aggregator Hook est bon, mais pas parfait. La limitation principale concerne la direction de la transaction, décrite comme suit :
-
Le prix actuel du pool V4 est celui correspondant au tick 0, noté currentPrice
-
Quand targetPrice > currentPrice, le pool V4 ne peut effectuer que swap 1 to 0
-
Quand targetPrice < currentPrice, le pool V4 ne peut effectuer que swap 0 to 1
Cette limitation peut être comprise intuitivement. On peut voir targetPrice comme le prix du marché, et currentPrice comme le prix généré par le vieux pool Dex suite à une transaction. Quand le prix du pool Dex est inférieur au prix du marché, le pool impose que les utilisateurs achètent uniquement token0 pour faire monter le prix, rétablissant ainsi l’équilibre. Inversement, quand le prix du pool Dex est supérieur au prix du marché, il impose d’acheter token1 pour le faire baisser.
Cette condition est codée comme suit :

IV. Discussion approfondie et perspectives
Nous pensons que la signification majeure de l'Aggregator Hook réside dans la réinvention de la perspective de conception des Hooks.
Auparavant, nous conceptions les Hooks sous l’angle du pool Uni V4, en réfléchissant à ce que le Hook pouvait apporter de nouveau à la « transaction ». L'Aggregator Hook propose une vision radicalement nouvelle. En raison de l'autonomie du Hook, le contrat n'a pas besoin d'être entièrement dédié au Hook — le Hook peut n'être qu'une fonction parmi d'autres, servant de pont vers un pool Uni V4, tandis que le contrat lui-même peut exécuter toute autre opération. La « transaction » et Uni V4 ne sont alors qu'une partie des fonctionnalités du contrat.
Prenons un exemple simple : certains petits projets affirment qu’après une levée de fonds, ils ajouteront une partie des jetons et fonds à UniSwap. À l’époque d’Uni V3, les opérations du contrat de levée et du contrat Uni V3 étaient asynchrones, et les utilisateurs devaient compter sur l’équipe du projet pour transférer les fonds. Avec le Hook Uni V4, pourquoi ne pas exploiter l’autonomie du Hook pour intégrer directement l’ajout de liquidité dans le même contrat ? Voire exécuter automatiquement l’ajout dès le dépôt de l’utilisateur (certes, cela engendrerait beaucoup de gaz, mais si certains utilisateurs veulent cette transparence, pourquoi pas ?). C’est fou, mais cela annonce les possibilités infinies des Hooks.
La principale limitation de l'Aggregator Hook reste sa consommation de gaz. Un swap Uni V3 consomme environ 120 000 unités de gaz, alors qu’avec nos multiples opérations d’ajout et de retrait de liquidité, un seul échange consomme entre 420 000 et 550 000 unités selon forge snapshot, bien au-dessus d’un swap normal. Cette méthode d’intégration de pools ne peut donc être utilisée que sur des L2 insensibles au stockage de gaz, ou sur des chaînes à faible coût de gaz. Le « trick » a son prix, c’est normal.
Il reste des axes d’amélioration, surtout sur le remplissage et le retrait de liquidité. Deux directions possibles, l’une simple, l’autre complexe. Commençons par la plus simple :
-
Dans la section Équilibre des prix, nous avons discuté du problème de direction. Si nous conservons la stratégie de retrait de liquidité, les règles entre targetPrice et currentPrice ne peuvent changer, mais tick0 et limitTick n’ont pas besoin d’être différents. Quand limitTick = tick0, le remplissage devient bidirectionnel, et la formule de calcul doit être adaptée. Cela permettrait d’assouplir légèrement la contrainte de direction — d’un tick.
Plus complexe :
-
Puisque nous envisageons déjà le remplissage bidirectionnel, pourquoi ne pas aller jusqu’au bout et cesser d’imposer le retrait systématique ? Ne retirer la liquidité que lorsque le gestionnaire du Hook-Pool le juge nécessaire. Cela réduirait davantage la consommation de gaz lors des swaps des utilisateurs, rendant l'Aggregator Hook plus « utilisable ». Bien sûr, cela pourrait conduire à un algorithme de remplissage de liquidité plus complexe que la solution précédente.
Le code source actuel du pool Aggregator Hook est le suivant :
https://github.com/Attens1423/Aggregator-Hook
Pour visualiser facilement les résultats des transactions, nous avons ajouté l'affichage des résultats dans le hook afterSwap, mais ce n'est pas obligatoire. De nombreuses valeurs intermédiaires sont imprimées, et peuvent être observées avec forge test pour assister à la performance de l'Aggregator Hook.
DODO V3 pourrait bien être le premier pool à franchir le pas. Notre prochain objectif est d'intégrer l'Aggregator Hook dans les pools DODO V3. Certaines mises à jour relatives aux réserves et à l'état du pool restent à effectuer. Après avoir passé tous les tests, nous le rendrons open source, réalisant ainsi notre vision initiale de Hook-Pool.
Bienvenue dans la communauté officielle TechFlow
Groupe Telegram :https://t.me/TechFlowDaily
Compte Twitter officiel :https://x.com/TechFlowPost
Compte Twitter anglais :https://x.com/BlockFlow_News














