On reconstruit un Uniswap v2, un prêt à la Aave et un oracle de prix : le Solidity est lisible, l'outillage et la sécurité ont vieilli.
Pourquoi ce livre
Une bourse classique tient un carnet d'ordres, la liste des offres d'achat et de vente à apparier. La DeFi, ou finance décentralisée, sait s'en passer. Des programmes posés sur une blockchain assurent les services financiers : le programme est la place de marché. Comment tient-elle debout, sans personne au guichet ? Samuel Zhou la reconstruit pour répondre. Le fil, tel que je le lis : chaque service financier se ramène à une formule, qu'on écrit dans un contrat puis qu'on teste.
Du livre, je garde sept idées en trois questions. Comment un programme fixe-t-il un prix sans personne en face (idées 1 et 2) ? Comment prête-t-il, à quel taux, et qui intervient quand la garantie ne suffit plus (idées 3 à 5) ? Et pourquoi tout s'écroule-t-il quand le prix qu'il lit est faux (idées 6 et 7) ?
Côté plateforme centralisée, je connais le décor : mandats de gestion sous agrément AMF, garde des actifs chez Fireblocks, connecteurs vers cinq exchanges. J'y pratique aussi l'Event Sourcing : chaque changement est stocké comme un événement qu'on ne réécrit jamais. L'autre côté m'échappe, celui où le programme est la place de marché.
Ces programmes s'appellent des smart contracts : une fois déployés sur la blockchain, personne ne peut plus les modifier. Le livre les écrit en Solidity, le langage des contrats d'Ethereum, puis les branche sur un front React. Ils gèrent des jetons (tokens), des actifs numériques dont un contrat tient le solde de chacun. Chaque opération consomme du gas, la commission payée au réseau.
Avant de construire, le cours commence par une vraie introduction (leçons 3 à 8). La DeFi y reçoit six traits : décentralisée, transparente, ouverte, sans dépositaire, anonyme, sans interruption. Une réserve suit aussitôt : « un projet DeFi peut être centralisé si son smart contract ne renonce pas à l'ownership ». Autrement dit, si un administrateur garde des pouvoirs spéciaux sur le contrat, la décentralisation n'est qu'une façade.
L'introduction définit aussi deux chiffres qu'affiche chaque protocole. La TVL (total value locked) est la valeur totale déposée dans ses contrats. L'APY (annual percentage yield) est le rendement sur un an, intérêts composés compris. L'exemple du livre dégonfle les promesses : une offre à 100 % d'APY sur un dépôt de 7 jours rapporte 1,34 % pour ces 7 jours. D'où sa mise en garde : « un APY élevé est parfois une stratégie marketing ».
L'introduction finit sur quatre failles de contrat, avec leur parade :
- la réentrance : un contrat rappelé avant d'avoir fini, qui se fait vider en boucle. Parade : le verrou ReentrancyGuard.
- selfdestruct : de l'ETH envoyé de force par un contrat qui s'autodétruit, de quoi fausser un solde. Parade : tenir le solde dans une variable du contrat.
- le dépassement de gas : une boucle qui grandit jusqu'à bloquer la fonction. Parade : optimiser le code.
- le hasard truqué : un tirage calculé sur l'heure du bloc, que le producteur du bloc peut choisir. Parade : un oracle de hasard, Chainlink VRF.
Les idées qui restent
1Pas de vendeur en face, une formule
Premier service à reconstruire, l'échange, et premier problème : sans serveur, qui tient le carnet d'ordres ? Pour le livre, un carnet tenu entièrement sur la chaîne est « un défi, à implémenter comme à utiliser » (leçon 24). Il construit donc autre chose. Imaginez un bureau de change sans guichetier, avec deux tiroirs et une règle de prix. Les deux tiroirs forment un pool : l'un d'ETH (l'ether, la monnaie d'Ethereum), l'autre d'USDT (un jeton qui vaut un dollar).
Le tout s'appelle un AMM (Automated Market Maker, teneur de marché automatique). Il vit dans un DEX, un exchange décentralisé. Le livre : « un pool de liquidité d'un DEX est un smart contract qui détient deux types de jetons ou plus » (leçon 23).
La règle de Uniswap v2, l'un des DEX les plus connus, est le produit constant : réserve A fois réserve B égale une constante K, que les échanges ne modifient pas. Mon exemple, sans frais :
Pool : 5 ETH et 10 000 USDT, donc K = 50 000, prix = 10 000 / 5 = 2 000 USDT.
J'achète 1 ETH : il reste 4 ETH, donc l'USDT doit monter à 50 000 / 4 = 12 500.
Je paie 2 500 USDT pour 1 ETH, le prix du pool devient 12 500 / 4 = 3 125.
C'est l'impact de prix : avec des réserves égales, acheter 90 % d'un jeton multiplie son prix par 100 (leçon 25). Le slippage (le prix bouge entre votre clic et la validation) n'est jamais nommé, mais son garde-fou existe : un minimum à recevoir, sous lequel l'échange est annulé, fixé par le front à 90 % de l'affichage (leçon 57). Le maximum à payer suit la même règle, à 110 %.
Le livre pose ce principe pour les échanges, dès le contrat : l'utilisateur fixe « le montant minimum qu'il veut recevoir, ou le montant maximum qu'il accepte de payer » (leçon 40). Ses propres pages de liquidité ne l'appliquent pas. Pour ajouter ou retirer de la liquidité, elles envoient 0 et 0 comme minimums (leçons 49 et 50) : l'opération passe, quel que soit le prix du moment.
Un parallèle de mon cru, pas du livre : un pool ressemble à une table SQL d'une seule ligne, avec deux colonnes de réserves. Chaque UPDATE doit respecter une règle : réserve d'ETH × réserve d'USDT = K. Le prix n'est stocké nulle part. Il se recalcule à chaque lecture. Si vous testez un tel pool, vérifiez cette règle après chaque échange, et non un prix écrit d'avance.
2Votre part du pool tient dans un jeton
Une formule ne suffit pas : il faut des contrats pour la porter, et des gens pour remplir les tiroirs. Le router est le guichet, la factory fabrique les caisses, chaque paire est une caisse. La paire tient les réserves et émet le LP token, qui prouve qu'on possède une part du pool (leçon 29). Ce jeton suit l'ERC-20, le standard commun des jetons : transfert, solde, approbation.
Quatre appels : créer une paire, échanger, ajouter de la liquidité (mint) ou en retirer (burn). Exemple : 100 BTC et 1 600 ETH dans un pool qui a émis 400 LP tokens. Qui en détient 40 possède 10 % et récupère 10 BTC et 160 ETH (leçon 23).
Cette part a un coût caché, la perte impermanente : rester dans le pool peut rapporter moins que garder ses deux jetons. L'exemple du livre part de 1 WETH (de l'ETH sous forme de jeton ERC-20) et 100 USDT déposés quand l'ETH vaut 100 USDT. L'ETH monte à 110. En retirant sa part, on récupère 0,9535 WETH et 104,88 USDT, soit 209,76 USDT. En gardant simplement ses jetons, on aurait 210 USDT : la perte est de 0,24 (leçon 28).
Mon explication du mécanisme, tirée de la formule de l'idée 1 : quand le prix monte, les acheteurs retirent de l'ETH du pool et y laissent des USDT : le fournisseur vend donc son ETH en route, au fil de la hausse. La perte apparaît à la baisse comme à la hausse, et disparaît si le prix revient. Pour le livre, elle est « inévitable » sans autre récompense. D'où les frais : chaque paire prélève 0,2 % sur chaque échange (leçon 40), au profit des fournisseurs.
3Prêter, c'est garder des parts qui montent
Ces parts de pool reviennent dans le deuxième service, le prêt. Pensez au prêteur sur gages : on dépose un bien, on reçoit de l'argent, on récupère le bien en remboursant. Le prêt DeFi fait pareil avec des jetons, sans dossier ni contrôle de crédit. Le collatéral (le dépôt qui garantit l'emprunt) fixe le plafond : on emprunte au plus le LTV (loan-to-value) fois sa valeur, par exemple 75 % de 1 000 $ dans mon exemple. Personne n'emprunte plus que les fonds du pool (leçon 82).
Le prêteur reçoit des parts de pool, un ERC-20 comme le LP token. Lily dépose 100 USDT contre 100 parts à 1 USDT. Une part vaut la liquidité totale divisée par le nombre de parts : les intérêts des emprunteurs gonflent la liquidité, donc la part. Six mois plus tard elle vaut 1,1 et Lily retire 110 USDT (leçon 87).
Bob emprunte 80 USDT à 5 % sur les 100 de Lily et rembourse un an plus tard avec 4 USDT d'intérêts, que Lily empoche : elle gagne 4 %. Taux de prêt = utilisation du pool (80 %) × taux d'emprunt (5 %) (leçon 84).
Chez soi, de mon cru, pas du livre : on n'écrit pas les intérêts sur la ligne de chaque prêteur. On garde deux nombres, la liquidité totale et le nombre de parts. La valeur d'une part se calcule à la lecture. Mille prêteurs, et un seul UPDATE quand les intérêts tombent. Le test qui va avec : déposer, faire entrer des intérêts, vérifier que le retrait rend plus que le dépôt.
Le livre fait la même économie pour le staking, qu'il traite avant le prêt. Le staking consiste à bloquer des jetons dans un contrat pour toucher des récompenses. L'exemple du livre : Tom et Alice ont chacun déposé 1 bitcoin dans le même pool de staking, qui paie en USDT. Tom l'a déposé il y a un an, Alice il y a deux ans. Aujourd'hui, Tom peut toucher 100 USDT et Alice 200 USDT. Même dépôt, mais Alice attend depuis deux fois plus longtemps.
Pour arriver à ces deux montants, le contrat ne paie personne à chaque bloc. Chaque bloc distribue une récompense fixe entre les déposants. Le contrat tient un seul compteur : la récompense gagnée par bitcoin déposé depuis l'ouverture du pool. Il ne calcule la part de chacun qu'au dépôt ou au retrait. Or ce compteur court aussi sur l'année où Tom n'était pas là. Au dépôt de Tom, le contrat note donc ce qui était déjà distribué. Le livre appelle ce montant la « reward debt » (dette de récompense). Ce n'est « pas la vraie dette qu'un utilisateur doit au smart contract » (leçon 70), seulement ce qu'on retranche au moment du retrait. La reward debt de Tom est plus grande que celle d'Alice, car il y a plus à retrancher pour lui.
4Passé le coude, emprunter fait mal
Le taux de Bob ne tombe pas du ciel : plus un pool se vide, plus il faut décourager les emprunts. L'utilisation mesure ce vide, c'est la part de la liquidité empruntée (80 USDT sur 100, 80 %).
Le contrat PoolConfiguration fixe six paramètres. Parmi eux, le taux de base (baseBorrowRate) et l'utilisation optimale, de 50 à 90 % selon le livre. S'y ajoutent deux hausses : optimalSpan, répartie jusqu'à ce seuil, et excessSpan, ajoutée au-delà (leçons 84 et 85).
if (utilizationRate > optimalUtilizationRate) {
return baseBorrowRate + optimalSpan + (excessSpan *
(utilizationRate - optimalUtilizationRate)) /
(1e18 - optimalUtilizationRate);
}
return baseBorrowRate + (utilizationRate * optimalSpan) / optimalUtilizationRate;
Le livre donne un exemple chiffré (leçon 85). Dans cet exemple, le taux monte de 1 % à 9 % jusqu'au coude, puis de 9 % à 60 % quand le pool se vide. La seconde pente, plus raide, pousse les emprunteurs à rembourser avant que le pool ne soit à sec.
Mes chiffres, pas ceux du livre (base 2 %, optimalSpan 4 %, excessSpan 60 %, seuil 80 %) : à 40 % d'utilisation l'emprunt coûte 4 %, à 80 % il coûte 6 %, à 90 % il coûte 2 + 4 + 60 × 10 / 20 = 36 %.
Solidity n'a pas de décimaux : chaque taux est un entier multiplié par 10^18, donc 1 % s'écrit 10^16. Dans le code du livre, un paramètre de la fonction de taux n'a pas de type, une coquille (leçon 87).
5Quand la garantie fond, le liquidateur touche une prime
Un taux bien réglé ne protège pas de tout : le prix de la garantie, le collatéral de l'idée 3, peut chuter. Le plafond d'emprunt baisse avec lui, et la dette finit par le dépasser. Le livre l'admet : « il n'existe aucun moyen proactif de régler le problème avec le système de prêt » (leçon 86).
La parade s'appelle la liquidation. Un tiers, le liquidateur, rembourse une partie de la dette à la place de l'emprunteur. En échange, il reçoit de la garantie de l'emprunteur, pour la même valeur plus une prime. L'exemple du livre : le liquidateur verse 1 000 USDT pour un compte en défaut. Il peut repartir avec 1 100 USDT de garantie (prime de 1,1), ou prendre du BTC si le pool BTC paie une prime de 1,2.
Deux réglages encadrent l'opération. Le close factor, inférieur à 1, limite la part de la dette remboursable en une transaction (leçon 94). La prime, elle, se règle d'après le LTV : trop haute, elle laisse les liquidateurs vider la garantie. Le code de la fonction liquidate n'est pas montré, par choix de l'auteur : « il est très long et nous ne le publierons pas ici, dans le cours ».
Ce vocabulaire est-il celui d'un vrai protocole ? Le livre le confronte à Aave, l'un des grands protocoles de prêt de la DeFi : « les workflows et concepts de la v2 d'Aave sont cohérents avec le protocole construit dans ce cours » (leçon 88). Il met les mots d'Aave en face des siens :
- le Max LTV d'Aave = le collateralRate du cours ;
- le reserve factor (la part des intérêts gardée par le protocole) = son reserve rate ;
- la pénalité de liquidation d'Aave = la prime du liquidateur.
Le livre lit aussi le pool ETH d'Aave v2 : 233,13 K ETH fournis, 76 748 empruntés, soit 32,92 % d'utilisation, emprunt à 2,60 %, prêt à 0,64 %.
La v3 est seulement présentée, avec deux fonctions « que nous n'implémenterons pas dans ce cours ». Le mode d'isolation fixe un plafond de dette pour les actifs risqués. L'E-mode donne un LTV de plus de 90 % entre stablecoins, des jetons indexés sur le dollar comme l'USDT. Absents du texte, par recherche : le « health factor », les aTokens, le taux stable.
La liquidation ne se déclenche pas toute seule, et l'une des dernières leçons extraites le rappelle (leçon 113). Contrairement au DEX, « un système de prêt crypto demande un effort et un coût d'entretien ». Quelqu'un doit écouter les emprunts et les retraits, vérifier la santé des comptes, puis liquider ceux qui sont en défaut. Le livre propose un script, ou une liste publique des comptes pour que la communauté s'en charge. Il conseille aussi de ne prêter que des actifs du top 100 des cryptos, plus durs à manipuler.
6Un seul pool, et le prix s'achète
Plafond d'emprunt, liquidation : tout le prêt repose sur le prix du collatéral. Reste à savoir d'où il vient. Un contrat ne connaît aucun prix : il le demande à un oracle, comme un prêteur sur gages à son expert. Le lire dans le ratio des réserves d'un seul pool, c'est le piège du livre : « cette façon est extrêmement dangereuse » (leçon 84), puisqu'une grosse commande le fait bouger (idée 1).
L'attaque se joue en quatre temps (leçon 98). On achète le jeton pour gonfler son prix. On en dépose un peu en collatéral, que l'oracle croit alors précieux. On emprunte d'autres actifs bien au-delà de sa vraie valeur. On revend le jeton. Avec un collateral rate de 80 %, gonfler le prix de 25 % suffit pour que le plafond d'emprunt égale la vraie valeur du dépôt (leçon 98). Au-delà, l'attaquant garde la différence.
Il faut des fonds et de la vitesse. Les fonds viennent d'un flash loan, un prêt sans collatéral remboursé dans la même transaction. La vitesse : tout enchaîner en une transaction depuis un contrat, ou en transactions ordonnées que personne n'intercale (leçon 98). Le livre cite Euler Finance : « la plus grosse attaque par flash loan au moment de l'écriture, en mars 2023, 197 millions de dollars » (leçon 98).
Le livre ne s'arrête pas à la théorie : il joue l'attaque dans un test (leçon 99). Le décor tient en deux petits pools, dont un de 10 BAR (un jeton de test) pour 1 ETH. L'attaquant, un simple compte de test, y achète du BAR avec 99 ETH, et le prix du BAR est multiplié par près de 10 000. Il dépose 0,26 BAR en collatéral, vide les pools de prêt, puis revend son BAR. Le test vérifie que son solde final dépasse son solde de départ : « l'attaquant gagne plus de 100 ETH en manipulant le prix du BAR ».
Côté web, de mon cru, pas du livre : on ne croit jamais une valeur qu'on n'a pas vérifiée. Un prix envoyé par le formulaire d'une boutique ne se reprend pas tel quel en PHP, on le relit en base. Ici, la valeur à contrôler vient d'un pool que n'importe qui peut déplacer le temps d'une transaction. Le test à écrire est le même dans les deux cas : jouer l'attaquant, puis vérifier que l'opération est refusée.
7Un bloc truqué se noie dans la moyenne
Si un seul pool se manipule, il faut un prix plus dur à déplacer. Première piste, Chainlink, l'un des oracles les plus utilisés : il agrège au moins 21 réponses pour le prix de l'ETH. Mais, comme les autres fournisseurs, il ne couvre que quelques centaines de cryptos (leçon 100).
Le livre prend l'approche de Uniswap v2. La chaîne valide les transactions par lots, les blocs, environ toutes les 12 secondes. À chaque bloc, chaque paire cumule prix × temps écoulé, et l'oracle en tire une moyenne sur une fenêtre, un TWAP (time-weighted average price). Elle « ne dépend pas de plusieurs sources d'oracle tout en résistant à la manipulation » (leçon 100). Raison, d'après la suite du texte : le prix moyen aplatit la fluctuation (leçon 105). Une manipulation tient dans un bloc (12 secondes) sur une fenêtre de 720 secondes, donc elle pèse peu.
Fenêtre de 720 secondes, périodes de 12, un script qui appelle update en boucle (du gas à chaque appel, leçon 105). L'attaque jouée en test à l'idée 6 (99 ETH, prix du BAR multiplié par près de 10 000) est rejouée contre ce nouvel oracle. Cette fois, l'emprunt est refusé :
// L'attaquant échange 99 ETH contre BAR, dépose tout son BAR, emprunte 99 WETH (l'ETH enveloppé en ERC-20)
// revertedWith : la transaction doit être annulée avec ce motif
await expect(assetPool.connect(user2).borrow(wethToken.address, toWei(99)))
.to.be.revertedWith("ACCOUNT_UNHEALTHY");
Après la manipulation, l'oracle v2 donne 2,16 ETH au jeton BAR, l'ancien oracle, qui lit le ratio brut, 723,47 ETH (leçon 105).
Mon avis, honnêtement
Je suis venu chercher la salle des machines de la DeFi et j'ai trouvé un atelier, pas un traité. Comment un programme fixe-t-il un prix sans personne en face ? Par une formule. Comment prête-t-il ? Avec des parts, un taux à deux pentes et des liquidateurs payés pour agir. Pourquoi tout s'écroule-t-il quand son prix est faux ? Parce qu'un seul pool s'achète, et le livre le prouve en code.
Sa force : chaque service va de la formule au contrat testé. La partie oracle est la meilleure, car le même test d'attaque réussit contre le mauvais oracle puis échoue contre le bon.
Ses faiblesses, avec leur coût pour vous :
- Un outillage daté, détaillé plus bas. Coût : le front est à réécrire avant de servir.
- Une sécurité survolée. Les quatre failles de l'introduction sont décrites (leçon 8), mais aucune attaque de réentrance n'est rejouée. Les leçons extraites ne font ni fuzzing (tests à entrées aléatoires) ni audit. Coût : rien ici ne prépare à la production.
- Quelques affirmations fausses. Le gas d'une boucle croîtrait « exponentiellement » avec le nombre de tours (leçon 8). Le graphique du livre est une image que l'extraction ne restitue pas. À mon sens, pas du livre, une boucle simple coûte à peu près le même gas à chaque tour : la croissance est proportionnelle, pas exponentielle. Une TVL élevée voudrait dire « un risque plus bas » (leçon 5). À mon sens aussi, la taille d'un dépôt ne dit rien de la qualité du code. Coût : lisez l'introduction avec un crayon.
- Un front envahissant. Le code React occupe environ un tiers du texte, en pages répétitives. Coût : des heures de lecture pour peu d'idées.
Mon conseil : lisez l'introduction, l'AMM, le prêt jusqu'à la liquidation et l'oracle, survolez le staking, sautez le front. Mon verdict, 5,8 sur 10.
Odilon
Toujours valable en 2026 ?
Le fond, oui : produit constant, parts de pool, taux à coude, liquidation, TWAP. Le code non : Uniswap v3 et v4 et Aave v3 dominent.
L'outillage du cours a vieilli. Les contrats se compilent et se testent avec Hardhat 2.12.6, le portefeuille se connecte par l'ancienne API de web3-react. Le front démarre avec create-react-app (9 mentions), un outil de démarrage React déprécié depuis. Il parle à la blockchain avec Ethers v5, la bibliothèque JavaScript du même rôle (84 occurrences de ethers.utils, aucun BrowserProvider). Ce front est à réécrire en Ethers v6, viem ou wagmi, les bibliothèques actuelles.
Pour qui ?
Lisez-le si
- vous venez de la finance ou du back-end et voulez voir un AMM, un prêt et un oracle de l'intérieur ;
- vous cherchez l'attaque d'oracle expliquée et testée ;
- vous voulez une introduction à la DeFi qui fait les calculs : APY, perte impermanente, taux, liquidation.
Passez si
- vous visez la production : aucun audit dans les leçons extraites, et le code de la liquidation n'est pas publié dans le cours ;
- vous voulez un front moderne ;
- vous cherchez les stablecoins, l'assurance ou les DAO (organisations autonomes décentralisées) : le cours les laisse de côté (leçon 7).
Ce livre fait partie d'ExpertEdge, l'abonnement aux livres techniques de Packt. Le code ODILON50 donne 50 % de remise sur l'abonnement annuel : le livre sur ExpertEdge. Lien affilié : je touche une commission si vous vous abonnez avec ce code, et mes notes n'en dépendent pas.
Pour aller plus loin
- La fiche Designing Data-Intensive Applications : le socle des systèmes distribués.
- La fiche Web Application Security : la sécurité que ce cours ne détaille pas.
- La fiche Quantitative Trading d'Ernest P. Chan : le côté trading, comment savoir si une stratégie gagne vraiment.
Fiche fondée sur la version cours ExpertEdge 2024 : 114 leçons extraites sur les 126 annoncées, quiz compris. Source : leçons 3 à 8, 23 à 30, 40, 49, 50, 57, 70, 82 à 88, 94, 98 à 105 et 113 lues en détail. Citations vérifiées mot pour mot, traduites ici. Les exemples signalés comme les miens sont de moi, pas du livre.
Commentaires (0)