Writing And Deploying Smart Contracts Using Foundry & Thirdweb Deploy
Tags: ethereum, smartcontracts, web3, solidity
Published: 2022-07-25 15:55:35

In this tutorial, we will discuss how using [Foundry](https://book.getfoundry.sh/) we can develop a Smart  Contract, write tests for it and deploy our Smart Contract to the blockchain using [thirdweb deploy](https://thirdweb.com/).

Tools and tech stack we'll be using:
- Solidity
- Foundry
- Thirdweb Deploy

> Note: Refer to this [repo](https://github.com/Nazeeh21/foundry-thirdweb) for the code reference.

### Why Foundry?
Hardhat is definitely a nice Ethereum Development Environment but [Foundry](https://book.getfoundry.sh/) has some more cool benefits to offer.
- Unlike Hardhat, [Foundry](https://book.getfoundry.sh/) allows us to write tests as well as scripts in Solidity
- Foundry comes with the Forge Standard library, which allows using [`Dappsys Test`](https://book.getfoundry.sh/reference/ds-test) to assert values.
- We can simply log values using `emit_log(string)`, `emit_int(int_value)`, `emit_uint(uint_value)`, `emit_address(address_value)`, etc. to log values of different data types
- To get more detailed information on the tests, we can simply use the `-v` flag after the test command. More the number of `v` will give us more detailed info. Example: `forge test -vvv`. We can add up to five `v` flags.
- We can mock a user (or we can say an account) using [`.prank`](https://book.getfoundry.sh/cheatcodes/prank.html) and [`.startPrank`](https://book.getfoundry.sh/cheatcodes/start-prank.html).
- We can set nounce, block number, and timestamp for an account.
- Foundry gives us the detailed gas report for our tests by running the below command.
```shell
forge test --gas-report
```
- Foundry provides us **Fuzzing** that allows us to define parameters for our test function and it will populate those parameters values on runtime

### Why thirdweb deploy?
- [Thirdweb deploy](https://thirdweb.com/) provides us a `thirdweb-cli` which allows deploying our Smart Contract to the blockchain without using our account's bare private key.
- After deploying the contract, it provides us a nice dashboard to interact with the deployed contract.
- It comes with some of the standard pre-built contracts like ERC-20, ERC-721, etc. so that we can directly deploy and use it from their dashboard.
- It supports deployment on multiple chains.
- It has powerful SDKs for our smart contracts with support for many languages and frameworks.

## Getting Started
To get started, we first need to install the foundry. Follow their docs [here](https://book.getfoundry.sh/getting-started/installation#install-the-latest-release-by-using-foundryup) to install and start running foundry locally. 

Once you have foundry up and running locally, create a new project by running the following command in your terminal and then `cd` into the project directory. For this tutorial, I'm naming my project `learn-foundry`, you can name it anything you want.

```sh
forge init learn-foundry
cd learn-foundry
```
You should see the following output in your terminal
![terminal-output](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3f30cfanqk5uwljbw795.png)
 
Let's understand what the project structure of this newly created project looks like.
```shell
$ tree . -d -L 1
.
├── lib
├── src
└── test

3 directories
```
The starter kit consists of Forge Standard Library pre-installed. This is the preferred testing library used for Foundry projects. Additionally, the template also comes with an empty starter contract and a simple test.

Let's write our own simple contract and test for it. For that open this project in your code editor and navigate to the `Contract.sol` file in the `src` folder under your root directory. Paste the below code in your `Contract.sol` file. For this tutorial, we'll be using a simple Contract that keeps track of a count and allows us to increment, decrement and get the count value. 
  
```sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

contract CountContract {
  uint public count;
  
  constructor (uint _count) {
    count = _count;
  }

  function setCount (uint _count) public {
    count = _count;
  }

  function increment() public {
    count++;
  }

  function decrement() public {
    count--;
  }
}
```
### Explanation of the Contract
I've added the `constructor` which will be executed while deploying the contract and in this function, I'm initializing the value of our `count` variable by taking input from the user.

Following that, `setCount` allows us to set the value of our `Count` variable. Likewise, the `increment` and `decrement` functions increase and decrease the value of our `count` variable.

### Writing tests

As we have our Contract ready, navigate to the `Contract.t.sol` file into the `test` folder, and let's write tests for our contract. We already have the `ContractTest` contract initiated by the foundry, inside that contract paste the below code.

```sol
    

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/Test.sol";
import "src/Contract.sol";

contract ContractTest is Test {
    CountContract countContract;
    function setUp() public {
        countContract = new CountContract(10);
    }

    function testIncrement() public {
        countContract.increment();
        assertEq(countContract.count(), 11);
    }

    function testDecrement() public {
        countContract.decrement();
        assertEq(countContract.count(), 9);
    }

    function testSetCount() public {
        countContract.setCount(20);
        assertEq(countContract.count(), 20);
    }
}
```
### Explanation of the `ContractTest` contract
In the first line of the contract, we are defining a variable `countContract` of type `CountContract`. 
After that, we have defined the `setUp` function which is an optional function invoked before each test case is run. In this, we're creating a new instance of our Smart Contract `CountContract` and passing 10 as an argument. Thus, we are initializing our `count` variable in our smart contract with the value of 10.

After that, we have the `testIncrement` function in which we are testing the increment of our `count` variable.  Here, we are asserting the value using the `assertEq` function which we're getting from Forge's standard `Test.sol`.
Likewise, we have `testDecrement` and `testSetCount` that tests `decrement` and `setCount` respectively. We have used `CountContract` in our tests, so we also need to import it by adding the following import statement above our test contract.

```tsx
import "src/Contract.sol";
```

> Note: Any functions prefixed with `test` is run as test cases.

Now, let's run our tests and see if our contract works as expected or not.

```shell
forge test
``` 
You should see the following output in your terminal
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1658498212599/0h_eLJE9w.png align="left")

### Deployment
As our tests are passed let's deploy our Smart Contract on the Rinkeby test net. For deployment, we are going to use `thirdweb-cli` from [thirdweb deploy](https://thirdweb.com/). For that, run the following command to detect contracts or extensions in our project.
```shell
npx thirdweb detect
```
Allow it to install the `thirdweb` package locally when prompted. You should see the following output on your terminal
![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1658504028244/-ncD8TFby.png align="left")

We have everything set up by now, so let's deploy our Smart Contract by running the following command.
```shell
npx thirdweb deploy
```
This command will compile our Smart Contract, upload the result and will open a thirdweb dashboard in your browser as shown below. If it doesn't open, then manually open the link from the terminal.
![thirdweb-dashboard](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g42y9cynqs0kd2byzphh.png) 

We have to pass the initial count parameter as we have required it in our constructor. Pass any number of your choice and select []**Rinkeby** from the *Network* dropdown. Connect your wallet to the thirdweb dashboard and make sure that you are on the Rinkeby test network. Once connected, click on the **Deploy Now** button. This will open 2 MetaMasks popups, **Confirm** both the transactions. Once the transactions are executed, it'll show the dashboard as shown below.

![thirdweb playground](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uckl7ulv8a6yxe62cx5k.png) 

That's it! You have successfully deployed your contract without risking your private key. You can now use this dashboard to play around with your contract. 

### Some useful resources on Foundry
- [Tutorial on Foundry](https://youtu.be/uelA2U9TbgM) 
- [Foundry CheatSheet](https://github.com/dabit3/foundry-cheatsheet)