Curve et l’invariant StableSwap – Les AMM décodés
Curve est un échangeur décentralisé (DEX) bâti sur Ethereum, optimisé pour le trading de stablecoins. L’automated market maker (AMM) de Curve utilise sa propre fonction de valeur, appelée invariant StableSwap. Ce protocole offre ainsi une haute liquidité, un faible slippage, et des récompenses de frais accrues pour les fournisseurs de liquidité.
Le terme stablecoins réfère ici aux jetons fournissant une représentation stable d’un autre actif. Il peut s’agir ainsi de stablecoins algorithmiques représentant une monnaie fiat, comme le DAI, ou des versions « enrobées » (wrapped) du BTC, par exemple.
Les réserves de liquidité de Curve (liquidity pools), dans leur forme la plus simple, sont des smart contracts utilisant la logique de l’invariant StableSwap. Ils permettent d’échanger deux ou plusieurs stablecoins. Dans cet article, nous allons étudier le protocole Curve en profondeur. Il permet de créer des pools aux fonctionnalités variées (comme les Lending Pools ou les Metapools). Curve intègre aussi parfaitement d’autres protocoles DeFi comme Synthetix.
L’invariant StableSwap, le pilier central de Curve Finance
Vue d’ensemble
StableSwap est un faiseur de marché automatisé (AMM) pour les stablecoins, qui combine deux fonctions de valeur bien connues : les formules à somme constante et à produit constant. C’est un AMM particulièrement efficace en ce qui concerne les stablecoins, assurant un slippage minimal, et générant des intérêts stables pour les fournisseurs de liquidité.
StableSwap solutionne les challenges de la stabilité et de la liquidité des stablecoins dans l’univers de la finance décentralisée. Les stablecoins sont indispensables, qu’il s’agisse de jetons algorithmiques comme le DAI, ou encore de jetons collatéralisés par des réserves de dollars, comme l’USDT, l’USDC, le PAX ou le TUSD. Ils sont largement utilisés par les arbitrageurs, et les échanges de grandes quantités de stablecoins peuvent s’avérer risqués avec les AMM classiques.
De même, les fournisseurs de liquidité souhaitant générer des intérêts via leurs stablecoins de manière décentralisée recherchent les protocoles les plus sécurisés et rentables.
C’est à ces fins que Michael Egorov a conçu StableSwap, le pilier central de Curve.
Rappel : somme constante et produit constant
La fonction de valeur la plus simple pour un AMM est l’équation de la somme constante. Considérons deux jetons x et y. La fonction à somme constante assure qu’après un échange, la somme des réserves de chaque jeton reste constante. Elle peut être généralisée pour i jetons différents :
Le prix correspond à la dérivée (– dxi / dxj) – qui sera toujours égale à 1 dans ce cas.
Comme ce modèle ne fonctionne pas pour les marchés volatils (à moins d’ajuster constamment le prix, par exemple en utilisant des oracles), la fonction à produit constant permet de rééquilibrer les réserves de jetons. Le solde de chaque jeton en réserve reste constant :
Utilisé sur Balancer, le produit constant est efficace pour les échanges de jetons ERC-20. Cependant, il n’est pas optimal en ce qui concerne les stablecoins, à cause du glissement du prix (price slippage). Afin de maintenir un bon niveau de liquidité, il faut de grandes quantités de fonds.
Avec StableSwap, l’invariant se situe entre la somme constante et le produit constant. Le prix (la dérivée dx/dy) va s’écarter légèrement de 1 seulement lorsque la quantité de jetons est équilibrée.
Le coefficient d’amplification
L’invariant de StableSwap comprend un paramètre appelé coefficient d’amplification (A). Il détermine si l’invariant est proche du produit constant (A=0) ou de la somme constante (A tend vers l’infini).
Le modèle est très bon quant au slippage, en comparaison du produit constant, et peut fournir de la liquidité pour n’importe quel prix :
Lorsque le prix commence à dévier du point d’équilibre (1), l’invariant commence à opérer de façon suboptimale, mais fournit toujours de la liquidité. Si le coefficient d’amplification A est correctement paramétré, la liquidité sera plus importante qu’avec la fonction à produit constant.
Construction de l’invariant
Le prix déterminé par la fonction de valeur est équivalent à la pente de sa courbe – sa dérivée. Dans le cas de la somme constante, la courbe est une droite, tandis qu’avec le produit constant, elle forme une hyperbole. L’objectif de l’invariant StableSwap est d’être le plus proche possible d’une droite lorsque les quantités de jetons sont équilibrées. Si les réserves sont déséquilibrées, il va devenir hyperbolique.
Rappels
Les invariants (somme constante et produit constant) pour n jetons (i énumérations) sont notés comme suit :
Si le prix des jetons est le même, alors D représente le nombre total de jetons dans le pool.
Propriétés de l’invariant
Quelles sont les propriétés désirées pour l’invariant ?
- Faible glissement du prix (slippage) : faible courbure ;
- Le slippage ne doit pas être nul : cela correspondrait à la fonction à somme constante, avec un levier infini ;
- Puisque le produit constant équivaut à un levier nul, l’invariant doit se situer entre les deux.
Le levier (leverage) est noté χ. Alors :
- L’invariant de la somme constante est multiplié par χ ;
- Le résultat est ajouté à l’invariant du produit constant.
Construction
Nous obtenons donc un invariant qui est équivalent au produit constant lorsque χ = 0 et à la somme constante lorsque χ = ∞. Cependant, χ doit être sans dimension et indépendant du nombre de jetons en réserve. L’invariant de la somme constante est donc multiplié par χDn-1 et ajouté à celui du produit constant. Nous avons alors :
En supposant que l’équation est tout le temps vérifiée, le levier des échanges est χ.
Le levier χ doit être dynamique pour les cas où le prix dévie fortement de 1. Lorsque le pool est parfaitement équilibré, χ est la constante 1; lorsque le pool se déséquilibre, χ tend vers 0. Nous avons alors :
Nous obtenons donc l’invariant StableSwap par substitution :
Pour un pool de xi jetons, D est calculé de telle sorte que l’équation reste vérifiée pour n’importe quel trade (xi pour xj). L’AMM va alors trouver une solution convergente par itération, pour D, ou pour xj lorsque toutes les autres variables sont connues.
L’invariant StableSwap est au cœur de la version 1 de Curve. Il est conçu spécifiquement pour les swaps de stablecoin vers stablecoin, qui ont un prix fixé de 1.
Avec la version 2 de Curve, l’équipe de développement a conçu un nouveau modèle d’AMM pour les jetons qui ne sont pas directement ancrés l’un à l’autre – par exemple l’ETH et le DAI.
Curve : un AMM pour les actifs à ancrage dynamique
Ce modèle d’AMM est aussi le résultat des travaux de Michael Egorov. Il assure de la liquidité pour des jetons qui ne sont pas ancrés entre eux, de façon plus efficace que le produit constant. Son invariant se nomme… CurveInvariant.
La liquidité est concentrée en utilisant l’oracle de prix interne de l’AMM. Le prix ne dévie que lorsque les pertes engendrées par un swap sont inférieures au profit généré par le protocole. Cela permet d’assurer une meilleure liquidité, et de meilleurs rendements pour les fournisseurs.
Transformation des invariants pour l’ancrage
Tout d’abord, il faut changer l’espace des prix à l’aide d’une transformation T(). Tous les prix sont convertis dans une zone proche de 1.
- Soit b = (b0, b1, …) le vecteur des soldes des jetons au sein du smart contract, bi étant le ième jeton supporté par le pool ;
- Soit p = (p0, p1, …) l’ensemble des coefficients pour ces soldes.
Les soldes réels b et les soldes transformés b’ peuvent ainsi être convertis entre eux de la façon suivante :
b = T(b’, p) = (b0p0, b1p1, …)
b’ = T-1(b,p) = (b0/p0, b1/p1, …)
L’invariant est représenté par une hypersurface – une courbe dans le cas de seulement 2 jetons :
L’hypersurface est définie par : I(b’) = 0
Par convention, la fonction de l’invariant sera choisie de telle sorte que p0 = 1. De cette façon, si l’actif 0 est l’USD, tous les prix peuvent être mesurés par rapport à l’USD. L’invariant sera alors construit tel que :
∀ x, I (x, x, …) = 0
L’invariant de StableSwap présente déjà cette propriété, ainsi que le nouvel invariant construit – CurveInvariant. Les dépôts (le solde des jetons dans les pools) vont déterminer l’hypersurface (ou courbe) de l’invariant.
L’invariant D doit donc être constant pour la même courbe de telle façon qu’il soit égal à la quantité totale de jetons dans le pool lorsqu’il est à l’équilibre :
- xeq = (xeq, xeq, …)
- I(xeq, D) = 0
- D = Nxeq
N est le nombre de jetons. Le point d’équilibre xeq – le vecteur vers lequel p s’ancre – est désormais facile à obtenir, puisque D paramétrise l’hypersurface.
Perte de réancrage (repegging loss)
Afin de minimiser les pertes pour le système, il faut mesurer de façon précise les profits et les pertes. La valeur de l’invariant du produit constant au point d’équilibre donne une bonne mesure du PnL. Comme avec la transformation ci-dessus, par commodité, le PnL pour chaque solde sera converti à la puissance de 1. Nous obtenons ainsi la fonction de valeur du portfolio :
Nous pouvons observer que lorsque le coefficient p change, l’ancrage change aussi, mais pas les soldes.
Le nouveau D est alors calculé pour les nouvelles valeurs b’. Ces D et pi sont substitués pour trouver xcp.
Le protocole permet de réduire xcp, mais seulement lorsque la perte de valeur de xcp n’excède pas la moitié du profit réalisé.
L’invariant CurveCrypto
Enfin, l’invariant CurveCrypto pour les ancrages dynamiques est défini comme suit. Tout d’abord, commençons par l’invariant StableSwap :
K sera défini différemment que lors de la construction de l’invariant StableSwap :
Où :
- A est le coefficient d’amplification ;
- γ est un petit nombre positif, qui représente la distance entre les deux lignes en pointillés sur le graphe ci-dessus.
Ce nouvel invariant fonctionne comme une superposition de l’invariant StableSwap et de l’invariant du produit constant.
Résolution de l’invariant CurveCrypto
Pour résoudre l’invariant pour un xi ou un D particulier, on le définit sous une forme F(x, D) = 0 :
Le protocole d’échange commence par résoudre l’équation pour D. Puis il la résout pour xj connaissant xi – prenant ainsi en compte la quantité de jetons i échangés. L’algorithme utilise la méthode de Newton :
- Tout d’abord, calcul de D par itération :
- Ensuite, déterminer :
L’algorithme est optimisé pour l’Ethereum Virtual Machine (EVM). Ainsi, résoudre l’équation ne coûte que 35k gas. Les valeurs de départ sont très importantes, puisque la fonction n’est pas monotone. Après avoir effectué des simulations, l’équipe de Curve a décidé de les fixer comme suit :
En utilisant différents cadres hypothétiques, les développeurs ont trouvé de bonnes valeurs pour la convergence de xi et de D.
Algorithme de réancrange (repegging algorithm)
Afin de calculer le PnL pour xcp nous devons suivre la croissance de xcp. Il est monitoré à chaque échange et lors de chaque dépôt dans le pool. Après chaque opération, la variable xcpprofit est multipliée par (xcp,après / xcp,avant) en partant de 1.
Il y a également la variable xcpprofitréel qui garde la trace des pertes après p ajustements. Si l’ajustement p cause :
L’oracle interne de prix est basé sur une moyenne mobile exponentielle appliquée dans un espace de dimension N (le nombre de jetons différents). Soient :
- plast le dernier prix rapporté ;
- t le temps écoulé (en secondes) depuis la dernière mise à jour ;
- T1/2 la demi-période de la moyenne mobile exponentielle.
Alors le prix de l’oracle est donné par :
p* = plast (1 – α) + αp*prev
Où α = 2-t/T1/2
Le vecteur de prix est ensuite ajusté pour p* dans un espace logarithmique. Ce modèle est approximé afin de faciliter les calculs :
Où s est la variation relative du prix.
Frais dynamiques
Les frais f vont de fmid à fout et sont déterminés comme suit :
Où :
Les frais s’étalent de 0,04 % à 0,4 % selon la proximité du prix effectif avec celui de l’oracle interne.
Les pools de liquidité sur Curve
Vue d’ensemble
Tous les pools de liquidité de Curve implémentent les invariants StableSwap ou CurveCrypto. Ils permettent aux utilisateurs de déposer et d’échanger deux jetons ou plus. Nous pouvons distinguer trois catégories de pools. Chacun d’entre eux présente différents niveaux de risque pour les fournisseurs de liquidité.
Quel que soit le type de pool choisi, le fournisseur de liquidité est exposé à tous les actifs qui le composent, qu’il dépose un seul des actifs, ou plusieurs.
Le vAPY représente le taux annuel de frais de trading récoltés par les fournisseurs de liquidité du pool. Ces frais augmentent avec le volume d’échange. Les jetons CRV sont créées (minted) pour les fournisseurs de liquidité, afin de garder la trace de leurs parts du pool. Ils reçoivent alors leurs intérêts via le mécanisme de retrait.
Les Plains Pools
Il s’agit de la forme la plus simple des pools StableSwap. Ils présentent au moins deux jetons, et tous les dépôts restent verrouillés au sein du smart contract en permanence. Ils ne peuvent pas être utilisés par d’autres pools, ou par d’autres protocoles DeFi. Ces pools sont idéaux pour les échanges de stablecoins, par exemple le 3Pool : USDT/USDC/DAI.
Le code source des Plain Pools (écrit en Vyper) est disponible ici : https://github.com/curvefi/curve-contract/blob/master/contracts/pool-templates/base/SwapTemplateBase.vy
Les Plain Pools présentent le niveau de risque le plus bas, puisque les liquidités restent au sein du smart contract. Les fournisseurs de liquidité ne supportent que le risque systémique liés à chacun des stablecoins.
Les Lending Pools
Il s’agit d’un type de pool plus avancé, présentant aussi plus de risque. En plus des intérêts générés via les frais de trading, les fournisseurs de liquidité vont générer des intérêts supplémentaires en prêtant (lend) leurs liquidités. Le lending est effectué grâce à des protocoles tiers, comme Compound, Yearn Finance, DyDx ou encore Aave.
Il y a différentes implémentations de Lending Pools, qui dépendent des mécanismes d’enrobage (wrapping) des jetons. Les types principaux sont les cTokens et les aTokens, basés sur les protocoles Compound et Aave.
Le risque est supérieur à cause des failles potentielles qui pourraient être présentes chez les protocoles tiers.
Les Metapools
Les Metapools permettent à leurs utilisateurs d’échanger un jeton contre un autre en utilisant un pool sous-jacent. Par exemple, il est possible d’échanger du BUSD (Binance USD) contre les jetons du 3Pool (USDT/USDC/DAI). C’est très utile, car cela évite la dilution des pools de base existants. De plus, cela permet de créer des pools contenant des actifs à faible liquidité.
Le système des Metapools n’expose pas automatiquement les fournisseurs de liquidité à tous les jetons du Metapool. En effet, les Metapools permettent d’échanger le jeton sous-jacent contre les jetons de liquidité (LP tokens) du pool de base.
Par exemple, un fournisseur de liquidité peut déposer des USDC dans le 3Pool. En échange, il recevra le jeton de liquidité du pool – le 3CRV. Ces jetons 3CRV peuvent alors être déposés dans le Metapool BUSD (BUSD et 3CRV). En retour, le fournisseur de liquidité recevra ainsi le jeton de liquidité du Metapool, busd3CRV. Ce jeton de liquidité peut ensuite être « staké » afin de recevoir des récompenses en CRV (plus de détails dans le chapitre consacré aux jauges de liquidité).
Administration des pools sur Curve
Seul le propriétaire d’un pool en possède les droits d’administration. Certains méthodes d’administration requièrent un processus de transaction en deux phases. Après une première transaction effectuant des mises à jour, un délai minimum peut être défini avant qu’une deuxième transaction ne confirme les changements. Les attributs des pools sont :
- Propriété ;
- Coefficient d’amplification ;
- Frais de trading (incluant les frais d’adminsitration).
Il est possible de mettre un pool en pause, mais seulement durant les 30 premiers jours suivant son déploiement. Ensuite, les fournisseurs de liquidité peuvent seulement retirer leurs fonds.
Les jetons de liquidité de Curve (LP tokens)
Les jetons de liquidité de Curve sont des ERC-20 dont les smart contracts ont évolué au cours du temps. Il y eut 3 mises à jour majeures du protocole (V1, V2, V3). Les codes sources en Vyper de chacune des versions des jetons LP sont disponibles ici :
- CurveTokenV1 : https://github.com/curvefi/curve-contract/blob/master/contracts/tokens/CurveTokenV1.vy
- CurveTokenV2 : https://github.com/curvefi/curve-contract/blob/master/contracts/tokens/CurveTokenV2.vy
- CurveTokenV3 : https://github.com/curvefi/curve-contract/blob/master/contracts/tokens/CurveTokenV3.vy
Les jetons de liquidité sont transférables et peuvent être déposés dans les Metapools, comme nous l’avons vu plus haut. Les fournisseurs de liquidité reçoivent également dans ce cas le jeton de liquidité dédié du Metapool.
Les contrats de dépôt sur Curve
Les contrats de dépôt d’un pool Curve sont appelés Deposit Zaps, et diffèrent suivant le type de pool. Par exemple, les Lending Pools peuvent n’intégrer que des jetons enrobés (wrapped coins), et les Metapools n’intègrent pas les jetons des pools de base.
Dépôt dans les Lending Pools
Les Lending Pools peuvent autoriser les échanges de jetons « enrobés » (wrapped tokens) et leur sous-jacent. Cependant, à cause de la taille limitée des smart contracts sur Ethereum, les dépôts et les retraits des jetons sous-jacents pour un Lending Pool sont gérés séparément de leur version « wrappée » – via le Deposit Zap. Les contrats de dépôt pour les Lending Pools peuvent être complexes, et proches de la taille limite d’Ethereum. La séparation des contrats permet de passer outre cette restriction.
Dépôts dans les Metapools
Les Metapools de Curve gèrent les échanges entre les jetons de pools de base, les jetons de liquidité associés (base pool LP tokens), et les jetons des Metapools. Il ne permettent cependant pas aux fournisseurs de liquidité de déposer et/ou de retirer des jetons disponibles dans les pools de base. Tout comme les Lending Pools, c’est dû à la taille maximale des msart contracts d’Ethereum.
Le smart contract des Metapools zaps est disponible ici : https://curve.readthedocs.io/ref-addresses.html#addresses-metapools
Les échanges d’actifs de classe différente (Cross Asset Swaps)
Description
Curve permet d’effectuer des Cross Asset Swaps très efficaces, grâce à l’intégration de Synthetix. Ce protocole permet de réaliser des conversions d’actifs synthétiques sans slippage. En le couplant avec le système de liquidité et les frais de Curve, les utilisateurs peuvent réaliser des cross-assets swaps pour de gros volumes, des frais de 0,4 %, et un glissement de prix minime.
Le contrat dédié s’appelle SynthSwap :
https://etherscan.io/address/0x58A3c68e2D3aAf316239c003779F71aCb870Ee47#code
Mécanismes
Supposons que nous possédons l’actif A, et que nous souhaitons l’échanger contre l’actif D. A et D doivent être de deux classes d’actifs différentes (par exemple, l’USD et l’ETH). Un pool Curve doit aussi autoriser l’échange entre A et D, avec un actif synthétique – dans notre cas sUSD et sETH.
- L’actif A est échangé dans le pool Curve pour B, un actif synthétique de même classe ;
- B est converti en C, un actif synthétique de la même classe que D ;
- Puisqu’il peut y avoir des fluctuations de prix entre B et C, on établit une période de règlement. C’est fait via Synthetix et le SIP-37 – https://docs.synthetix.io/integrations/settlement/ ;
- C est échangé sur Curve pour D à la fin de période de règlement.
Durant la période de règlement, un jeton non-fongible (ERC-721) est créé par le contrat SynthSwap. Il représente ainsi un IOU – une reconnaisse de dette – pour le swap. Ce NFT est transférable, et sera brûlé lors du règlement. Il présente un identifiant unique, non-séquentiel, qui ne sera jamais réutilisé.
Utilité
Les Cross Asset Swaps sont efficaces pour de gros volumes (supérieurs à 1 million de dollars). Il y a des risque de front–running, à cause de la période de règlement. En effet, les participants au marché peuvent voir qu’un swap post-règlement va se produire, une fois que le premier trade est initié. Pour pallier le problème, D est donc gardé hors-chaîne durant la transaction de A vers C. Il y a alors plusieurs actions possibles qui rendent la prédiction du résultat du trade très difficile, et empêchent de trader contre :
- Swap partiel de C vers D, puis conversion de C en de multiples actifs ;
- Les utilisateurs peuvent effectuer le second swap n’importe quand ;
- Pas de deuxième échange : l’utilisateur récupère C.
Le NFT associé ne sera pas brûlé tant que C n’est pas complètement échangé, ou que le second swap est annulé. Si besoin est, les utilisateurs peuvent ajouter des swaps A -> B -> C, et le solde du NFT correspondant sera mis à jour.
Le code source et la documentation concernant les Cross Asset Swaps se trouve ici : https://github.com/curvefi/curve-cross-asset-swaps
La DAO de Curve
Curve possède sa propre organisation autonome décentralisée.
Vue d’ensemble de Curve DAO
Curve est constitué d’un ensemble de smart contracts, connectés grâce à Aragon. Le système de vote d’Aragon a été modifié, afin de pondérer les votes des utilisateurs en fonction de la quantité de jetons de gouvernance (CRV) qu’ils verrouillent.
Le code source de l’application de vote d’Aragon est ici :
https://github.com/aragon/aragon-apps/tree/master/apps/voting
L’implémentation de Curve est là :
https://github.com/curvefi/curve-aragon-voting
Enfin, les contrats de la DAO de Curve sont ici :
https://github.com/curvefi/curve-dao-contracts
Les utilisateurs de Curve doivent donc verrouiller leurs CRV afin de pouvoir voter. La mise sous séquestre des jetons leur donne également droit à un boost quant à la liquidité qu’ils fournissent.
Les veCRV (vote-escroweed CRV)
Lorsque les CRV sont verrouillés, Curve distribue des jetons veCRV à leurs propriétaires. La quantité de veCRV croît avec la durée de mise sous séquestre. Ils confèrent un boost de liquidité de 2,5x. Cela fonctionne comme un mécanisme incitatif, afin d’encourager les utilisateurs de Curve à participer à la gouvernance du protocole.
Les veCRV sont des jetons ERC-20 (non-standards) gérés par le contrat VotingEscrow :
https://etherscan.io/address/0x5f3b5dfeb7b28cdbd7faba78963ee202a494e2a2
Ils présentent les caractéristiques suivantes :
- Les veCRV ne peuvent pas être transférés ;
- Verrouiller des CRV est la seule façon d’en obtenir ;
- La durée de mise sous séquestre maximale est de 4 ans ;
- 1 CRV verrouillé pour la période maximale donne droit à un solde de 1 veCRV ;
- Le solde des veCRV décroît de façon linéaire en fonction de la période de déverrouillage restante des CRV correspondants.
Les jauges de liquidité et le Minter de CRV
Les jauges de liquidité (Liquidity Gauges) mesurent la liquidité fournie par les utilisateurs (en dollars). Chaque pool dispose de sa propre jauge. Ces jauges déterminent quelle quantité de CRV sera donnée au fournisseur de liquidité, à travers l’inflation. Elles présentent différentes pondérations. Ce sont les votes de la DAO qui déterminent le poids relatif des jetons au sein d’une jauge.
Les poids des jauges peuvent être trouvés ici :
https://dao.curve.fi/minter/gauges
Trois smart contracts déterminent l’allocation des CRV, leur distribution et leur minting :
- LiquidityGauge : mesure la liquidité fournie au cours du temps ;
- GaugeController : ce contrat central maintient l’index des jauges, les poids, et détermine le taux de minting de CRV pour chaque jauge ;
- Minter : crée les CRV en fonction des jauges.
L’inflation des CRV est réduite par 21/4 chaque année, avec :
- Un taux initial de 22% ;
- Une provision initiale de 1,273 milliards de CRV ;
- Un maximum asymptotique tendant vers 3,03 milliards de CRV.
La courbe d’inflation des CRV ressemble à ceci :
Types de jauges
Les jauges de liquidité sont regroupées par types au sein du contrôleur. Il est possible d’ajuster l’émission de CRV pour toutes les jauges d’un même type. Les types actuels sont :
- Ethereum (stableswap pools) ;
- Fantom ;
- Polygon (Matic) ;
- xDAI ;
- Ethereum (crypto pools) ;
- Arbitrum ;
- Avalanche ;
- Harmony.
Récompenses de jauges
Elles sont gérées par le contrat LiquidityGaugeReward. On l’utilise pour staker les jetons de liquidité dans un contrat de récompenses de staking Synthetix. Il assure ainsi la distribution des jetons en récompense. Le contrat SNX correspondant est ici :
https://github.com/Synthetixio/synthetix/blob/master/contracts/StakingRewards.sol
Les jauges de liquidité V2 et V3
La version 2 de la jauge de liquidité de Curve comprend une interface ERC-20 complète : ainsi, les dépôts sont « tokénisés » et peuvent être directement transférés entre comptes, sans avoir à retirer et redéposer les fonds. Cela permet aussi d’activer ou de désactiver le staking à n’importe quel moment, et ce pour 8 jetons différents.
La V3 des jauges de liquidité est la version actuelle déployée sur le mainnet d’Ethereum. Elle comprend de nombreuses fonctionnalités très pratiques, par exemple des coûts en gas réduits, ou encore la possibilité de rediriger les récompenses vers un compte alternatif.
Le contrôleur de jauge
Le smart contract GaugeController est déployé à l’adresse suivante :
https://etherscan.io/address/0x2F50D538606Fa9EDD2B11E2446BEb18C9D5846bB
Le Minter
Le Minter de CRV est déployé ici :
https://etherscan.io/address/0xd061D61a4d941c39E5453435B6345Dc261C2fcE0
Son code source se trouve là :
https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/Minter.vy
Les jauges de Curve pour les sidechains d’Ethereum
Curve est également disponible sur plusieurs sidechains d’Ethereum. Les CRV sont aussi créés pour les fournisseurs de liquidité qui utilisent ces sidechains et les pools correspondants. Le smart contrat peut être trouvé ici :
https://github.com/curvefi/curve-dao-contracts/tree/master/contracts/gauges/sidechain
À haut niveau, l’implémentation de Curve sur une sidechain n’est pas chose aisée, car les contrats sont complexes. La DAO de Curve ne peut ainsi pas être directement implémentée sur les sidechains d’Ethereum. Cependant, certaines de ses fonctionnalités – comme l’émission des CRV – sont intégrées sur les sidechains où des pools sont actifs.
Le processus de distribution des CRV sur une sidechain fonctionne ainsi :
- Tout d’abord, le contrat RootChainGauge crée (mint) les CRV chaque semaine sur Ethereum et les transfère via un bridge sur la sidechain ;
- Ensuite, le contrat ChildChainStreamer reçoit les CRV et les transfère vers le contrat RewardsOnlyGauge ;
- Enfin, les fournisseurs de liquidité qui ont reçu leurs CRV sur le contrat RewardsOnlyGauge peuvent les réclamer à tout instant.
On peut recevoir de multiples jetons en récompense sur une sidechain. Par exemple, le pool am3CRV sur Polygon donne droit à la fois à des CRV et à des WMATIC.
Les frais sur Curve
Les fournisseurs de liquidité peuvent réclamer leur part des frais collectés n’importe quand. Cependant, ils ne seront convertis en 3CRV qu’une fois par semaine. Les frais de trading sont toujours collectés dans le jeton de sortie lors d’un échange. Lors d’un dépôt ou d’un retrait, les fournisseurs de liquidité paient également des frais – de telle sorte qu’un swap requiert la même quantité de frais qu’un dépôt du jeton jeton d’entrée et qu’un retrait du jeton de sortie dans le pool.
Les frais sont gérés par un contrat nommé Proxy Ownership. C’est ce contrat qui permet aux utilisateurs de retirer leur part de frais, les convertit en 3CRV, puis les envoie vers le Fee Distributor Contract.
- Les frais sont ainsi collectés sous forme de plusieurs jetons différents ;
- Puis ils sont échangés en USD ;
- Enfin, il sont déposés dans le 3Pool pour obtenir des 3CRV en retour.
Ce processus est appelé le « burn process« . Il est coûteux en gas, étant donné qu’il implique de nombreuses transactions complexes.
Frais d’administration
Chaque propriétaire de pool peut définir des frais d’administration pour son pool. Ils sont définis dans le contrat correspondant, et sont donc publics. Ils sont visibles en utilisant la commande admin_balances
.
Processus de burn
Le burn process est spécifique à chaque jeton. En appelant la fonction PoolProx.burn
, les jetons sont tout d’abord transférés dans le contrat Burner, avant d’appeler la fonction burn
.
Cette fonction convertit les jetons directement en 3CRV – ou prend le plus court chemin possible. En effet, cela peut demander plusieurs « sauts » avant de convertir les frais en 3CRV.
Au total, il y a 9 contrats Burner différents, qui traitent différentes catégories de jetons. La séquence de la conversion est donc très importante, car il est nécessaire d’éviter de brûler le même jeton deux fois, pour des raisons de coûts et d’efficience.
Distribution des frais
Les frais sont distribués aux détenteurs de jetons veCRV via le contrat suivant (FeeDistributor) : https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/FeeDistributor.vy
Les récompenses sont calculées en se basant sur le ratio entre le solde en veCRV des utilisateurs et la provision totale de veCRV au début de chaque semaine, puis elles sont distribuées à la fin de la semaine.
Les soldes en 3CRV sont tracés au sein du contrat FeeDistributor – token checkpoint – afin de déterminer la quantité de frais à distribuer.
La propriété du protocole Curve
Les fonctionnalités d’administration sont contrôlées par les détenteurs de veCRV – les CRV mis sous séquestre, via la DAO de Curve. L’appel aux fonctions d’administration n’est alors possible qu’après une proposition de gouvernance fructueuse.
Plusieurs contrats assurent la propriété du protocole – protocol ownership :
- Le contrat de la DAO de Curve ;
- L’agent Aragon ;
- L’Ownership Proxy : il se décompose en deux contrats principaux, le PoolProxy, qui administre les contrats d’échange, et le GaugeProxy, qui concerne les jauges de liquidité ;
- Les contrats de Curve.
Il est donc possible de changer la propriété des proxies avec un vote de la DAO.
Les agents de la DAO de Curve
La DAO de Curve s’appuie sur Aragon pour assurer la gouvernance décentralisée du protocole. Les trois adresses propriétaires de l’Aragon Agent sont gouvernées par deux DAO indépendantes : la Community DAO et l’Emergency DAO.
La DAO de la Communauté dispose de la propriété de deux comptes administrateurs :
- Ownership Admin : il contrôle la plupart des fonctionnalités, et requiert un quorum de 30 % de la DAO et 51% de votes positifs de la communauté pour pouvoir effectuer n’importe quelle action.
- parameter Admin : il contrôle les paramètres des pools, et requiert un quorum de 30 % ainsi que 51 % de votes positifs pour pouvoir effectuer une action.
La DAO d’urgence – Emergency DAO – a le pouvoir de détruire les pools et les jauges de liquidité, en cas de circonstances extraordinaires. Les 9 membres de cette DAO sont des membres de confiance de l’équipe de Curve, et de la communauté DeFi dans son ensemble.
Le Pool Proxy
Le contrat PoolProxy est utilisé pour la propriété (indirecte) des contrats d’échange, et son code source se trouve ici : https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/PoolProxy.vy
Le Gauge Proxy
Le contrat GaugeProxy est utilisé pour la propriété indirecte des jauges de liquidité; son code source se trouve là : https://github.com/curvefi/curve-dao-contracts/blob/master/contracts/GaugeProxy.vy
Le registre de Curve
Le registre de Curve est composé de contrats, qui peuvent être trouvés ici : https://github.com/curvefi/curve-pool-registry
Le contrat AddressProvider est immuable et on l’utilise pour l’intégration on-chain des adresses actuelles des autres composants du registre. Il est déployé à la même adresse sur Ethereum et sur toutes les sidechains/layer 2 où Curve est actif. Il s’agit donc du point d’entrée pour les intégrateurs on-chain : tous les autres contrats au sein du registre ont un identifiant au sein du fournisseur d’adresse.
Le contrat principal est Registry : il est utilisé pour localiser les pools, envoyer des requêtes et référencer les jetons supportés.
PoolInfo est un contrat conçu pour une utilisation off-chain : il permet ainsi de requêter de grands ensembles de données à propos d’un pool.
Enfin, le contrat Swaps est le contrat d’échange, utiliser pour trouver les pools pertinents et obtenir les taux d’échange lors d’un swap.
Curve et la Metapool Factory
La Metapool Factory permet à n’importe quel utilisateur de Curve de déployer un Metapool. Les codes source des contrats de la Factory sont accessibles ici :
https://github.com/curvefi/curve-factory
La Metapool Factory présente 3 composants principaux : le contrat principal (Factory), un contrat proxy pour déployer les Metapools (de la même façon qu’avec Uniswap V1), et les contrats de dépôt – les Zaps, qui « enrobent » les actifs déposés ou retirés d’un pool.
Le Deployer
La contrat de la Factory est déployé à cette adresse : https://etherscan.io/address/0xB9fC157394Af804a3578134A6585C0dc9cc990d4
Son code source est accessible ici : https://github.com/curvefi/curve-factory/blob/master/contracts/Factory.vy
Les utilisateurs doivent être précautionneux lors d’un déploiement d’un pool, car le contrat de la Factory présente des limitations. Ainsi, utiliser des jetons incompatibles peut entraîner la perte des fonds. De plus, les pools déployés via la Factory ne peuvent pas être mis en pause ou détruits, et ne sont pas éligibles aux récompenses en CRV.
Les Pools
En utilisant la Factory pour déployer un nouveau pool, le contrat proxy cible un contrat d’implémentation, basé sur le contrat BasePool. Ces contrats d’implémentations se trouvent sur le dépôt suivant :
https://github.com/iamdefinitelyahuman/curve-factory/blob/master/contracts
Ils sont déployés aux adresses suivantes :
- 3Pool : https://etherscan.io/address/0x5F890841f657d90E081bAbdB532A05996Af79Fe6
- sBTC : https://etherscan.io/address/0x2f956eee002b0debd468cf2e0490d1aec65e027f
Les oracles
Les Metapools comprennent des oracles de prix : ce sont des Time-Weighted Average Price oracles (TWAP), tout comme sur Uniswap.
Les contrats de dépôt
Les contrats de dépôt de la Metapool Factory permettent aux utilisateurs d’ajouter et de retirer de la liquidité en utilisant le jeton sous-jacent du pool. Ce sont donc des Zaps spécifiques : un seul contrat est utilisé pour tous les Metapools ciblant un des Base pools.
Le migrateur de liquidité
Ce contrat (LiquidityMigrator) sert à transférer la liquidité d’un Metapool à un autre, il est déployé ici :
https://etherscan.io/address/0xd6930b7f661257DA36F93160149b031735237594
Son code source est accessible sur le dépôt suivant :
https://github.com/curvefi/curve-factory/blob/master/contracts/PoolMigrator.vy
Curve, en conclusion
Nous avons désormais couvert de façon extensive les mécanismes du protocole Curve. Curve.Finance est l’une des principales plateformes DeFi pour échanger des stablecoins sur Ethereum et ses solutions de couche secondaire. Elle et présente une haute liquidité, ainsi qu’un faible slippage. En termes de valeur totale verrouillée (total value locked ou TVL), nous parlons de plus de 5 milliards de dollars déposés dans ses pools.
Curve est donc spécifiquement conçue pour le trading de stablecoins, et combine deux fonctions de prix pour fournir un revenu peu risqué pour les fournisseurs de liquidité.
En alimentant les pools de liquidité avec des protocoles externes, les fournisseurs de liquidité peuvent alors obtenir des revenus supplémentaires. Il s’agit de la plateforme d’échange décentralisée (DEX) de stablecoins la plus avancée : un must–known pour chaque utilisateur d’Ethereum qui souhaite comprendre l’automated market making dans l’univers de la finance décentralisée.
Ressources
- Le livre blanc de Curve
- La documentation générale
- La documentation technique