Uniswap : construire un Automated Market Maker sur Ethereum – Les AMM décodés

Pour notre premier cas d’étude dans cette série sur les AMM (automated market makers ou faiseurs de marché automatisés) nous nous penchons sur le cas d’Uniswap. Uniswap est l’un des trois AMM les plus utilisés sur Ethereum, et peut être considéré comme le premier AMM à fonction constante.
La première version du protocole fut lancée en novembre 2018, durant la Devcon 4. C’est une plateforme d’échange décentralisée, qui utilise un protocole à fonction constants pour fournir de la liquidité aux traders.
Uniswap V1 était conçue pour être simple : un DEX dédié aux échanges de jetons ERC-20 pour les utilisateurs d’Ethereum. Son équipe de développement souhaitait bâtir un modèle où décentralisation, sécurité et résistance à la censure étaient optimaux.
Le code source d’Uniswap est open-source et se trouve sur ce dépôt GitHub.

Principes d’Uniswap

Uniswap utilise la formule du produit constant au cœur de son protocole d’échange de jetons (token swap) décentralisé. Ses utilisateurs peuvent échanger n’importe quel type de jeton ERC-20. Uniswap repose sur un ensemble de smart contracts. Chaque ERC-20 listé sur la plateforme a son contrat dédié, appelé exchange contract – contrat d’échange.

Un programme, appelé Uniswap Factory, permet à tout utilisateur de créer un exchange contract pour n’importe quel ERC-20. La Factory est donc un registre qui regroupe tous les jetons ajoutés à l’ensemble du système.

Chaque contrat d’échange présente deux réserves (vaults, coffres numériques). L’un a un solde en ethers (ETH) et l’autre un solde en ERC-20, correspondant au contrat. Ces réserves sont également appelées liquidity pools pour ce jeton ERC-20. N’importe quel utilisateur d’Ethereum peut déposer de la liquidité, à la fois en ETH et en ERC-20, dans le pool. Lorsque ses fonds sont verrouillés au sein du smart contract, cet utilisateur devient un fournisseur de liquidité (liquidity provider ou LP). Il sera ensuite récompensé pour son apport.

Cette récompense est proportionnelle au stake (enjeu), c’est-à-dire à la quantité de fonds déposés par le fournisseur de liquidité. Afin de garder la trace des liquidités déposées dans le pool, le protocole utilise un jeton spécial. Ces jetons sont appelés LP tokens (liquidity provider tokens) et sont créés lorsque des liquidités sont ajoutées. Si le fournisseur de liquidité décide de retirer ses fonds, les jetons LP correspondant sont brûlés. Enfin, sa part correspondante de la réserve lui est envoyée.

Licorne-Uniswap

Les fonctionnalités d’Uniswap V1

L’équipe de développement d’Uniswap avait bâti les fondations d’un modèle duquel de nombreux AMM se sont inspirés dans les mois suivants. Les fonctionnalités de la plateforme étaient basiques et se focalisaient sur l’expérience utilisateur :

  • Intégration de n’importe quel jeton ERC-20 via l’Uniswap Factory ;
  • Échanges en une transaction unique pour les paires ETH/ERC-20 ;
  • Possibilité d’acheter n’importe quel jeton ERC-20 à partir de n’importe quel portefeuille en utilisant l’Ethereum Name Service (ENS) ;
  • Création de DEX Uniswap privés et personnalisés ;
  • Implémentation de l’interface (front-end) sur mobile.

L’objectif était d’obtenir des frais de transaction (gas fees) peu coûteux – ce qui s’avéra être un gros problème – et une sécurité maximale. Les smart contracts d’Uniswap V1 étaient codés en Vyper. Ils furent audités en utilisant une méthode appelée lightweight formal verficationvérification formelle légère.

Comment fonctionne Uniswap ?

L’algorithme de market making automatisé (AMM) d’Uniswap utilise judicieusement la formule du produit constant : x*y = k. Le pricing des jetons est sensible à la liquidité (liquidity sensitive). Il est déterminé automatiquement par le produit constant. Chaque contrat d’échange (un par paire ETH/ERC-20) contient de la liquidité pour chaque élément de la paire.

Les prix sont calculés comme fonction de la taille relative des deux réserves (liquidity pools) et de la taille de l’échange (trade).

Échange de jetons (token swap)

Lorsqu’un trader souhaite échanger un jeton, dans n’importe quelle direction (ETH vers ERC-20 ou ERC-20 vers ETH), la liquidité est simplement ajoutée dans le pool correspondant. Dans le même temps, la liquidité est retirée de la réserve opposée. Étant donné que l’ether est le carburant principal du réseau Ethereum, et présent pour chaque échange ETH/ERC-20, il est l’intermédiaire de paiement utilisé pour échanger des jetons ERC-20 contre d’autres jetons ERC-20, en une transaction unique. Les utilisateurs d’Uniswap peuvent aussi échanger et transférer des jetons vers une adresse différente de l’originale, en une seule transaction.

Il n’y a donc aucun carnet d’ordres : les utilisateurs d’Uniswap échangent leurs jetons avec les réserves du protocole.

Trois variables déterminent le prix d’un jeton :

  • La taille (quantité) de la réserve en ETH dédié à l’ERC-20 échangé ;
  • La taille (quantité) de la réserve du jeton ERC-20 ;
  • La quantité vendue (entrée, input) ou achetée (sortie, output).

Les effets sur la liquidité

La formule du produit constant utilise le ratio entre les réserves d’ETH et du jeton ERC-20 correspondant pour fixer le prix du jeton. Ainsi, n’importe quel échange affecte ce ratio :

  • Lorsque l’on vend des ETH pour un jeton ERC-20, la réserve d’ETH augmente, tandis que la réserve d’ERC-20 diminue.
  • Lorsque l’on achète des ETH avec un jeton ERC-20, la réserve d’ETH diminue, tandis que la réserve d’ERC-20 augmente.

Cela signifie donc que plus la taille du trade est grande, et plus ce dernier aura d’effet sur le ratio ETH/ERC-20 du pool. Par conséquent, le volume de l’échange influe sur le glissement du prix (price slippage). Le prix coté par l’AMM peut alors être appelé « prix relatif », car il peut dériver de la valeur de marché globale du jeton.

Les acteurs qui ont vocation à réduire le slippage sont les arbitrageurs. Ils vont ainsi ajouter de la liquidité quand c’est nécessaire et tirer profit des fluctuations du prix.

Ordres ETH/ERC-20

Pour les ordres de vente (exact input) la quantité achetée (output) est calculée comme suit :

// Vendre des ETH pour des ERC20
const inputAmount = userInputEthValue
const inputReserve = web3.eth.getBalance(exchangeAddress)
const outputReserve = tokenContract.methods.balanceOf(exchangeAddress).call()

// Vendre des ERC20 pour des ETH
const inputAmount = userInputTokenValue
const inputReserve = tokenContract.methods.balanceOf(exchangeAddress).call()
const outputReserve = web3.eth.getBalance(exchangeAddress)

// Output amount (quantité achetée)
const numerator = inputAmount * outputReserve * 997
const denominator = inputReserve * 1000 + inputAmount * 997
const outputAmount = numerator / denominator

Pour les ordres d’achat (exact output), le coût (input) est calculé comme suit :

// Achat d'ERC20 avec des ETH
const outputAmount = userInputTokenValue
const inputReserve = web3.eth.getBalance(exchangeAddress)
const outputReserve = tokenContract.methods.balanceOf(exchangeAddress).call()

// Achat d'ETH avec des ERC20
const outputAmount = userInputEthValue
const inputReserve = tokenContract.methods.balanceOf(exchangeAddress).call()
const outputReserve = web3.eth.getBalance(exchangeAddress)

// Coût
const numerator = outputAmount * inputReserve * 1000
const denominator = (outputReserve - outputAmount) * 997
const inputAmount = numerator / denominator + 1

Les frais revenant au fournisseur de liquidité sont les suivants :

fee = inputAmount * 0.003

Le taux de l’échange (exchange rate) est la quantité en sortie divisée par la quantité en entrée :

const rate = outputAmount / inputAmount

Ordres ERC-20/ERC-20

Nous avons 4 variables nécessaires pour déterminer les prix lors d’un échange entre une paire de jetons ERC-20 :

  • Tout d’abord, la taille de la réserve d’ETH pour le jeton ERC-20 en entrée ;
  • Puis la taille de la réserve en ERC-20 pour le jeton en entrée ;
  • Ensuite, la taille de la réserve d’ETH pour l’ERC-20 en sortie ;
  • Enfin, la taille de la réserve du jeton ERC-20 en sortie.

Bien sûr, la quantité de jetons vendues (exact input) et la quantité de jetons achetés (output) sont aussi des paramètres nécessaires.

Pour les ordres de vente (exact input), on calcule la quantité achetée (output) ainsi :

// Conversion TokenA (ERC20) vers ETH 
const inputAmountA = userInputTokenAValue
const inputReserveA = tokenContractA.methods.balanceOf(exchangeAddressA).call()
const outputReserveA = web3.eth.getBalance(exchangeAddressA)

const numeratorA = inputAmountA * outputReserveA * 997
const denominatorA = inputReserveA * 1000 + inputAmountA * 997
const outputAmountA = numeratorA / denominatorA

// Conversion ETH vers TokenB
const inputAmountB = outputAmountA
const inputReserveB = web3.eth.getBalance(exchangeAddressB)
const outputReserveB = tokenContract.methods.balanceOf(exchangeAddressB).call()

const numeratorB = inputAmountB * outputReserveB * 997
const denominatorB = inputReserveB * 1000 + inputAmountB * 997
const outputAmountB = numeratorB / denominatorB

Pour les ordres d’achat (exact output), le coût (input) est calculé ainsi :

// Achat de TokenB avec ETH
const outputAmountB = userInputTokenBValue
const inputReserveB = web3.eth.getBalance(exchangeAddressB)
const outputReserveB = tokenContractB.methods.balanceOf(exchangeAddressB).call()

// Coût
const numeratorB = outputAmountB * inputReserveB * 1000
const denominatorB = (outputReserveB - outputAmountB) * 997
const inputAmountB = numeratorB / denominatorB + 1

// Achat d'ETH avec TokenA
const outputAmountA = userInputEthValue
const inputReserveA = tokenContractA.methods.balanceOf(exchangeAddressA).call()
const outputReserveA = web3.eth.getBalance(exchangeAddressA)

// Coût
const numeratorA = outputAmountA * inputReserveA * 1000
const denominatorA = (outputReserveA - outputAmountA) * 997
const inputAmountA = numeratorA / denominatorA + 1

Les frais des fournisseurs de liquidité s’appliquent deux fois dans ce cas (0,3% + 0,3%) :

const exchangeAFee = inputAmountA * 0.003
const exchangeBFee = inputAmountB * 0.003

Puisque l’utilisateur apporte seulement le jeton A, ils peuvent être représentés ainsi :

const combinedFee = inputAmountA * 0.00591

Le taux d’échange (exchange rate) est alors :

const rate = outputAmountB / inputAmountA

L’arbitrage

Les mécanismes d’arbitrage assurent que le prix relatif d’un actif ne déviera pas trop de son prix intrinsèque. Avec ces opportunités d’arbitrage, de la liquidité est également régulièrement ajoutée dans les réserves. En effet, s’il y a de grosses fluctuations du prix, les arbitrageurs en bénéficient, en ajoutant de la liquidité dans les pools.

Frais et LP tokens

Les frais d’Uniswap s’élèvent à 0,3 %. Ces commissions s’appliquent pour chaque trade, et les jetons correspondant sont ajoutés aux pools de liquidité. Cela garantit donc que la quantité d’actifs dans les réserves augmentera avec le temps et l’usage, quels que soient les changements du ratio entre les deux actifs de la paire.

Ces frais bénéficient aux fournisseurs de liquidité. Lorsqu’un LP souhaite retirer ses fonds, les jetons LP correspondants sont brûlés. Ces jetons déterminent les parts du pool que possède le fournisseur de liquidité. Les frais sont donc ajoutés aux fonds retirés comme récompense, au prorata des liquidités fournies.

En utilisant les pools Uniswap « standards » (créés avec la Factory), les fournisseurs de liquidité ne peuvent créer des LP tokens que pour un unique pool d’ERC-20 dédié. Cela assure que la liquidité pour un ERC-20 donné ne sera pas dispersée à travers plusieurs réserves.

Les jetons de liquidité (LP tokens) sont hautement divisibles. Les fournisseurs de liquidité peuvent décider de les brûler à tout instant. Ils reçoivent alors leurs fonds proportionnellement à leur contribution.

Plongée dans le code d’Uniswap

Dans cette partie, nous allons passer en revue les principales fonctions du protocole Uniswap.

Fonctions de liquidity minting

Chaque contrat d’échange contient une réserve d’ETH et de son ERC-20 associé. Il s’agit donc des soldes en ETH et en ERC-20 de chaque contrat :

const ethReserve = web3.eth.getBalance(exchangeAddress)
const tokenReserve = tokenContract.methods.balanceOf(exchangeAddress)

Ajout de liquidités

Le protocole utilise la fonction addLiquidity() lorsque les fournisseurs de liquidité déposent dans les réserves. Les jetons de liquidité sont alors créés :

exchange.methods.addLiquidity(min_liquidity, max_tokens, deadline).send({ value: ethAmount })

La quantité de jetons LP dépend de la quantité d’ETH envoyés vers la fonction. Le fournisseur de liquidité doit aussi déposer la valeur correspondante en jetons ERC-20. C’est donc le premier fournisseur de liquidité d’un pool qui définit le taux de change initial. S’il dévie du taux des marchés externes, les arbitrageurs peuvent alors ramener les prix à l’équilibre, aux dépens du fournisseur de liquidité.

  • ethAmount est la quantité exacte d’ETH déposée, soit la moitié de la valeur totale des liquidités fournies par le LP. Cette variable est utilisée pour déterminer la quantité d’ERC-20 devant être déposés.
  • max_tokens est utilisée pour borner les fluctuations du taux de change. Pour le premier fournisseur de liquidité, il s’agit donc de la quantité exacte de jetons déposés.
  • min_liquidity est utilisé en combinant les deux variables précédentes pour borner le taux auquel les jetons de liquidité sont créés.
  • La deadline permet de fixer un délai après lequel la transaction ne peut pas être exécutée. Ainsi, les mineurs n’ont pas la possibilité de retenir des transactions signées et de les exécuter en fonction du prix du marché à leur avantage.

Retrait de liquidités

La fonction removeLiquidity() permet aux LP de retirer leur part de la réserve :

exchange.methods.removeLiquidity(amount, min_eth, min_tokens, deadline).send()

amount spécifie la quantité de jetons de liquidité à brûler. En la divisant par la quantité totale de jetons de liquidité, on obtient le pourcentage d’ETH et d’ERC20 que le fournisseur de liquidité retire.

Ces liquidités sont donc retirées au même ratio que celui des réserves lors du retrait. Ici encore, si le taux de change est mauvais, alors il y a une opportunité d’arbitrage qui corrigera le prix.

Ajustements des ordres

L’AMM d’Uniswap est déployé totalement on-chain. Il y a donc un délai entre le moment où une transaction est signée (initiation du trade) et le bloc dans lequel elle est incluse. Cela engendre des fluctuations de prix.

Il est possible d’ajuster la quantité minimale vendue pour un ordre de vente, ou la quantité maximale achetée pour un ordre d’achat. De la même façon, on peut fixer un délai à partir duquel la transaction ne sera plus exécutée. Le trader a ainsi la garantie que son ordre ne sera pas exécuté si les conditions requises (quantité, prix et latence) ne sont pas remplies.

Les deadlines pour la transaction sont définies en secondes :

web3.eth.getBlock('latest', (error, block) => {
deadline = block.timestamp + 300 // la transaction expire dans 300 seconds (5 minutes)
})

Par exemple, après un délai de 300 secondes, la transaction ne sera pas incluse par les mineurs. Ces deadlines de transaction présentent deux avantages :

  • Les traders peuvent empêcher les mineurs de « suspendre » leurs transactions pour des périodes de temps longues. En effet, ils pourraient être tentés de les inclure dans un bloc en fonction des mouvements du marché ;
  • Cela limite l’incertitude quant aux frais en gas pour les utilisateurs.

Réserves de liquidité personnalisées

Tandis que les réserves publiques enregistrées avec la Factory sont liées à leur DEX dédié, les utilisateurs d’Uniswap peuvent créer des pools personnalisés (custom pools). Ils possèdent leurs propres paramètres. Les mécanismes de formation des prix peuvent être différents, tout comme les frais ou le système de création des jetons de liquidité.

Bien entendu, dévier du modèle initial d’Uniswap peut engendrer des problèmes en termes de sécurité du protocole.

Les challenges des AMM du type Uniswap

Concevoir un AMM à fonction constante présente de nombreux défis à surmonter. Chaque design d’AMM décentralisé est un compromis entre les propriétés désirées pour le protocole et les limitations qui en découlent.

La première contrainte est évidemment de bâtir un système qui assure une sécurité maximale pour les fonds des fournisseurs de liquidité. Il faut ensuite maximiser les retours sur investissement des LP, pour les encourager à déposer dans les réserves. Enfin, l’allocation du capital doit être optimale, pour assurer la meilleure liquidité possible pour le marché.

Les pertes impermanentes

Les pertes impermanentes (impermanent losses) se produisent lorsqu’un fournisseur de liquidité retire ses fonds après que le ratio de réserve ait changé.

Quand un fournisseur de liquidité brûle ses jetons LP, afin de retirer ses parts d’ethers et d’ERC-20 des pools de liquidité, ces fonds sont retirés au taux d’échange courant, déterminé par le ratio de réserve :

  • ethWithdrawn = ehtPool * (amountBurned / totalAmount)
  • tokensWithdrawn = tokenPool * (amountBurned / totalAmount)

Un risque pour les fournisseurs de liquidité

Avec les fluctuations des prix du marché, les fournisseurs de liquidité peuvent perdre de la valeur si le ratio de réserve courant diffère du ratio initial (au moment de leur dépôt). C’est ce qu’on appelle une perte impermanente : la différence entre la valeur initiale des deux actifs déposés dans les réserves de l’AMM et leur valeur courante.

Il s’agit d’un des risques principaux pour les fournisseurs de liquidité : perdre de la valeur en prêtant et verrouillant leurs jetons plutôt que de les avoir simplement conservés à l’abri dans un wallet. Le risque de pertes impermanentes dépend du nombre de fournisseurs de liquidité contribuant à un pool, et de la quantité de jetons en présence.

Les pertes impermanentes subviennent quelle que soit la direction que prend le prix de la paire d’actifs. La seule chose qui importe, c’est la valeur absolue de la différence entre prix de dépôt et prix de retrait.

Le mécanisme des pertes impermanentes

L’impermanent loss est donc la différence entre la valeur des LP tokens lors du retrait, et la valeur théorique des actifs sous-jacents – s’ils n’avaient pas été verrouillés dans la réserve. Nous allons illustrer ce mécanisme avec un exemple.

Disons que Bob dépose 10 ETH, et la quantité d’ERC-20 correspondante dans un pool de liquidité. Au moment du dépôt, 1 ETH = 1000 $. Avec un ratio de 50/50, Bob doit donc déposer 10 ETH + 10000 $ dans la réserve.

Si le pool a une valeur totale de 100 000 $ (50 ETH et 50 000 $), alors Bob possède 20 % du pool – (20000/100000)*100.

Bob a donc contribué au pool en déposant sa part d’ethers et de stablecoins. Il peut retirer ses parts à tout instant en brûlant ses jetons LP. Nous parlons bien de parts, et non d’un nombre de jetons fixé !

Si la valeur des actifs déposés (l’ETH dans notre cas) change durant la période de lending, Bob souffrira de pertes impermanentes. Plus le prix courant de l’ether diverge du prix initial, plus la perte est importante.

On utilise le terme « impermanente » car si le prix des actifs revient à sa valeur initiale, le fournisseur de liquidité ne perd rien. Les frais de trading, donnés en récompense au fournisseur de liquidité, aident à compenser une perte impermanente potentielle.

Calcul des pertes impermanentes

Disons que depuis le dépôt des 10 ETH de Bob, le prix de l’ether soit passé de 1000 à 2000 $. La fonction à produit constant nous donne :

k = 50 * 50 000 = 2 500 000

Le prix de l’ether est le suivant :

ETHPrice = TokenLiquidity / ETHLiquidity = 50 000 / 50 = 1000

La liquidité pour chaque actif de la paire est calculée ainsi :

eth_liquidity_pool = sqrt(constant_product / eth_price)

token_liquidity_pool = sqrt(constant_product * eth_price)

Si le nouveau prix de l’ether est de 2000 $, alors :

ETHLiquidity = 35,355

USDTLiquidity = 70 710,6

Nous pouvons vérifier, en utilisant le produit constant, que k est bien le même :

ETHLiquidity * USDTLiquidity = 35,355 * 70 710,6 = 2 500 000

Si Bob souhaite retirer ses parts des réserves, il obtiendra donc 20% de la quantité d’ethers et d’USDT présents dans le pool :

  • 20% de 35 ETH soit 7 ETH ;
  • 20% de 70 710 USDT soit 14142 USDT.

Si nous calculons la valeur totale de ses actifs, nous obtenons :

7 * 2000 + 14 142 = 28 142 USDT

S’il n’avait pas effectué de dépôt, la valeur totale des actifs de Bob serait :

10 * 2000 + 10 000 = 30 000 USDT

Bob souffre donc d’une perte impermanente de 30000 – 28142 = 1858 USDT.

Modélisation

Il est possible de modéliser les pertes impermanentes comme une fonction du prix courant (en tant que pourcentage du prix initial) et de la variation de la valeur totale des actifs (en pourcentage également) :

Source : AlfaBlock

Nous pouvons observer que :

  • Un changement de prix de 1,25x donne une perte impermanente de 0,6%
  • 1,5x => 2%
  • 1,75x => 3,8 %
  • 2x => 5,7 %
  • 3x => 13,4 %
  • 4x => 20 %
  • 5x => 25,5 %.

Les frais accumulés durant la période de farming doivent donc compenser la perte impermanente résultant des fluctuations des prix. Ainsi, si le fournisseur de liquidité souhaite générer du profit, ces variations ne doivent pas être trop importantes.

Atténuation des pertes impermanentes

Il n’y a qu’un seul moyen d’éviter les pertes impermanentes, car les marchés crypto sont hautement volatils. Il s’agit de n’apporter de la liquidité que pour des paires de stablecoins !

De la même façon, le risque de perte impermanente sera réduit en fournissant de la liquidité pour les paires d’actifs incluant un stablecoin. Ainsi, plus les actifs de la paire sont sujets à la volatilité, plus le risque est élevé. Cependant, si le fournisseur de liquidité a une stratégie « stablecoin only« , il ne bénéficiera pas d’un marché haussier.

Les fournisseurs de liquidité qui souhaitent réduire leur risque de perte impermanente choisiront donc des cryptomonnaies et des jetons à faible volatilité – s’ils existent. Ils doivent également choisir consciencieusement le moment où ils retirent leurs fonds en brûlant leurs jetons de liquidité.

Sur les DEX à haut volume utilisant des AMM, et dans des conditions de marché normales, les frais compensent les pertes impermanentes. C’est ainsi que le farming reste profitable pour les fournisseurs de liquidité.

Efficience du capital

Il y a aussi un autre inconvénient des AMM à fonction constante comme Uniswap qui mérite d’être mentionné. Il s’agit de la relative inefficience du capital déposé dans les pools.

Ces réserves nécessitent une quantité de liquidités bien plus importante que les carnets d’ordres des plateformes centralisées traditionnelles. De ce fait, une grande quantité de cette liquidité n’est accessible que lorsqu’on se trouve sur la partie extrême de l’hyperbole de la fonction à produit constant. Et c’est aussi lorsqu’on tend vers un de ces asymptotes de la courbe que l’impact de la fonction est le plus fort sur les prix. La liquidité correspondante, bien qu’accessible, ne sera donc jamais utilisée par les traders rationnels.

Ce phénomène est typique des AMM à fonction constante comme Uniswap. On parle de « liquidité fainéante » (lazy liquidity). Sur les plateforme d’échange centralisées, les market makers peuvent déterminer exactement la quantité de liquidité qu’ils souhaitent placer dans les carnets d’ordres, à tel ou tel niveau de prix. Ce n’est pas le cas avec les CFMM : les fournisseurs de liquidité n’ont aucune influence sur les niveaux de prix.

Il est possible d’améliorer l’efficience du capital en utilisant d’autres fonctions pour définir les relations entre les pools de liquidité. Il existe également des mécanismes de concentration de la liquidité, que nous étudierons dans les articles suivants de cette série sur les AMM. C’est notamment le cas pour Curve et pour la V3 d’Uniswap.

Le slippage

Nous avons quantifié ci-dessus les impacts d’un trade sur le prix des jetons. Nous avons donc une idée de la façon dont les échanges à gros volume entraînent du slippage. C’est un inconvénient typique des AMM à fonction constante. Ces derniers entraînent d’importants coûts de slippage pour les traders qui drainent trop de liquidité en exécutant des ordres à gros volume.

Uniswap : un proof of concept pour les AMM de la DeFi

En conclusion, mentionnons le fait qu’Uniswap est né après une suggestion de Vitalik Buterin lui-même. En 2016, il incitait ainsi les développeurs et les chercheur à concevoir une plateforme d’échange décentralisée basée sur les AMM. À l’époque, les spreads étaient terriblement élevés sur les DEX on-chain. Vitalik suggéra alors de se tourner vers les automated market makers, similaires à ceux qui sont utilisés sur les marchés prédictifs.

Hayden Adams commença à travailler à ce projet, puis la première version fut déployée quelques mois après. Présentée comme une preuve de concept, Uniswap eut une croissance rapide, et attira de la liquidité depuis de nombreux utilisateurs à travers le monde. La vraie révolution, ce sont ses mécanismes d’incitation économique, qui attirent les fonds de la communauté Ethereum toute entière.

Grâce aux subventions de la Fondation Ethereum, le projet Uniswap put se développer. L’équipe de développement fut rapidement financée par Paradigm. Malgré les obstacles, l’équipe a continuellement amélioré son produit, et aujourd’hui, Uniswap est la plateforme d’échange décentralisée agrégeant le plus de valeur de toute l’industrie crypto.

Uniswap a également servi de fondation pour toute une génération d’AMM. Certains de ses smart contracts sont toujours repris par des plateformes plus modernes. Il s’agit donc d’un modèle d’AMM qui a passé avec succès l’épreuve du temps.

Bien entendu, l’univers de la DeFi est en perpétuel bouillonnement. De nombreux AMM ont adopté des fonctions de prix différentes selon leurs cas d’usage. Nous verrons dans les articles suivants qu’il est possible de redéfinir ces fonctions, pour échanger des cryptoactifs spécifiques, comme les stablecoins. De la même façon, les expérimentations d’Uniswap ont permis de développer et de proposer de nombreuses fonctionnalités et mécanismes d’incitation économique, afin d’améliorer les AMM dédiés à la finance décentralisée.

Bibliographie

Morgan Phuc

Cofounder @ 8Decimals & Partner @ Node Guardians - Making crypto great again - Journal du Coin / BitConseil