Switching from Remix to Local Setup for Blockchain Development (Using foundry)

Setting up Solidity project with Foundry

Switching from Remix to Local Setup for Blockchain Development (Using 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 -

  1. How to setup a foundry project

  2. How to spin up a local blockchain network for testing (using ANVIL)

  3. Best practices on using private key.

  4. How to deploy a smart contract to this local blockchain network

  5. How to deploy the same smart contract to a Testnet?

Pre requisites

  1. VS Code must be installed

  2. Forge installation

  3. 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 -

  1. Delete the script/Counter.s.sol (The file, not the folder)

  2. Delete src/Counter.sol (The file, not the folder)

  3. 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

💡
Notice the “.s.sol” extension. This is a convention, which is for files that are basically used for scripting. Solidity is a contract based language, however, it can be used for writing scripts as well. Such scripts, by convention must have the extension - “.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

  1. Available accounts - These are public account addresses - with preloaded 1000 ETH

  2. Private keys - These are the corresponding private keys for those accounts

  3. 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

💡
Note how you need to enter the password to the keystore and not enter the private key at all!

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

  1. Create a new app

  1. Go ahead and select “Ethereum” and create app.

  2. 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
💡
While - you could use Sepolia to continue, I had some issues with the gas fees, and hence used BNB Testnet. And hence below, the binance-testnet etherscan is used

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!