Ethereum Dev Stack
Ganache • Node • Web3 • MetaMask • Truffle • Hardhat • Solidity

Everything you need to build smart contracts — step by step.

This page is your hands‑on reference for the classroom and lab: installation, configuration, first contract, testing, deployment, and common pitfalls.

Glossary
  • Node.js JavaScript runtime required for Truffle/Hardhat and DApp tooling.
  • MetaMask Browser wallet (keys, accounts, signing, networks).
  • Ganache Local Ethereum chain (test accounts & faucets).
  • Truffle Framework: compile, migrate, test (Mocha/Chai).
  • Hardhat Dev environment: tasks, plugins, console, local node.
  • web3.js / ethers.js JS libraries to talk to Ethereum.
  • Solidity Smart‑contract language compiled to EVM bytecode.

Quick Overview: When to use what?

Ganache
  • Spin up a local chain instantly
  • Prefunded accounts for testing
  • Good for demos & deterministic tests
Hardhat
  • Great DX, plugin ecosystem
  • Built‑in network + console + tasks
  • TypeScript friendly
Truffle
  • Battle‑tested migrations
  • Mocha/Chai testing
  • Tight with Ganache
web3.js vs ethers.js
  • ethers: modern, typed, small API
  • web3: older, broad adoption
  • Pick one per project

Videos ▶️

Short clips to reinforce the toolchain. Captions available on YouTube.

Clip 1
Starts at 0:43
Clip 2
Starts at 0:12
Clip 3
Full video

Install Node.js (use nvm)

Recommended: install with nvm so students can switch versions easily.

# macOS/Linux
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# restart shell, then
nvm install --lts
nvm use --lts
node -v
npm -v
# Windows (PowerShell): use nvm-windows or Node installer
# https://github.com/coreybutler/nvm-windows
If a package says "requires Node >= X", use nvm install X and nvm use X.

Install & Configure MetaMask

  1. Install the MetaMask browser extension (Chrome/Brave/Firefox).
  2. Create a wallet → write down the 12/24‑word seed (offline!).
  3. Add networks: Localhost 8545 (Ganache/Hardhat), Sepolia (testnet), Mainnet.
  4. Import a private key from Ganache to test sending txs.
NEVER use real mainnet funds for classroom testing. Use testnets or local nodes only.
Tip: Turn on "Show test networks" in MetaMask settings.

Install Ganache (local chain)

Ganache provides a local blockchain with prefunded accounts and an RPC endpoint at http://127.0.0.1:8545.

# Install Ganache CLI (Node tool)
npm install -g ganache
# Run local chain
npx ganache --wallet.totalAccounts 10 --wallet.defaultBalance 1000
Copy a private key from Ganache to MetaMask (import account) to send transactions locally.

VS Code Extensions

  • Solidity (Juan Blanco): syntax + compile
  • Prettier: consistent formatting
  • ESLint: quality for scripts

Truffle Quickstart

mkdir hello-truffle && cd hello-truffle
npm init -y
npm install --save-dev truffle
npx truffle init
# Configure networks in truffle-config.js (development@8545)
# Compile
npx truffle compile
# Start Ganache in another terminal, then migrate
npx truffle migrate --network development
# Test
npx truffle test
If migrations hang: check RPC URL/port (8545), unlock an account, or reset Ganache.

Hardhat Quickstart

mkdir hello-hardhat && cd hello-hardhat
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox
npx hardhat # select "Create a JavaScript project"
# Run local node
npx hardhat node
# In another terminal, run tests
npx hardhat test
# Deploy to local node
npx hardhat run scripts/deploy.js --network localhost
Hardhat console: npx hardhat console --network localhost to interact with contracts.

Which one should students use?

  • Hardhat: modern DX, great for TypeScript, rich plugin ecosystem.
  • Truffle: simple mental model + fits Ganache labs; good for beginners.
  • Both compile Solidity via solc and produce ABI + bytecode.

web3.js vs ethers.js (pick one)

  • ethers.js: smaller API, strong typings, great docs.
  • web3.js: long history, many examples; larger surface.
// ethers: connect and read balance
import { ethers } from "ethers";
const provider = new ethers.JsonRpcProvider("http://127.0.0.1:8545");
const balance = await provider.getBalance("0xYourAddress");
console.log(ethers.formatEther(balance));
// web3.js: connect and read balance
import Web3 from "web3";
const web3 = new Web3("http://127.0.0.1:8545");
const balance = await web3.eth.getBalance("0xYourAddress");
console.log(web3.utils.fromWei(balance, "ether"));

Front‑end wiring (MetaMask provider)

// In a browser dapp
if (window.ethereum){
  const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' });
  // use ethers.js
  const provider = new ethers.BrowserProvider(window.ethereum);
  const signer = await provider.getSigner();
  console.log('Account', await signer.getAddress());
}
Never store private keys in frontend code. MetaMask signs for you.

Solidity Basics

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

contract Counter {
    uint256 public count;
    function inc() external { count += 1; }
    function dec() external { require(count>0, "underflow"); count -= 1; }
}
// Hardhat deploy script (scripts/deploy.js)
const hre = require("hardhat");
async function main(){
  const Counter = await hre.ethers.getContractFactory("Counter");
  const counter = await Counter.deploy();
  await counter.waitForDeployment();
  console.log("Counter deployed:", await counter.getAddress());
}
main();
Compiler version matters. Set it in hardhat.config.js or truffle-config.js.

Testing Patterns

// Hardhat + Mocha/Chai (test/counter.js)
const { expect } = require("chai");

describe("Counter", function(){
  it("increments and decrements", async function(){
    const Counter = await ethers.getContractFactory("Counter");
    const c = await Counter.deploy();
    await c.waitForDeployment();
    await c.inc();
    expect(await c.count()).to.equal(1n);
    await c.dec();
    expect(await c.count()).to.equal(0n);
  });
});
Use npx hardhat coverage (with plugin) to measure test coverage.

Local → Testnet → Mainnet

  1. Develop on Ganache/Hardhat node.
  2. Deploy to Sepolia (test ETH via faucet).
  3. After audits/review, deploy to mainnet.
Environment variables: store private keys & RPC URLs in .env and use dotenv.
# Example .env
SEPOLIA_RPC=https://sepolia.infura.io/v3/YOUR_KEY
PRIVATE_KEY=0xabc...
// hardhat.config.js
require("dotenv").config();
module.exports = {
  solidity: "0.8.20",
  networks: {
    localhost: { url: "http://127.0.0.1:8545" },
    sepolia: {
      url: process.env.SEPOLIA_RPC,
      accounts: [process.env.PRIVATE_KEY]
    }
  }
};

Contract Verification

  • Hardhat plugin: @nomicfoundation/hardhat-verify
  • Verify on Etherscan for transparency and ABIs
  • Tag releases in Git, include commit hash in metadata

Common Pitfalls & How to Avoid Them

  • Wrong network in MetaMask: txs never land → check RPC and chainId.
  • Non‑matching compiler: contract won’t verify → align solc versions.
  • Gas estimation errors: add checks & use estimateGas before sending.
  • Time‑dependent code: use block timestamps carefully; test edge cases.
  • Reentrancy: follow Checks‑Effects‑Interactions; consider ReentrancyGuard.
  • Integer math: solidity ^0.8 has built‑in overflow checks; still validate inputs.
  • Approvals: front‑ends should show exact allowances; add revoke path.
  • Upgrades: proxy patterns add complexity; test storage layout changes thoroughly.

Security Quick Checklist

  • Run static analyzers (Slither, MythX‑style tools)
  • 100% test coverage on money flows
  • Use onlyOwner/AccessControl for admin
  • Pause switches (Pausable) and rate limits
  • Separate hot (ops) and cold (treasury) wallets
  • Bug bounty before mainnet

Self‑Check (Answers Included)

Q1. What is Ganache used for?
A local Ethereum chain with prefunded accounts for fast, repeatable testing.
Q2. Why use nvm for Node.js?
To switch Node versions per project, matching toolchain requirements.
Q3. MetaMask role in development?
Key management and tx signing in the browser; exposes window.ethereum to DApps.
Q4. Truffle vs Hardhat?
Truffle = classic migrations & Ganache fit; Hardhat = modern DX, plugins, console, TS‑friendly.
Q5. web3.js vs ethers.js?
Either works; ethers has smaller, typed API; pick one for consistency.
Q6. One common security pitfall?
Reentrancy; avoid by CEI pattern or using ReentrancyGuard.