New Ethereum talks, every Monday. The week's conference uploads by event, in your inbox.

Loading player…

Foundry 🛠 A Complete Introduction to Smart Contract Development with Foundry

ETHGlobalMon, Oct 9, 2023, 12:00 AM

Join Camila Ramos Garzon from Fuel Network and Nader Dabit from Aave Companies for a workshop titled "A Complete Introduction to Smart Contract Development with Foundry." Thank you to everyone who joined us for ETHBogotá 🇨🇴 and helped us kick off Devcon Week. With over 1400 attendees from 62 different countries, ETHBogotá was our biggest hackathon in Latin America ever! ----------------------------------------------- Follow us: https://twitter.com/ETHGlobal​ Check us out: https://ethglobal.co​m Email us at: hello@ethglobal.com #ethereum #web3 #blockchain #eth

Transcript

foreign [Applause] [Music] key mission statements as a developer Advocate is to make sure that computer science education in general is widely accessible to people from all over the world and that means that when you're in a different country with a different language making sure that those people can access education in the same way I did a check here and everyone here speaks English so I'll lean more towards English on that for sure and all of this stuff that's published is in English but it would actually be great for us to potentially translate it so cool we're gonna do a Foundry Workshop a complete introduction to Smart contract development with Foundry so natter is being my emotional support right now but then we're gonna switch then he's going to get on and I'll be his emotional support cool so Foundry is a portable fast and modular toolkit for ethereum application development so you might have heard of it but you might have heard of others that fall into the same category in that part of this stack so maybe hard hat maybe truffle um so it falls into the same place it does the same thing where it's tooling around development and we'll talk about exactly what are some of the unique values and the unique propositions that Foundry has and how you can leverage it in your smart contract development so why Foundry like I said there's other competitors if you look here there's oh is it ugly for you guys too yeah okay it's okay it's in the middle so there's hard hat there's truffle there's brownie there's anchor but kind of like what is the unique proposition of Foundry and where are we here talking about Foundry specifically so a few different reasons one is that it lets you write your tests in solidity instead of JavaScript and we say instead of JavaScript because I think at least for both of us before Foundry we were using hard hat and when you're writing your tests there you're writing your tests in JavaScript even though your smart contracts are in solidity so with Foundry it allows you to kind of have just less context switching and less mental overhead of like writing in one language and then testing in a different the next one is that it's really really fast if you've used hard hat or anything else and then you use Foundry you'll be able to feel the difference and tell the difference and it's partially because it's written in Rust so it's able to leverage a lot of the Key properties that come with rest and why rest is gaining so much popularity right now another really cool thing that we're going to go over today in the workshop is an improved developer experience with fuzzing so fuzzing is an automated testing strategy that basically lets you as a developer make sure that you're testing for all possible cases so you know when you write unit tests or maybe functional tests you're checking that an output for a very specific input matches you know what you expect so you're like check that the output equals one check that the output equals two but there's no way that you can manually write tests to handle every possible outcome so that's exactly what fuzzing does is it makes sure that you as a developer are seeing all of the edge cases all of the kind of failed cases that are out there so you can make sure that you're handling those and then so okay these one of these are out of pocket out of order so talking about the tools that come with Foundry and what we're going to talk about exactly today are Anvil forage and cast so starting with Anvil Anvil's a local ethereum node similar to what you've already seen in hard hat or ganache where you can spin up your local ethereum node and use it for testing your contracts and interacting over our PC cast is another CLI tool that allows you to interact with the smart contracts this is where you actually like send transactions read data from the network and I just like we're not going to talk too deeply about this next part but I would encourage you guys to check it out in The Foundry book which is linked at the end Cass also has some really cool sub commands that you can use for decoding call data and sending arbitrary messages and a bunch of other things and then this is the one that was in the wrong place oh forage okay well um I didn't put one in the slides but the other one is forage and that's like what you use to like your your tooling your tooling what do you call it that's kind of one of the main commands yeah like when you do hard hat in it it's it's the the equivalent to that so when you're doing Forge so now we're gonna actually walk through if you want to apply your laptop you can follow along if you want to do this later on your own and just watch you can do that if you want to follow along go to natter's Twitter he just tweeted out the the link to it so you can see it up close so you don't have to squint thank you for that introduction so I'm gonna get off stage and help people if they run into stuff while we're doing it yeah so what we're going to be going over today is an open source GitHub repo that you can obviously follow along with today or if you are um watching at home or watching this at any other time and you don't have time to follow along you can do this obviously at another time but I've kind of tried to make this the most concise introductory level Workshop to kind of get all of to me the most important exciting things about Foundry covered in a short amount of time and along with this Workshop I've linked to a couple of really great resources um one of them is The Foundry book and it's a great resource obviously um the other two though or one of them is something that I actually reference almost on a daily basis when I'm writing smart contracts with Foundry and this is something I created called The Foundry cheat sheet and this basically just has like all the copy and paste commands for like the 90 of the work that I do with Foundry so you might want to know how do you send a contract call to an address that's local how do you send a contract call to a live contract how do you do this or that there's a lot of good copy and paste code that you can use here and I believe that we are going to actually merge this into The Foundry book there's already kind of a GitHub issue open there so for right now The Foundry cheats you to separate but it might be part of the book later and then the other is a video tutorial that I've done on getting started with Foundry it's very similar to this Workshop but maybe a little bit more in depth so with that being said the pre the only prerequisite for this Workshop is that you have rust and salt and if you want to see where this actual GitHub repo is it's actually github.com3 I think the um the URL was was actually the slides there so github.com3 the very top Workshop should be there and the things that we're going to be covering today are testing and assertions fuzzing logging running a local node and deploying to that node we're going to be looking at calling contract contract calls directly from your command line to that local node installing and using libraries so in hard hat we can use npm to install like open Zeppelin contracts and stuff like that and with Forge you can actually do the same we're going to look at how to configure the remapping so that your text editor understands where these libraries are but also the development environment knows where those are as well and we're going to also look at some of the more interesting things that you're probably doing on a daily day-to-day basis like mocking users so let's say you want to kind of like run a contract call from one user and then test it out by transferring a token to another user and all that stuff how do you do that well we're going to cover that today and and um that should be I think a really great overview once you go through this then I think at least for me this was everything I needed to to get started building so with that being said Cami kind of gave an introduction around a lot of this overview stuff that I'm going to skip now and we're going to actually go directly to getting the installation done now if you if you don't have rust installed it might take a little time for you to actually do that so you might not be able to follow along but once you have rust installed you're going to be installing a Foundry up and once you have Foundry up installed you can just run this command boundary up and this will either install Foundry or it will install the latest version of Foundry so before this Workshop I ran Foundry up and broke everything in the workshop because things changed so I had to go back and make some updates but uh the only thing that really changed with the new update was the actual original contract that was scaffolded by Foundry they used to just scaffold out an empty contract now they scaffold out a counter example which is actually much nicer and honestly it's also a good contract to play around with if you're learning so with that being said what we want to do is install Foundry by running this command and running Foundry up like I mentioned and what that's actually going to do it's going to install a couple of different uh libraries or a couple of different tools I would say and gaming already kind of covered those but once you do the installation you're going to have three different CLI commands available to you one is Forge one is cast and one is amble Forge we're going to use to create a new project we're going to use it to do testing and stuff like that cast is actually what you're going to use to then make contract calls against any live contract and it doesn't have to be a contract created by by Foundry actually you can literally just use this cast to interact with any live evm Network which is cool and then amble is what you'll use to spin up a local node so with that being said we're going to run Forge and knit and this will scaffold out a new project so I'm going to go ahead and open my command line and is that readable for everyone okay cool try to make it big enough so we're going to run Forge init well first of all let me just show you that we're in an empty directory now so fortunate will scaffold out a new a new project and while that's scaffolding out I'm going to open that up in my text editor and we're going to look at the folder structure and we're going to see that we have the SRC directory which holds our main contracts we have our test which holds what our tests obviously and then we have our script which is actually what you're going to use to deploy your contracts and scripting is actually really cool and it's I think it's something that wasn't there when Foundry first came out and then lib is like the node modules but it's for this environment so if you install opens up on contracts it'll go in the lib folder and you can immediately start doing things so if you wanted to run a build you could say Forge build and this is going to compile your contracts and it's going to give you the apis so if you ever use hard hat you know you compile you get your apis and you can use those to make client-side calls or you can use them to deploy and verify your contract on something like etherscan once you run Forge build you're going to have this out directory and this out directory holds your apis um you can also run Forge test and we're going to be actually running back through these commands again with the new code base because we don't really know what that's testing because we haven't even looked at the contract so what I'm going to do is go back to my code base and what I want to do is we're going to instead of using this counter example we're going to do a Hello World which is going to just give us a little bit more room to work with to show some of the functionality that you might not be able to do with just a counter example so in order to do that I'm going to rename this to hello world dot Sol and everything that I'm doing is actually covered in the workshop materials copy and paste directly from here so don't worry if like you know you're not keeping up you can literally just go here and copy and paste so what I've done is I've renamed counter to hello world and this is a very basic hello world contract that I'm going to go ahead and paste here the only functionality that we have is that we have two variables we have a greeting and we have a version when we make a new greeting we're going to increment the version and we're going to have a function that just Returns the greeting so it's about as simple as you can get but it also I think is a good basic starting point you know so the contract is there this isn't on solidity development it's on Foundry development so we're going to actually go now to the test and we're going to spend more time on testing and what we want to do is we're going to go to test folder slash counter.t.soul we're going to rename that to hello world .

t.soul and you're going to notice that in this example contract here that we have a couple of functions and they start with the word test now with Foundry any function that starts with the word test will automatically be tested when you run Forge test it doesn't even have to be in this directory so keep that in mind when you're writing your test if you create a test in the test that doesn't start with test it won't actually get tested um at least by default so what we want to do is just go ahead and copy this test oops and we're going to walk through the assertions that are being had there all right so we have this the first thing that you might notice that's different is that we have this setup function and this just allows you to create some type of initial variable or whatever that you want to reuse across all of your other tests so it often makes sense to just create a new instance of the contract and then you can just like reuse that instance of the contract so that's kind of what we're doing here we're creating this variable called hello that initializes a new Hello World contract and then we can just now say Hello dot whatever the method of that contract is that we want to to call so the first test that we're going to run is we want to get the value that's returned from the greeting and and make sure that it what we expect what we expect it to be is this because the Constructor takes in that initial argument and we're doing that now that's interesting but I think the most interesting thing to be keeping an eye out for is this assertion assert equals so you have about a dozen different assertions that you can work with and I have a link in the workshop to all those assertions so you can assert equality you can assert things like greater than less than equal to you can search truthiness pretty much anything that you would probably need for assertion so it's a really really basic tests here right we're just kind of like making sure the greeting isn't equal to the string that we expect it to be um and then we're going to also do an update and we're going to say the initial um version of the the version is zero I guess you could say we're going to then create a new greeting which should increment that version number to one and then we're going to assert that that is equal to one and also assert that the greeting is equal to hello world so with that being said we can now run Forge test that should work that's that's cool and all but that's not all that interesting let's kind of look at more interesting stuff so now that we have our basic project set up let's dive in to more stuff so I mentioned some of these other assertions we're not going to really be using any of those other ones but here are some of them and here's the link to view more but we want to look at now is fuzzing so fuzzing is cool because we don't actually have to pass in the argument that is expected here fuzzing can actually take care of that for us and therefore you have um also more I would say variation in the types of tests that are run because it will basically automatically inject just different variables there so instead of passing in the variable ourselves we're going to use fuzzing here and we're just gonna we're just gonna Define that there is a variable that should be passed in there and then Foundry will automatically inject that and it'll make it available for us everything else kind of I would say stays the same so now if we run Forge test again it should still work but if I go to maybe change this greeting to something else obviously like Hello World then that should maybe break okay so the greeting that's coming in is some value that we don't know so how do we know how what if we want to know that value we can start logging it out and if you want to log you have about a dozen different logging methods that you can use you can just use a straight up basic log which is just log which is really simple and you can also log integers if you know for sure that there's going to be an integer log string you can do log name String which would be something like console.log passing in the first argument is the string the second argument is the value so let's do some logging so I'm going to go back to test two and what I want to log out is the value that is returned from the Greet method which should just be hello world but you're going to notice when I run this test that nothing is logged out because by default logging isn't enabled you have to actually ask for more verbose logging so what we're going to do is just pass the dash VV and then now we see that we have the logs there so hello world so that's how logging works you just want to pass in the verbosity and I think there's up to four v's and I don't know what that would do but let's see there we go um so I've never really really need that that much honestly but okay so we have some basic stuff going on we're going to dive even even deeper to more interesting stuff even we only have five minutes but I think we have enough time uh next we want to go ahead and run a local ethereum node so in hard hat we would run npx hard hat node and and Foundry you just type in the word anvil and this spins up a node and here you see that we have 10 different accounts in 10 different private keys so what I want to do now is go ahead and set a an environment variable to one of these product keys and then that way we can start interacting with the network and referencing that private key is a as an environment variable so to deploy the actual contract to the network we need to run a script and we already have a basic script in our project here under Scripts we want to just rename this to helloworld.s dot Sol and we have this run function and then we have this broadcast method on the VM that actually does the deployment and that's kind of where we're going to be doing our work so I'm going to copy this and not a whole lot has changed we still have this empty setup method because we're not really using it um we're doing the vm.broadcast and then after that whatever is called we'll be actually deployed and all we're saying is like we want a new uh hello world contract deployed and then we're passing in the Constructor argument of the string and then from there we should be ready to go so how do you actually run this well we are going to use the forge the forge CLI and we're going to say Forge script we're going to define the location of the script we're going to Define where the RPC is that it's going to be deployed to so if this was like inferior you would set an RPC endpoint but since we're running locally we're going to set the localhost 8545 and then we're going to set the private key as the private key that we stored in our environment variable and then we're going to say broadcast because if you don't say broadcast it doesn't actually deploy that so let's do this without broadcast and I'm going to go ahead and open my terminal and this will basically just give you a simulation of the the deployment so this will just tell you you know whatever information about the deployment like how much gas would be used and stuff like that and then when you're ready to deploy you just run that again and then you just say Dash Dash broadcast and then what you should be given is the contract address and we're going to also be using that so now we've deployed and we see some logging that's happened there in our anvil and you also see the the transaction ID and the contract ID so now that we've deployed our contract what we want to do is store that in an environment variable so I'm going to go ahead and do that well let me just do this so we have two environment variables now we have our contract address and our private key and now we want to call that contract because we want to start reading information from our contract locally so what we can do is say cast call and we're going to pass in the contract address and the method so we have that stored in our environment variable so we can just reference it and then what we want to do is called greet and we know that it's going to return a string and we get hello from Foundry that's what we expected pretty basic stuff but it's pretty cool to be you know calling that from the command line we we want to now send an update to update the greeting so we're going to say cast send we're going to say update greeting we're going to pass in the new greeting and then everything else is the same so if I copy that and then I go back and read the greeting again this should now have my new greeting and there we go we've read the contract we've updated and we've then read the new value so now that we've kind of gone over some of the basics let's look at how to install a new package so one of the most popular packages is open Zeppelin contracts so let's create an erc721 and what we're going to do is just say Forge install open Zeppelin slash opens up on contracts very similar to like npm install and what I need to do first is make a commit because they don't like that if you have uncommitted code okay so we're installing open Zeppelin contracts and after that's installed it just should just show up in our lib folder right there and we now need to configure our remappings because we need to tell our local environment where to find that code once we try to import it and use it so you can actually run Forge remappings and see already whatever remappings are configured and here you kind of already see them trying to kind of make some assumptions about your environment but we want to set a custom remapping so if you would like to do that you can actually just create a new file called remappings.

txt and we will set our remapping for open Zeppelin here and now we can actually just import that directly from open Zeppelin without having to reference the entire path and it looks something like that so we're going to we have maybe three more minutes and we're already over a little bit but we still have just one more thing to cover we want to look at mocking another user which is you know I think one of the more useful things that you could probably like learn here so to do that we're going to be going to make a new ERC 721. sole this is a really basic contract but you see now we're actually importing from open Zeppelin contracts which is pretty cool we're creating an ERC 721 called Devcon panda and we will just have a mint function pretty basic stuff and we're going to also have a test for this because this is going to be the part where we're actually learning something in the test thank you okay so the test that we have set up for right now is really basic we haven't added any of the um the mocking features yet but what we want to do is simulate another user so we have two users we have NOAA and we have Sophia and what we want to do is like create a token transfer it to another person we want to make sure that only the owner of that token can actually transfer the token so to do that we are going to use the prank method and you can either say prank and prank will be using the next call only to prank that user or you can say start prank and it will do all of the um users or all of the the calls that come after that until you call stop prank so this will like wrap up the workshop I know a little bit over um I'm going to go ahead and create the the function that we're going to be doing here and we have this method where we're going to test a transfer so we want to Mint a new token to NOAA we want to start pranking and simulating us being Noah we want to then transfer to Sophia and then we want to check the owner of that token and then assert that Sophia is indeed the owner and if we run for its tests that should work we want to actually only test this contract and if you would like to do that you can pass in the match contract so now we're only testing that one and to make sure that everything is working good we're going to assert that Bob is the owner when he's not the owner and everything fails which is what we want okay so that that's basically it we're not covering everything you can run Forge coverage which is a pretty cool command to give you test coverage and you can go even that's not working because the test has failed but anyways Forge covers is really nice so that wraps up the workshop I'm sorry we started a couple minutes late I'm sorry we went a couple minutes late over check out the GitHub repo walk through all that stuff a little bit slower if you'd like to learn more thank you foreign

Automatic transcript — names and jargon may be misspelled.