Switching from Remix to Local Setup for Blockchain Development (Using foundry)
Setting up Solidity project with Foundry
After working with Remix, the next question that anyone with prior development experience would ask is - “A web based IDE? That doesn’t sound very convenient…”
And honestly, I get you! And that is why we have a Solidity based framework called FOUNDRY.
The following guide covers -
How to setup a foundry project
How to spin up a local blockchain network for testing (using ANVIL)
Best practices on using private key.
How to deploy a smart contract to this local blockchain network
How to deploy the same smart contract to a Testnet?
Pre requisites
VS Code must be installed
Install “solidity VS Code extension” - for code formatting and intellisence
1. How to setup a foundry project
In a new project directory (should be empty), run forge init
This will generate a bunch of folders.
Do the following clean ups -
Delete the
script/Counter.s.sol
(The file, not the folder)Delete
src/Counter.sol
(The file, not the folder)Delete
tests/Counter.t.sol
(The file, not the folder)
In src/ - create a new file “SimpleStorage.sol”
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract SimpleStorage {
uint256 myFavoriteNumber;
struct Person {
uint256 favoriteNumber;
string name;
}
// uint256[] public anArray;
Person[] public listOfPeople;
mapping(string => uint256) public nameToFavoriteNumber;
function store(uint256 _favoriteNumber) public {
myFavoriteNumber = _favoriteNumber;
}
function retrieve() public view returns (uint256) {
return myFavoriteNumber;
}
function addPerson(string memory _name, uint256 _favoriteNumber) public {
listOfPeople.push(Person(_favoriteNumber, _name));
nameToFavoriteNumber[_name] = _favoriteNumber;
}
}
In script/ Create a new file DeploySimpleStorage.s.sol
The following code and convention , of using it as a “Scripting” language as well is ONLY VALID FOR FOUNDRY and will not work in other frameworks.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
import {Script} from "forge-std/Script.sol";
import {SimpleStorage} from "../src/SimpleStorage.sol";
contract DeploySimpleStorage is Script {
function run() external returns (SimpleStorage) {
// Any transaction you want to perform should be between this
vm.startBroadcast();
SimpleStorage simpleStorage = new SimpleStorage();
vm.stopBroadcast();
}
}
Compiling the project.
To compile the project run - (Ps: you can ignore the warnings)
forge compile
(This will generate an “out” folder - with abi, bytecode etc)
2. How to spin up a local blockchain network for testing (using ANVIL)
Installing Foundry, should have also automatically download Anvil as a tool. Anvil is a cli tool that can be used to spin up a local blockchain environment.
Run the following in the CLI
anvil
When this command is run, it will printout the following
Available accounts - These are public account addresses - with preloaded 1000 ETH
Private keys - These are the corresponding private keys for those accounts
It also then prints some details regarding chain id, genesis block etc, that can be used.
With this your local blockchain is up and running
RPC URL - 127.0.0.1:8545
Chain ID - 31337
3. Best practices on using private key
To interact with this local blockchain - deploying the contract and accessing it, you obviously need to use an account (private key)
But using the private key in the CLI (Also, DO NOT use the VSCode Terminal, Use the native terminal) - Means pasting in the private key, in plain text, again and again. This should be avoided. We can use a keystore, to encrypt our private key and use the keystore while interacting with the blockchain to ensure more security and obscuring our private key. Lets see how to achieve this.
Assume you want to encrypt the following private key (Chill, this is a one of anvil keys)
0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
Run
cast wallet import myKey --interactive
Now you have successfully created an encrypted keystore - “myKey” (You can give it whatever name you want
Once you make this, you no longer need to copy-paste your private key. Simply ensure you use a secure password.
You can list all the wallets using
cast wallet list
4. Deploying smart contract to the local network
To deploy, we will use the DeployScript -
The sender in the below command is the “public address” of the corresponding private key you are using.
forge script script/DeploySimpleStorage.s.sol --rpc-url <http://127.0.0.1:8545> --broadcast --account myKey --sender 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266
On entering the password, you should get a success.
Your contract address (in the above example) is given in the terminal -
0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
After this, you would see a “broadcast” folder create.
The “transaction” key in the run-latest.json is the “API Data” that is sent to the blockchain network (Similar to a traditional HTTP post request)
"transaction": {
"from": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
"gas": "0x6c852",
"value": "0x0",
"input": "0x6080604052348015600e575f5ffd5b506105378061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610055575f3560e01c80632e64cec1146100595780632ebce6311461006f5780636057361d146100905780636f760f41146100a45780638bab8dd5146100b7575b5f5ffd5b5f545b6040519081526020015b60405180910390f35b61008261007d36600461023e565b6100e2565b604051610066929190610255565b6100a261009e36600461023e565b5f55565b005b6100a26100b2366004610330565b610196565b61005c6100c5366004610372565b805160208183018101805160028252928201919093012091525481565b600181815481106100f1575f80fd5b5f9182526020909120600290910201805460018201805491935090610115906103ac565b80601f0160208091040260200160405190810160405280929190818152602001828054610141906103ac565b801561018c5780601f106101635761010080835404028352916020019161018c565b820191905f5260205f20905b81548152906001019060200180831161016f57829003601f168201915b5050505050905082565b60408051808201909152818152602081018381526001805480820182555f91909152825160029091027fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf68101918255915190917fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf701906102169082610430565b5050508060028360405161022a91906104eb565b908152604051908190036020019020555050565b5f6020828403121561024e575f5ffd5b5035919050565b828152604060208201525f82518060408401528060208501606085015e5f606082850101526060601f19601f8301168401019150509392505050565b634e487b7160e01b5f52604160045260245ffd5b5f82601f8301126102b4575f5ffd5b813567ffffffffffffffff8111156102ce576102ce610291565b604051601f8201601f19908116603f0116810167ffffffffffffffff811182821017156102fd576102fd610291565b604052818152838201602001851015610314575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f60408385031215610341575f5ffd5b823567ffffffffffffffff811115610357575f5ffd5b610363858286016102a5565b95602094909401359450505050565b5f60208284031215610382575f5ffd5b813567ffffffffffffffff811115610398575f5ffd5b6103a4848285016102a5565b949350505050565b600181811c908216806103c057607f821691505b6020821081036103de57634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561042b57805f5260205f20601f840160051c810160208510156104095750805b601f840160051c820191505b81811015610428575f8155600101610415565b50505b505050565b815167ffffffffffffffff81111561044a5761044a610291565b61045e8161045884546103ac565b846103e4565b6020601f821160018114610490575f83156104795750848201515b5f19600385901b1c1916600184901b178455610428565b5f84815260208120601f198516915b828110156104bf578785015182556020948501946001909201910161049f565b50848210156104dc57868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f82518060208501845e5f92019182525091905056fea2646970667358221220beaeb58e0c3283f483e7dd74539e70c86cd2396aca6791be51ab3325431cecbb64736f6c634300081c0033",
"nonce": "0x1",
"chainId": "0x7a69"
}
Note: All values here are in hex format, we can easily see the decimal (base10) value using our cli.
Lets check how much gas was spent on this transaction -
cast to-base 0x6c852 dec
Interacting with the contract
Just like remix IDE, gives us those “buttons” to click and interact with a contract
We can use the CLI to interact with the blockchain. Here is how we can do it.
Sending the transaction (Equivalent to the “orange” buttons)
The argument, after send is nothing but the deployed contract address
cast send 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 "store(uint256)" 123456 --rpc-url <http://127.0.0.1:8545> --account myKey
Here, “123456” is simply the argument to the “store” function. This has to be of the type uint256. (Similar to what we would put in the input box in remix).
When we put this in the CLI, We are again prompted with the keystore password. Reminding us the brilliant practice we have implemented of minimising the use of our private key.
Once done, we get a success with the following output.
Reading from the chain (Equivalent to the “blue” buttons)
Use the “call” and “retrieve” arguments
❯ cast call 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 "retrieve()" --rpc-url <http://127.0.0.1:8545> --account myKey
You would get the following thing
0x000000000000000000000000000000000000000000000000000000000001e240
Use cask, to decode the hex to decimal
The output is what was the input to be stored
4. How to deploy the same smart contract to a Testnet?
The first thing that we need is the RPC URL.
For this, we will be accessing “Alchemy” - which will give us the RPC URL
Once you sign up (alchemy.com)
Follow below
- Create a new app
Go ahead and select “Ethereum” and create app.
Once the app is created, select “Sepolia” from dropdown
And copy the network url.
Now, we need to get the private key - of a wallet, that has testnet funds in it. I will use my meta mask wallet for this.
Now use the same command (forge script…) , but replace the variables
forge script script/DeploySimpleStorage.s.sol --rpc-url $RPC_URL --broadcast --account $KEY_STORE --sender $PUBLIC_ADDRESS
The contract is successfully deployed and can be viewed on the network’s blockchain explorer.
I deployed mine here - https://testnet.bscscan.com/tx/0x68ddf0877637f7e855bdbac3a3d4a1eb777d6dbe2537b281164528c25d4a63f2
You can use the same cli commands, with the updated RPC URLs to send and retrieve data on-chain.
Feel free to reach out if you face any roadblocks here!