Mastering Foundry: Episode 1 - Getting Started with Foundry

Mastering Foundry: Episode 1 - Getting Started with Foundry

Install, Deploy and Interact with Smart Contracts using Foundry


Side note, if you don't want to read, but want to watch a video, check it out here.

Welcome to the first episode of our series where we dive into the world of blockchain development with Foundry. In this episode, we'll cover the basics: installation, using the local test net Anvil, deploying smart contracts both locally and on the Scroll network, verifying your contract and finally, interacting with your contract.

1. How to Install Foundry

To install Foundry, you can use the following command:

curl -L https://foundry.paradigm.xyz | bash

After running this command, remember to source your .zshenv file to ensure your path is updated:

source /Users/your_username/.zshen

To verify the installation, update Foundry using Foundryup and check the version with Forge—version.

2. Create a Foundry Project

Next up we create a Foundry project

Create a new folder and navigate into it

mkdir project1 cd project1

Use the command forge init to create a new foundry project

forge init

Foundry keeps track of its setting in a .toml file. Install with better TOML in vs-code to format your .toml file and increase readability.

Next up use the Solidity by nomic foundation plugin to format Solidity.

3. Compiling in foundry

Inside the src folder you will find your contracts. Over here we can write or add our smart contract. I took this simple smart contract from Solidity by example and pasted in the Counter.sol

Don’t forget to change the name.

While we’re at it, lets comment out the test file and rename the deploy script. If you don’t do this, Foundry will throw a bunch of errors, because it can’t find the Counter.sol

That’s because we renamed it.

After this go ahead and run

forge compile

Navigat to the out folder and then to EtherWallet (the name of our contract) and you will find the abi over here.

ABI stands Application Binary Interface and basically is a json file with all the functions, variables and inputs our smart contract works with.

4. Time to deploy using the Local Testnet Anvil

Anvil is a local Ethereum testnet that is easy to set up and use.

Type anvil in your terminal and it automagically spins up a local testnet.

Inside your terminal it will point towards the local server that’s running the test network. Mine runs on http://127.0.0.1:8545 in your browser.

You can connect MetaMask to your local anvil node, by adding a new network.

Just click add network in your settings under Network. The most important part is adding the right local server address (this one http://127.0.0.1:8545)**)

You can also import the accounts in your terminal in MetaMask.

Go to Settings>Accounts>Import Account

Paste one of the private keys from your terminal here and voila. Your account is added.

Now run the following command to deploy your contract to anvil

forge create <NAME CONTRACT> --rpc-url <LOCALHOST> --interactive

My command looks something like this

forge create EtherWallet --rpc-url http://127.0.0.1:7545 --interactive

Pass one of the private keys that shows up in your terminal.

Boom done.

Warning

Messing around with private keys is tricky business. Anyone who has your keys has access to your contracts and funds. We don’t want that. You can delete the history of your terminal by running

history -c

It’s best practise to do that, so your terminal history is cleared after passing the private keys. More on using your keys later.

5. Deploying with Script

Foundry also allows you to deploy smart contracts by running a script. In your Foundry project there is a folder called script. Scripts are recognisable through the s.sol extension. We can rename the script file to DeployEtherWallet.s.sol.

This is what your script should look like

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

import {Script, console2} from "forge-std/Script.sol";
import {EtherWallet} from "../src/EtherWallet.sol";

contract EtherWalletScript is Script {
    function run() external returns (EtherWallet) {
       vm.startBroadcast();

       EtherWallet etherWallet = new EtherWallet();

       vm.stopBroadcast();
       return etherWallet;
   }
}

Using Anvil, you can simulate on-chain transactions. Deploy scripts can be run with an RPC URL:

forge script script/DeployEtherWallet.s.sol --rpc-url http://127.0.0.1:8545 --broadcast

Notice how we added —broadcast to the command. This command generates a folder called dry run containing details about our transaction.

You can also deploy by passing your private keys directly, though this is not recommended.

forge script script/DeployEtherWallet.s.sol --rpc-url http://127.0.0.1:8545 --broadcast --private-key <KEY HERE>

Remember to clear your command history (History -c) for security if you've used any private keys.

6. Using .env file

Another way to pass private keys, is to keep them in a seperate file. This is fine for a development environment, but not production.

Create a .env file in the foundry project manually or run the following command

touch .env

The content of the file looks something like this for local development:

PRIVATE_KEY=90872345902345723459-23745
RPC_URL=http://127.0.0.1:8545

Stick to these exact names for the variables. So don’t do RPCURL. Somehow I ran into issues when I changed the variable names slightly…just saying.

Next ‘load’ the .env file in foundry by running

source .env

Finally now you can deploy locally by running

forge script script/DeployEtherWallet.s.sol --rpc-url $RPC_URL --broadcast --private-key $PRIVATE_KEY

7. Deploying to Scroll Network

To deploy on a live testnet like the Scroll network, we first need to setup the .env file different. Here’s an example

PRIVATE_KEY=90872345902345723459-23745
RPC_URL=https://sepolia-rpc.scroll.io/

You need to pass the RPC URL for the network. Check out the Scroll Docs for the rpc url or something like chainlist.org

Export the private keys from MetaMask and add it to your .env file.

Remember…be careful with this…

Re-load your .env file in foundry

source .env

Now you can run the following command to deploy to a live testnet. Ps. make sure your wallet has some funds to deploy. To fund your wallet with some scroll testnet eth, check out this link.

forge script script/DeployEtherWallet.s.sol --rpc-url $RPC_URL --broadcast --private-key $PRIVATE_KEY

8. Verifying the Contract

Verifying your contract makes your contract readable on a blockchain scanner like etherscan or Scroll Scan. It also allows users to interact with the smart contract via the blockchain scanner.

First we need to adjust the .env file.

PRIVATE_KEY=39048124
RPC_URL=https://sepolia-rpc.scroll.io/
ETHERSCAN_API_KEY=139028423
VERIFIER_URL=https://api-sepolia.scrollscan.com/api

You can get an API key over here. Note, you will need to sign up for an account. Don’t worry…it’s free (for limited use)

To verify your contract, use the forge verify-contract command with the necessary details:

forge verify-contract <CONTRACTADDRESS> <CONTRACTNAME>\
  --verifier-url $VERIFIER_URL \
  --etherscan-api-key $ETHERSCAN_API_KEY

An example:

forge verify-contract 0x998608B4f83249c4217ADb9060Fb739d4A52C6A2 EtherWallet\
  --verifier-url $VERIFIER_URL \
  --etherscan-api-key $ETHERSCAN_API_KEY

Note, my contract doesn’t take any arguments in the constructor. If yours does, adjust the command to:

forge verify-contract 0xContractAddress EtherWallet\
  --verifier-url $VERIFIER_URL \
  --etherscan-api-key $ETHERSCAN_API_KEY \
  --constructor-args <your constructor arguments>

If your contract has constructor arguments, you can specify these in ABI-encoded form with the --constructor-args option. For example, if your constructor takes two uint256 variables:

--constructor-args $(cast abi-encode "constructor(uint256,uint256)" 0 7)

9. Interacting with your smart contract

You can interact with your smart contract by using the command cast.

To transact with a function use cast send

cast send <CONTRACT ADDRESS> <FUNCTIONNAME> <VALUE> --private-key $PRIVATE_KEY --rpc-url $RPC_URL

You will need to put the function name within quotation marks.

Example to send eth to the smart contract Ether Wallet:

cast send 0x998608B4f83249c4217ADb9060Fb739d4A52C6A2 --value 100000000000000000 --private-key $PRIVATE_KEY --rpc-url $RPC_URL

Example with my contract to withdraw eth

cast send 0x998608B4f83249c4217ADb9060Fb739d4A52C6A2 "withdraw(uint)" 99999999999999990 --private-key $PRIVATE_KEY --rpc-url $RPC_URL

To retrieve data use

cast call 0x998608B4f83249c4217ADb9060Fb739d4A52C6A2 "getBalance()" --rpc-url $RPC_URL

Note we’re not passing the private-keys in the last command, because retrieving data doesn’t require a state change. In other words we’re not changing balances or moving funds. If this happens we have to prove to the blockchain, that we have the authorisation to do so via our private keys.

Tips and Tricks

  • Converting Hexadecimal to Decimal: Use cast --to-base <hex value> decimal.

  • Environment Variables: Load your environment variables with source .env for enhanced security and convenience.

Stay tuned for the next episode, where we'll delve deeper into Foundry's capabilities and explore more advanced topics in smart contract development. Happy coding!