Now that Foundry is installed, we can build out the functionality of our smart contract written in Solidity. We'll create various functions that allow you to increment, decrement, and read a number whose state is kept in your smart contract.
All of the functions will have different visibility modifiers and types that constrain the behavior of your functions. We'll create our own custom error that is thrown whenever you step outside the bounds of your intended functionality.
Noah Hein: [0:02] To begin, we will open up our Contract.sol file in our src folder. The first thing that you'll notice is this very first line is a comment. SPDX-License-Identifier is just what software license you would like your program to use. We will be keeping this as unlicensed, since we are not planning to publish this. [0:23] On our first line of code, you can see that we're declaring our Solidity compiler's version with pragma solidity. We're saying that we are going to grab a version greater than .8.13. Then we're declaring a contract whose name is Contract.
[0:40] Let's go ahead. We will change contract to the Number. Then we will declare a private variable of type uint. We will call that num. There's no value here. We are just creating the variable that we will assign a value to via the constructor. Our constructor will take another uint argument, and we will call this _num, and we will just set num = _num. This constructor will run whenever this contract is deployed and then never again.
[1:28] The next thing that we want to make is a mutator function, we will call this increment(), and we will need to give it a visibility modifier of public, which means that anything or anyone has access to this. Anyone will be able to increment our private variable called num through this public function. We will just set num += 1.
[1:58] Next thing that we'll do is another function, and this will be decrement(). This will again be a public function. However, we also want for this one to take an argument of _num. You can see this underscore syntax that we've used both in the decrement and in the constructor is not necessary but is considered best practice whenever you are manipulating a variable that is contained within your smart contract.
[2:29] Since we are manipulating num, if you are going through a smart contract and you see this underscore, there should be a variable that doesn't have the prefix attached, that its state is kept in the smart contract itself. For decrement, we will then call num and then we will take away whatever the value of _num is.
[2:59] The last thing that we're going to do is create a reader function because currently we have no way to read the value. Since this is a private variable, we do not have access to it. For this reader function we will again make this a public.
[3:16] There is another modifier, and this is called view, and view means that no state is going to change in this contract. It will throw a compiler error if you attempt to change state in the contents of a view labeled function. Since we're going to be returning something, we need to declare the return type as well. It will be returns(uint). You can see here we can just return num.
[3:55] Awesome. This is the entirety of the smart contract that we will be using. However, and you may notice that this on line 16 is potentially a bug since everything in this contract is of type uint. We are taking any number an arbitrary argument and taking it away from num. There is potential for underflow errors to occur here.
[4:22] We want to account for that. We will create a custom error, and we will call it UnsafeDecrement(). Here, what we can do is we will just wrap this in an if statement. We could say if ( num - _num ) > , then we can go ahead and safely deduct the parameter num from our value of num.
[4:51] If it wouldn't be greater than zero, then we don't want to do it. What we will do here is we will just call else, and we will use the keyword revert, which will abort the execution of this function and it will revert any state that had changed. We will say revert UnsafeDecrement and that will throw this custom error that we established earlier.
[5:16] Now we can know that this will always be safe to do so, and it will throw an error should we perform a dangerous or unsafe decrement.