From 24273eab0d127c17f3ba7058ec6b545b9388b6f0 Mon Sep 17 00:00:00 2001 From: Joshua <62268199+minimalsm@users.noreply.github.com> Date: Fri, 13 Feb 2026 23:52:02 +0000 Subject: [PATCH] i18n(fr): translation import part 09 of 13 (23 files) --- .../secure-development-workflow/index.md | 30 +- .../tutorials/send-token-ethersjs/index.md | 66 +- .../index.md | 174 +++--- .../tutorials/server-components/index.md | 295 +++++++++ .../index.md | 30 +- .../developers/tutorials/short-abi/index.md | 307 +++++---- .../index.md | 79 ++- .../tutorials/stealth-addr/index.md | 443 +++++++++++++ .../index.md | 2 +- .../index.md | 131 ++-- .../token-integration-checklist/index.md | 88 +-- .../index.md | 102 +-- .../index.md | 44 +- .../uniswap-v2-annotated-code/index.md | 587 +++++++++--------- .../tutorials/using-websockets/index.md | 74 ++- .../index.md | 110 ++-- .../index.md | 76 +-- .../index.md | 92 +-- .../tutorials/yellow-paper-evm/index.md | 266 ++++---- public/content/translations/fr/eips/index.md | 41 +- .../fr/energy-consumption/index.md | 65 +- .../translations/fr/eth/supply/index.md | 80 +++ .../translations/fr/ethereum-forks/index.md | 320 +++++----- 23 files changed, 2182 insertions(+), 1320 deletions(-) create mode 100644 public/content/translations/fr/developers/tutorials/server-components/index.md create mode 100644 public/content/translations/fr/developers/tutorials/stealth-addr/index.md create mode 100644 public/content/translations/fr/eth/supply/index.md diff --git a/public/content/translations/fr/developers/tutorials/secure-development-workflow/index.md b/public/content/translations/fr/developers/tutorials/secure-development-workflow/index.md index 5cf6f987b11..50c1eaa8aae 100644 --- a/public/content/translations/fr/developers/tutorials/secure-development-workflow/index.md +++ b/public/content/translations/fr/developers/tutorials/secure-development-workflow/index.md @@ -1,15 +1,12 @@ --- -title: Liste de contrôle de sécurité des contrats intelligents -description: Un flux de travail suggéré pour la rédaction de contrats intelligents sécurisés +title: "Liste de contrôle de sécurité des contrats intelligents" +description: "Un flux de travail suggéré pour la rédaction de contrats intelligents sécurisés" author: "Trailofbits" -tags: - - "contrats intelligents" - - "sécurité" - - "solidity" +tags: [ "contrats intelligents", "sécurité", "solidité" ] skill: intermediate lang: fr published: 2020-09-07 -source: Créer des contrats sécurisés +source: Building secure contracts sourceUrl: https://github.com/crytic/building-secure-contracts/blob/master/development-guidelines/workflow.md --- @@ -19,26 +16,25 @@ Voici un processus de haut niveau que nous vous recommandons de suivre lors de l Recherchez les vulnérabilités connues : -- Vérifiez vos contrats avec [Slither](https://github.com/crytic/slither). Cet outil intègre plus de 40 détecteurs pour les vulnérabilités connues. Exécutez-le à chaque enregistrement d'un nouveau code et assurez-vous que son rapport soit positif (ou utilisez le mode triage pour mettre sous silence certains problèmes). -- Vérifiez vos contrats avec [Crytic](https://crytic.io/). Il vérifie 50 vulnérabilités que Slither ne détecte pas. Cryptic peut également aider votre équipe à rester le maître du jeu en faisant apparaître facilement les problèmes de sécurité dans les Pull Requests sur GitHub. +- Examinez vos contrats avec [Slither](https://github.com/crytic/slither). Cet outil intègre plus de 40 détecteurs pour les vulnérabilités connues. Exécutez-le à chaque enregistrement d'un nouveau code et assurez-vous que son rapport soit positif (ou utilisez le mode triage pour mettre sous silence certains problèmes). +- Examinez vos contrats avec [Crytic](https://crytic.io/). Il vérifie 50 vulnérabilités que Slither ne détecte pas. Cryptic peut également aider votre équipe à rester le maître du jeu en faisant apparaître facilement les problèmes de sécurité dans les Pull Requests sur GitHub. Considérez les caractéristiques spéciales de votre contrat : -- Vos contrats sont-ils évolutifs ? Vérifiez votre code de mise à niveau pour les défauts avec [`slither-check-upgradeability`](https://github.com/crytic/slither/wiki/Upgradeability-Checks) ou [Crytic](https://blog.trailofbits.com/2020/06/12/upgradeable-contracts-made-safer-with-crytic/). Nous avons documenté 17 façons dont les mises à niveau peuvent mal tourner. +- Vos contrats sont-ils évolutifs ? Examinez votre code de mise à niveau pour y déceler des failles avec [`slither-check-upgradeability`](https://github.com/crytic/slither/wiki/Upgradeability-Checks) ou [Crytic](https://blog.trailofbits.com/2020/06/12/upgradeable-contracts-made-safer-with-crytic/). Nous avons documenté 17 façons dont les mises à niveau peuvent mal tourner. - Est-ce que vos contrats doivent se conformer aux ERC? Vérifiez-les avec [`slither-check-erc`](https://github.com/crytic/slither/wiki/ERC-Conformance). Cet outil identifie instantanément les écarts de six spécifications courantes. -- Avez-vous des tests unitaires dans Truffe ? Enrichissez-les avec [`slither-prop`](https://github.com/crytic/slither/wiki/Property-generation). Il génère automatiquement une suite de propriétés de sécurité robustes pour les fonctionnalités de l'ERC20 en fonction de votre code spécifique. -- Intégrez-vous des jetons tiers ? Consultez notre [liste de contrôle d'intégration de jetons](/developers/tutorials/token-integration-checklist/) avant de vous fier à des contrats externes. +- Intégrez-vous des jetons tiers ? Examinez notre [liste de contrôle d'intégration de jetons](/developers/tutorials/token-integration-checklist/) avant de dépendre de contrats externes. Inspectez visuellement les fonctions de sécurité critiques de votre code : -- Examinez l'afficheur [inheritance-graph](https://github.com/trailofbits/slither/wiki/Printer-documentation#inheritance-graph) de Slither. Évitez les surcharges involontaires et les problèmes de linéarisation C3. -- Examinez l'afficheur [résumé de fonction](https://github.com/trailofbits/slither/wiki/Printer-documentation#function-summary) de Slither. Il signale la visibilité des fonctions et les contrôles d'accès. -- Examinez l'afficheur [variables et accès](https://github.com/trailofbits/slither/wiki/Printer-documentation#variables-written-and-authorization) de Slither. Il signale les contrôles d'accès aux variables d'état. +- Examinez l'imprimante [inheritance-graph](https://github.com/trailofbits/slither/wiki/Printer-documentation#inheritance-graph) de Slither. Évitez les surcharges involontaires et les problèmes de linéarisation C3. +- Examinez l'imprimante [function-summary](https://github.com/trailofbits/slither/wiki/Printer-documentation#function-summary) de Slither. Il signale la visibilité des fonctions et les contrôles d'accès. +- Examinez l'imprimante [vars-and-auth](https://github.com/trailofbits/slither/wiki/Printer-documentation#variables-written-and-authorization) de Slither. Il signale les contrôles d'accès aux variables d'état. Documentez les propriétés critiques de sécurité et utilisez des générateurs de tests automatisés pour les évaluer : - Apprenez à [documenter les propriétés de sécurité de votre code](/developers/tutorials/guide-to-smart-contract-security-tools/). C'est difficile au départ, mais c'est l'activité la plus importante pour obtenir un bon résultat. C'est également un prérequis à l'utilisation des techniques avancées de ce tutoriel. -- Definissez les propriétés de sécurité en Solidity, pour les utiliser avec [Echidna](https://github.com/crytic/echidna) et [Manticore](https://manticore.readthedocs.io/en/latest/verifier.html). Concentrez-vous sur votre automate, les contrôles d'accès, les opérations arithmétiques, les interactions externes et la conformité aux normes. +- Définissez les propriétés de sécurité dans Solidity, pour les utiliser avec [Echidna](https://github.com/crytic/echidna) et [Manticore](https://manticore.readthedocs.io/en/latest/verifier.html). Concentrez-vous sur votre automate, les contrôles d'accès, les opérations arithmétiques, les interactions externes et la conformité aux normes. - Définissez les propriétés de sécurité avec [l'API Python de Slither](/developers/tutorials/how-to-use-slither-to-find-smart-contract-bugs/). Concentrez-vous sur l'héritage, les dépendances des variables, les contrôles d'accès et d'autres problèmes structurels. - Exécutez vos tests de propriété sur chaque commit avec [Crytic](https://crytic.io). Crytic peut consommer et évaluer les tests de propriétés de sécurité pour que tout le monde dans votre équipe puisse facilement voir qu'ils passent sur GitHub. Les tests en échec peuvent bloquer les commits. @@ -51,6 +47,6 @@ Enfin, soyez attentifs aux problèmes que les outils automatisés ne peuvent pas ## Demandez de l'aide {#ask-for-help} -[Les heures de bureau d'Ethereum](https://calendly.com/dan-trailofbits/office-hours) se déroulent tous les mardis après-midi. Ces sessions en tête à tête sont l'occasion de nous poser toutes vos questions sur la sécurité, de dépannage à l'aide de nos outils et d'obtenir des commentaires d'experts sur votre approche actuelle. Nous vous aiderons à travailler à travers ce guide. +Les [heures de permanence Ethereum](https://calendly.com/dan-trailofbits/office-hours) ont lieu tous les mardis après-midi. Ces sessions en tête à tête sont l'occasion de nous poser toutes vos questions sur la sécurité, de dépannage à l'aide de nos outils et d'obtenir des commentaires d'experts sur votre approche actuelle. Nous vous aiderons à travailler à travers ce guide. Rejoignez notre Slack : [Empire Hacking](https://join.slack.com/t/empirehacking/shared_invite/zt-h97bbrj8-1jwuiU33nnzg67JcvIciUw). Nous sommes toujours disponibles dans les canaux #crytic et #ethereum si vous avez des questions. diff --git a/public/content/translations/fr/developers/tutorials/send-token-ethersjs/index.md b/public/content/translations/fr/developers/tutorials/send-token-ethersjs/index.md index 8352a365b03..985479e5f4e 100644 --- a/public/content/translations/fr/developers/tutorials/send-token-ethersjs/index.md +++ b/public/content/translations/fr/developers/tutorials/send-token-ethersjs/index.md @@ -1,27 +1,25 @@ --- -title: Envoyer des jetons avec ethers.js -description: Guide à l'intention des débutants sur l'envoi de jetons à l'aide d'ether.js. +title: "Envoyer des jetons à l'aide d'ethers.js" +description: "Guide pour débutants sur l'envoi de jetons à l'aide d'ethers.js." author: Kim YongJun -tags: - - "ETHERS.JS" - - "ERC-20" - - "JETONS" +tags: [ "ETHERS.JS", "ERC-20", "JETONS" ] skill: beginner lang: fr published: 2021-04-06 --- -## Envoyer un jeton avec ethers.js (5.0) {#send-token} +## Envoyer un jeton avec ethers.js(5.0) {#send-token} -### Dans ce tutoriel, vous allez apprendre à {#you-learn-about} +### Dans ce tutoriel, vous apprendrez comment {#you-learn-about} - Importer ethers.js - Transférer un jeton -- Définir le prix du gaz en fonction de l'état du trafic réseau +- Définir le prix du gaz en fonction de l'état du trafic du réseau ### Pour commencer {#to-get-started} -Pour commencer, nous devons d'abord importer la bibliothèque ethers.js dans notre JavaScript en intégrant ethers.js (5.0) +Pour commencer, nous devons d'abord importer la bibliothèque ethers.js dans notre JavaScript. +Inclure ethers.js(5.0) ### Installation {#install-ethersjs} @@ -29,16 +27,16 @@ Pour commencer, nous devons d'abord importer la bibliothèque ethers.js dans not /home/ricmoo> npm install --save ethers ``` -ES6 dans le navigateur : +ES6 dans le navigateur ```html ``` -ES3 (UMD) dans le navigateur : +ES3 (UMD) dans le navigateur ```html @@ -27,19 +25,19 @@ Si vous préférez installer la bibliothèque pour l'utiliser dans votre back-en npm install web3 --save ``` -Ensuite, pour importer Web3.js dans un script Node.js ou un projet frontend, vous pouvez utiliser l'instruction JavaScript suivante : +Ensuite, pour importer Web3.js dans un script Node.js ou un projet frontend Browserify, vous pouvez utiliser la ligne JavaScript suivante : ```js const Web3 = require("web3") ``` -Maintenant que nous avons importé la bibliothèque au sein du projet, nous devons l'initialiser. Notre projet doit être en mesure de communiquer avec la blockchain. La plupart des librairies Ethereum communiquent avec un [nœud](/developers/docs/nodes-and-clients/) via des appels RPC. Pour lancer notre fournisseur Web3, nous instancierons une instance Web3 en passant comme constructeur l'URL du fournisseur. Si vous disposez d'un nœud ou [d'une instance Ganache qui s'exécute sur votre ordinateur](https://ethereumdev.io/testing-your-smart-contract-with-existing-protocols-ganache-fork/) cela ressemblera à ça : +Maintenant que nous avons inclus la bibliothèque dans le projet, nous devons l'initialiser. Votre projet doit pouvoir communiquer avec la blockchain. La plupart des bibliothèques Ethereum communiquent avec un [nœud](/developers/docs/nodes-and-clients/) via des appels RPC. Pour lancer notre fournisseur Web3, nous instancierons une instance Web3 en passant comme constructeur l'URL du fournisseur. Si vous avez un nœud ou une [instance de ganache qui s'exécute sur votre ordinateur](https://ethereumdev.io/testing-your-smart-contract-with-existing-protocols-ganache-fork/), cela ressemblera à ceci : ```js const web3 = new Web3("http://localhost:8545") ``` -Si vous souhaitez accéder directement à un nœud hébergé, vous pouvez utiliser Infura. Vous pouvez également utiliser les programmes gratuits fournis par [Cloudflare](https://cloudflare-eth.com/), [Moralis](https://moralis.io), ou [Alchimie](https://alchemy.com/ethereum): +Si vous souhaitez accéder directement à un nœud hébergé, vous trouverez des options sur les [nœuds en tant que service](/developers/docs/nodes-and-clients/nodes-as-a-service). ```js const web3 = new Web3("https://cloudflare-eth.com") @@ -56,7 +54,7 @@ web3.eth.getBlockNumber(function (error, result) { }) ``` -Si vous exécutez ce programme, il affichera simplement le dernier numéro de bloc : le haut de la blockchain. Vous pouvez également utiliser les appels de fonctions `await/async` pour éviter d'imbriquer les rappels dans votre code : +Si vous exécutez ce programme, il affichera simplement le dernier numéro de bloc : le sommet de la blockchain. Vous pouvez également utiliser les appels de fonction `await/async` pour éviter d'imbriquer des callbacks dans votre code : ```js async function getBlockNumber() { @@ -68,27 +66,27 @@ async function getBlockNumber() { getBlockNumber() ``` -Vous pouvez consulter toutes les fonctions disponibles sur l'instance Web3 dans la [documentation officielle de Web3.js](https://docs.web3js.org/). +Vous pouvez voir toutes les fonctions disponibles sur l'instance Web3 dans [la documentation officielle de web3.js](https://docs.web3js.org/). -La plupart des bibliothèques Web3 sont asynchrones parce qu'en arrière-plan, la bibliothèque fait appel au serveur JSON RPC pour accéder au noeud qui renvoie le résultat. +La plupart des bibliothèques Web3 sont asynchrones car, en arrière-plan, la bibliothèque effectue des appels JSON-RPC au nœud qui renvoie le résultat. Si vous travaillez dans le navigateur, certains portefeuilles injectent directement une instance Web3 et vous devriez essayer de l'utiliser dans la mesure du possible, surtout si vous prévoyez d'interagir avec l'adresse Ethereum de l'utilisateur pour effectuer des transactions. -Voici le snippet pour détecter si un portefeuille MetaMask est disponible et si c'est le cas, tenter de l'activer. Cela vous permettra plus tard de lire le solde de l'utilisateur et de valider les transactions que vous souhaitez faire sur la blockchain Ethereum : +Voici l'extrait de code pour détecter si un portefeuille MetaMask est disponible et essayer de l'activer si c'est le cas. Cela vous permettra par la suite de lire le solde de l'utilisateur et de lui permettre de valider les transactions que vous souhaitez lui faire effectuer sur la blockchain Ethereum : ```js if (window.ethereum != null) { state.web3 = new Web3(window.ethereum) try { - // Request account access if needed + // Demander l'accès au compte si nécessaire await window.ethereum.enable() - // Accounts now exposed + // Comptes maintenant exposés } catch (error) { - // User denied account access... + // L'utilisateur a refusé l'accès au compte... } } ``` -Des alternatives aux web3.js comme [Ethers.js](https://docs.ethers.io/) existent et sont également couramment utilisées. Dans le prochain tutoriel, nous verrons [comment prendre en charge facilement les nouveaux blocs entrants sur la blockchain et voir ce qu'ils contiennent](https://ethereumdev.io/listening-to-new-transactions-happening-on-the-blockchain/). +Des alternatives à web3.js comme [Ethers.js](https://docs.ethers.io/) existent et sont également couramment utilisées. Dans le prochain tutoriel, nous verrons [comment écouter facilement les nouveaux blocs entrants sur la blockchain et voir ce qu'ils contiennent](https://ethereumdev.io/listening-to-new-transactions-happening-on-the-blockchain/). diff --git a/public/content/translations/fr/developers/tutorials/short-abi/index.md b/public/content/translations/fr/developers/tutorials/short-abi/index.md index 1d49f96f1bc..3e8966bc61c 100644 --- a/public/content/translations/fr/developers/tutorials/short-abi/index.md +++ b/public/content/translations/fr/developers/tutorials/short-abi/index.md @@ -1,85 +1,106 @@ --- -title: "Minimiser les ABIs pour l'optimisation des données d'appel" -description: Optimisation des contrats intelligents pour les Rollups optimistes +title: "ABI courtes pour l'optimisation des données d'appel" +description: Optimisation des contrats intelligents pour les rollups optimistes author: Ori Pomerantz lang: fr -tags: - - "Couche 2" +tags: [ "couche 2" ] skill: intermediate published: 2022-04-01 --- ## Introduction {#introduction} -Dans cet article, vous en apprendrez plus sur les [Rollups optimistes](/developers/docs/scaling/optimistic-rollups), le coût des transactions qui leur est appliqué, et comment la structure de coûts distincte nous oblige à optimiser différents éléments sur le réseau principal Ethereum. Vous apprendrez également à implémenter cette optimisation. +Dans cet article, vous en apprendrez plus sur les [rollups optimistes](/developers/docs/scaling/optimistic-rollups), le coût des transactions qui leur est appliqué et la manière dont cette structure de coûts différente nous oblige à optimiser pour des éléments différents de ceux du réseau principal d'Ethereum. +Vous apprendrez également comment mettre en œuvre cette optimisation. -### Devoir de transparence {#full-disclosure} +### Transparence totale {#full-disclosure} -Je suis un employé à temps plein chez [Optimism](https://www.optimism.io/), les exemples illustrant cet article seront donc exécutés sur Optimism. Cependant, la technique expliquée ici devrait aussi bien fonctionner pour d'autres rollups. +Je suis un employé à temps plein d'[Optimism](https://www.optimism.io/), les exemples de cet article seront donc exécutés sur Optimism. +Cependant, la technique expliquée ici devrait aussi bien fonctionner pour d'autres rollups. ### Terminologie {#terminology} -Lorsque l'on parle des rollups, le terme 'Couche 1' (L1) est généralement utilisé pour le réseau principal, le réseau Ethereum de production. Le terme 'Couche 2' (L2) est utilisé pour les rollups ou tout autre système qui se base sur L1 pour la sécurité, mais qui réalise son traitement hors chaîne. +Lorsque l'on parle des rollups, le terme « couche 1 » (L1) est utilisé pour le réseau principal, le réseau de production Ethereum. +Le terme « couche 2 » (L2) est utilisé pour le rollup ou tout autre système qui s'appuie sur L1 pour la sécurité, mais qui effectue la plupart de son traitement hors chaîne. -## Comment pouvons-nous encore réduire le coût des transactions L2 ? {#how-can-we-further-reduce-the-cost-of-L2-transactions} +## Comment pouvons-nous réduire davantage le coût des transactions L2 ? {#how-can-we-further-reduce-the-cost-of-L2-transactions} -[Les Rollups optimistes](/developers/docs/scaling/optimistic-rollups) doivent conserver un registre de chaque historique de transaction afin que toute personne qui le souhaite puisse le passer en revue et vérifier que l'état actuel est correct. La façon la plus économique de récupérer des données sur le réseau principal Ethereum est de les écrire en tant que données d'appel. Cette solution a été choisie à la fois par [Optimism](https://help.optimism.io/hc/en-us/articles/4413163242779-What-is-a-rollup-) et [Arbitrum](https://developer.offchainlabs.com/docs/rollup_basics#intro-to-rollups). +Les [rollups optimistes](/developers/docs/scaling/optimistic-rollups) doivent conserver un enregistrement de chaque transaction historique afin que n'importe qui puisse les parcourir et vérifier que l'état actuel est correct. +Le moyen le plus économique d'inscrire des données sur le réseau principal d'Ethereum est de les écrire en tant que données d'appel. +Cette solution a été choisie à la fois par [Optimism](https://help.optimism.io/hc/en-us/articles/4413163242779-What-is-a-rollup-) et [Arbitrum](https://developer.offchainlabs.com/docs/rollup_basics#intro-to-rollups). ### Coût des transactions L2 {#cost-of-l2-transactions} -Le coût des transactions L2 est composé de deux éléments : +Le coût des transactions L2 se compose de deux éléments : 1. Le traitement L2, qui est généralement extrêmement bon marché -2. Le stockage L1, lié aux coûts de gaz du réseau principal +2. Le stockage L1, qui est lié aux coûts de gaz du réseau principal -Au moment d'écrire cet article, le coût de gaz L2 sur Optimism est de 0,001 [Gwei](/developers/docs/gas/#pre-london) Le coût de gaz L1, en revanche, est d'environ 40 gwei. [Vous pouvez voir les prix actuels ici](https://public-grafana.optimism.io/d/9hkhMxn7z/public-dashboard?orgId=1&refresh=5m). +Au moment où j'écris ces lignes, sur Optimism, le coût du gaz L2 est de 0,001 [Gwei](/developers/docs/gas/#pre-london). +Le coût du gaz L1, en revanche, est d'environ 40 gwei. +[Vous pouvez voir les prix actuels ici](https://public-grafana.optimism.io/d/9hkhMxn7z/public-dashboard?orgId=1&refresh=5m). -Un octet de données d'appel coûte soit 4 gaz (s'il est nul) soit 16 gaz (s'il s'agit d'une autre valeur). L'une des opérations les plus coûteuses de l'EVM est d'écrire sur le stockage. Le coût maximum d'écriture d'un mot de 32 octets pour un stockage sur L2 est de 22 100 gaz. Soit actuellement 22,1 gwei. Si nous parvenons à sauvegarder un seul octet zéro de données d'appel, nous pourrons écrire environ 200 octets de stockage et sortir gagnants de l'opération. +Un octet de données d'appel coûte soit 4 gaz (s'il est nul), soit 16 gaz (s'il s'agit de n'importe quelle autre valeur). +L'une des opérations les plus coûteuses sur l'EVM est l'écriture sur le stockage. +Le coût maximum de l'écriture d'un mot de 32 octets sur le stockage en L2 est de 22 100 gaz. Actuellement, cela représente 22,1 gwei. +Ainsi, si nous pouvons économiser un seul octet nul de données d'appel, nous pourrons écrire environ 200 octets sur le stockage et être tout de même gagnants. ### L'ABI {#the-abi} -La grande majorité des transactions accèdent à un contrat provenant d'un compte externe. La plupart des contrats sont écrits en Solidity et interprètent leur champ de données conformément à l'[interface binaire d'application (ABI)](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding). +La grande majorité des transactions accèdent à un contrat provenant d'un compte externe. +La plupart des contrats sont écrits en Solidity et interprètent leur champ de données selon [l'interface binaire de l'application (ABI)](https://docs.soliditylang.org/en/latest/abi-spec.html#formal-specification-of-the-encoding). -Cependant, l'ABI a été conçu pour L1, où un octet de données d'appels coûte approximativement la même chose que quatre opérations arithmétiques, et non pas pour L2 où un octet de données d'appel coûte plus de mille opérations arithmétiques. Par exemple, [voici une transaction de transfert ERC-20](https://kovan-optimistic.etherscan.io/tx/0x7ce4c144ebfce157b4de99d8ad53a352ae91b57b3fa06d8a1c79439df6bfa998). Les données d'appel sont divisées ainsi : +Cependant, l'ABI a été conçue pour L1, où un octet de données d'appel coûte approximativement la même chose que quatre opérations arithmétiques, et non pour L2 où un octet de données d'appel coûte plus de mille opérations arithmétiques. +Les données d'appel sont divisées comme suit : -| Section | Longueur | Bytes | Octets gaspillés | Gaz gaspillé | Octets nécessaires | Gaz nécessaire | -| ---------------------- | -------: | ----: | ---------------: | -----------: | -----------------: | -------------: | -| Sélecteur de fonction | 4 | 0-3 | 3 | 48 | 1 | 16 | -| Zéros | 12 | 4-15 | 12 | 48 | 0 | 0 | -| Adresse de destination | 20 | 16-35 | 0 | 0 | 20 | 320 | -| Montant | 32 | 36-67 | 17 | 64 | 15 | 240 | -| Total | 68 | | | 160 | | 576 | +| Section | Longueur | Octets | Octets gaspillés | Gaz gaspillé | Octets nécessaires | Gaz nécessaire | +| ---------------------- | -------: | -----: | ---------------: | -----------: | -----------------: | -------------: | +| Sélecteur de fonction | 4 | 0-3 | 3 | 48 | 1 | 16 | +| Zéros | 12 | 4-15 | 12 | 48 | 0 | 0 | +| Adresse de destination | 20 | 16-35 | 0 | 0 | 20 | 320 | +| Montant | 32 | 36-67 | 17 | 64 | 15 | 240 | +| Total | 68 | | | 160 | | 576 | -Explication : +Explication : -- **Sélecteur de fonction** : Le contrat a moins de 256 fonctions, nous pouvons donc les caractériser avec un seul octet. Ces octets sont typiquement non nuls et [coûtent donc seize gaz](https://eips.ethereum.org/EIPS/eip-2028). -- **Zéros** : Ces octets sont toujours nuls car une adresse de vingt-quatre octets ne nécessite pas un mot de trente-deux octets pour la contenir. Les octets qui contiennent la valeur zéro ont un coût de quatre gaz ([voir le Livre Jaune](https://ethereum.github.io/yellowpaper/paper.pdf), Annexe G, p. 27, la valeur de `G``txdatazero`). -- **Montant** : Si nous supposons que dans ce contrat `les décimales` sont de dix-huit (la valeur normale) et que le nombre maximum de jetons que nous transférons sera de 1018, nous obtenons un montant maximum de 1036. 25615 > 1036, donc 15 octets suffisent. +- **Sélecteur de fonction** : Le contrat a moins de 256 fonctions, nous pouvons donc les distinguer avec un seul octet. + Ces octets sont généralement non nuls et [coûtent donc seize gaz](https://eips.ethereum.org/EIPS/eip-2028). +- **Zéros** : Ces octets sont toujours nuls car une adresse de vingt octets ne nécessite pas un mot de trente-deux octets pour la contenir. + Les octets qui contiennent la valeur zéro coûtent quatre gaz ([voir le Livre Jaune](https://ethereum.github.io/yellowpaper/paper.pdf), Annexe G, + p. 27, la valeur pour `G``txdatazero`). +- **Montant** : Si nous supposons que dans ce contrat `decimals` est de dix-huit (la valeur normale) et que le montant maximum de jetons que nous transférons sera de 1018, nous obtenons un montant maximum de 1036. + 25615 > 1036, donc quinze octets suffisent. -Le gaspillage de 160 gaz sur L1 est normalement négligeable. Une transaction coûte un minimum de [21 000 gaz](https://yakkomajuri.medium.com/blockchain-definition-of-the-week-ethereum-gas-2f976af774ed), ainsi, un supplément de 0,8 % n'a pas grande importance. Cependant, sur L2, les choses sont différentes. La quasi-totalité du coût de la transaction consiste à l'écrire sur L1. En plus des données d'appel de la transaction, il y a 109 octets d'en-tête de la transaction (adresse de destination, signature, etc.). Le coût total est donc `109*16+576+160=2480`, et nous en gaspillons environ 6,5%. +Un gaspillage de 160 gaz sur L1 est normalement négligeable. Une transaction coûte au moins [21 000 gaz](https://yakkomajuri.medium.com/blockchain-definition-of-the-week-ethereum-gas-2f976af774ed), donc 0,8 % supplémentaires n'ont pas d'importance. +Cependant, sur L2, les choses sont différentes. La quasi-totalité du coût de la transaction consiste à l'écrire sur L1. +En plus des données d'appel de la transaction, il y a 109 octets d'en-tête de transaction (adresse de destination, signature, etc.). +Le coût total est donc `109*16+576+160=2480`, et nous en gaspillons environ 6,5 %. ## Réduire les coûts lorsque vous ne contrôlez pas la destination {#reducing-costs-when-you-dont-control-the-destination} -En supposant que vous n'ayez pas de contrôle sur le contrat de destination, vous pouvez toujours utiliser une solution similaire à [celle-ci](https://github.com/qbzzt/ethereum.org-20220330-shortABI). Passons en revue les fichiers pertinents. +En supposant que vous n'ayez pas le contrôle sur le contrat de destination, vous pouvez toujours utiliser une solution similaire à [celle-ci](https://github.com/qbzzt/ethereum.org-20220330-shortABI). +Passons en revue les fichiers pertinents. ### Token.sol {#token-sol} -[Ceci est le contrat de destination](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/contracts/Token.sol). Il s'agit d'un contrat standard ERC-20, avec une fonction supplémentaire. Cette fonction `faucet` permet à n'importe quel utilisateur d'obtenir un jeton à utiliser. Elle rendrait inutile la création d'un contrat ERC-20, mais elle facilite la vie quand un ERC-20 existe uniquement pour faciliter les tests. +[Ceci est le contrat de destination](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/contracts/Token.sol). +Il s'agit d'un contrat standard ERC-20, avec une fonction supplémentaire. +Cette fonction `faucet` permet à n'importe quel utilisateur d'obtenir un jeton à utiliser. +Elle rendrait inutile la création d'un contrat ERC-20, mais elle facilite la vie quand un ERC-20 existe uniquement pour faciliter les tests. ```solidity /** - * @dev Gives the caller 1000 tokens to play with + * @dev Donne à l'appelant 1000 jetons avec lesquels jouer */ function faucet() external { _mint(msg.sender, 1000); } // function faucet ``` -[Vous pouvez voir un exemple de ce contrat en cours de déploiement ici](https://kovan-optimistic.etherscan.io/address/0x950c753c0edbde44a74d3793db738a318e9c8ce8). - ### CalldataInterpreter.sol {#calldatainterpreter-sol} -[Ceci est le contrat que les transactions sont censées appeler au moyen de données d'appel plus courtes](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/contracts/CalldataInterpreter.sol). Revenons dessus ligne par ligne. +[Ceci est le contrat que les transactions sont censées appeler avec des données d'appel plus courtes](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/contracts/CalldataInterpreter.sol). +Revenons dessus ligne par ligne. ```solidity //SPDX-License-Identifier: Unlicense @@ -89,7 +110,7 @@ pragma solidity ^0.8.0; import { OrisUselessToken } from "./Token.sol"; ``` -Nous avons besoin de savoir comment appeler la fonction token. +Nous avons besoin de la fonction du jeton pour savoir comment l'appeler. ```solidity contract CalldataInterpreter { @@ -97,19 +118,19 @@ contract CalldataInterpreter { OrisUselessToken public immutable token; ``` -L'adresse du jeton pour lequel nous sommes un proxy. +L'adresse du jeton pour lequel nous sommes un mandataire (proxy). ```solidity /** - * @dev Specify the token address - * @param tokenAddr_ ERC-20 contract address + * @dev Spécifier l'adresse du jeton + * @param tokenAddr_ Adresse du contrat ERC-20 */ constructor( address tokenAddr_ ) { token = OrisUselessToken(tokenAddr_); - } // constructor + } // constructeur ``` L'adresse du jeton est le seul paramètre que nous devons spécifier. @@ -119,19 +140,21 @@ L'adresse du jeton est le seul paramètre que nous devons spécifier. private pure returns (uint) { ``` -Lire une valeur dans les données d'appel. +Lire une valeur à partir des données d'appel. ```solidity uint _retVal; require(length < 0x21, - "calldataVal length limit is 32 bytes"); + "La limite de longueur de calldataVal est de 32 octets"); require(length + startByte <= msg.data.length, - "calldataVal trying to read beyond calldatasize"); + "calldataVal essaie de lire au-delà de calldatasize"); ``` -Nous allons charger en mémoire un unique mot de 32 octets (256 bits) et supprimer les octets qui ne font pas partie du champ souhaité. Cet algorithme ne fonctionne pas pour des valeurs de plus de 32 octets, et bien sûr nous ne pouvons lire au-delà de la fin des données d'appel. Sur L1, il serait pertinent de ne pas réaliser ces tests pour économiser du gaz, mais sur L2, le gaz est extrêmement bon marché, ce qui permet de réaliser toutes les vérifications possibles. +Nous allons charger un unique mot de 32 octets (256 bits) en mémoire et supprimer les octets qui ne font pas partie du champ que nous voulons. +Cet algorithme ne fonctionne pas pour des valeurs de plus de 32 octets, et bien sûr nous ne pouvons pas lire au-delà de la fin des données d'appel. +Sur L1, il peut être nécessaire d'ignorer ces tests pour économiser du gaz, mais sur L2, le gaz est extrêmement bon marché, ce qui permet toutes les vérifications de cohérence auxquelles nous pouvons penser. ```solidity assembly { @@ -141,14 +164,16 @@ Nous allons charger en mémoire un unique mot de 32 octets (256 bits) et supprim Nous aurions pu copier les données de l'appel à `fallback()` (voir ci-dessous), mais il est plus facile d'utiliser [Yul](https://docs.soliditylang.org/en/v0.8.12/yul.html), le langage d'assemblage de l'EVM. -Nous utilisons ici [l'opcode CALLDATALOAD](https://www.evm.codes/#35) pour lire les octets `startByte` à `startByte+31` dans la pile. En général, la syntaxe d'un opcode dans Yul est `(,...)`. +Ici, nous utilisons [l'opcode CALLDATALOAD](https://www.evm.codes/#35) pour lire les octets `startByte` à `startByte+31` dans la pile. +En général, la syntaxe d'un opcode dans Yul est `(,...)`. ```solidity _retVal = _retVal >> (256-length*8); ``` -Seuls les octets de `longueur` les plus significatives font partie du champ, donc nous [décalons vers la droite](https://en.wikipedia.org/wiki/Logical_shift) pour nous débarrasser des autres valeurs. Ceci présente l'avantage supplémentaire de déplacer la valeur à droite du champ, il s'agit donc de la valeur elle-même plutôt que la valeur multipliée par 256quelque chose. +Seuls les octets de `longueur` les plus significatifs font partie du champ, donc nous effectuons un [décalage à droite](https://en.wikipedia.org/wiki/Logical_shift) pour nous débarrasser des autres valeurs. +Ceci présente l'avantage supplémentaire de déplacer la valeur à droite du champ, il s'agit donc de la valeur elle-même plutôt que la valeur multipliée par 256quelque chose. ```solidity @@ -159,7 +184,8 @@ Seuls les octets de `longueur` les plus significatives font partie du champ, don fallback() external { ``` -Lorsqu'un appel à un contrat Solidity ne correspond à aucune des signatures de fonction, il appelle [la fonction `fallback()`](https://docs.soliditylang.org/en/v0.8.12/contracts.html#fallback-function) (en supposant qu'il y en ait une). Dans le cas de `CalldataInterpreter`, _tous les appels_ arrivent ici car il n'y a pas d'autres fonctions `external` ou `public`. +Lorsqu'un appel à un contrat Solidity ne correspond à aucune des signatures de fonction, il appelle [la fonction `fallback()`](https://docs.soliditylang.org/en/v0.8.12/contracts.html#fallback-function) (en supposant qu'il y en ait une). +Dans le cas de `CalldataInterpreter`, n'importe quel appel arrive ici car il n'y a pas d'autres fonctions `external` ou `public`. ```solidity uint _func; @@ -167,23 +193,27 @@ Lorsqu'un appel à un contrat Solidity ne correspond à aucune des signatures de _func = calldataVal(0, 1); ``` -Lit le premier octet des données d'appel, qui nous indique la fonction. Il y a deux raisons pour lesquelles une fonction ne serait pas disponible ici : +Lit le premier octet des données d'appel, qui nous indique la fonction. +Il y a deux raisons pour lesquelles une fonction ne serait pas disponible ici : -1. Les fonctions `pure` ou `view` ne changent pas l'état et ne coûtent pas de gaz (lorsqu'elles sont appelées hors chaîne). Essayer de réduire leur coût en gaz n'a aucun sens. -2. Les fonctions reposent sur [`msg.sender`](https://docs.soliditylang.org/en/v0.8.12/units-and-global-variables.html#block-and-transaction-properties). La valeur de `msg.sender` va être l'adresse du `CalldataInterpreter`, pas celle de l'appelant. +1. Les fonctions `pure` ou `view` ne modifient pas l'état et ne coûtent pas de gaz (lorsqu'elles sont appelées hors chaîne). + Essayer de réduire leur coût en gaz n'a aucun sens. +2. Fonctions qui s'appuient sur [`msg.sender`](https://docs.soliditylang.org/en/v0.8.12/units-and-global-variables.html#block-and-transaction-properties). + La valeur de `msg.sender` sera l'adresse de `CalldataInterpreter`, et non celle de l'appelant. -Malheureusement, [au regard des spécifications ERC-20](https://eips.ethereum.org/EIPS/eip-20), cela ne laisse qu'une seule fonction, `transfer`. Cela nous laisse avec uniquement deux fonctions : `transfer` (parce que nous pouvons appeler `transferFrom`) et `faucet` (parce que nous pouvons retourner les jetons à celui qui nous a appelés). +Malheureusement, [en examinant les spécifications ERC-20](https://eips.ethereum.org/EIPS/eip-20), cela ne laisse qu'une seule fonction, `transfer`. +Cela nous laisse avec uniquement deux fonctions : `transfer` (parce que nous pouvons appeler `transferFrom`) et `faucet` (parce que nous pouvons retourner les jetons à celui qui nous a appelés). ```solidity - // Call the state changing methods of token using - // information from the calldata + // Appeler les méthodes de changement d'état du jeton en utilisant + // les informations des données d'appel // faucet if (_func == 1) { ``` -Un appel à la fonction `faucet()`, qui n'a pas de paramètres. +Un appel à `faucet()`, qui n'a pas de paramètres. ```solidity token.faucet(); @@ -192,10 +222,12 @@ Un appel à la fonction `faucet()`, qui n'a pas de paramètres. } ``` -Après avoir appelé `token.faucet()`, nous obtenons des jetons. Cependant, comme pour le contrat proxy, nous n'avons pas **besoin** des jetons. L'EOA (compte détenu en externe) ou le contrat qui nous appelait en a besoin. Nous transférons donc tous nos jetons à ceux qui nous ont appelés. +Après avoir appelé `token.faucet()`, nous obtenons des jetons. Cependant, en tant que contrat mandataire, nous n'avons pas **besoin** de jetons. +L'EOA (compte détenu en externe) ou le contrat qui nous a appelés en a besoin. +Nous transférons donc tous nos jetons à ceux qui nous ont appelés. ```solidity - // transfer (assume we have an allowance for it) + // transfer (supposons que nous ayons une allocation pour cela) if (_func == 2) { ``` @@ -212,26 +244,27 @@ Nous autorisons uniquement les appelants à transférer les jetons qu'ils possè address(uint160(calldataVal(1, 20))), ``` -L'adresse de destination commence à l'octet #1 (l'octet #0 est la fonction). En tant qu'adresse, elle fait 20 octets de long. +L'adresse de destination commence à l'octet n° 1 (l'octet n° 0 est la fonction). +En tant qu'adresse, elle fait 20 octets de long. ```solidity calldataVal(21, 2) ``` -Pour ce contrat particulier, nous supposons que le nombre maximum de jetons que n'importe qui voudra transférer tiendra dans deux octets (moins de 65536). +Pour ce contrat particulier, nous supposons que le nombre maximum de jetons que n'importe qui voudra transférer tiendra dans deux octets (moins de 65 536). ```solidity ); } ``` -Dans l'ensemble, un transfert prend 35 octets de données d'appel : +Dans l'ensemble, un transfert prend 35 octets de données d'appel : -| Section | Longueur | Bytes | -| ---------------------- | -------: | ----: | -| Sélecteur de fonction | 1 | 0 | -| Adresse de destination | 32 | 1-32 | -| Montant | 2 | 33-34 | +| Section | Longueur | Octets | +| ---------------------- | -------: | -----: | +| Sélecteur de fonction | 1 | 0 | +| Adresse de destination | 32 | 1-32 | +| Montant | 2 | 33-34 | ```solidity } // fallback @@ -241,22 +274,23 @@ Dans l'ensemble, un transfert prend 35 octets de données d'appel : ### test.js {#test-js} -[Ce test unitaire JavaScript](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/test/test.js) nous montre comment utiliser ce mécanisme (et comment vérifier qu'il fonctionne correctement). Je vais supposer que vous comprenez [chai](https://www.chaijs.com/) et [ethers](https://docs.ethers.io/v5/) et uniquement vous expliquer les parties applicables spécifiquement au contrat. +[Ce test unitaire JavaScript](https://github.com/qbzzt/ethereum.org-20220330-shortABI/blob/master/test/test.js) nous montre comment utiliser ce mécanisme (et comment vérifier qu'il fonctionne correctement). +Je vais supposer que vous comprenez [chai](https://www.chaijs.com/) et [ethers](https://docs.ethers.io/v5/) et que je n'expliquerai que les parties qui s'appliquent spécifiquement au contrat. ```js const { expect } = require("chai"); describe("CalldataInterpreter", function () { - it("Should let us use tokens", async function () { + it("Devrait nous permettre d'utiliser des jetons", async function () { const Token = await ethers.getContractFactory("OrisUselessToken") const token = await Token.deploy() await token.deployed() - console.log("Token addr:", token.address) + console.log("Adresse du jeton :", token.address) const Cdi = await ethers.getContractFactory("CalldataInterpreter") const cdi = await Cdi.deploy(token.address) await cdi.deployed() - console.log("CalldataInterpreter addr:", cdi.address) + console.log("Adresse CalldataInterpreter :", cdi.address) const signer = await ethers.getSigner() ``` @@ -264,21 +298,24 @@ describe("CalldataInterpreter", function () { Nous commençons par déployer les deux contrats. ```javascript - // Get tokens to play with + // Obtenir des jetons pour jouer avec const faucetTx = { ``` -Nous ne pouvons pas utiliser les fonctions de haut niveau que nous utiliserions normalement (comme `token.faucet()`) pour créer des transactions, car nous ne suivons pas l'ABI. Au lieu de cela, nous devons construire nous-mêmes la transaction et ensuite l'envoyer. +Nous ne pouvons pas utiliser les fonctions de haut niveau que nous utiliserions normalement (telles que `token.faucet()`) pour créer des transactions, car nous ne suivons pas l'ABI. +Au lieu de cela, nous devons construire nous-mêmes la transaction et ensuite l'envoyer. ```javascript to: cdi.address, data: "0x01" ``` -Nous devons fournir deux paramètres pour la transaction : +Nous devons fournir deux paramètres pour la transaction : -1. `to`, l'adresse de destination. Il s'agit de l'interpréteur des données d'appel du contrat. -2. `data`, les données d'appel à envoyer. Dans le cas d'un appel faucet, les données sont un octet unique, `0x01`. +1. `to`, l'adresse de destination. + Il s'agit du contrat d'interprétation des données d'appel. +2. `data`, les données d'appel à envoyer. + Dans le cas d'un appel au faucet, les données sont un octet unique, `0x01`. ```javascript @@ -286,26 +323,27 @@ Nous devons fournir deux paramètres pour la transaction : await (await signer.sendTransaction(faucetTx)).wait() ``` -Nous appelons la [méthode du signataire `sendTransaction`](https://docs.ethers.io/v5/api/signer/#Signer-sendTransaction) car nous avons déjà spécifié la destination (`faucetTx.to`) et nous avons besoin que la transaction soit signée. +Nous appelons la méthode `sendTransaction` [du signataire](https://docs.ethers.io/v5/api/signer/#Signer-sendTransaction) car nous avons déjà spécifié la destination (`faucetTx.to`) et nous avons besoin que la transaction soit signée. ```javascript -// Check the faucet provides the tokens correctly +// Vérifier que le faucet fournit les jetons correctement expect(await token.balanceOf(signer.address)).to.equal(1000) ``` -Ici, nous vérifions le solde. Il n'est pas nécessaire d'économiser du gaz pour les fonctions `view`, nous les exécutons donc normalement. +Ici, nous vérifions le solde. +Il n'est pas nécessaire d'économiser du gaz sur les fonctions de `vue`, nous les exécutons donc normalement. ```javascript -// Give the CDI an allowance (approvals cannot be proxied) +// Donner une allocation au CDI (les approbations ne peuvent pas être mandatées) const approveTX = await token.approve(cdi.address, 10000) await approveTX.wait() expect(await token.allowance(signer.address, cdi.address)).to.equal(10000) ``` -Donner à l'interprète des données d'appel une allocation pour pouvoir effectuer des transferts. +Donner à l'interprète de données d'appel une allocation pour pouvoir effectuer des transferts. ```javascript -// Transfer tokens +// Transférer des jetons const destAddr = "0xf5a6ead936fb47f342bb63e676479bddf26ebe1d" const transferTx = { to: cdi.address, @@ -313,53 +351,50 @@ const transferTx = { } ``` -Créer une transaction de transfert. Le premier octet est "0x02", suivi de l'adresse de destination, et enfin du montant (0x0100, qui est de 256 décimal). +Créer une transaction de transfert. Le premier octet est « 0x02 », suivi de l'adresse de destination, et enfin du montant (0x0100, qui correspond à 256 en décimal). ```javascript await (await signer.sendTransaction(transferTx)).wait() - // Check that we have 256 tokens less + // Vérifier que nous avons 256 jetons en moins expect (await token.balanceOf(signer.address)).to.equal(1000-256) - // And that our destination got them + // Et que notre destination les a reçus expect (await token.balanceOf(destAddr)).to.equal(256) }) // it }) // describe ``` -### Exemple {#example} - -Si vous souhiatez voir ces fichiers en action sans les exécuter vous-même, suivez ces liens : - -1. [Déploiement de `OrisUselessToken`](https://kovan-optimistic.etherscan.io/tx/1410744) sur l'[adresse `0x950c753c0edbde44a74d3793db738a318e9c8ce8`](https://kovan-optimistic.etherscan.io/address/0x950c753c0edbde44a74d3793db738a318e9c8ce8). -2. [Déploiement de `CalldataInterpreter`](https://kovan-optimistic.etherscan.io/tx/1410745) sur l'[adresse `0x16617fea670aefe3b9051096c0eb4aeb4b3a5f55`](https://kovan-optimistic.etherscan.io/address/0x16617fea670aefe3b9051096c0eb4aeb4b3a5f55). -3. [Appel de `faucet()`](https://kovan-optimistic.etherscan.io/tx/1410746). -4. [Appel de `OrisUselessToken.approve()`](https://kovan-optimistic.etherscan.io/tx/1410747). Cet appel doit aller directement au contrat de jeton car le traitement repose sur `msg.sender`. -5. [Appel de `transfer()`](https://kovan-optimistic.etherscan.io/tx/1410748). - -## Réduire les coûts lorsque vous contrôlez le contrat de destination {#reducing-the-cost-when-you-do-control-the-destination-contract} +## Réduire le coût lorsque vous contrôlez le contrat de destination {#reducing-the-cost-when-you-do-control-the-destination-contract} -Si vous avez le contrôle sur le contrat de destination, vous pouvez créer des fonctions qui contournent la vérification `msg.sender` dans la mesure où elles font confiance à l'interpréteur des données d'appel. [Vous pouvez voir un exemple de comment cela fonctionne ici, dans la branche `control-contract`](https://github.com/qbzzt/ethereum.org-20220330-shortABI/tree/control-contract). +Si vous avez le contrôle sur le contrat de destination, vous pouvez créer des fonctions qui contournent la vérification de `msg.sender` dans la mesure où elles font confiance à l'interpréteur des données d'appel. +[Vous pouvez voir un exemple de la façon dont cela fonctionne ici, dans la branche `control-contract`](https://github.com/qbzzt/ethereum.org-20220330-shortABI/tree/control-contract). -Si le contrat ne répondait qu'à des transactions externes, nous pourrions nous contenter d'un seul contrat. Cependant, cela casserait [la composabilité](/developers/docs/smart-contracts/composability/). Il est préférable d'avoir un contrat capable de répondre aux appels traditionnels ERC-20 et un autre contrat destiné aux transactions avec de courts appels de données. +Si le contrat ne répondait qu'à des transactions externes, nous pourrions nous contenter d'un seul contrat. +Cependant, cela briserait [la composabilité](/developers/docs/smart-contracts/composability/). +Il est préférable d'avoir un contrat qui répond aux appels ERC-20 normaux, et un autre contrat qui répond aux transactions avec des données d'appel courtes. ### Token.sol {#token-sol-2} -Dans cet exemple, nous pouvons modifier `Token.sol`. Cela nous permet d'avoir un certain nombre de fonctions que seul le proxy peut appeler. Voici les nouveaux éléments : +Dans cet exemple, nous pouvons modifier `Token.sol`. +Cela nous permet d'avoir un certain nombre de fonctions que seul le mandataire peut appeler. +Voici les nouvelles parties : ```solidity - // The only address allowed to specify the CalldataInterpreter address + // La seule adresse autorisée à spécifier l'adresse CalldataInterpreter address owner; - // The CalldataInterpreter address + // L'adresse CalldataInterpreter address proxy = address(0); ``` -Le contrat ERC-20 doit connaître l'identité du proxy autorisé. Cependant, nous ne pouvons pas définir cette variable dans le constructeur, car nous n'en connaissons pas encore la valeur. Ce contrat est instauré en premier car le proxy attend l'adresse du jeton dans son constructeur. +Le contrat ERC-20 doit connaître l'identité du mandataire autorisé. +Cependant, nous ne pouvons pas définir cette variable dans le constructeur, car nous n'en connaissons pas encore la valeur. +Ce contrat est instancié en premier car le mandataire attend l'adresse du jeton dans son constructeur. ```solidity /** - * @dev Calls the ERC20 constructor. + * @dev Appelle le constructeur ERC20. */ constructor( ) ERC20("Oris useless token-2", "OUT-2") { @@ -367,47 +402,50 @@ Le contrat ERC-20 doit connaître l'identité du proxy autorisé. Cependant, nou } ``` -L'adresse du créateur (appelé `owner`) est stockée ici car c'est la seule adresse autorisée à définir le proxy. +L'adresse du créateur (appelé `propriétaire`) est stockée ici car c'est la seule adresse autorisée à définir le mandataire. ```solidity /** - * @dev set the address for the proxy (the CalldataInterpreter). - * Can only be called once by the owner + * @dev définit l'adresse pour le mandataire (le CalldataInterpreter). + * Ne peut être appelé qu'une seule fois par le propriétaire */ function setProxy(address _proxy) external { - require(msg.sender == owner, "Can only be called by owner"); - require(proxy == address(0), "Proxy is already set"); + require(msg.sender == owner, "Ne peut être appelé que par le propriétaire"); + require(proxy == address(0), "Le mandataire est déjà défini"); proxy = _proxy; } // function setProxy ``` -Le proxy dispose d'un accès privilégié, car il peut contourner les contrôles de sécurité. Pour être sûr de pouvoir faire confiance au proxy, nous ne laissons que `le propriétaire` appeler cette fonction, et qu'une seule fois. Une fois que le `proxy` dispose d'une valeur réelle (pas zéro), cette valeur ne peut pas changer, donc même si le propriétaire décide de jouer au voyou, ou si l'élément mnémonique est révélé, nous restons en sécurité. +Le mandataire dispose d'un accès privilégié, car il peut contourner les contrôles de sécurité. +Pour être sûr de pouvoir faire confiance au mandataire, nous ne laissons que le `propriétaire` appeler cette fonction, et une seule fois. +Une fois que `proxy` a une valeur réelle (non nulle), cette valeur ne peut pas changer, donc même si le propriétaire décide de devenir malveillant, ou si la mnémonique pour celui-ci est révélée, nous sommes toujours en sécurité. ```solidity /** - * @dev Some functions may only be called by the proxy. + * @dev Certaines fonctions ne peuvent être appelées que par le mandataire. */ modifier onlyProxy { ``` -Ceci est une [fonction `modifier`](https://www.tutorialspoint.com/solidity/solidity_function_modifiers.htm), qui modifie la façon dont les autres fonctions marchent. +Ceci est une [fonction `modificatrice`](https://www.tutorialspoint.com/solidity/solidity_function_modifiers.htm), elle modifie le fonctionnement des autres fonctions. ```solidity require(msg.sender == proxy); ``` -Tout d'abord, vérifier que nous avons été appelés par le proxy et personne d'autre. Dans le cas contraire, `annuler`. +Tout d'abord, vérifiez que nous avons été appelés par le mandataire et personne d'autre. +Sinon, `revert`. ```solidity _; } ``` -Si c'est le cas, exécuter la fonction que nous modifions. +Si c'est le cas, exécutez la fonction que nous modifions. ```solidity - /* Functions that allow the proxy to actually proxy for accounts */ + /* Fonctions qui permettent au mandataire de servir de mandataire pour les comptes */ function transferProxy(address from, address to, uint256 amount) public virtual onlyProxy() returns (bool) @@ -436,17 +474,18 @@ Si c'est le cas, exécuter la fonction que nous modifions. } ``` -Il s'agit de trois opérations pour lesquelles le message doit normalement provenir directement de l'entité qui transfère les jetons ou approuve une allocation. Nous avons ici une version proxy de ces opérations qui : +Il s'agit de trois opérations qui nécessitent normalement que le message provienne directement de l'entité qui transfère les jetons ou qui approuve une allocation. +Nous avons ici une version mandataire de ces opérations qui : -1. Est modifiée par `onlyProxy()` afin que personne d'autre ne soit autorisé à les contrôler. +1. est modifiée par `onlyProxy()` afin que personne d'autre ne soit autorisé à les contrôler. 2. Récupère l'adresse qui serait normalement `msg.sender` en tant que paramètre supplémentaire. ### CalldataInterpreter.sol {#calldatainterpreter-sol-2} -L'interpréteur de données d'appel est presque identique à celui ci-dessus, à la différence que les fonctions proxy reçoivent un paramètre `msg.sender` et qu'il n'est pas nécessaire d'effectuer d'allocation pour le `transfert`. +L'interpréteur de données d'appel est presque identique à celui ci-dessus, à la différence que les fonctions mandatées reçoivent un paramètre `msg.sender` et qu'il n'est pas nécessaire d'effectuer d'allocation pour le `transfert`. ```solidity - // transfer (no need for allowance) + // transfert (pas besoin d'allocation) if (_func == 2) { token.transferProxy( msg.sender, @@ -455,7 +494,7 @@ L'interpréteur de données d'appel est presque identique à celui ci-dessus, à ); } - // approve + // approbation if (_func == 3) { token.approveProxy( msg.sender, @@ -486,21 +525,22 @@ await cdi.deployed() await token.setProxy(cdi.address) ``` -Nous devons indiquer au contrat ERC-20 à quel proxy faire confiance +Nous devons indiquer au contrat ERC-20 à quel mandataire faire confiance ```js -console.log("CalldataInterpreter addr:", cdi.address) +console.log("Adresse CalldataInterpreter :", cdi.address) -// Need two signers to verify allowances +// Besoin de deux signataires pour vérifier les allocations const signers = await ethers.getSigners() const signer = signers[0] const poorSigner = signers[1] ``` -Pour vérifier `approve()` et `transferFrom()`, nous avons besoin d'un second signataire. Nous l'appelons `poorSigner` car il ne récupère aucun de nos jetons (il a bien entendu besoin d'ETH). +Pour vérifier `approve()` et `transferFrom()`, nous avons besoin d'un second signataire. +Nous l'appelons `poorSigner` car il ne reçoit aucun de nos jetons (il doit bien sûr avoir de l'ETH). ```js -// Transfer tokens +// Transférer des jetons const destAddr = "0xf5a6ead936fb47f342bb63e676479bddf26ebe1d" const transferTx = { to: cdi.address, @@ -509,10 +549,10 @@ const transferTx = { await (await signer.sendTransaction(transferTx)).wait() ``` -Dans la mesure où le contrat ERC-20 fait confiance au proxy (`cdi`), nous n'avons pas besoin d'une allocation pour relayer les transferts. +Étant donné que le contrat ERC-20 fait confiance au mandataire (`cdi`), nous n'avons pas besoin d'une allocation pour relayer les transferts. ```js -// approval and transferFrom +// approbation et transferFrom const approveTx = { to: cdi.address, data: "0x03" + poorSigner.address.slice(2, 42) + "00FF", @@ -527,24 +567,19 @@ const transferFromTx = { } await (await poorSigner.sendTransaction(transferFromTx)).wait() -// Check the approve / transferFrom combo was done correctly +// Vérifier que la combinaison approbation / transferFrom a été effectuée correctement expect(await token.balanceOf(destAddr2)).to.equal(255) ``` -Tester les deux nouvelles fonctions. Notez que `transferFromTx` nécessite deux paramètres d'adresse : le donneur de l'allocation et le destinataire. +Tester les deux nouvelles fonctions. +Notez que `transferFromTx` nécessite deux paramètres d'adresse : le donneur de l'allocation et le destinataire. -### Exemple {#example-2} - -Si vous souhiatez voir ces fichiers en action sans les exécuter vous-même, suivez ces liens : +## Conclusion {#conclusion} -1. [Déploiement de `OrisUselessToken-2`](https://kovan-optimistic.etherscan.io/tx/1475397) à l'adresse [`0xb47c1f550d8af70b339970c673bbdb2594011696`](https://kovan-optimistic.etherscan.io/address/0xb47c1f550d8af70b339970c673bbdb2594011696). -2. [Déploiement de `CalldataInterpreter`](https://kovan-optimistic.etherscan.io/tx/1475400) à l'adresse [`0x0dccfd03e3aaba2f8c4ea4008487fd0380815892`](https://kovan-optimistic.etherscan.io/address/0x0dccfd03e3aaba2f8c4ea4008487fd0380815892). -3. [Appel de `setProxy()`](https://kovan-optimistic.etherscan.io/tx/1475402). -4. [Appel de `faucet()`](https://kovan-optimistic.etherscan.io/tx/1475409). -5. [Appel de `transferProxy()`](https://kovan-optimistic.etherscan.io/tx/1475416). -6. [Appel de `approveProxy()`](https://kovan-optimistic.etherscan.io/tx/1475419). -7. [Appel de `transferProxy()`](https://kovan-optimistic.etherscan.io/tx/1475421). Notez que cet appel provient d'une adresse différente des autres, `poorSigner` au lieu du `signer`. +[Optimism](https://medium.com/ethereum-optimism/the-road-to-sub-dollar-transactions-part-2-compression-edition-6bb2890e3e92) et [Arbitrum](https://developer.offchainlabs.com/docs/special_features) cherchent tous deux des moyens de réduire la taille des données d'appel écrites sur L1 et donc le coût des transactions. +Cependant, en tant que fournisseurs d'infrastructures à la recherche de solutions génériques, nos capacités sont limitées. +En tant que développeur de dapps, vous avez des connaissances spécifiques à l'application, ce qui vous permet d'optimiser vos données d'appel bien mieux que nous ne pourrions le faire avec une solution générique. +Nous espérons que cet article vous aidera à trouver la solution idéale pour vos besoins. -## Conclusion {#conclusion} +[Voir ici pour plus de mon travail](https://cryptodocguy.pro/). -[Optimism](https://medium.com/ethereum-optimism/the-road-to-sub-dollar-transactions-part-2-compression-edition-6bb2890e3e92) et [Arbitrum](https://developer.offchainlabs.com/docs/special_features) recherchent des moyens de réduire la taille des données d'appel écrites en L1 et donc le coût des transactions. Cependant, en tant que fournisseurs d'infrastructures pour des solutions génériques, nos capacités sont limitées. En tant que développeur dApp, vous avez des connaissances spécifiques concernant l'application, ce qui vous permet d'optimiser vos données d'appel bien mieux que nous ne pourrions le faire avec une solution générique. J'espère que cet article vous aidera à trouver la solution idéale pour vos besoins. diff --git a/public/content/translations/fr/developers/tutorials/smart-contract-security-guidelines/index.md b/public/content/translations/fr/developers/tutorials/smart-contract-security-guidelines/index.md index b84fbff256d..2e5d8d3c749 100644 --- a/public/content/translations/fr/developers/tutorials/smart-contract-security-guidelines/index.md +++ b/public/content/translations/fr/developers/tutorials/smart-contract-security-guidelines/index.md @@ -1,15 +1,12 @@ --- -title: Directives de sécurité pour les contrats intelligents -description: Une liste de contrôle des consignes de sécurité à prendre en compte lors de la création de votre DApp +title: "Directives de sécurité pour les contrats intelligents" +description: "Une liste de contrôle des consignes de sécurité à prendre en compte lors de la création de votre DApp" author: "Trailofbits" -tags: - - "solidity" - - "contrats intelligents" - - "sécurité" +tags: [ "solidité", "contrats intelligents", "sécurité" ] skill: intermediate lang: fr published: 2020-09-06 -source: Créer des contrats sécurisés +source: Building secure contracts sourceUrl: https://github.com/crytic/building-secure-contracts/blob/master/development-guidelines/guidelines.md --- @@ -23,72 +20,72 @@ La conception du contrat doit être discutée à l'avance, avant de rédiger une La documentation peut être écrite à différents niveaux et devrait être mise à jour lors de l'implémentation des contrats : -- **Une description simple du système en anglais**, décrivant ce que font les contrats et toutes hypothèses sur le code base. -- **Schéma et diagrammes architecturaux**, y compris les interactions contractuelles et la machine d'état du système. [Slither printers](https://github.com/crytic/slither/wiki/Printer-documentation) peut aider à générer ces schémas. -- **Documentation de code approfondi**, le [format Natspec](https://solidity.readthedocs.io/en/develop/natspec-format.html) peut être utilisé pour Solidity. +- **Une description simple du système**, décrivant ce que font les contrats et les hypothèses concernant la base de code. +- **Schémas et diagrammes d'architecture**, incluant les interactions entre contrats et la machine à états du système. [Les imprimantes de Slither](https://github.com/crytic/slither/wiki/Printer-documentation) peuvent vous aider à générer ces schémas. +- **Documentation de code approfondie**, le format [Natspec](https://docs.soliditylang.org/en/develop/natspec-format.html) peut être utilisé pour Solidity. -### Calcul On-chain vs Off-chain {#on-chain-vs-off-chain-computation} +### Calcul en chaîne ou hors chaîne {#onchain-vs-offchain-computation} -- **Conserver le plus de code que vous pouvez hors chaîne.** Garder la couche en chaîne petite. Pré-traiter les données avec du code hors chaîne de telle façon que la vérification en chaîne soit simple. Avez-vous besoin d'une liste ordonnée ? Trier la liste hors chaîne, puis ne vérifier que son ordre en chaîne. +- **Gardez autant de code que possible hors chaîne.** Gardez la couche en chaîne de petite taille. Prétraitez les données avec du code hors chaîne de manière à ce que la vérification en chaîne soit simple. Avez-vous besoin d'une liste ordonnée ? Trier la liste hors chaîne, puis ne vérifier que son ordre en chaîne. -### Mise à jour {#upgradeability} +### Évolutivité {#upgradeability} -Nous avons discuté des différentes solutions de mise à niveau dans [notre blogpost](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/). Faites un choix délibéré de prendre en charge la possibilité de mise à niveau ou non avant de rédiger un code. La décision influencera la façon dont vous structurerez notre code. En général, nous recommandons : +Nous avons abordé les différentes solutions d'évolutivité dans [notre article de blog](https://blog.trailofbits.com/2018/09/05/contract-upgrade-anti-patterns/). Faites un choix délibéré de prendre en charge la possibilité de mise à niveau ou non avant de rédiger un code. La décision influencera la façon dont vous structurerez notre code. En général, nous recommandons : -- **Favoriser [la migration de contract](https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/) plutôt que la mise à niveau.** Le système de migration présente bon nombre des mêmes avantages que l'évolutif, sans ses inconvénients. -- **Utilisation du modèle de séparation des données par rapport à celui du delegatecallproxy.** Si votre projet a une séparation d'abstraction claire, la possibilité de mise à niveau à l'aide de la séparation des données ne nécessitera que quelques ajustements. Le delegatecallproxy nécessite une expertise EVM et est très exposé aux erreurs. -- **Documentez la procédure de migration/mise à niveau avant le déploiement.** Si vous devez réagir sous pression sans aucune instructions, vous ferez des erreurs. Écrivez la procédure à suivre à l'avance. Cela devrait inclure : +- **Privilégiez la [migration de contrat](https://blog.trailofbits.com/2018/10/29/how-contract-migration-works/) plutôt que l'évolutivité.** Les systèmes de migration présentent bon nombre des mêmes avantages que les systèmes évolutifs, sans leurs inconvénients. +- **Utilisez le modèle de séparation des données plutôt que celui de delegatecallproxy.** Si votre projet présente une séparation claire de l'abstraction, l'évolutivité utilisant la séparation des données ne nécessitera que quelques ajustements. Le delegatecallproxy nécessite une expertise EVM et est très exposé aux erreurs. +- **Documentez la procédure de migration/mise à niveau avant le déploiement.** Si vous devez réagir dans l'urgence sans directives, vous ferez des erreurs. Écrivez la procédure à suivre à l'avance. Cela devrait inclure : - Les appels qui initient les nouveaux contrats - Où sont stockées les clés et comment y accéder - Comment vérifier le déploiement ! Développez et testez un script de post-déploiement. -## Directives d'exécution {#implementation-guidelines} +## Directives d'implémentation {#implementation-guidelines} -**Opter pour la simplicité.** Utilisez toujours la solution la plus simple qui correspond à votre but. Tout membre de votre équipe devrait être en mesure de comprendre votre solution. +**Recherchez la simplicité.** Utilisez toujours la solution la plus simple et adaptée à votre objectif. Tout membre de votre équipe devrait être en mesure de comprendre votre solution. -### Composition de la fonction {#function-composition} +### Composition de fonctions {#function-composition} L'architecture de votre code de base devrait rendre votre code facile à vérifier. Évitez les choix architecturaux qui réduisent la capacité à raisonner sur son exactitude. -- **Séparer la logique de votre système**, soit par des contrats multiples, soit en regroupant des fonctions similaires (par exemple, authentification, arithmétique, ...). -- **Écrire de petites fonctions, avec un objectif clair.** Cela facilitera la révision et permettra le test de composantes individuelles. +- **Divisez la logique de votre système**, soit à travers plusieurs contrats, soit en regroupant des fonctions similaires (par exemple, l'authentification, l'arithmétique, etc.). +- **Écrivez des fonctions courtes avec un objectif clair.** Cela facilitera la revue et permettra de tester les composants individuels. ### Héritage {#inheritance} -- **Gardez l'héritage gérable.** L'héritage doit être utilisé pour diviser la logique, cependant, votre projet devrait viser à minimiser la profondeur et la largeur de l'arbre d'héritage. -- **Utilisez l'imprimante [d'héritage de Slither](https://github.com/crytic/slither/wiki/Printer-documentation#inheritance-graph) pour vérifier la hiérarchie des contrats.** L'imprimante d'héritage vous aidera à revoir la taille de la hiérarchie. +- **Maintenez l'héritage gérable.** L'héritage doit être utilisé pour diviser la logique, cependant, votre projet doit viser à minimiser la profondeur et la largeur de l'arborescence d'héritage. +- **Utilisez l'[imprimante d'héritage](https://github.com/crytic/slither/wiki/Printer-documentation#inheritance-graph) de Slither pour vérifier la hiérarchie des contrats.** L'imprimante d'héritage vous aidera à examiner la taille de la hiérarchie. ### Événements {#events} -- **Enregistre toutes les opérations cruciales.** Les événements aideront à déboguer le contrat pendant le développement, et à le surveiller après le déploiement. +- **Journalisez toutes les opérations cruciales.** Les événements vous aideront à déboguer le contrat pendant le développement et à le surveiller après le déploiement. -### Éviter les pièges connus {#avoid-known-pitfalls} +### Évitez les pièges connus {#avoid-known-pitfalls} -- **Soyez conscient des problèmes de sécurité les plus courants.** Il existe beaucoup de ressources en ligne à apprendre sur les problèmes communs, tels que [Ethernaut CTF](https://ethernaut.openzeppelin.com/), [Capturez l'Ether](https://capturetheether.com/), ou [Les contrats Not-so-smart](https://github.com/crytic/not-so-smart-contracts/). -- **Soyez conscient des sections d'avertissements dans la [documentation Solidity](https://solidity.readthedocs.io/en/latest/).** Les sections d'avertissements vous informeront du comportement non-évident du langage. +- **Soyez conscient des problèmes de sécurité les plus courants.** Il existe de nombreuses ressources en ligne pour en apprendre davantage sur les problèmes courants, telles que [Ethernaut CTF](https://ethernaut.openzeppelin.com/), [Capture the Ether](https://capturetheether.com/) ou [Not so smart contracts](https://github.com/crytic/not-so-smart-contracts/). +- **Prenez connaissance des sections d'avertissement dans la [documentation de Solidity](https://docs.soliditylang.org/en/latest/).** Les sections d'avertissement vous informeront sur les comportements non évidents du langage. ### Dépendances {#dependencies} -- **Utilisez des bibliothèques logicielles bien testées.** Importer du code depuis des bibliothèques bien testées réduira la probabilité d'écrire du code bogué. Si vous voulez écrire un contrat ERC20, utilisez [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20). -- **Utilisez un dependency manager; évitez le code copier-coller** Si vous comptez sur une source externe, vous devez la tenir à jour avec la source originale. +- **Utilisez des bibliothèques bien testées.** L'importation de code à partir de bibliothèques bien testées réduira la probabilité d'écrire du code bogué. Si vous voulez écrire un contrat ERC20, utilisez [OpenZeppelin](https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC20). +- **Utilisez un gestionnaire de dépendances ; évitez de copier-coller du code.** Si vous dépendez d'une source externe, vous devez la maintenir à jour par rapport à la source d'origine. -### Tests et vérification {#testing-and-verification} +### Test et vérification {#testing-and-verification} -- **Écrivez des tests unitaires approfondis.** Une suite de tests étendue est cruciale pour construire des logiciels de haute qualité. -- **Écrivez [Slither](https://github.com/crytic/slither), [Echidna](https://github.com/crytic/echidna) et [Manticore](https://github.com/trailofbits/manticore) vérifications et propriétés personnalisées.** Des outils automatisés vous aideront à sécuriser votre contrat. Examinez le reste de ce guide pour savoir comment écrire des vérifications et des propriétés efficaces. -- **Utilisez [crytic.io](https://crytic.io/).** Crytic intégré avec GitHub, fournit un accès aux détecteurs privés de Slither et effectue des vérifications de propriétés personnalisées depuis Echidna. +- **Rédigez des tests unitaires approfondis.** Une suite de tests complète est essentielle pour créer un logiciel de haute qualité. +- **Rédigez des vérifications et des propriétés personnalisées pour [Slither](https://github.com/crytic/slither), [Echidna](https://github.com/crytic/echidna) et [Manticore](https://github.com/trailofbits/manticore).** Les outils automatisés vous aideront à garantir la sécurité de votre contrat. Examinez le reste de ce guide pour savoir comment écrire des vérifications et des propriétés efficaces. +- **Utilisez [crytic.io](https://crytic.io/).** Crytic s'intègre à GitHub, fournit un accès à des détecteurs Slither privés et exécute des vérifications de propriétés personnalisées à partir d'Echidna. ### Solidity {#solidity} -- **Favoriser Solidity 0.5 plutôt que 0.4 et 0.6.** Selon nous, Solidity 0.5 est plus sécurisée et a de meilleures pratiques intégrées que 0.4. Solidity 0.6 s'est révélée trop instable pour la production et a besoin de temps pour se développer. -- **Utilisez une version stable pour la compilation ; utilisez la dernière version pour vérifier les avertissements.** Vérifiez que votre code n'a aucun problème rapporté avec la dernière version du compilateur. Cependant, Solidity a un cycle de publication rapide et a un historique de bogues du compilateur, donc nous ne recommandons pas la dernière version pour le déploiement (voir la [recommandation de version solc](https://github.com/crytic/slither/wiki/Detector-Documentation#recommendation-33) de Slither ). -- **N'utilisez pas d'assemblage Inline.** L'assemblage nécessite une expertise EVM. N'écrivez pas de code EVM si vous n'avez pas maîtrisé _le Livre jaune_. +- **Privilégiez Solidity 0.5 par rapport aux versions 0.4 et 0.6.** À notre avis, Solidity 0.5 est plus sécurisé et intègre de meilleures pratiques que la version 0.4. Solidity 0.6 s'est révélée trop instable pour la production et a besoin de temps pour se développer. +- **Utilisez une version stable pour la compilation ; utilisez la dernière version pour vérifier les avertissements.** Vérifiez que votre code ne présente aucun problème signalé avec la dernière version du compilateur. Cependant, Solidity a un cycle de publication rapide et un historique de bogues du compilateur, nous ne recommandons donc pas la dernière version pour le déploiement (voir la [recommandation de version solc](https://github.com/crytic/slither/wiki/Detector-Documentation#recommendation-33) de Slither). +- **N'utilisez pas l'assembly en ligne.** L'assembly nécessite une expertise de l'EVM. N'écrivez pas de code EVM si vous ne _maîtrisez_ pas le Livre jaune. ## Directives de déploiement {#deployment-guidelines} Une fois le contrat développé et déployé : -- **Surveillez vos contrats.** Surveillez les logs et soyez prêt à réagir en cas de contrat ou de portefeuille compromis. -- **Ajoutez vos informations de contact à [blockchain-security-contacts](https://github.com/crytic/blockchain-security-contacts).** Cette liste aide des tiers à vous contacter si une faille de sécurité est découverte. -- **Sécurisez les portefeuilles d'utilisateurs privilégiés.** Suivez nos [meilleures pratiques](https://blog.trailofbits.com/2018/11/27/10-rules-for-the-secure-use-of-cryptocurrency-hardware-wallets/) si vous stockez des clés dans des hardware wallets. -- **Ayez une réponse au plan d'incident.** Considérez que vos contrats intelligents peuvent être compromis. Même si vos contrats sont exempts de bogues, un attaquant peut prendre le contrôle des clés du propriétaire du contrat. +- **Surveillez vos contrats.** Surveillez les journaux et soyez prêt à réagir en cas de compromission d'un contrat ou d'un portefeuille. +- **Ajoutez vos coordonnées à [blockchain-security-contacts](https://github.com/crytic/blockchain-security-contacts).** Cette liste aide les tierces parties à vous contacter si une faille de sécurité est découverte. +- **Sécurisez les portefeuilles des utilisateurs à privilèges.** Suivez nos [meilleures pratiques](https://blog.trailofbits.com/2018/11/27/10-rules-for-the-secure-use-of-cryptocurrency-hardware-wallets/) si vous stockez des clés dans des portefeuilles matériels. +- **Ayez un plan d'intervention en cas d'incident.** Tenez compte du fait que vos contrats intelligents peuvent être compromis. Même si vos contrats sont exempts de bogues, un attaquant peut prendre le contrôle des clés du propriétaire du contrat. diff --git a/public/content/translations/fr/developers/tutorials/stealth-addr/index.md b/public/content/translations/fr/developers/tutorials/stealth-addr/index.md new file mode 100644 index 00000000000..b84c3087e17 --- /dev/null +++ b/public/content/translations/fr/developers/tutorials/stealth-addr/index.md @@ -0,0 +1,443 @@ +--- +title: "Utilisation des adresses furtives" +description: "Les adresses furtives permettent aux utilisateurs de transférer des actifs de manière anonyme. Après avoir lu cet article, vous serez en mesure de : expliquer ce que sont les adresses furtives et comment elles fonctionnent, comprendre comment utiliser les adresses furtives d'une manière qui préserve l'anonymat et écrire une application web qui utilise des adresses furtives." +author: Ori Pomerantz +tags: + [ + "Adresse furtive", + "confidentialité", + "cryptographie", + "rust", + "wasm" + ] +skill: intermediate +published: 2025-11-30 +lang: fr +sidebarDepth: 3 +--- + +Vous êtes Bill. Pour des raisons que nous n'aborderons pas, vous voulez faire un don à la campagne "Alice pour la Reine du Monde" et que Alice sache que vous avez fait un don afin qu'elle vous récompense si elle gagne. Malheureusement, sa victoire n'est pas garantie. Il existe une campagne concurrente, "Carol pour l'Impératrice du Système solaire". Si Carol gagne et qu'elle découvre que vous avez fait un don à Alice, vous aurez des ennuis. Vous ne pouvez donc pas simplement transférer 200 ETH de votre compte à celui d'Alice. + +[ERC-5564](https://eips.ethereum.org/EIPS/eip-5564) apporte la solution. Cet ERC explique comment utiliser les [adresses furtives](https://nerolation.github.io/stealth-utils) pour un transfert anonyme. + +**Avertissement** : La cryptographie derrière les adresses furtives est, à notre connaissance, solide. Cependant, il existe des attaques potentielles par canal auxiliaire. [Ci-dessous](#go-wrong), vous verrez ce que vous pouvez faire pour réduire ce risque. + +## Comment fonctionnent les adresses furtives {#how} + +Cet article tentera d'expliquer les adresses furtives de deux manières. La première est [comment les utiliser](#how-use). Cette partie est suffisante pour comprendre le reste de l'article. Ensuite, il y a [une explication des mathématiques sous-jacentes](#how-math). Si la cryptographie vous intéresse, lisez également cette partie. + +### La version simple (comment utiliser les adresses furtives) {#how-use} + +Alice crée deux clés privées et publie les clés publiques correspondantes (qui peuvent être combinées en une seule méta-adresse de double longueur). Bill crée également une clé privée et publie la clé publique correspondante. + +En utilisant la clé publique d'une partie et la clé privée de l'autre, vous pouvez dériver un secret partagé connu uniquement d'Alice et de Bill (il ne peut pas être dérivé des seules clés publiques). À l'aide de ce secret partagé, Bill obtient l'adresse furtive et peut y envoyer des actifs. + +Alice obtient également l'adresse à partir du secret partagé, mais comme elle connaît les clés privées des clés publiques qu'elle a publiées, elle peut également obtenir la clé privée qui lui permet de retirer des fonds de cette adresse. + +### Les mathématiques (pourquoi les adresses furtives fonctionnent de cette manière) {#how-math} + +Les adresses furtives standard utilisent la [cryptographie sur les courbes elliptiques (ECC)](https://blog.cloudflare.com/a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography/#elliptic-curves-building-blocks-of-a-better-trapdoor) pour obtenir de meilleures performances avec moins de bits de clé, tout en conservant le même niveau de sécurité. Mais pour la plupart, nous pouvons ignorer cela et prétendre que nous utilisons l'arithmétique ordinaire. + +Il y a un nombre que tout le monde connaît, _G_. Vous pouvez multiplier par _G_. Mais en raison de la nature de l'ECC, il est pratiquement impossible de diviser par _G_. La façon dont la cryptographie à clé publique fonctionne généralement dans Ethereum est que vous pouvez utiliser une clé privée, _Ppriv_, pour signer des transactions qui sont ensuite vérifiées par une clé publique, _Ppub = GPpriv_. + +Alice crée deux clés privées, _Kpriv_ et _Vpriv_. _Kpriv_ sera utilisée pour dépenser l'argent de l'adresse furtive, et _Vpriv_ pour voir les adresses qui appartiennent à Alice. Alice publie ensuite les clés publiques : _Kpub = GKpriv_ et _Vpub = GVpriv_ + +Bill crée une troisième clé privée, _Rpriv_, et publie _Rpub = GRpriv_ dans un registre central (Bill aurait pu aussi l'envoyer à Alice, mais nous supposons que Carol écoute). + +Bill calcule _RprivVpub = GRprivVpriv_, ce qu'il s'attend à ce qu'Alice sache aussi (expliqué ci-dessous). Cette valeur est appelée _S_, le secret partagé. Ceci donne à Bill une clé publique, _Ppub = Kpub+G\*hachage(S)_. À partir de cette clé publique, il peut calculer une adresse et y envoyer toutes les ressources qu'il souhaite. À l'avenir, si Alice gagne, Bill peut lui communiquer _Rpriv_ pour prouver que les ressources proviennent de lui. + +Alice calcule _RpubVpriv = GRprivVpriv_. Ceci lui donne le même secret partagé, _S_. Comme elle connaît la clé privée, _Kpriv_, elle peut calculer _Ppriv = Kpriv+hachage(S)_. Cette clé lui permet d'accéder aux actifs dans l'adresse qui résulte de _Ppub = GPpriv = GKpriv+G\*hachage(S) = Kpub+G\*hachage(S)_. + +Nous avons une clé de visualisation distincte pour permettre à Alice de sous-traiter aux services de campagne de domination mondiale de Dave. Alice est prête à faire connaître à Dave les adresses publiques et à l'informer lorsque plus d'argent est disponible, mais elle ne veut pas qu'il dépense l'argent de sa campagne. + +Parce que la visualisation et la dépense utilisent des clés distinctes, Alice peut donner à Dave _Vpriv_. Alors Dave peut calculer _S = RpubVpriv = GRprivVpriv_ et de cette façon obtenir les clés publiques (_Ppub = Kpub+G\*hachage(S)_). Mais sans _Kpriv_, Dave ne peut pas obtenir la clé privée. + +Pour résumer, voici les valeurs connues des différents participants. + +| Alice | Publié | Bill | Dave | | +| ------------------------------------------------------------------------- | ----------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------- | +| G | G | G | G | | +| _Kpriv_ | – | – | – | | +| _Vpriv_ | – | – | _Vpriv_ | | +| _Kpub = GKpriv_ | _Kpub_ | _Kpub_ | _Kpub_ | | +| _Vpub = GVpriv_ | _Vpub_ | _Vpub_ | _Vpub_ | | +| – | – | _Rpriv_ | – | | +| _Rpub_ | _Rpub_ | _Rpub = GRpriv_ | _Rpub_ | | +| _S = RpubVpriv = GRprivVpriv_ | – | _S = RprivVpub = GRprivVpriv_ | _S = _RpubVpriv_ = GRprivVpriv_ | | +| _Ppub = Kpub+G\*hachage(S)_ | – | _Ppub = Kpub+G\*hachage(S)_ | _Ppub = Kpub+G\*hachage(S)_ | | +| _Adresse=f(Ppub)_ | – | _Adresse=f(Ppub)_ | _Adresse=f(Ppub)_ | _Adresse=f(Ppub)_ | +| _Ppriv = Kpriv+hachage(S)_ | – | – | – | | + +## Quand les adresses furtives tournent mal {#go-wrong} + +_Il n'y a pas de secrets sur la blockchain_. Bien que les adresses furtives puissent vous offrir une certaine confidentialité, cette confidentialité est sensible à l'analyse du trafic. Pour prendre un exemple trivial, imaginez que Bill finance une adresse et envoie immédiatement une transaction pour publier une valeur _Rpub_. Sans le _Vpriv_ d'Alice, nous ne pouvons pas être sûrs qu'il s'agit d'une adresse furtive, mais c'est le pari à faire. Ensuite, nous voyons une autre transaction qui transfère tous les ETH de cette adresse vers l'adresse du fonds de campagne d'Alice. Nous ne pourrons peut-être pas le prouver, mais il est probable que Bill vient de faire un don à la campagne d'Alice. Carol le penserait certainement. + +Il est facile pour Bill de séparer la publication de _Rpub_ du financement de l'adresse furtive (en les faisant à des moments différents, à partir d'adresses différentes). Cependant, cela est insuffisant. Le schéma que Carol recherche est que Bill finance une adresse, et qu'ensuite le fonds de campagne d'Alice retire des fonds de celle-ci. + +Une solution consiste à ce que la campagne d'Alice ne retire pas l'argent directement, mais l'utilise pour payer un tiers. Si la campagne d'Alice envoie 10 ETH aux services de campagne de domination mondiale de Dave, Carol sait seulement que Bill a fait un don à l'un des clients de Dave. Si Dave a suffisamment de clients, Carol ne serait pas en mesure de savoir si Bill a fait un don à Alice, qui est sa concurrente, ou à Adam, Albert ou Abigail dont Carol se moque. Alice peut inclure une valeur de hachage avec le paiement, puis fournir à Dave la pré-image, pour prouver que c'était bien son don. Alternativement, comme indiqué ci-dessus, si Alice donne à Dave son _Vpriv_, il sait déjà de qui provient le paiement. + +Le principal problème de cette solution est qu'elle exige qu'Alice se soucie du secret alors que ce secret profite à Bill. Alice peut vouloir maintenir sa réputation afin que l'ami de Bill, Bob, fasse également un don. Mais il est aussi possible qu'elle n'hésite pas à dénoncer Bill, car il aura alors peur de ce qui arrivera si Carol gagne. Bill pourrait finir par apporter encore plus de soutien à Alice. + +### Utilisation de plusieurs couches furtives {#multi-layer} + +Au lieu de compter sur Alice pour préserver la vie privée de Bill, Bill peut le faire lui-même. Il peut générer plusieurs méta-adresses pour des personnages de fiction, Bob et Bella. Bill envoie ensuite des ETH à Bob, et « Bob » (qui est en fait Bill) les envoie à Bella. « Bella » (également Bill) les envoie à Alice. + +Carol peut toujours faire une analyse du trafic et voir le pipeline Bill-Bob-Bella-Alice. Cependant, si « Bob » et « Bella » utilisent également des ETH à d'autres fins, il n'apparaîtra pas que Bill ait transféré quoi que ce soit à Alice, même si Alice retire immédiatement de l'adresse furtive vers l'adresse connue de sa campagne. + +## Écrire une application d'adresse furtive {#write-app} + +Cet article explique une application d'adresse furtive [disponible sur GitHub](https://github.com/qbzzt/251022-stealth-addresses.git). + +### Outils {#tools} + +Il existe [une bibliothèque d'adresses furtives typescript](https://github.com/ScopeLift/stealth-address-sdk) que nous pourrions utiliser. Cependant, les opérations cryptographiques peuvent être gourmandes en ressources de l'unité centrale. Je préfère les implémenter dans un langage compilé, tel que [Rust](https://rust-lang.org/), et utiliser [WASM](https://webassembly.org/) pour exécuter le code dans le navigateur. + +Nous allons utiliser [Vite](https://vite.dev/) et [React](https://react.dev/). Ce sont des outils standard de l'industrie ; si vous ne les connaissez pas, vous pouvez utiliser [ce tutoriel](/developers/tutorials/creating-a-wagmi-ui-for-your-contract/). Pour utiliser Vite, nous avons besoin de Node. + +### Voir les adresses furtives en action {#in-action} + +1. Installez les outils nécessaires : [Rust](https://rust-lang.org/tools/install/) et [Node](https://nodejs.org/en/download). + +2. Clonez le dépôt GitHub. + + ```sh + git clone https://github.com/qbzzt/251022-stealth-addresses.git + cd 251022-stealth-addresses + ``` + +3. Installez les prérequis et compilez le code Rust. + + ```sh + cd src/rust-wasm + rustup target add wasm32-unknown-unknown + cargo install wasm-pack + wasm-pack build --target web + ``` + +4. Démarrez le serveur web. + + ```sh + cd ../.. + npm install + npm run dev + ``` + +5. Accédez à [l'application](http://localhost:5173/). Cette page d'application comporte deux cadres : l'un pour l'interface utilisateur d'Alice et l'autre pour celle de Bill. Les deux cadres ne communiquent pas ; ils ne sont sur la même page que pour des raisons de commodité. + +6. En tant qu'Alice, cliquez sur **Generate a Stealth Meta-Address**. Cela affichera la nouvelle adresse furtive et les clés privées correspondantes. Copiez la méta-adresse furtive dans le presse-papiers. + +7. En tant que Bill, collez la nouvelle méta-adresse furtive et cliquez sur **Generate an address**. Cela vous donne l'adresse à financer pour Alice. + +8. Copiez l'adresse et la clé publique de Bill et collez-les dans la zone "Clé privée pour l'adresse générée par Bill" de l'interface utilisateur d'Alice. Une fois ces champs remplis, vous verrez la clé privée pour accéder aux actifs à cette adresse. + +9. Vous pouvez utiliser [un calculateur en ligne](https://iancoleman.net/ethereum-private-key-to-address/) pour vous assurer que la clé privée correspond à l'adresse. + +### Comment le programme fonctionne {#how-the-program-works} + +#### Le composant WASM {#wasm} + +Le code source qui se compile en WASM est écrit en [Rust](https://rust-lang.org/). Vous pouvez le voir dans [`src/rust_wasm/src/lib.rs`](https://github.com/qbzzt/251022-stealth-addresses/blob/main/src/rust-wasm/src/lib.rs). Ce code est principalement une interface entre le code JavaScript et [la bibliothèque `eth-stealth-addresses`](https://github.com/kassandraoftroy/eth-stealth-addresses). + +**`Cargo.toml`** + +[`Cargo.toml`](https://doc.rust-lang.org/cargo/reference/manifest.html) en Rust est analogue à [`package.json`](https://docs.npmjs.com/cli/v9/configuring-npm/package-json) en JavaScript. Il contient les informations sur le paquet, les déclarations de dépendance, etc. + +```toml +[package] +name = "rust-wasm" +version = "0.1.0" +edition = "2024" + +[dependencies] +eth-stealth-addresses = "0.1.0" +hex = "0.4.3" +wasm-bindgen = "0.2.104" +getrandom = { version = "0.2", features = ["js"] } +``` + +Le paquet [`getrandom`](https://docs.rs/getrandom/latest/getrandom/) doit générer des valeurs aléatoires. Cela ne peut pas être fait par des moyens purement algorithmiques ; cela nécessite l'accès à un processus physique comme source d'entropie. Cette définition spécifie que nous obtiendrons cette entropie en interrogeant le navigateur dans lequel nous nous exécutons. + +```toml +console_error_panic_hook = "0.1.7" +``` + +[Cette bibliothèque](https://docs.rs/console_error_panic_hook/latest/console_error_panic_hook/) nous donne des messages d'erreur plus significatifs lorsque le code WASM panique et ne peut pas continuer. + +```toml +[lib] +crate-type = ["cdylib", "rlib"] +``` + +Le type de sortie requis pour produire du code WASM. + +**`lib.rs`** + +Ceci est le vrai code Rust. + +```rust +use wasm_bindgen::prelude::*; +``` + +Les définitions pour créer un paquet WASM à partir de Rust. Elles sont documentées [ici](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/index.html). + +```rust +use eth_stealth_addresses::{ + generate_stealth_meta_address, + generate_stealth_address, + compute_stealth_key +}; +``` + +Les fonctions dont nous avons besoin de [la bibliothèque `eth-stealth-addresses`](https://github.com/kassandraoftroy/eth-stealth-addresses). + +```rust +use hex::{decode,encode}; +``` + +Rust utilise généralement des [tableaux](https://doc.rust-lang.org/std/primitive.array.html) d'octets (`[u8; ]`) pour les valeurs. Mais en JavaScript, nous utilisons généralement des chaînes de caractères hexadécimales. [La bibliothèque `hex`](https://docs.rs/hex/latest/hex/) traduit pour nous d'une représentation à l'autre. + +```rust +#[wasm_bindgen] +``` + +Générer des liaisons WASM pour pouvoir appeler cette fonction depuis JavaScript. + +```rust +pub fn wasm_generate_stealth_meta_address() -> String { +``` + +La manière la plus simple de renvoyer un objet avec plusieurs champs est de renvoyer une chaîne JSON. + +```rust + let (address, spend_private_key, view_private_key) = + generate_stealth_meta_address(); +``` + +La [`generate_stealth_meta_address`](https://docs.rs/eth-stealth-addresses/latest/eth_stealth_addresses/fn.generate_stealth_meta_address.html) renvoie trois champs : + +- La méta-adresse (_Kpub_ et _Vpub_) +- La clé privée de visualisation (_Vpriv_) +- La clé privée de dépense (_Kpriv_) + +La syntaxe [tuple](https://doc.rust-lang.org/std/primitive.tuple.html) nous permet de séparer à nouveau ces valeurs. + +```rust + format!("{{\"address\":\"{}\",\"view_private_key\":\"{}\",\"spend_private_key\":\"{}\"}}", + encode(address), + encode(view_private_key), + encode(spend_private_key) + ) +} +``` + +Utilisez la macro [`format!`](https://doc.rust-lang.org/std/fmt/index.html) pour générer la chaîne codée en JSON. Utilisez [`hex::encode`](https://docs.rs/hex/latest/hex/fn.encode.html) pour transformer les tableaux en chaînes hexadécimales. + +```rust +fn str_to_array(s: &str) -> Option<[u8; N]> { +``` + +Cette fonction transforme une chaîne hexadécimale (fournie par JavaScript) en un tableau d'octets. Nous l'utilisons pour analyser les valeurs fournies par le code JavaScript. Cette fonction est compliquée en raison de la façon dont Rust gère les tableaux et les vecteurs. + +L'expression `` est appelée une [générique](https://doc.rust-lang.org/book/ch10-01-syntax.html). `N` est un paramètre qui contrôle la longueur du tableau retourné. La fonction est en fait appelée `str_to_array::`, où `n` est la longueur du tableau. + +La valeur de retour est `Option<[u8; N]>`, ce qui signifie que le tableau retourné est [facultatif](https://doc.rust-lang.org/std/option/). C'est un modèle typique en Rust pour les fonctions qui peuvent échouer. + +Par exemple, si nous appelons `str_to_array::10("bad060a7")`, la fonction est censée renvoyer un tableau de dix valeurs, mais l'entrée n'est que de quatre octets. La fonction doit échouer, et elle le fait en renvoyant `None`. La valeur de retour pour `str_to_array::4("bad060a7")` serait `Some<[0xba, 0xd0, 0x60, 0xa7]>`. + +```rust + // decode renvoie Result, _> + let vec = decode(s).ok()?; +``` + +La fonction [`hex::decode`](https://docs.rs/hex/latest/hex/fn.decode.html) renvoie un `Result, FromHexError>`. Le type [`Result`](https://doc.rust-lang.org/std/result/) peut contenir soit un résultat réussi (`Ok(valeur)`) soit une erreur (`Err(erreur)`). + +La méthode `.ok()` transforme le `Result` en une `Option`, dont la valeur est soit la valeur `Ok()` en cas de succès, soit `None` dans le cas contraire. Enfin, [l'opérateur point d'interrogation](https://doc.rust-lang.org/std/option/#the-question-mark-operator-) interrompt les fonctions actuelles et renvoie un `None` si l'`Option` est vide. Sinon, il déballe la valeur et la renvoie (dans ce cas, pour assigner une valeur à `vec`). + +Cela ressemble à une méthode étrangement alambiquée pour gérer les erreurs, mais `Result` et `Option` garantissent que toutes les erreurs sont gérées, d'une manière ou d'une autre. + +```rust + if vec.len() != N { return None; } +``` + +Si le nombre d'octets est incorrect, c'est un échec, et nous retournons `None`. + +```rust + // try_into consomme vec et tente de créer [u8; N] + let array: [u8; N] = vec.try_into().ok()?; +``` + +Rust a deux types de tableaux. Les [tableaux](https://doc.rust-lang.org/std/primitive.array.html) ont une taille fixe. Les [vecteurs](https://doc.rust-lang.org/std/vec/index.html) peuvent s'agrandir et se réduire. `hex::decode` renvoie un vecteur, mais la bibliothèque `eth_stealth_addresses` veut recevoir des tableaux. [`.try_into()`](https://doc.rust-lang.org/std/convert/trait.TryInto.html#required-methods) convertit une valeur en un autre type, par exemple, un vecteur en un tableau. + +```rust + Some(array) +} +``` + +Rust ne vous oblige pas à utiliser le mot-clé [`return`](https://doc.rust-lang.org/std/keyword.return.html) lorsque vous retournez une valeur à la fin d'une fonction. + +```rust +#[wasm_bindgen] +pub fn wasm_generate_stealth_address(stealth_address: &str) -> Option { +``` + +Cette fonction reçoit une méta-adresse publique, qui inclut à la fois _Vpub_ et _Kpub_. Elle renvoie l'adresse furtive, la clé publique à publier (_Rpub_), et une valeur d'analyse d'un octet qui accélère l'identification des adresses publiées qui peuvent appartenir à Alice. + +La valeur de l'analyse fait partie du secret partagé (_S = GRprivVpriv_). Cette valeur est disponible pour Alice, et sa vérification est beaucoup plus rapide que de vérifier si _f(Kpub+G\*hachage(S))_ est égal à l'adresse publiée. + +```rust + let (address, r_pub, scan) = + generate_stealth_address(&str_to_array::<66>(stealth_address)?); +``` + +Nous utilisons la fonction [`generate_stealth_address`](https://docs.rs/eth-stealth-addresses/latest/eth_stealth_addresses/fn.generate_stealth_address.html) de la bibliothèque. + +```rust + format!("{{\"address\":\"{}\",\"rPub\":\"{}\",\"scan\":\"{}\"}}", + encode(address), + encode(r_pub), + encode(&[scan]) + ).into() +} +``` + +Préparer la chaîne de sortie codée en JSON. + +```rust +#[wasm_bindgen] +pub fn wasm_compute_stealth_key( + address: &str, + bill_pub_key: &str, + view_private_key: &str, + spend_private_key: &str +) -> Option { + . + . + . +} +``` + +Cette fonction utilise la fonction [`compute_stealth_key`](https://docs.rs/eth-stealth-addresses/latest/eth_stealth_addresses/fn.compute_stealth_key.html) de la bibliothèque pour calculer la clé privée permettant de retirer des fonds de l'adresse (_Rpriv_). Ce calcul nécessite ces valeurs : + +- L'adresse (_Adresse=f(Ppub)_) +- La clé publique générée par Bill (_Rpub_) +- La clé privée de visualisation (_Vpriv_) +- La clé privée de dépense (_Kpriv_) + +```rust +#[wasm_bindgen(start)] +``` + +[`#[wasm_bindgen(start)]`](https://wasm-bindgen.github.io/wasm-bindgen/reference/attributes/on-rust-exports/start.html) spécifie que la fonction est exécutée lorsque le code WASM est initialisé. + +```rust +pub fn main() { + console_error_panic_hook::set_once(); +} +``` + +Ce code spécifie que la sortie de la panique soit envoyée à la console JavaScript. Pour le voir en action, utilisez l'application et donnez à Bill une méta-adresse invalide (il suffit de changer un chiffre hexadécimal). Vous verrez cette erreur dans la console JavaScript : + +``` +rust_wasm.js:236 panicked at /home/ori/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/subtle-2.6.1/src/lib.rs:701:9: +assertion `left == right` failed + left: 0 + right: 1 +``` + +Suivi d'une trace de la pile d'exécution. Donnez ensuite à Bill la méta-adresse valide, et à Alice une adresse ou une clé publique invalide. Vous verrez cette erreur : + +``` +rust_wasm.js:236 panicked at /home/ori/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/eth-stealth-addresses-0.1.0/src/lib.rs:78:9: +keys do not generate stealth address +``` + +Encore une fois, suivi d'une trace de pile. + +#### L'interface utilisateur {#ui} + +L'interface utilisateur est écrite en utilisant [React](https://react.dev/) et servie par [Vite](https://vite.dev/). Vous pouvez en apprendre davantage sur eux en utilisant [ce tutoriel](/developers/tutorials/creating-a-wagmi-ui-for-your-contract/). Il n'y a pas besoin de [WAGMI](https://wagmi.sh/) ici car nous n'interagissons pas directement avec une blockchain ou un portefeuille. + +La seule partie non évidente de l'interface utilisateur est la connectivité WASM. Voici comment ça marche. + +**`vite.config.js`** + +Ce fichier contient [la configuration de Vite](https://vite.dev/config/). + +```js +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import wasm from "vite-plugin-wasm"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(), wasm()], +}) +``` + +Nous avons besoin de deux plugins Vite : [react](https://www.npmjs.com/package/@vitejs/plugin-react) et [wasm](https://github.com/Menci/vite-plugin-wasm#readme). + +**`App.jsx`** + +Ce fichier est le composant principal de l'application. C'est un conteneur qui inclut deux composants : `Alice` et `Bill`, les interfaces utilisateur pour ces utilisateurs. La partie pertinente pour WASM est le code d'initialisation. + +```jsx +import init from './rust-wasm/pkg/rust_wasm.js' +``` + +Lorsque nous utilisons [`wasm-pack`](https://rustwasm.github.io/docs/wasm-pack/), il crée deux fichiers que nous utilisons ici : un fichier wasm avec le code réel (ici, `src/rust-wasm/pkg/rust_wasm_bg.wasm`) et un fichier JavaScript avec les définitions pour l'utiliser (ici, `src/rust_wasm/pkg/rust_wasm.js`). L'exportation par défaut de ce fichier JavaScript est le code qui doit être exécuté pour initialiser WASM. + +```jsx +function App() { + . + . + . + useEffect(() => { + const loadWasm = async () => { + try { + await init(); + setWasmReady(true) + } catch (err) { + console.error('Error loading wasm:', err) + alert("Wasm error: " + err) + } + } + + loadWasm() + }, [] + ) +``` + +Le [hook `useEffect`](https://react.dev/reference/react/useEffect) vous permet de spécifier une fonction qui s'exécute lorsque les variables d'état changent. Ici, la liste des variables d'état est vide (`[]`), donc cette fonction n'est exécutée qu'une seule fois lorsque la page se charge. + +La fonction d'effet doit retourner immédiatement. Pour utiliser du code asynchrone, tel que le `init` de WASM (qui doit charger le fichier `.wasm` et prend donc du temps), nous définissons une fonction interne [`async`](https://en.wikipedia.org/wiki/Async/await) et l'exécutons sans `await`. + +**`Bill.jsx`** + +C'est l'interface utilisateur pour Bill. Elle a une seule action, créer une adresse basée sur la méta-adresse furtive fournie par Alice. + +```jsx +import { wasm_generate_stealth_address } from './rust-wasm/pkg/rust_wasm.js' +``` + +En plus de l'exportation par défaut, le code JavaScript généré par `wasm-pack` exporte une fonction pour chaque fonction dans le code WASM. + +```jsx +