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!