Uniswap et l’évolution des AMM décentralisés – Les AMM décodés
Les premiers modèles d’AMM (automated market makers) pour la finance décentralisée virent le jour sur Ethereum, grâce aux smart contracts. Originellement, réaliser des échanges décentralisés avec des réserves de liquidité (liquidity pools) était un challenge. Les premières solutions furent proposées par Bancor (courbe de liaison ou bonding curve) et Uniswap (fonction à produit constant).
Ces protocoles étaient loin d’être parfaits. Ils pouvaient être grandement améliorés en termes d’efficience (frais, slippage, profondeur de marché) et de fonctionnalités.
Les chercheurs travaillant sur les AMM ont proposé de nouveaux modèles. Conjointement, les développeurs des plateformes d’échange décentralisées (DEX) ont constamment amélioré leur expérience utilisateur, et ajouté de nouvelles fonctionnalités.
Nous présenterons ici les principales améliorations du protocole Uniswap, ainsi que les nouvelles fonctions de prix qui servent de fondations pour les AMM les plus élaborés.
Uniswap V2
Selon les mots de ses développeurs eux-mêmes, la première version d’Uniswap était une preuve de concept : un nouveau type de place de marché décentralisée. Après les premières expérimentations, le protocole devait être amélioré. Hayden Adams, Noah Zinsmeister et Dan Robinson publièrent donc le livre blanc d’Uniswap V2 en mars 2020.
Plusieurs nouvelles fonctionnalités firent leur apparition : la possibilité d’échanger des ERC-20 entre eux, les flash swaps, et les oracles de prix.
Les paires d’ERC-20
Sur Uniswap V1, les réserves de liquidité étaient toujours composées d’ETH et d’un jeton ERC-20. Cette décision fut prise par conception. En effet, l’ether était l’actif du réseau Ethereum le plus liquide, et ne présentait aucun risque de plateforme. Un échange (swap) entre deux ERC-20 était simplement routé à travers l’ETH. Cela améliorait ainsi l’expérience utilisateur, et réduisait la fragmentation des liquidités.
Avec Uniswap V2, n’importe quel jeton ERC-20 peut être directement « poolé » avec un autre ERC-20. Les smart contrats principaux (core contracts) utilisent du wrapped ether (WETH) à la place de l’ether lui-même. Le contrat de routage permet de réaliser un échange direct entre les deux jetons.
Les pools ERC-20/ERC-20 confèrent ainsi plusieurs avantages, à la fois pour les traders et pour les fournisseurs de liquidité :
- Les fournisseurs de liquidité peuvent s’exposer à plus de jetons ERC-20 sans être exposés à l’ether ;
- Les traders ont accès à plus de paires d’échange (particulièrement les stablecoins) ;
- Les prix sont meilleurs, car le routage via l’ETH impliquait des frais supérieurs.
De même, on peut échanger deux jetons ERC-20 même s’ils ne forment pas une paire dans un pool. Il suffit alors qu’un chemin entre les deux jetons existe. Les smart contracts de routage sont optimisés pour choisir le meilleur chemin entre les deux jetons.
L’oracle de prix d’Uniswap
La première version d’Uniswap proposait un oracle de prix approximatif. En effet, le prix marginal d’un jeton sur Ethereum à l’instant est calculé en divisant les réserves du jeton d’entrée a par celles du jeton de sortie b :
Les failles de l’oracle sur Uniswap V1
Grâce à l’arbitrage, le prix sur Uniswap va tendre vers le prix de marché relatif des jetons. Cependant, cet type d’oracle peut être manipulé, et les hackers trouvèrent vite la faille :
- Acheter de l’ETH depuis une paire ETH/stablecoin ;
- Lorsque le prix est suffisamment gonflé, déclencher le règlement d’un contrat dérivé sur un autre exchange utilisant l’oracle ;
- Finaliser l’opération en vendant les ETH dans le premier pool, pour le faire revenir à son « vrai » prix.
Afin de combler cette lacune, le prix doit être mesuré et enregistré :
- Soit avant que le premier trade ne soit inscrit dans un bloc Ethereum ;
- Soit après que le dernier trade du bloc précédent ait eu lieu.
De cette façon, l’attaquant qui essaie de manipuler le prix avec sa transaction sera contré par les arbitrageurs, qui vont réaliser le trade inverse au sein du même bloc. Un mineur pourrait tenter de manipuler le prix à la fin d’un bloc, cependant, il devra également miner le bloc suivant pour que l’arbitrage soit profitable. On parle de minage égoiste (selfish mining attack).
L’oracle d’Uniswap V2
Uniswap V2 inclut un oracle de prix on-chain. Plus précisément, le protocole implémente des flux de prix on-chain décentralisés et résistants à la manipulation. Les prix sont ainsi mesurés lorsqu’ils sont très coûteux à manipuler, et l’oracle sauvegarde les données historiques.
L’oracle on-chain procède de la façon suivante :
- Tout d’abord, le prix de marché est mesuré au début de chaque bloc, avant qu’un trade n’ait eu lieu ;
- Le prix de marché est ensuite mesuré à la fin du bloc et sauvegardé ;
- Puis une variable unique, cumulative, stockée au sein du core contract, est pondérée par la durée durrant laquelle ce prix existait. Il s’agit ainsi de la somme du prix, pour chaque seconde dans l’histoire complète du contrat ;
- Enfin, le prix de marché à la fin du bloc est ajouté à cette variable.
Le prix de marché au début d’un bloc est très difficile à manipuler à cause des arbitrageurs qui vont renverser le trade de l’attaquant. Grâce à l’enregistrement de chaque prix à la clôture des blocs, l’oracle fournit des prix moyens temporellement pondérés (time-weighted average prices ou TWAP) pour chaque période de temps supérieure à une seconde.
Comment cela fonctionne-t-il ? Voici les mathématiques d’un oracle de prix.
Fonctionnement de l’oracle on-chain
En d’autres termes, l’oracle utilise un accumulateur pour tracer les prix de marché à chaque seconde :
Pour obtenir le prix moyen pondéré pour la période entre le temps t1 et le temps t2, nous devons soustraire t1 de t2 et diviser le résultat par la période écoulée en secondes :
Le smart contract de l’accumulateur ne stocke pas les données historiques. Les utilisateurs de l’oracle doivent donc choisir t1 et t2, appeler le contrat au début de la période et stocker cette valeur.
Plus la période est longue, et plus il est difficile d’attaquer l’oracle, mais moins le prix est à jour. Le coût d’une attaque pour faire dévier le prix de 5% sur un TWAP d’une heure est à peu près égal aux somme perdues en arbitrage et en frais pour faire bouger le prix de 5 % à chaque bloc durant une heure.
Les flash swaps
Cette nouvelle fonctionnalité permet aux traders d’obtenir un actif sans payer pour celui-ci. Les flash swaps permettent de retirer n’importe quel ERC-20 sur Uniswap, lorsqu’une des conditions suivantes est remplie :
- Tous les jetons retirés seront payés à la fin de la transaction ;
- Un certain pourcentage des jetons est payé à la fin de la transaction, tandis que le restant est rendu ;
- Tous les jetons retirés sont rendus.
On parle de transaction atomique (atomic transaction). Les frais réglés aux fournisseurs de liquidité sont de 0,3 % pour chaque entrée, et ce même si les jetons retirés sont renvoyés.
Les flash swaps permettent donc aux traders de recevoir des actifs, et de les utiliser ailleurs à leur guide avant de les payer (ou de les rendre) plus tard dans la transaction.
C’est très utile, car le capital requis pour réaliser des transactions complexes en plusieurs étapes n’est plus nécessaire. Par exemple, un arbitrageur qui n’a pas les fonds requis pour acheter un jeton sur Uniswap, puis le revendre sur un autre plateforme, peut passer par un flash swap.
Frais de protocole
Avec Uniswap V2, une nouvelle commission fit son apparition : le protocol fee. Ces frais de 0,05 % peuvent être activés ou non, et si c’est le cas, ils vont vers une adresse feeTo
spécifiée. L’idée est de récompenser les détenteurs du jeton UNI (le jeton de gouvernance natif du protocole) grâce à ces frais.
À l’heure d’écriture, les protocol fees n’ont pas encore été activés. Ce sera le cas si les utilisateurs d’Uniswap le décident via le processus de gouvernance du protocole.
Meta-transactions
Cela permet aux fournisseurs de liquidité de transférer leurs parts d’un pool avec une simple signature, plutôt que d’exécuter une transaction on-chain depuis leur compte Ethereum. En appelant la fonction permit
, n’importe qui peut soumettre sa signature.
Nouvelle architecture des contrats
Le smart contrat principal – core pair contract – fut réécrit pour la V2 d’Uniswap. Il est désormais écrit en Solidity (la V1 était codée en Vyper). Afin de minimiser la surface d’attaque, toutes les fonctionnalités de trading – hormis le simple swap – sont gérées séparément par le contrat de routage.
Certaines parties de la fonctionnalité de swap sont aussi gérées par le routeur. Tout d’abord, les vendeurs transfèrent leurs actifs vers le core contract, avant d’appeler la fonction swap
. Puis le contrat mesure la quantité d’actifs reçue (en comparant les soldes avant et après le transfert). Cela signifie qu’il est aussi possible d’utiliser les meta-transactions à la place de la fonction transferFrom pour initier unetransaction.
Les wrapped ethers
Les wrapped ethers (wETH) ou ethers « enrobés » sont des jetons ERC-20 qui représentent de « vrais ethers », et qui ne peuvent être échangés qu’avec d’autres ERC-20. Les « vrais » ethers correspondants sont verrouillés dans un contrat, pour garantir la valeur des wETH. Ils sont très utiles pour des raisons d’interopérabilité.
La première version de l’AMM d’Uniswap utilisait les ETH natifs pour des raisons d’économies de gas. La version 2 intègre n’importe quel jeton ERC-20 : utiliser de l’ETH natif ne faisait plus sens – cela doublerait la taille du code. De plus, cela engendrerait un problème de fragmentation de la liquidité, entre les paires en ETH natif et celles en wETH.
Il faut donc « wrap » ses ethers, avant de les transférer vers les réserves de liquidité.
Uniswap V3
La troisième version d’Uniswap vit le jour un an après le lancement de la V2 du protocole. Elle offre encore plus de flexibilité et de contrôle aux fournisseurs de liquidité. Les chercheurs se sont focalisés sur l’efficacité du capital, tout en améliorant encore un peu plus l’oracle de prix.
La liquidité concentrée
Il s’agit de la fonctionnalité la plus notable d’Uniswap V3. Les fournisseurs de liquidité peuvent concentrer leur capital sur des fourchettes de prix personnalisées. Cela améliore ainsi la liquidité sur les niveaux de prix choisis. En d’autres termes, au lieu d’utiliser continuellement la fonction à produit constant, les fournisseurs de liquidité peuvent créer leurs courbes de prix propres.
Au sein d’un pool, il est possible de combiner toutes les positions concentrées individuellement par les LP. Les utilisateurs du protocole échangent avec cette liquidité combinée; les LP reçoivent leur part des frais en proportion de la liquidité qu’ils ont concentré dans la fourchette de prix considérée.
Efficacité du capital
La concentration de la liquidité a un effet bénéfique : elle augmente l’efficacité du capital des fournisseurs de liquidité. La profondeur de marché reste la même que sur Uniswap V2, mais il y a moins de capital à risque. Le capital « préservé » peut alors être :
- Investi sur différents actifs ;
- Transféré sur d’autres protocoles DeFi ou plateformes ;
- Conservé dans un environnement externe ;
- Placé sur d’autres fourchettes de prix, afin d’augmenter l’exposition du fournisseur de liquidité et lui rapporter plus de commissions.
Liquidité active
La notion de liquidité active renvoie au capital qui est alloué sur la fourchette de prix (range) courante du marché. Si le prix dévie de ce range, la liquidité est retirée du pool, et le fournisseur ne reçoit plus de frais. Il devra attendre que le prix de l’actif revienne dans cette fourchette, ou mettre son range à jour en l’accordant avec le prix courant.
Range orders
Ces ordres ressemblent aux ordres à cours limité sur une plateforme de change classique. Les fournisseurs de liquidité déposent leurs jetons dans une fourchette de prix spécifiée (au-dessus ou au-dessous du prix courant). Si le prix de marché entre dans le range spécifié, l’actif déposé sera vendu, et le fournisseur de liquidité recevra ses frais pour l’échange.
Le prix moyen d’exécution d’un range order est tout simplement la moyenne géométrique du prix minimum et du prix maximum spécifiés.
Frais flexibles
Tandis qu’Uniswap V2 avait introduit des frais de protocole (pouvant être activés ou pas), Uniswap V3 offre un modèle de frais beaucoup plus flexible. Les fournisseurs de liquidité peuvent choisir entre 3 niveaux de frais par paire de trading : 0,05 %, 0,1 % et 0,3 %.
Ils peuvent ainsi ajuster leur marge, en se basant sur le risque que chaque paire représente. Par exemple, une paire de stablecoins sera beaucoup moins risquée qu’une paire ERC-20/ETH. Les LP peuvent donc choisir des frais de 0,05 % pour la première, et de 0,3 % pour la seconde.
Des oracles améliorés
L’équipe de développement a nettement amélioré l’oracle TWAP pour la V3. À la place d’une unique somme cumulative, on peut stocker de multiples accumulateurs de prix dans la zone de mémoire dédiée. Ainsi, on peut créer des oracles plus avancés – calcul de moyennes mobiles simples et exponentielles, filtrage de certaines valeurs…
Cela réduit aussi le coût en gas nécessaire pour maintenir les oracles à jour de moitié. Il en va de même pour les coût du calcul des TWAP sur des smart contracts externes.
Autres types d’AMM à fonction constante
Il existe d’autres modèles et implémentations d’AMM à fonction constante, qui permettent d’échanger plus de deux actifs au sein d’une même réserve de liquidité. Une version naïve est l’AMM à somme constante, tandis que la version étendue du produit constant est l’AMM à moyenne constante.
Chacun de ces modèles présente des avantages spécifiques pour un certain type d’actifs (jetons ERC-20 ou stablecoins). Avant d’entrer dans les détails de ces AMM dans les articles suivants, voici une introduction.
AMM à somme constante
Les AMM à somme constante sont l’extension du modèle de l’AMM à fonction constante, pour des pools à actifs multiples (> 2). Ils satisfont la fonction d’état suivante :
Où les Ri sont les réserves de chaque actif, et k une constante.
Ainsi, le graphe d’un AMM à somme constante pour seulement une paire d’actif ressemble à ceci :
Dans le cas de deux jetons, son équation est donc x + y = k. Comme nous pouvons le voir, il n’y a aucun slippage ! Cependant, un tel modèle ne fournit pas une liquidité infinie au marché. Si le ratio entre le prix d’un actif et celui de sa contrepartie est de zéro, alors il n’y a plus de liquidité disponible pour cet actif. Ce type de situation se produit si un des participants au marché draine la liquidité d’un côté (le fameux money pumping).
AMM à moyenne constante
Un automated market maker à moyenne constante est la généralisation d’un AMM à produit constant, pour plus de deux actifs, et pour des pondérations de réserves pouvant dériver de la règle des 50/50. Nous étudierons ce modèle en détails dans l’article consacré à Balancer. Ces protocoles satisfont l’équation suivante (en l’absence de frais) :
Où Riwi est la réserve de chaque actif, wi le poids de chaque actif, et k une constante.
Les marchés à moyenne constante assurent que la moyenne géométrique pondérée des différentes réserve reste constante.
Dans cet exemple, la fonction définissant ce portfolio de 3 actifs sera :
AMM à fonctions hybrides
En conclusion, et avant de nous attaquer aux modèles d’AMM décrits ci-dessus, nous pouvons dire que les développeurs des protocoles d’AMM ont pris en considération les inconvénients et les failles de leurs prédécesseurs.
Les fonctions de prix présentées plus haut servent de fondation aux protocoles DeFi les plus avancés, comme Balancer ou Curve. Elles furent adaptées afin de satisfaire les besoins de ces protocoles, en cherchant les meilleurs compromis pour fournir une liquidité efficace, un faible slippage et de bonnes incitations économiques.
Bibliographie
- Le livre blanc d’Uniswap V2
- Présentation officielle d’Uniswap V2
- Présentation d’Uniswap V3
- Le livre blanc d’Uniswap V3