Foundry/Anvil: A local Ethereum node for development.

4 min readJun 21, 2024

Introduction

Smart contracts are the backbone of decentralized applications (DApps) on the Ethereum blockchain. To streamline development and testing, we can use Anvil, a local Ethereum node provided by Foundry. This article will guide you through writing, deploying, and testing a simple smart contract using Anvil.

Prerequisites

Before we begin, ensure you have the following installed:

  • Foundry: Install Foundry by running:
curl -L https://foundry.paradigm.xyz | bash
foundryup

Step 1: Create a Simple Smart Contract

First, let’s write a basic smart contract in Solidity. We’ll create a contract that allows us to store and retrieve an integer value.

  1. Create a new directory for your project:
mkdir StorageProject
cd StorageProject

2. Initialize a Foundry project:

forge init

Create the smart contract file: Create a file named SimpleStorage.sol in the src directory with the following content:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract SimpleStorage {
uint256 private storedData;

function set(uint256 x) public {
storedData = x;
}

function get() public view returns (uint256) {
return storedData;
}
}

Step 2: Set Up Anvil

Anvil is a local Ethereum node that simulates the Ethereum network, making it ideal for testing and development.

  1. Start Anvil: Open a terminal and start Anvil by running:
anvil
This will launch a local Ethereum node and provide you with a list of generated accounts and their private keys.

Step 3: Deploy the Smart Contract

Next, we’ll deploy the SimpleStorage contract to the Anvil node.

  1. Create a deployment script: Create a new file named deploy.js in the scripts
A new file named deploy.js

directory with the following content:

const { ethers } = require("ethers");

async function main() {
// Connect to Anvil
const provider = new ethers.providers.JsonRpcProvider("http://localhost:8545");
const signer = provider.getSigner(0);

// Compile the contract
const fs = require("fs");
const solc = require("solc");

const source = fs.readFileSync("src/SimpleStorage.sol", "utf8");
const input = {
language: "Solidity",
sources: {
"SimpleStorage.sol": {
content: source,
},
},
settings: {
outputSelection: {
"*": {
"*": ["abi", "evm.bytecode"],
},
},
},
};

const output = JSON.parse(solc.compile(JSON.stringify(input)));
const contractData = output.contracts["SimpleStorage.sol"]["SimpleStorage"];
const bytecode = contractData.evm.bytecode.object;
const abi = contractData.abi;

// Deploy the contract
const factory = new ethers.ContractFactory(abi, bytecode, signer);
const contract = await factory.deploy();
await contract.deployed();

console.log("SimpleStorage deployed to:", contract.address);
}

main().catch((error) => {
console.error(error);
process.exit(1);
});

Explaning the contract deploy.js

Import Libraries

const { ethers } = require(“ethers”);
const fs = require(“fs”);
const solc = require(“solc”);
  • ethers: This library is used for interacting with the Ethereum blockchain.
  • fs: This module provides an API for interacting with the file system, allowing you to read and write files.
  • solc: This is the Solidity compiler used to compile Solidity source code.

Main Function

The main function is declared as an async function, which allows the use of await to handle asynchronous operations.

async function main() {

Connect to Anvil

const provider = new ethers.providers.JsonRpcProvider("http://localhost:8545");
const signer = provider.getSigner(0);
  • provider: This connects to the Anvil local Ethereum node running at http://localhost:8545.
  • signer: This is the default signer (account) used to sign transactions. getSigner(0) gets the first account generated by Anvil.

Compile the Contract

const source = fs.readFileSync("src/SimpleStorage.sol", "utf8");
const input = {
language: "Solidity",
sources: {
"SimpleStorage.sol": {
content: source,
},
},
settings: {
outputSelection: {
"*": {
"*": ["abi", "evm.bytecode"],
},
},
},
};

const output = JSON.parse(solc.compile(JSON.stringify(input)));
const contractData = output.contracts["SimpleStorage.sol"]["SimpleStorage"];
const bytecode = contractData.evm.bytecode.object;
const abi = contractData.abi;
  • fs.readFileSync("src/SimpleStorage.sol", "utf8"): Reads the content of the SimpleStorage.sol file as a string.
  • input: Prepares the input for the Solidity compiler. It specifies the language (Solidity), the source code, and the desired outputs (ABI and bytecode).
  • solc.compile: Compiles the Solidity source code.
  • JSON.parse: Parses the compiler output from JSON format.
  • contractData: Extracts the compiled contract data, specifically the ABI and bytecode, for the SimpleStorage contract.
  • bytecode: The compiled bytecode of the contract.
  • abi: The Application Binary Interface of the contract, which defines how to interact with it.

Deploy the Contract

const factory = new ethers.ContractFactory(abi, bytecode, signer);
const contract = await factory.deploy();
await contract.deployed();

console.log("SimpleStorage deployed to:", contract.address);
  • ethers.ContractFactory: This is a factory for deploying new smart contracts. It takes the contract's ABI, bytecode, and signer as arguments.
  • factory.deploy(): Deploys the contract to the blockchain. This is an asynchronous operation, so await is used.
  • contract.deployed(): Waits until the deployment transaction is mined, ensuring the contract is deployed.
  • contract.address: Logs the deployed contract's address to the console.

Handle Errors

main().catch((error) => {
console.error(error);
process.exit(1);
});
  • .catch((error) => { ... }): Catches any errors that occur during the execution of the main function.
  • console.error(error): Logs the error to the console.
  • process.exit(1): Exits the process with a status code of 1, indicating an error occurred.

Install necessary dependencies:

Make sure you have ethers and solc installed. You can install them via npm:

npm install ethers solc

Run the deployment script:

Execute the script to deploy the contract:

node scripts/deploy.js
This script connects to the Anvil node, compiles the smart contract, and deploys it.

My GitHub profile where I have been actively contributing to various projects and repositories. I believe you might find my work interesting and valuable.

Here is the link to my GitHub profile: https://github.com/DCVglobalnetwork

I would be honored if you could follow me and explore my contributions.

--

--

Magda Jankowska
Magda Jankowska

Written by Magda Jankowska

Security Researcher for Web3 Cybersecurity Chainlink Advocate https://github.com/DCVglobalnetwork

No responses yet