Créer et déployer une application DeFi
Dans ce tutoriel, nous allons créer une application DeFi avec Solidity dans laquelle les utilisateurs peuvent déposer un jeton ERC20 dans le contrat intelligent et ce jeton va générer et leur transférer des jetons Farm. Par la suite, les utilisateurs pourront retirer leurs jetons ERC20 en brûlant leur jeton Farm sur un contrat intelligent et les jetons ERC20 leur seront transférés en retour.
Installer Truffle et Ganache
Si c'est votre première création de contrat intelligent, il vous faudra configurer votre environnement. Nous allons utiliser deux outils : Truffle(opens in a new tab) et Ganache(opens in a new tab).
Truffle est un environnement de développement et un framework de test pour l'établissement de contrats intelligents pour Ethereum. Avec Truffle, il est facile de créer et de déployer des contrats intelligents sur la blockchain. Ganache permet de créer une blockchain Ethereum locale afin de tester les contrats intelligents. Il simule les fonctionnalités du réseau réel et les 10 premiers comptes sont financés avec 100 éther de test, rendant ainsi le déploiement et le test du contrat intelligent gratuit et facile. Ganache est disponible en tant qu'application de bureau et outil de ligne de commande. Pour cet article nous allons utiliser l'application UI Desktop.
(opens in a new tab)Application de bureau pour utilisateur Ganache
Pour créer notre projet, exécutez les commandes suivantes :
mkdir your-project-namecd your-project-nametruffle init
Cela créera un projet vide pour l'établissement et le déploiement de nos contrats intelligents. La structure du projet créée est la suivante :
test
: Dossier des contrats intelligents Soliditymigrations
: Dossier des scripts de déploiementtest
: Dossier pour tester nos contrats intelligentstruffle-config.js
: Fichier de configuration Truffle
Créer un jeton ERC20
Nous devons premièrement créer notre jeton ERC20 que nous miserons dans le contrat intelligent. Pour créer notre jeton fongible, nous devrons commencer par installer la bibliothèque OpenZeppelin. Cette bibliothèque contient les implémentations de normes telles qu'ERC20 et ERC721. Pour l'installer, exécutez la commande :
npm install @openzeppelin/contracts
En utilisant la bibliothèque OpenZeppelin nous pouvons créer notre jeton ERC20 en écrivant sur contracts/MyToken.sol
avec le code de Solidity suivant :
1pragma solidity ^0.8.0;23import "@openzeppelin/contracts/token/ERC20/ERC20.sol";45contract MyToken is ERC20 {6 constructor() public ERC20("MyToken", "MTKN"){7 _mint(msg.sender, 1000000000000000000000000);8 }9}Afficher toutCopier
Dans le code ci-dessus à la :
Ligne 3 : Nous importons le contrat ERC20.sol depuis openzeppelin qui contient l'implémentation de la norme de ce jeton.
Ligne 5 : Nous héritons du contrat ERC20.sol.
Ligne 6 : Nous appelons le constructeur ERC20.sol et passons le nom et les paramètres du symbole respectivement en tant que
"MyToken"
et"MTKN"
.Ligne 7 : Nous générons et transférons 1 million de jetons pour le compte qui déploie le contrat intelligent (nous utilisons les 18 décimales par défaut pour le jeton ERC20, ce qui signifie que si nous voulons générer 1 jeton, il se présentera sous la forme 1000000000000000000, 1 avec 18 zéros).
Nous pouvons voir ci-dessous l'implémentation du constructeur ERC20.sol où le champ _decimals
est défini à 18 :
1string private _name;2string private _symbol;3uint8 private _decimals;45constructor (string memory name_, string memory symbol_) public {6 _name = name_;7 _symbol = symbol_;8 _decimals = 18;9}Afficher toutCopier
Compiler le jeton ERC20
Pour compiler notre contrat intelligent, nous devons d'abord vérifier notre version du compilateur de Solidity. Vous pouvez la vérifier en exécutant la commande :
truffle version
La version par défaut est la version Solidity v0.5.16
. Puisque notre jeton est écrit en utilisant la version Solidity 0.6.2
, si nous exécutons la commande pour compiler nos contrats, nous allons générer une erreur de compilation. Afin de spécifier quelle version de compilateur Solidity utiliser, allez dans le fichier truffle-config.js
et définissez la version désirée du compilateur comme ci-dessous :
1// Configure your compilers2compilers: {3 solc: {4 version: "^0.8.0", // Fetch exact version from solc-bin (default: truffle's version)5 // docker: true, // Use "0.5.1" you've installed locally with docker (default: false)6 // settings: { // See the solidity docs for advice about optimization and evmVersion7 // optimizer: {8 // enabled: false,9 // runs: 20010 // },11 // evmVersion: "byzantium"12 // }13 }14}Afficher tout
Maintenant, nous pouvons compiler notre contrat intelligent en exécutant la commande suivante :
truffle compile
Déployer le jeton ERC20
Après la compilation, nous pouvons maintenant déployer notre jeton.
Dans le dossier migrations
, créez un fichier appelé 2_deploy_Tokens.js
. Ce fichier est l'endroit où nous allons déployer à la fois notre jeton ERC20 et notre contrat intelligent FarmToken. Le code ci-dessous est utilisé pour déployer notre contrat MyToken.sol :
1const MyToken = artifacts.require("MyToken")23module.exports = async function (deployer, network, accounts) {4 // Deploy MyToken5 await deployer.deploy(MyToken)6 const myToken = await MyToken.deployed()7}
Ouvrez Ganache et sélectionnez l'option "Quickstart" pour démarrer une blockchain Ethereum en local. Pour déployer notre contrat, lancez :
truffle migrate
L'adresse utilisée pour déployer nos contrats est la première de la liste d'adresses que Ganache nous indique. Pour vérifier, nous pouvons ouvrir l'application de bureau Ganache et ainsi vérifier que le solde d'ether pour le premier compte a été réduit en raison du coût d'ether pour déployer nos contrats intelligents :
(opens in a new tab)Application de bureau Ganache
Pour vérifier que 1 million de jetons MyToken ont été envoyés à l'adresse de déploiement, nous pouvons utiliser la console Truffle pour interagir avec notre contrat intelligent déployé.
Afin d'interagir avec notre contrat intelligent, exécutez la commande suivante :
truffle console
Nous pouvons maintenant écrire les commandes suivantes dans le terminal :
Récupère le contrat intelligent :
myToken = await MyToken.deployed()
Récupère le tableau de comptes depuis Ganache :
accounts = await web3.eth.getAccounts()
Récupère le solde pour le premier compte :
balance = await myToken.balanceOf(accounts[0])
Formate le solde à partir de 18 décimales :
web3.utils.fromWei(balance.toString())
En exécutant les commandes ci-dessus, nous constatons que la première adresse a en fait 1 million de MyTokens :
La première adresse dispose de 1 000 000 de MyTokens
Créer un Contrat Intelligent FarmToken
Le contrat intelligent FarmToken aura 3 fonctions :
balance()
: Transférer le solde de MyToken sur le contrat intelligent FarmToken.deposit(uint256 _amount)
: Transférer MyToken pour le compte de l'utilisateur sur le Contrat Intelligent FarmToken puis frapper et transférer FarmToken à l'utilisateur.withdraw(uint256 _amount)
: Brûler les FarmTokens de l'utilisateur et transférer MyTokens à l'adresse de l'utilisateur.
Jetons un œil au constructeur FarmToken :
1pragma solidity ^0.6.2;23import "@openzeppelin/contracts/token/ERC20/IERC20.sol";4import "@openzeppelin/contracts/utils/Address.sol";5import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";6import "@openzeppelin/contracts/token/ERC20/ERC20.sol";78contract FarmToken is ERC20 {9 using Address for address;10 using SafeMath for uint256; // As of Solidity v0.8.0, mathematical operations can be done safely without the need for SafeMath11 using SafeERC20 for IERC20;1213 IERC20 public token;1415 constructor(address _token)16 public17 ERC20("FarmToken", "FRM")18 {19 token = IERC20(_token);20 }Afficher toutCopier
Lignes 3-6 : Nous importons depuis openzeppelin les contrats suivants : IERC20.sol, Address.sol, SafeERC20.sol et ERC20.sol.
Ligne 8 : Le FarmToken héritera du contrat ERC20.
Lignes 14-19 : Le constructeur FarmToken recevra comme paramètre l'adresse du contrat MyToken et nous attribuerons son contrat à notre variable publique appelée
token
.
Implémentons la fonction balance()
. Elle ne recevra aucun paramètre et retournera le solde de MyToken sur ce contrat intelligent. Il s'implémente comme indiqué ci-dessous :
1function balance() public view returns (uint256) {2 return token.balanceOf(address(this));3}Copier
Pour la fonction deposit(uint256 _amount)
, il recevra comme paramètre le montant que l'utilisateur veut déposer et il frappera et transférera FarmTokens à l'utilisateur :
1function deposit(uint256 _amount) public {2 // Amount must be greater than zero3 require(_amount > 0, "amount cannot be 0");45 // Transfer MyToken to smart contract6 token.safeTransferFrom(msg.sender, address(this), _amount);78 // Mint FarmToken to msg sender9 _mint(msg.sender, _amount);10}Afficher toutCopier
Pour la fonction withdraw(uint256 _amount)
, nous recevrons comme paramètre la quantité de FarmTokens que l'utilisateur veut brûler, puis transférerons la même quantité de MyTokens à l'utilisateur :
1function withdraw(uint256 _amount) public {2 // Burn FarmTokens from msg sender3 _burn(msg.sender, _amount);45 // Transfer MyTokens from this smart contract to msg sender6 token.safeTransfer(msg.sender, _amount);7}Copier
Nous allons maintenant déployer notre contrat intelligent. Pour ce faire, nous retournerons au fichier 2_deploy_Tokens.js
et ajouterons le nouveau contrat à déployer :
1const MyToken = artifacts.require("MyToken")2const FarmToken = artifacts.require("FarmToken")34module.exports = async function (deployer, network, accounts) {5 // Deploy MyToken6 await deployer.deploy(MyToken)7 const myToken = await MyToken.deployed()89 // Deploy Farm Token10 await deployer.deploy(FarmToken, myToken.address)11 const farmToken = await FarmToken.deployed()12}Afficher tout
Notez que lors du déploiement du FarmToken, nous passons comme paramètre l'adresse du contrat MyToken déployé.
Exécutez maintenant truffle compile
et truffle migrate
pour déployer nos contrats.
Testons notre contrat intelligent. Au lieu d'utiliser la console truffle
pour interagir avec notre contrat intelligent, nous allons créer un script pour automatiser ce processus. Créez un dossier appelé scripts
et ajoutez le fichier suivant getMyTokenBalance.js
. Il vérifiera le solde de MyTokens sur le contrat intelligent FarmToken :
1const MyToken = artifacts.require("MyToken")2const FarmToken = artifacts.require("FarmToken")34module.exports = async function (callback) {5 myToken = await MyToken.deployed()6 farmToken = await FarmToken.deployed()7 balance = await myToken.balanceOf(farmToken.address)8 console.log(web3.utils.fromWei(balance.toString()))9 callback()10}Afficher tout
Pour exécuter ce script, exécutez la commande suivante :
truffle exec .\scripts\getMyTokenBalance.js
Nous obtiendrons le résultat attendu qui est 0. Si vous avez comme message d'erreur que FarmToken n'est pas encore déployé, cela signifie que le réseau truffle n'a pas reçu la dernière version du code du contrat. Fermez tout simplement ganache, démarrez-le à nouveau et veillez à exécuter truffle migrate
.
Maintenant, misons MyToken sur le contrat intelligent. Dès lors que la fonction deposit(uint256 _amount)
appelle la fonction safeTransferFrom
de l'ERC20, l'utilisateur doit d'abord approuver le contrat intelligent pour transférer MyToken en nom et place de l'utilisateur. Donc, sur le script ci-dessous, nous allons d'abord approuver cette étape puis nous appellerons la fonction :
1const MyToken = artifacts.require("MyToken")2const FarmToken = artifacts.require("FarmToken")34module.exports = async function (callback) {5 const accounts = await new web3.eth.getAccounts()6 const myToken = await MyToken.deployed()7 const farmToken = await FarmToken.deployed()89 // Returns the remaining number of tokens that spender will be allowed to spend on behalf of owner through transferFrom.10 // This is zero by default.11 const allowanceBefore = await myToken.allowance(12 accounts[0],13 farmToken.address14 )15 console.log(16 "Amount of MyToken FarmToken is allowed to transfer on our behalf Before: " +17 allowanceBefore.toString()18 )1920 // In order to allow the Smart Contract to transfer to MyToken (ERC-20) on the accounts[0] behalf,21 // we must explicitly allow it.22 // We allow farmToken to transfer x amount of MyToken on our behalf23 await myToken.approve(farmToken.address, web3.utils.toWei("100", "ether"))2425 // Validate that the farmToken can now move x amount of MyToken on our behalf26 const allowanceAfter = await myToken.allowance(accounts[0], farmToken.address)27 console.log(28 "Amount of MyToken FarmToken is allowed to transfer on our behalf After: " +29 allowanceAfter.toString()30 )3132 // Verify accounts[0] and farmToken balance of MyToken before and after the transfer33 balanceMyTokenBeforeAccounts0 = await myToken.balanceOf(accounts[0])34 balanceMyTokenBeforeFarmToken = await myToken.balanceOf(farmToken.address)35 console.log("*** My Token ***")36 console.log(37 "Balance MyToken Before accounts[0] " +38 web3.utils.fromWei(balanceMyTokenBeforeAccounts0.toString())39 )40 console.log(41 "Balance MyToken Before TokenFarm " +42 web3.utils.fromWei(balanceMyTokenBeforeFarmToken.toString())43 )4445 console.log("*** Farm Token ***")46 balanceFarmTokenBeforeAccounts0 = await farmToken.balanceOf(accounts[0])47 balanceFarmTokenBeforeFarmToken = await farmToken.balanceOf(farmToken.address)48 console.log(49 "Balance FarmToken Before accounts[0] " +50 web3.utils.fromWei(balanceFarmTokenBeforeAccounts0.toString())51 )52 console.log(53 "Balance FarmToken Before TokenFarm " +54 web3.utils.fromWei(balanceFarmTokenBeforeFarmToken.toString())55 )56 // Call Deposit function from FarmToken57 console.log("Call Deposit Function")58 await farmToken.deposit(web3.utils.toWei("100", "ether"))59 console.log("*** My Token ***")60 balanceMyTokenAfterAccounts0 = await myToken.balanceOf(accounts[0])61 balanceMyTokenAfterFarmToken = await myToken.balanceOf(farmToken.address)62 console.log(63 "Balance MyToken After accounts[0] " +64 web3.utils.fromWei(balanceMyTokenAfterAccounts0.toString())65 )66 console.log(67 "Balance MyToken After TokenFarm " +68 web3.utils.fromWei(balanceMyTokenAfterFarmToken.toString())69 )7071 console.log("*** Farm Token ***")72 balanceFarmTokenAfterAccounts0 = await farmToken.balanceOf(accounts[0])73 balanceFarmTokenAfterFarmToken = await farmToken.balanceOf(farmToken.address)74 console.log(75 "Balance FarmToken After accounts[0] " +76 web3.utils.fromWei(balanceFarmTokenAfterAccounts0.toString())77 )78 console.log(79 "Balance FarmToken After TokenFarm " +80 web3.utils.fromWei(balanceFarmTokenAfterFarmToken.toString())81 )8283 // End function84 callback()85}Afficher tout
Pour exécuter ce script : truffle exec .\scripts\transferMyTokenToFarmToken.js
. Vous devriez voir sur votre console :
sortie de transferMyTokenToFarmToken.js
Comme nous pouvons le voir, nous avons déposé avec succès MyTokens sur le contrat intelligent car le premier compte est maintenant associé à FarmTokens.
Afin de retirer :
1const MyToken = artifacts.require("MyToken")2const FarmToken = artifacts.require("FarmToken")34module.exports = async function (callback) {5 const accounts = await new web3.eth.getAccounts()6 const myToken = await MyToken.deployed()7 const farmToken = await FarmToken.deployed()89 // Verify accounts[0] and farmToken balance of MyToken before and after the transfer10 balanceMyTokenBeforeAccounts0 = await myToken.balanceOf(accounts[0])11 balanceMyTokenBeforeFarmToken = await myToken.balanceOf(farmToken.address)12 console.log("*** My Token ***")13 console.log(14 "Balance MyToken Before accounts[0] " +15 web3.utils.fromWei(balanceMyTokenBeforeAccounts0.toString())16 )17 console.log(18 "Balance MyToken Before TokenFarm " +19 web3.utils.fromWei(balanceMyTokenBeforeFarmToken.toString())20 )2122 console.log("*** Farm Token ***")23 balanceFarmTokenBeforeAccounts0 = await farmToken.balanceOf(accounts[0])24 balanceFarmTokenBeforeFarmToken = await farmToken.balanceOf(farmToken.address)25 console.log(26 "Balance FarmToken Before accounts[0] " +27 web3.utils.fromWei(balanceFarmTokenBeforeAccounts0.toString())28 )29 console.log(30 "Balance FarmToken Before TokenFarm " +31 web3.utils.fromWei(balanceFarmTokenBeforeFarmToken.toString())32 )3334 // Call Deposit function from FarmToken35 console.log("Call Withdraw Function")36 await farmToken.withdraw(web3.utils.toWei("100", "ether"))3738 console.log("*** My Token ***")39 balanceMyTokenAfterAccounts0 = await myToken.balanceOf(accounts[0])40 balanceMyTokenAfterFarmToken = await myToken.balanceOf(farmToken.address)41 console.log(42 "Balance MyToken After accounts[0] " +43 web3.utils.fromWei(balanceMyTokenAfterAccounts0.toString())44 )45 console.log(46 "Balance MyToken After TokenFarm " +47 web3.utils.fromWei(balanceMyTokenAfterFarmToken.toString())48 )4950 console.log("*** Farm Token ***")51 balanceFarmTokenAfterAccounts0 = await farmToken.balanceOf(accounts[0])52 balanceFarmTokenAfterFarmToken = await farmToken.balanceOf(farmToken.address)53 console.log(54 "Balance FarmToken After accounts[0] " +55 web3.utils.fromWei(balanceFarmTokenAfterAccounts0.toString())56 )57 console.log(58 "Balance FarmToken After TokenFarm " +59 web3.utils.fromWei(balanceFarmTokenAfterFarmToken.toString())60 )6162 // End function63 callback()64}Afficher tout
Pour exécuter ce script : truffle exec .\scripts\transferMyTokenToFarmToken.js
. Comme nous pouvons le constater avec l'exemple ci-dessous, nous avons réussi à récupérer les MyTokens et nous avons supprimé les FarmTokens :
sortie de withdrawMyTokenFromTokenFarm.js
Références
Contrats - Documentation OpenZeppelin(opens in a new tab)
Outils Sympas pour contrats intelligents | Suite Truffle(opens in a new tab)
Ganache | Suite Truffle(opens in a new tab)
Qu'est-ce que DeFi ? Guide du débutant (mise à jour 2021) (99bitcoins.com)(opens in a new tab)
DeFi - Le classement de la finance décentralisée sur DeFi Llama(opens in a new tab)
Dernière modification: @MATsxm(opens in a new tab), Invalid DateTime