Foundry Fundamentals Part-1
Foundry Setup
Installing Foundry
curl -L https://foundry.paradigm.xyz | bash
Install Foundry components
foundryup
Create a folder
mkdir foundry-f23
cd foundry-f23
Creating a new project
forge init nameOfNewFolder
We will get these files under foundry-f23
lib
is the folder where all your dependencies are installed, here you'll find things like:
forge-std
(the forge library used for testing and scripting)openzeppelin-contracts
is the most battle-tested library of smart contracts- and many more, depending on what you need/install
scripts
is a folder that houses all your scripts
src
is the folder where you put all your smart contracts
test
is the folder that houses all your tests
foundry.toml
- gives configuration parameters for Foundry
More on these folders and files later.
Please right-click src
, click on New File
and name it SimpleStorage.sol
. Copy the code available here.
One last thing, please delete Counter.s.sol
, Counter.sol
and Counter.t.sol
. These files are a set of basic smart contracts that Foundry provides as a default when you create a new Foundry project.
Deploy a smart contract locally using Anvil
anvil
Deploy a smart contract locally using Forge
To find out more about forge’s capabilities type
forge --help
Each blockchain (private or public) has an RPC URL (RPC SERVER) that acts as an endpoint. When we tried to deploy our smart contract, forge tried to use http://localhost:8545/
, which doesn't host any blockchain. Thus, let's try to deploy our smart contract specifying the place where we want to deploy it.
forge create SimpleStorage --rpc-url <http://127.0.0.1:8545> --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efe784d7bf4f2ff80
*private key is invalid
Private Key Safety
Having a private key in plain text is extremely bad. The private key(s) we used in the last lesson are well-known keys for local testing, you shouldn’t use those on mainnet and keeping them in plain text is ok, but any other private key should be kept hidden, especially your production key or key’s associated with accounts that hold crypto.
Moreover, it’s very bad to have private keys in bash history (hit the up arrow and see the key you used to deploy).
You can delete your history by typing:
history -c
Deploy a smart contract locally using Anvil
In Foundry we keep our scripts in the script
folder.
Please create a new file called DeploySimpleStorage.s.sol
.
Using .s.sol
as a suffix is a naming convention for Foundry scripts, in future lessons, when we'll write Foundry tests, these will bear the suffix of .t.sol
.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {Script} from "forge-std/Script.sol";
import {SimpleStorage} from "../src/SimpleStorage.sol";
contract DeploySimpleStorage is Script {
function run() external returns (SimpleStorage) {
vm.startBroadcast();
SimpleStorage simpleStorage = new SimpleStorage();
vm.stopBroadcast();
return simpleStorage;
}
}
run
is an external function that will return the SimpleStorage
contract.
In the Run function, we are going to use a distinctive keyword: vm
. Foundry has a distinctive feature known as cheat codes. The vm
keyword is a cheat code in Foundry, and thereby only works in Foundry.
vm.startBroadcast
indicates the starting point for the list of transactions that get to be sent to the RPC URL
;
Similarly, vm.stopBroadcast
indicates the ending point of the list of transactions that get to be sent to the RPC URL
;
forge script script/DeploySimpleStorage.s.sol --rpc-url <http://127.0.0.1:8545>
[⠆] Compiling...
[⠔] Compiling 2 files with 0.8.19
[⠒] Solc 0.8.19 finished in 1.08s
Compiler run successful!
Script ran successfully.
Gas used: 338569
== Return ==
0: contract SimpleStorage 0x90193C961A926261B756D1E5bb255e67ff9498A1If you wish to simulate on-chain transactions pass a RPC URL.
Hit the up arrow key and add --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7f4f2ff80
at the end.
forge script script/DeploySimpleStorage.s.sol --rpc-url <http://127.0.0.1:8545> --broadcast --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
Transaction: 0x73eb9fb4ef7b159e03c50d669c42e2ec4eeaa9358bea0a710cb07168e5192570
Contract created: 0x5fbdb2315678afecb367f032d93f642f64180aa3
Gas used: 357088
Block Number: 1
Block Hash: 0x8ea564f146e04bb36fc27f0b491223a023b5882d2fcfce3ff85e0dd152e611e4
Block Time: "Tue, 16 Apr 2024 13:39:51 +0000"
Having our private key in plain text is very bad,
Create a new file in the root of your project called .env
. Then, go the .gitignore
file and make sure .env
is in there.
The .env
file will host environment variables. Variables that are of a sensitive nature that we don't want to expose in public.
PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
RPC_URL=http://127.0.0.1:8545
forge script script/DeploySimpleStorage.s.sol --rpc-url $RPC_URL --broadcast --private-key $PRIVATE_KEY
we showed you how to configure and use a .env
file to hold your private key and rpc url, some developments have taken place since that lesson was made so ... You should never use a .env
again.
Encrypting your Keys Using ERC2335
For now, let’s pretend our private key is this:
0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
(key 0 from Anvil)
Type the following command in your terminal
cast wallet import nameOfAccountGoesHere --interactive
Foundry has a built-in tool known as Cast
. Cast
comes loaded with numerous commands to interact with. Learn more about them by typing cast --help
. One such useful command is send
which is designed to sign and publish a transaction. To view help about send
, type cast send --help
.
To use send
we need a signature and some arguments.
cast send 0x5FbDB2315678afecb367f032d93F642f64180aa3 "store(uint256)" 1337 --rpc-url $RPC_URL --private-key $PRIVATE_KEY
What did we just do?
Let’s break it down:
cast send
is the command we used to sign and publish our transaction;0x5FbDB2315678afecb367f032d93F642f64180aa3
or any other address is the target of ourcast send
, the contract we are interacting with;"store(uint256)"
is the signature of the function we are calling.1337
is the number we pass to thestore
function. As we can see in the function signature, we are expected to provide anuint256
input. You can obviously provide any number you want, as long as it fitsuint256
.- you already know what
-rpc-url $RPC_URL --private-key $PRIVATE_KEY
are. The place where we send and the private key we use to sign.
Reading information from the blockchain
cast
conveniently provides a way to read information stored on the blockchain. Type cast call --help
in your terminal to find out more. It works similarly to send
, where you have to provide a signature and some arguments. The difference is you are only peering into the storage, not modifying it.
Call the following command in your terminal:
cast call 0x5FbDB2315678afecb367f032d93F642f64180aa3 "retrieve()"
We receive back the following:
0x0000000000000000000000000000000000000000000000000000000000000539
This represents a hex value. In the previous lessons, we learned how to convert this to a normal number.
Type the following command in your terminal:
cast --to-base 0x0000000000000000000000000000000000000000000000000000000000000539 dec
Thank you for reading, I hope this article helped you understand the concepts.
Connect with me: