Je pense qu'Uniswap v4 sera bientôt disponible pour tout le monde !

Cette fois, l'équipe Uniswap a des objectifs ambitieux et prévoit d'introduire de nombreuses nouvelles fonctionnalités [1], notamment la prise en charge d'un nombre illimité de pools de liquidité et de frais dynamiques pour chaque paire de trading, la conception singleton, la comptabilité éclair, les Hooks et la prise en charge du jeton ERC1155. standard. Tirant parti du stockage transitoire introduit par EIP-1153, Uniswap v4 devrait être publié après la mise à niveau d'Ethereum Cancun.

Parmi les nombreuses innovations, le mécanisme Hook a attiré une large attention en raison de son puissant potentiel. Le mécanisme Hook prend en charge l’exécution de code spécifique à des moments spécifiques du cycle de vie du pool de liquidité, améliorant considérablement l’évolutivité et la flexibilité du pool.

Cependant, le mécanisme du crochet peut également être une arme à double tranchant. Bien qu’il soit puissant et flexible, utiliser Hook en toute sécurité constitue également un défi de taille. La complexité des hooks apporte inévitablement de nouveaux vecteurs d’attaque potentiels. Par conséquent, nous espérons écrire une série d'articles pour présenter systématiquement les problèmes de sécurité et les risques potentiels liés au mécanisme Hook, afin de promouvoir le développement de la sécurité de la communauté. Nous pensons que ces informations aideront à construire un Hook Uniswap v4 sûr.

En guise de début de cette série d'articles, cet article présente les concepts liés au mécanisme Hook dans Uniswap v4 et décrit les risques de sécurité du mécanisme Hook.

Le mécanisme d'Uniswap V4

Avant de plonger dans le vif du sujet, nous devons avoir une compréhension de base des mécanismes d’Uniswap v4. Selon l'annonce officielle [1] et le livre blanc [2], les Hooks, l'architecture singleton et la comptabilité éclair sont trois fonctions importantes pour mettre en œuvre des pools de liquidité personnalisés et obtenir un routage efficace entre plusieurs pools.

1.1 Crochet

Les Hooks font référence à des contrats qui s'exécutent à différentes étapes du cycle de vie du pool de liquidités. L'équipe Uniswap espère permettre à chacun de prendre des décisions de compromis en introduisant les Hooks. De cette manière, il est possible de prendre en charge nativement des frais dynamiques, d'ajouter des ordres de plafonnement des prix en chaîne ou de répartir les ordres importants via un teneur de marché moyen pondéré dans le temps (TWAMM).

Il existe actuellement huit rappels Hook, répartis en quatre groupes (chaque groupe contient une paire de rappels) :

  • avantInitialize/afterInitialize

  • avantModifierPosition/aprèsModifierPosition

  • avantSwap/aprèsSwap

  • avantDonate/afterDonate

Ce qui suit est le processus d'échange de Hooks introduit dans le livre blanc [2].

Figure 1 : Processus Exchange Hook

L'équipe Uniswap a présenté comment procéder avec quelques exemples (tels que TWAMM Hook[3]), et les participants de la communauté ont également apporté quelques contributions. La documentation officielle[4] renvoie également au référentiel Awesome Uniswap v4 Hooks[5], qui rassemble davantage d'exemples de Hook.

1.2 Singleton, comptabilité éclair et mécanisme de verrouillage

L'architecture Singleton et la comptabilité flash sont conçues pour améliorer les performances en réduisant les coûts et en garantissant l'efficacité. Il introduit un nouveau contrat singleton, dans lequel tous les pools de liquidités sont conservés dans le même contrat intelligent. Cette conception singleton s'appuie sur un PoolManager pour stocker et gérer l'état de tous les pools.

Dans les versions antérieures du protocole Uniswap, les opérations telles que l'échange ou l'ajout de liquidités impliquaient des transferts directs de jetons. La version v4 est différente en ce sens qu'elle introduit une comptabilité éclair et un mécanisme de verrouillage.

Le mécanisme de verrouillage fonctionne comme suit :

1. Un contrat de casier demande un verrouillage sur PoolManager.

2. PoolManager ajoute l'adresse du contrat de casier à la file d'attente lockData et appelle son rappel lockAcquired.

3. Le contrat de casier exécute sa logique dans le rappel. Lors de l'exécution, l'interaction du contrat de casier avec le pool peut entraîner des incréments de devise non nuls. Cependant, à la fin de l’exécution, tous les deltas doivent s’établir à zéro. De plus, si la file d'attente lockData n'est pas vide, seul le dernier contrat de casier peut effectuer des opérations.

4. PoolManager vérifie l'état de la file d'attente lockData et l'incrément de devise. Après vérification, PoolManager supprimera le contrat de casier.

En résumé, le mécanisme de verrouillage empêche les accès simultanés et garantit que toutes les transactions peuvent être effacées. Le contrat de casier s'applique aux verrous dans l'ordre, puis exécute les transactions via le rappel lockAcquired. Le rappel Hook correspondant sera déclenché avant et après chaque opération de pool. Enfin, le PoolManager vérifie l'état.

Cette approche signifie que l'opération ajuste le solde net interne (c'est-à-dire le delta) plutôt que d'effectuer un transfert instantané. Les éventuelles modifications seront enregistrées dans la balance interne du pool, et le transfert effectif sera effectué en fin d'opération (i.e. lock). Ce processus garantit qu'il n'y a pas de jetons en circulation, préservant ainsi l'intégrité des fonds.

En raison du mécanisme de verrouillage, les comptes de propriété externes (EOA) ne peuvent pas interagir directement avec PoolManager. Au lieu de cela, toute interaction doit se produire par le biais d’un contrat. Ce contrat fait office de casier intermédiaire et doit demander un verrou avant d'effectuer toute opération sur le pool.

Il existe deux principaux scénarios d’interaction contractuelle :

  • Un certain contrat de casier provient de la base de code officielle ou est déployé par les utilisateurs. Dans ce cas, nous pouvons considérer l’interaction comme passant par le routeur.

  • Un contrat de casier et Hook sont intégrés dans un même contrat, ou contrôlés par une entité tierce. Dans ce cas, nous pouvons considérer l’interaction comme se produisant via des Hooks. Dans ce cas, Hook joue à la fois le rôle de contrat de casier et est responsable de la gestion des rappels.

Modèle de menace

Avant de discuter des problèmes de sécurité associés, nous devons identifier le modèle de menace. Nous considérons principalement les deux situations suivantes :

  • Modèle de menace I : les hooks eux-mêmes sont inoffensifs, mais présentent des vulnérabilités.

  • Modèle de menace II : les hooks sont intrinsèquement malveillants.

Dans les sections suivantes, nous discutons des problèmes de sécurité potentiels basés sur ces deux modèles de menace.

2.1 Problèmes de sécurité dans le modèle de menace I

Le modèle de menace I se concentre sur les vulnérabilités liées au Hook lui-même. Ce modèle de menace suppose que les développeurs et leurs Hooks sont inoffensifs. Cependant, des vulnérabilités connues existantes dans les contrats intelligents peuvent également apparaître dans Hooks. Par exemple, si un Hook est implémenté en tant que contrat évolutif, il peut rencontrer des problèmes similaires à la vulnérabilité UUPSUpgradeable d'OpenZeppelin.

Compte tenu des facteurs ci-dessus, nous avons choisi de nous concentrer sur les vulnérabilités potentielles propres à la version v4. Dans Uniswap v4, les Hooks sont des contrats intelligents capables d'exécuter une logique personnalisée avant ou après les opérations du pool principal, y compris l'initialisation, la modification de position, l'échange et la collecte. Bien que les Hooks soient censés implémenter des interfaces standard, ils permettent également l'inclusion d'une logique personnalisée. Par conséquent, notre discussion se limitera à la logique impliquant l’interface Hook standard. Nous essaierons ensuite d'identifier les sources possibles de vulnérabilités, par exemple, comment les Hooks pourraient abuser de ces fonctions Hook standard.

Plus précisément, nous nous concentrerons sur les deux types de Hooks suivants :

  • La première astuce consiste à conserver les fonds des utilisateurs. Dans ce cas, un attaquant peut attaquer ce hook pour transférer des fonds, entraînant une perte d’actifs.

  • Le deuxième type de hook stocke les données d’état clés sur lesquelles s’appuient les utilisateurs ou d’autres protocoles. Dans ce cas, l’attaquant peut tenter de modifier l’état critique. Des risques potentiels peuvent survenir lorsqu'un état incorrect est utilisé par d'autres utilisateurs ou protocoles.

Veuillez noter que les hooks en dehors de ces deux domaines sortent du cadre de notre discussion.

Puisqu'il n'y a pas de véritables cas d'utilisation pour les Hooks au moment d'écrire ces lignes, nous extrairons quelques informations du référentiel Awesome Uniswap v4 Hooks.

Après une plongée approfondie dans le référentiel Awesome Uniswap v4 Hooks (hash de validation 3a0a444922f26605ec27a41929f3ced924af6075), nous avons découvert plusieurs vulnérabilités critiques. Ces vulnérabilités proviennent principalement d'interactions risquées entre les hooks, PoolManager et des tiers externes, et peuvent être principalement divisées en deux catégories : les problèmes de contrôle d'accès et les problèmes de validation des entrées. Veuillez consulter le tableau ci-dessous pour connaître les résultats spécifiques :

Au total, nous avons trouvé 22 projets pertinents (hors projets non liés à Uniswap v4). Parmi ces projets, nous estimons que 8 (36%) sont vulnérables. Sur les huit projets vulnérables, six présentaient des problèmes de contrôle d'accès et deux étaient vulnérables aux appels externes non fiables.

2.1.1 Problèmes de contrôle d'accès

Dans cette partie de la discussion, nous nous concentrons principalement sur les problèmes qui peuvent être causés par les fonctions de rappel de la v4, notamment les rappels à 8 hooks et les rappels de verrouillage. Bien sûr, il existe d’autres situations qui doivent être vérifiées, mais ces situations varient selon la conception et dépassent le cadre de notre discussion.

Ces fonctions ne doivent être appelées que par PoolManager et ne peuvent pas être appelées par d'autres adresses (y compris EOA et contrats). Par exemple, dans le cas où les récompenses sont distribuées par clés de pool, les récompenses peuvent être réclamées de manière incorrecte si la fonction correspondante peut être appelée par n'importe quel compte.

Par conséquent, il est crucial d’établir des mécanismes de contrôle d’accès solides pour les hooks, d’autant plus qu’ils peuvent être appelés par d’autres parties que le pool lui-même. En gérant strictement les droits d’accès, les pools de liquidité peuvent réduire considérablement le risque d’interactions non autorisées ou malveillantes avec les hooks.

2.1.2 Problèmes de vérification des entrées

Dans Uniswap v4, en raison du mécanisme de verrouillage, les utilisateurs doivent obtenir un verrou via le contrat avant d'effectuer toute opération de pool de fonds. Cela garantit que le contrat participant actuellement à l'interaction est le dernier contrat de casier.

Il existe néanmoins un scénario d'attaque possible, à savoir des appels externes non fiables en raison d'une validation d'entrée inappropriée dans certaines implémentations vulnérables de Hook :

  • Premièrement, le hook ne vérifie pas le pool de fonds avec lequel l’utilisateur a l’intention d’interagir. Il pourrait s'agir d'un pool malveillant contenant de faux jetons et exécutant une logique nuisible.

  • Deuxièmement, certaines fonctions de hook de clé autorisent des appels externes arbitraires.

Les appels externes non fiables sont extrêmement dangereux car ils peuvent conduire à différents types d’attaques, y compris ce que nous appelons les attaques de réentrée.

Afin d'attaquer ces hooks vulnérables, un attaquant peut enregistrer un pool de fonds malveillant pour ses propres faux jetons, puis appeler le hook pour effectuer des opérations dans le pool de fonds. Lors de l’interaction avec le pool, la logique du jeton malveillant détourne le flux de contrôle afin d’adopter un comportement indésirable.

2.1.3 Mesures préventives contre le modèle de menace I

Pour contourner ces problèmes de sécurité liés aux hooks, il est crucial d'authentifier les interactions en appliquant correctement les contrôles d'accès nécessaires aux fonctions externes/publiques sensibles et en validant les paramètres d'entrée. De plus, la protection contre la réentrance peut contribuer à garantir que le hook n’est pas exécuté de manière répétée dans le flux logique standard. En mettant en œuvre des mesures de sécurité appropriées, les pools peuvent réduire les risques associés à de telles menaces.

2.2 Problèmes de sécurité dans le modèle de menace II

Dans ce modèle de menace, nous supposons que le développeur et son hook sont malveillants. En raison de la vaste portée, nous nous concentrons uniquement sur les problèmes de sécurité liés à la version v4. Par conséquent, la clé est de savoir si le hook fourni peut gérer les actifs cryptographiques transférés ou autorisés par l’utilisateur.

Puisque la méthode d’accès au hook détermine les autorisations qui peuvent être accordées au hook, nous divisons le hook en deux catégories :

  • Hooks gérés : les hooks ne sont pas des points d’entrée. Les utilisateurs doivent interagir avec le hook via un routeur (éventuellement fourni par Uniswap).

  • Hooks autonomes : les hooks sont des points d’entrée qui permettent aux utilisateurs d’interagir directement avec eux.

Figure 2 : Exemple de Hook malveillant

2.2.1 Hook géré

Dans ce cas, les actifs cryptographiques de l'utilisateur (y compris les jetons natifs et autres jetons) sont transférés ou autorisés au routeur. Étant donné que PoolManager effectue des vérifications de solde, il n’est pas facile pour les hooks malveillants de voler directement ces actifs. Il existe néanmoins une surface d’attaque potentielle. Par exemple, le mécanisme de gestion des dépenses de la version v4 peut être manipulé par des attaquants via des hooks.

2.2.2 Crochet indépendant

La situation est encore plus compliquée lorsque les Hooks sont utilisés comme points d’entrée. Dans ce cas, le hook gagne plus de puissance puisque l’utilisateur peut interagir directement avec lui. En théorie, un hook peut faire tout ce qu’il veut avec cette interaction.

Dans la version v4, la vérification de la logique du code est très critique. Le principal problème est de savoir si la logique du code peut être manipulée. Si un hook peut être mis à niveau, cela signifie qu'un hook apparemment sûr peut devenir malveillant après avoir été mis à niveau, ce qui présente un risque important. Ces risques comprennent :

  • Agents évolutifs (peuvent être directement attaqués) ;

  • Avec une logique d’autodestruction. Il peut être attaqué lorsque selfdestruct et create2 sont appelés conjointement.

2.2.3 Mesures préventives contre le modèle de menace II

Il est crucial d’évaluer si le hook est malveillant. Plus précisément, pour les hooks gérés, nous devons nous concentrer sur le comportement de gestion des frais ; tandis que pour les hooks autonomes, l’accent est mis sur leur capacité à être mis à niveau.

en conclusion

Dans cet article, nous fournissons d’abord un bref aperçu des mécanismes de base liés aux problèmes de sécurité Hook d’Uniswap v4. Par la suite, nous proposons deux modèles de menaces et décrivons brièvement les risques de sécurité associés.

Dans les articles suivants, nous procéderons à une analyse approfondie des problèmes de sécurité sous chaque modèle de menace.