GitHub Repo : - https://github.com/PradhumnaPancholi/Figbot
Salut tout le monde! Il y a peu de temps, j'apprenais Dapp Tools car il dispose d'outils fantastiques pour développer et auditer des contrats intelligents. Et même si j'ai adoré l'expérience, j'ai vite appris qu'elle en était au stade de développement clandestin. Cela signifie que les utilisateurs occasionnels/individuels ne peuvent pas dépendre des responsables pour le support et les mises à jour.
Puis je suis tombé sur Foundry . Il a tout ce que Dapp Tools offre à part l'exécution symbolique intégrée (ce qui n'est pas un problème pour moi car j'utilise Manticor e de Trail of Bits ). Et ceci est lié à l'audit et n'est donc pas un obstacle au développement de contrats intelligents par un effort d'imagination.
Après avoir travaillé un peu avec Foundry, j'ai apprécié l'expérience et je voulais la partager avec d'autres. D'où cet article.
Cet article passera en revue les avantages de Foundry, le processus d'installation, le développement d'un NFT (car tout le monde s'y intéresse), le test du contrat et son déploiement avec Figment Datahub .
Foundry est une boîte à outils ultra-rapide, portable et modulaire pour le développement d'applications Ethereum écrite en Rust.
La fonderie est composée de trois composants :
Aujourd'hui, l'accent sera mis sur Forge. Mais je publierai des articles approfondis sur Caste et Anvil dans les semaines à venir.
Il existe de nombreux outils de développement de contrats intelligents comme Truffle, Hardhat et Brownie. Mais l'une des principales raisons pour lesquelles j'ai examiné Dapp Tools en premier lieu était les tests de solidité natifs. L'écriture de contrats intelligents n'est pas difficile lors du basculement entre des frameworks comme Hardhat et Brownie. Et ce sont des outils incroyables avec des plugins, mais il faut bien connaître JavaScript/TypeScript et Python pour effectuer des tests.
Foundry nous permet d'écrire nos tests nativement dans Solidity. Cela permet de gagner beaucoup de temps lors de l'intégration de nouveaux développeurs et rend le processus plus fluide. Dans mon expérience d'aider les gens à naviguer dans le développement de contrats intelligents, j'ai appris que le moyen le meilleur et le plus efficace pour les développeurs juniors de s'engager dans des projets DAO/maintenus par la communauté est d'écrire des tests et d'apprendre la base de code elle-même. Je me souviens que Scupy Trooples a mentionné une fois qu'ils avaient utilisé la même approche lors du développement d'Alchemix Finance sur Bankless .
En plus de cela, le fuzzing intégré, les codes de triche, Cast et Anvil en font une suite solide pour tester les contrats intelligents. Il y aura bientôt des articles plus détaillés sur ces composants. [Analyseur statique facile à intégrer]
Plongeons-nous et construisons un projet NFT maintenant.
Si vous êtes sur Mac ou Linux, il vous suffit d'exécuter deux commandes :
curl -L https://foundry.paradigm.xyz | bash
foundryup
Assurez-vous de fermer le terminal avant d'exécuter foundryup
.
Et voila ! Vous avez terminé.
Pour Windows, vous devez avoir installé Rust puis :
cargo install --git https://github.com/foundry-rs/foundry --locked
Pour cet article, nous allons créer un projet NFT simple appelé Figbots.
Commencez par créer un répertoire appelé "Figbots". Et exécutez forge init
une fois que vous êtes dans le répertoire. Cette commande créera un projet de fonderie pour vous avec git
initialisé.
Jetons un coup d'œil à la structure des dossiers. Vous avez trois dossiers principaux, à savoir src, lib et test. Très explicite ici, vous écrivez vos contrats dans src
, les tests dans test
et lib
contient toutes les bibliothèques que vous avez installées, par exemple OpenZeppelin. En plus de cela, vous obtenez foundry.toml
qui contient toutes les configurations, tout comme hardhat.config.js
et brownie-config.yaml
si vous avez utilisé ces frameworks. Une autre chose intéressante est .github, où vous pouvez écrire vos actions Github. Je trouve cela très utile pour les tests lorsque je travaille en équipe.
Commençons à construire ! Nous allons créer un NFT simple appelé Figbot avec un approvisionnement, un coût (pour la frappe) et un retrait limités. Avec cette approche, nous pouvons couvrir les bords pour différents tests. Tout d'abord, renommez Contract.sol
et test/Contract.t.sol
en Figbot.sol
et Figbot.t.sol
respectivement. Maintenant, nous ne pouvons pas écrire de contrats intelligents sans Openzeppelin, n'est-ce pas ?
L'installation de bibliothèques avec Foundry est légèrement différente de Hardhat et Brownie. Nous n'avons pas de packages npm ou pip. Nous installons les bibliothèques directement depuis la source (dépôt GitHub) dans Foundry.
forge install Openzeppelin/openzeppelin-contracts
Nous pouvons maintenant importer l'extension ERC721URIStorage.sol pour créer notre NFT. Pour vérifier que tout va bien, nous pouvons lancer la commande forge build
, et elle compilera notre projet. Le compilateur vous criera dessus s'il y a quelque chose qui ne va pas. Sinon, vous obtiendrez une compilation réussie.
Comme tout autre gestionnaire de packages, Forge vous permet d'utiliser forge install <lib>,
forge remove <lib>
et forge update <lib>
pour gérer vos dépendances.
Nous utiliserons trois contrats de l'Openzeppelin. Compteurs, ERC721URIStorage et Ownable. Il est temps de télécharger notre ressource sur IPFS en utilisant Pinata . Nous utilisons le contrat Ownable pour définir le owner
de l'adresse de déploiement et avons accès au modificateur onlyOwner
pour autoriser uniquement le propriétaire à retirer des fonds. Counters
pour nous aider avec les identifiants de jeton et ERC721URIStorage
pour simplifier le contrat NFT.
Définition de la variable d'état :
MAX_SUPPLY
à 100COST
à 0,69 étherTOKEN_URI
à CID, nous recevons de PinataUtilisation de Counter pour l'ID de jeton :
using Counters for Counters.Counter;
Counters.Counter private tokenIds;
Constructeur ERC721 :
constructor() ERC721(“Figbot”, “FBT”) {}
Fonction menthe :
msg.value
est supérieur à COST
tokenIds.current()
est supérieur ou égal à MAX_SUPPLY
_safeMint
et _setTokenURI
Fonction de retrait :
function withdrawFunds() external onlyOwner { uint256 balance = address(this).balance; require(balance > 0, "No ether left to withdraw"); (bool success, ) = (msg.sender).call{value: balance}(""); require(success, "Withdrawal Failed"); emit Withdraw(msg.sender, balance); }
Fonction TotalSupply :
function totalSupply() public view returns (uint256) { return _tokenIds.current(); }
Comme nous le savons tous, tester nos contrats intelligents est vraiment important. Dans cette section, nous allons écrire quelques tests pour acquérir une solide compréhension du forge test
et nous habituer à écrire des tests en solidité native. Nous serons trois codes de triche Foundry (je les adore !) pour gérer les états de compte en fonction de notre scénario de test.
Nous testerons les scénarios suivants :
Comme nous pouvons avoir une logique complexe dans nos contrats intelligents. Et on s'attend à ce qu'ils se comportent différemment selon l'état, le compte utilisé pour invoquer, l'heure, etc. Pour faire face à de tels scénarios, nous pouvons utiliser des cheatcodes pour gérer l'état de la blockchain. Nous pouvons utiliser ces codes de triche en utilisant l'instance vm
, qui fait partie de la bibliothèque de Test
de Foundry.
Nous utiliserons trois cheatcodes dans nos tests :
startPrank
: Définit msg.sender
pour tous les appels suivants jusqu'à ce que stopPrank
soit appelé.
stopPrank
:
Arrête une farce active commencée par startPrank
, en réinitialisant msg.sender
et tx.origin
aux valeurs avant que startPrank
ne soit appelé.
deal
: Définit le solde d'une adresse fournie par l'adresse au solde donné.
Foundry est livré avec une bibliothèque de test intégrée. Nous commençons par importer cette bibliothèque de tests, notre contrat (celui que nous voulons tester), définir le test, définir les variables et la fonction setUp
.
pragma solidity ^0.8.13; import"forge-std/Test.sol"; import "../src/Figbot.sol"; contract FigbotTest is Test { Figbot figbot; address owner = address(0x1223); address alice = address(0x1889); address bob = address(0x1778); function setUp() public { vm.startPrank(owner); figbot = new Figbot(); vm.stopPrank(); } }
Pour les variables d'état, nous créons une variable figbot
de type Figbot
. C'est aussi l'endroit où j'aime définir les comptes d'utilisateurs. Dans Foundry, vous pouvez décrire une adresse en utilisant la syntaxe address(0x1243)
. vous pouvez utiliser quatre caractères alphanumériques pour cela. J'ai créé les comptes nommés propriétaire, Alice et bob, respectivement.
Maintenant notre fonction setUp
. Il s'agit d'une exigence pour écrire des tests dans Foundry. C'est là que nous effectuons tous les déploiements et les choses de cette nature. J'ai utilisé le cheatcode startPrank
pour passer l'utilisateur au "propriétaire". Par défaut, Foundry utilise une adresse spécifique pour déployer des contrats de test. Mais cela rend plus difficile le test de fonctions avec des privilèges spéciaux tels que withdrawFunds
. Par conséquent, nous passons au compte "propriétaire" pour ce déploiement.
En commençant par un simple test d'assertion pour apprendre la convention Foundry. Par convention, toutes les fonctions de test doivent avoir le préfixe test
. Et nous utilisons assertEq
pour tester si deux valeurs sont égales.
Nous appelons notre fonction MaxSupply
et testons si la valeur du résultat est 100, comme nous l'avons décrit dans notre contrat. Et nous utilisons forge test
pour exécuter nos tests.
Et voilà !!! nous avons un test réussi.
Maintenant que nous avons écrit un test simple, écrivons-en un avec des cheatcodes. La fonction première de notre contrat.
balanceOf
Alice est 1 Nous avons une autre fonction de test utilisée pour les tests que nous prévoyons d'échouer. Le préfixe utilisé pour un tel test est testFail
. Nous testerons si la fonction mint
revient si l'appelant n'a pas suffisamment de fonds.
balanceOf
Bob est 1 Parce que la menthe n'a pas traversé, le solde de Bob ne sera pas 1. Par conséquent, il échouera, ce qui est exactement ce pour quoi nous sommes utilisés testFail
. Ainsi, lorsque vous exécutez forge test
, cela passera.
Ici, nous allons tester une fonction que seul le "propriétaire" peut exécuter avec succès. Pour ce test, nous allons :
withdrawFunds
de fonds (en cas de succès, le solde du propriétaire devrait être de 0,69 éther)Maintenant que nous avons testé notre contrat, il est temps de le déployer. Nous avons besoin de clés privées pour un portefeuille (avec un test ETH de Rinkeby) et une URL RPC. Pour notre URL RPC, nous utiliserons Figment DataHu .
Figment DataHub nous fournit une infrastructure pour développer sur le Web 3. Il prend en charge plusieurs chaînes comme Ethereum, Celo, Solana, Terra, etc.
Vous pouvez obtenir votre URL RPC pour Rinkeby sous l'onglet "Protocoles".
Ouvrez votre terminal pour saisir ces deux éléments en tant que variables d'environnement.
export FIG_RINKEBY_URL=<Your RPC endpoint> export PVT_KEY=<Your wallets private key>
Une fois que nous avons les variables d'environnement, nous sommes tous prêts à déployer
forge create Figbot --rpc-url=$FIG_RINKEBY_URL --private-key=$PVT_KEY
Nous avons presque fini ici. Jusqu'à présent, nous avons écrit, testé et déployé un contrat intelligent avec Foundry et Figment DataHub. Mais nous n'avons pas encore tout à fait terminé. Nous allons maintenant vérifier notre contrat. Nous devrons configurer notre clé API Etherscan pour cela.
export ETHERSCAN_API=<Your Etherscan API Key>
Et maintenant, nous pouvons vérifier notre contrat intelligent.
forge verify-contract --chain-id <Chain-Id> --num-of-optimizations 200 --compiler-version <Compiler Version> src/<Contract File>:<Contract> $ETHERSCAN_API
Toutes nos félicitations! Vous pouvez désormais rédiger, tester et déployer des contrats intelligents à l'aide de Foundry. J'espère que vous avez apprécié et appris de cet article. J'ai vraiment aimé écrire ça. N'hésitez pas à me faire part de vos réflexions à ce sujet.