Skip to content
Published on

Blockchain & Web3 Developer Guide 2025

Authors

Introduction

In 2025, the blockchain ecosystem has matured beyond speculative hype into genuine technical infrastructure. Ethereum's Dencun upgrade, the explosive growth of Layer 2 rollups, and RWA (Real World Assets) tokenization meeting mainstream finance have driven demand for Web3 developers to all-time highs.

This guide systematically covers blockchain fundamentals, Solidity smart contract development, security, the DeFi/NFT ecosystem, and Web3 developer careers.

Key Expressions

ExpressionMeaning
Smart ContractSelf-executing program on the blockchain. Code is the contract
Layer 2Scaling solutions built on top of mainnet (L1). Increases throughput, reduces cost
DeFiDecentralized Finance. Financial services via smart contracts without intermediaries
Gas OptimizationTechniques to minimize smart contract execution cost (Gas)

1. Blockchain Fundamentals

1.1 What Is a Blockchain?

A blockchain is a technology where all participants in a distributed network share the same transaction record (ledger). Each block contains the hash of the previous block, forming a chain.

┌──────────┐    ┌──────────┐    ┌──────────┐
Block 0  │───▶│ Block 1  │───▶│ Block 2 (Genesis)│    │          │    │          │
Hash: 0a │    │ Prev: 0a │    │ Prev: 7f │
Nonce: 42│    │ Hash: 7f │    │ Hash: b3 │
Txs: []  │    │ Txs: [..] │   │ Txs: [..]└──────────┘    └──────────┘    └──────────┘

1.2 Consensus Mechanism Comparison

FeaturePoW (Proof of Work)PoS (Proof of Stake)DPoS
Energy ConsumptionVery HighLowLow
DecentralizationHighMediumLow
TPS7-1530-100K+1000+
Representative ChainsBitcoinEthereum 2.0EOS, Tron
Participation RequirementHash power (GPU/ASIC)Staked assetsDelegated votes
FinalityProbabilistic (6 blocks)Epoch-based deterministicFast deterministic

1.3 Hash Functions and Merkle Trees

Blockchain integrity relies on cryptographic hash functions.

import hashlib

def calculate_hash(block_data):
    """Calculate SHA-256 hash of block data"""
    data_string = str(block_data).encode()
    return hashlib.sha256(data_string).hexdigest()

# Merkle Tree implementation
def merkle_root(transactions):
    if len(transactions) == 0:
        return hashlib.sha256(b'').hexdigest()
    if len(transactions) == 1:
        return transactions[0]

    new_level = []
    for i in range(0, len(transactions), 2):
        left = transactions[i]
        right = transactions[i + 1] if i + 1 < len(transactions) else left
        combined = hashlib.sha256((left + right).encode()).hexdigest()
        new_level.append(combined)

    return merkle_root(new_level)

1.4 Transaction Lifecycle

User -> Create Transaction -> Sign (Private Key) -> Broadcast
    -> Enter Mempool -> Validator/Miner Selection -> Block Inclusion
    -> Consensus -> Block Finalization -> State Update

2. Ethereum and the EVM Deep Dive

2.1 Ethereum Architecture

Ethereum started with the vision of a World Computer. While Bitcoin only stores transaction records, Ethereum can execute arbitrary logic through its Turing-complete virtual machine (EVM).

┌─────────────────────────────────────────┐
Ethereum Network├─────────────────────────────────────────┤
│  ┌─────────┐  ┌──────────┐  ┌────────┐ │
│  │   EOA   │  │ Contract │  │Contract│ │
│  │ Account │──│ Account  │──│Account │ │
 (User) (Code)(Code)  │ │
│  └─────────┘  └──────────┘  └────────┘ │
├─────────────────────────────────────────┤
EVM (Execution Engine)├─────────────────────────────────────────┤
State Trie (State Storage)└─────────────────────────────────────────┘

2.2 How the EVM Works

The EVM is a stack-based virtual machine using 256-bit word sizes.

EVM Memory Model:
┌─────────────┐
StackMax 1024 depth, LIFO
   (256-bit)├─────────────┤
MemoryByte array, volatile
  (expandable)├─────────────┤
StorageKey-value, persistent
  (256->256)└─────────────┘

Key Opcode examples:

PUSH1 0x60    // Push 0x60 to stack
PUSH1 0x40    // Push 0x40 to stack
MSTORE        // Memory[0x40] = 0x60
CALLVALUE     // Push msg.value to stack
DUP1          // Duplicate stack top
ISZERO        // 1 if zero, else 0

2.3 Gas System

Every EVM operation incurs a Gas cost.

OperationGas CostDescription
ADD / SUB3Arithmetic
MUL / DIV5Multiplication / Division
SLOAD2100 (cold) / 100 (warm)Storage read
SSTORE20000 (new) / 5000 (update)Storage write
CALL2600 (cold) / 100 (warm)External call
CREATE32000Contract creation

Gas cost formula:

Total Cost = Gas Used * Gas Price (Gwei)
           = Gas Used * (Base Fee + Priority Fee)

Example: 21000 Gas * 30 Gwei = 630,000 Gwei = 0.00063 ETH

3. Solidity Smart Contract Development

3.1 Basic Syntax

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

/**
 * @title SimpleStorage
 * @dev Basic state storage contract
 */
contract SimpleStorage {
    // State variables
    uint256 private storedValue;
    address public owner;
    mapping(address => uint256) public balances;

    // Events
    event ValueChanged(address indexed setter, uint256 newValue);

    // Modifiers
    modifier onlyOwner() {
        require(msg.sender == owner, "Not the owner");
        _;
    }

    constructor(uint256 _initialValue) {
        owner = msg.sender;
        storedValue = _initialValue;
    }

    function setValue(uint256 _value) external onlyOwner {
        storedValue = _value;
        emit ValueChanged(msg.sender, _value);
    }

    function getValue() external view returns (uint256) {
        return storedValue;
    }
}

3.2 ERC-20 Token Implementation

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyToken is ERC20, Ownable {
    uint256 public constant MAX_SUPPLY = 1_000_000 * 10**18;

    constructor() ERC20("MyToken", "MTK") Ownable(msg.sender) {
        _mint(msg.sender, MAX_SUPPLY);
    }

    function burn(uint256 amount) external {
        _burn(msg.sender, amount);
    }
}

3.3 ERC-721 NFT Implementation

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract MyNFT is ERC721, ERC721URIStorage, Ownable {
    uint256 private _nextTokenId;
    uint256 public mintPrice = 0.05 ether;
    uint256 public maxSupply = 10000;

    constructor() ERC721("MyNFT", "MNFT") Ownable(msg.sender) {}

    function mint(string memory uri) external payable {
        require(msg.value >= mintPrice, "Insufficient payment");
        require(_nextTokenId < maxSupply, "Max supply reached");

        uint256 tokenId = _nextTokenId++;
        _safeMint(msg.sender, tokenId);
        _setTokenURI(tokenId, uri);
    }

    function tokenURI(uint256 tokenId)
        public view override(ERC721, ERC721URIStorage)
        returns (string memory)
    {
        return super.tokenURI(tokenId);
    }

    function supportsInterface(bytes4 interfaceId)
        public view override(ERC721, ERC721URIStorage)
        returns (bool)
    {
        return super.supportsInterface(interfaceId);
    }

    function withdraw() external onlyOwner {
        payable(owner()).transfer(address(this).balance);
    }
}

3.4 Advanced Pattern: Upgradeable Proxy

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

// Implementation V1
contract BoxV1 {
    uint256 private value;

    function store(uint256 newValue) public {
        value = newValue;
    }

    function retrieve() public view returns (uint256) {
        return value;
    }
}

// Implementation V2 (after upgrade)
contract BoxV2 {
    uint256 private value;

    function store(uint256 newValue) public {
        value = newValue;
    }

    function retrieve() public view returns (uint256) {
        return value;
    }

    function increment() public {
        value += 1;
    }
}

4. Development Tools: Hardhat vs Foundry

4.1 Hardhat Setup and Usage

# Project initialization
mkdir my-project && cd my-project
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox

# Create Hardhat project
npx hardhat init
// hardhat.config.js
require("@nomicfoundation/hardhat-toolbox");

module.exports = {
  solidity: {
    version: "0.8.20",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200,
      },
    },
  },
  networks: {
    sepolia: {
      url: process.env.SEPOLIA_RPC_URL || "",
      accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
    },
    hardhat: {
      forking: {
        url: process.env.MAINNET_RPC_URL || "",
        blockNumber: 18_000_000,
      },
    },
  },
};

Hardhat test example:

const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("SimpleStorage", function () {
  let storage;
  let owner;
  let addr1;

  beforeEach(async function () {
    [owner, addr1] = await ethers.getSigners();
    const SimpleStorage = await ethers.getContractFactory("SimpleStorage");
    storage = await SimpleStorage.deploy(42);
  });

  it("Should store the initial value", async function () {
    expect(await storage.getValue()).to.equal(42);
  });

  it("Should allow owner to set value", async function () {
    await storage.setValue(100);
    expect(await storage.getValue()).to.equal(100);
  });

  it("Should reject non-owner setValue", async function () {
    await expect(
      storage.connect(addr1).setValue(100)
    ).to.be.revertedWith("Not the owner");
  });
});

4.2 Foundry Setup and Usage

# Install Foundry
curl -L https://foundry.paradigm.xyz | bash
foundryup

# Create project
forge init my-foundry-project
cd my-foundry-project
# foundry.toml
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
optimizer = true
optimizer_runs = 200
solc_version = "0.8.20"

[profile.default.fuzz]
runs = 1000
max_test_rejects = 65536

[rpc_endpoints]
mainnet = "https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY"
sepolia = "https://eth-sepolia.g.alchemy.com/v2/YOUR_KEY"

Foundry test (written in Solidity):

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

import "forge-std/Test.sol";
import "../src/SimpleStorage.sol";

contract SimpleStorageTest is Test {
    SimpleStorage public store;
    address public owner = address(this);
    address public user = address(0x1);

    function setUp() public {
        store = new SimpleStorage(42);
    }

    function testInitialValue() public view {
        assertEq(store.getValue(), 42);
    }

    function testSetValue() public {
        store.setValue(100);
        assertEq(store.getValue(), 100);
    }

    function testFailNonOwnerSetValue() public {
        vm.prank(user);
        store.setValue(100); // This call will revert
    }

    // Fuzz test
    function testFuzzSetValue(uint256 value) public {
        store.setValue(value);
        assertEq(store.getValue(), value);
    }
}

4.3 Hardhat vs Foundry Comparison

FeatureHardhatFoundry
LanguageJavaScript/TypeScriptSolidity
Test SpeedModerateVery fast (10x+)
Fuzz TestingPlugin requiredBuilt-in
Debuggingconsole.logforge debug (step)
Fork TestingSupportedSupported (faster)
Plugin EcosystemRichGrowing
Gas Reportshardhat-gas-reporterforge test --gas-report
Learning CurveJS developer friendlySolidity-focused

5. Smart Contract Security

5.1 Reentrancy Attack

The most famous smart contract vulnerability, responsible for the 2016 DAO hack (60 million dollar loss).

// Vulnerable code
contract VulnerableVault {
    mapping(address => uint256) public balances;

    function deposit() external payable {
        balances[msg.sender] += msg.value;
    }

    // DANGEROUS: state update after external call
    function withdraw() external {
        uint256 amount = balances[msg.sender];
        require(amount > 0, "No balance");

        // External call (attack vector)
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");

        // State update AFTER external call!
        balances[msg.sender] = 0;
    }
}

// Attacker contract
contract Attacker {
    VulnerableVault public vault;

    constructor(address _vault) {
        vault = VulnerableVault(_vault);
    }

    function attack() external payable {
        vault.deposit{value: msg.value}();
        vault.withdraw();
    }

    // withdraw()'s call returns here -> calls withdraw() again
    receive() external payable {
        if (address(vault).balance > 0) {
            vault.withdraw();
        }
    }
}

Solution: Checks-Effects-Interactions Pattern

contract SecureVault {
    mapping(address => uint256) public balances;
    bool private locked;

    modifier noReentrant() {
        require(!locked, "Reentrant call");
        locked = true;
        _;
        locked = false;
    }

    function withdraw() external noReentrant {
        uint256 amount = balances[msg.sender];
        require(amount > 0, "No balance");

        // Effects (update state first)
        balances[msg.sender] = 0;

        // Interactions (external call last)
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
    }
}

5.2 Integer Overflow/Underflow

Before Solidity 0.8.0, there was no automatic overflow check.

// Solidity before 0.7.x: DANGEROUS!
// uint8 max = 255; max + 1 = 0 (overflow)
// uint8 min = 0;   min - 1 = 255 (underflow)

// Solidity 0.8.0+: Automatically reverts
// Use unchecked blocks when performance is needed
function unsafeIncrement(uint256 x) pure returns (uint256) {
    unchecked {
        return x + 1; // No overflow check (saves Gas)
    }
}

5.3 Security Checklist

Security Audit Checklist:

[1] Reentrancy
    - CEI pattern applied
    - ReentrancyGuard usage

[2] Access Control
    - onlyOwner / Role-based access
    - Initialization function protection

[3] Arithmetic
    - Solidity 0.8+ (automatic checks)
    - Review unchecked blocks

[4] External Calls
    - Check call return values
    - Set gas limits

[5] Frontrunning
    - Commit-reveal pattern
    - Consider Flashbots

[6] Oracle Manipulation
    - Use TWAP (Time-Weighted Average Price)
    - Multiple oracle sources

[7] Flash Loan Attacks
    - Defense against single-tx manipulation
    - Price validation logic

[8] Storage Collision (Proxy)
    - EIP-1967 storage slots
    - Upgrade testing

5.4 Major Hack Incidents

IncidentYearLossVulnerability
The DAO201660M USDReentrancy
Ronin Bridge2022625M USDPrivate key compromise
Wormhole2022320M USDSignature verification bypass
Euler Finance2023197M USDDonate function vulnerability
Mango Markets2022114M USDOracle manipulation

6. Layer 2 Solutions Comparison

6.1 What Is Layer 2?

Layer 2 (L2) extends throughput while inheriting Ethereum mainnet (L1) security.

┌─────────────────────────────────────────┐
Users (Dapps)├────────────┬────────────┬───────────────┤
OptimisticZK RollupValidiumRollup     │            │               │
 (Arbitrum,  (zkSync,    (StarkEx,Optimism,Scroll,   │  zkPorter)Base)Linea)    │               │
├────────────┴────────────┴───────────────┤
Ethereum L1 (Security Layer)└─────────────────────────────────────────┘

6.2 Optimistic vs ZK Rollup

FeatureOptimistic RollupZK Rollup
VerificationFraud ProofValidity Proof
Withdrawal Time7 days (challenge period)Minutes to hours
EVM CompatibilityHighGrowing (zkEVM)
Gas Cost10-50x cheaper than L150-100x cheaper than L1
Representative ChainsArbitrum, Optimism, BasezkSync Era, Scroll, Linea
MaturityHighRapidly growing

6.3 Major L2 Chains Detailed Comparison

TVL (Total Value Locked) Rankings (2025):

1. Arbitrum One    - TVL: ~18B USD
   - Nitro tech stack
   - Full EVM compatibility
   - Stylus (Rust/C++ support)

2. Base            - TVL: ~12B USD
   - Coinbase backed
   - OP Stack based
   - Strong consumer app presence

3. Optimism        - TVL: ~8B USD
   - OP Stack (Superchain vision)
   - Bedrock upgrade
   - RetroPGF (public goods funding)

4. zkSync Era      - TVL: ~4B USD
   - zkEVM (LLVM-based)
   - Native Account Abstraction
   - Hyperchain scaling

5. Scroll          - TVL: ~2B USD
   - Type-2 zkEVM
   - Ethereum bytecode compatible

6.4 Developing on L2

// Deploy to Arbitrum (Hardhat)
// Add networks to hardhat.config.js
module.exports = {
  networks: {
    arbitrum: {
      url: "https://arb1.arbitrum.io/rpc",
      accounts: [process.env.PRIVATE_KEY],
      chainId: 42161,
    },
    base: {
      url: "https://mainnet.base.org",
      accounts: [process.env.PRIVATE_KEY],
      chainId: 8453,
    },
    optimism: {
      url: "https://mainnet.optimism.io",
      accounts: [process.env.PRIVATE_KEY],
      chainId: 10,
    },
  },
};

// Deploy script
async function main() {
  const Contract = await ethers.getContractFactory("MyContract");
  const contract = await Contract.deploy();
  await contract.waitForDeployment();
  console.log("Deployed to:", await contract.getAddress());
}

7. Understanding DeFi Protocols

7.1 DeFi Core Primitives

DeFi Stack:
┌─────────────────────────────────────┐
Aggregator / Frontend  (1inch, DefiLlama, Zapper)├─────────────────────────────────────┤
Application Layer  (Aave, Uniswap, MakerDAO)├─────────────────────────────────────┤
Protocol Layer  (AMM, Lending, Derivatives)├─────────────────────────────────────┤
Asset Layer  (ERC-20, ERC-721, Wrapped)├─────────────────────────────────────┤
Settlement Layer  (Ethereum, L2 Rollups)└─────────────────────────────────────┘

7.2 AMM (Automated Market Maker)

Uniswap V2's core formula: x * y = k

// Simple AMM implementation
contract SimpleAMM {
    uint256 public reserveA;
    uint256 public reserveB;
    uint256 public totalLiquidity;
    mapping(address => uint256) public liquidity;

    // Add liquidity
    function addLiquidity(uint256 amountA, uint256 amountB) external {
        reserveA += amountA;
        reserveB += amountB;

        uint256 liq;
        if (totalLiquidity == 0) {
            liq = sqrt(amountA * amountB);
        } else {
            liq = min(
                (amountA * totalLiquidity) / reserveA,
                (amountB * totalLiquidity) / reserveB
            );
        }
        liquidity[msg.sender] += liq;
        totalLiquidity += liq;
    }

    // Swap: put A, get B
    function swapAForB(uint256 amountAIn) external returns (uint256) {
        // Calculate based on x * y = k
        uint256 amountBOut = (amountAIn * reserveB) / (reserveA + amountAIn);

        // Apply 0.3% fee
        amountBOut = (amountBOut * 997) / 1000;

        reserveA += amountAIn;
        reserveB -= amountBOut;
        return amountBOut;
    }

    function sqrt(uint256 x) internal pure returns (uint256) {
        uint256 z = (x + 1) / 2;
        uint256 y = x;
        while (z < y) {
            y = z;
            z = (x / z + z) / 2;
        }
        return y;
    }

    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }
}

7.3 Lending Protocol Concepts

Lending Protocol (e.g., Aave):

1. Supply (Deposit)
   User -> Deposit assets -> Receive aTokens (auto-accruing interest)

2. Borrow
   Deposit collateral -> Check Health Factor (HF) -> Borrow assets
   HF = Collateral Value * LTV / Debt Value

3. Liquidation
   HF below 1 -> Liquidator repays debt -> Buys collateral at discount

Collateral ratio examples:
- ETH: LTV 80%, Liquidation threshold 82.5%
- USDC: LTV 77%, Liquidation threshold 80%

8. Gas Optimization Techniques

8.1 Storage Optimization

// Bad: each variable uses a separate slot
contract BadPacking {
    uint256 a; // slot 0 (32 bytes)
    uint8 b;   // slot 1 (1 byte, 31 wasted)
    uint256 c; // slot 2
    uint8 d;   // slot 3
}
// Total: 4 slots

// Good: variable packing saves slots
contract GoodPacking {
    uint256 a; // slot 0
    uint256 c; // slot 1
    uint8 b;   // slot 2 (b and d share a slot)
    uint8 d;   // slot 2
}
// Total: 3 slots (saves 20000 gas from SSTORE)

8.2 Loop Optimization

// Bad
function sumBad(uint256[] memory arr) public pure returns (uint256) {
    uint256 total = 0;
    for (uint256 i = 0; i < arr.length; i++) {
        total += arr[i];
    }
    return total;
}

// Good: cache length + unchecked increment
function sumGood(uint256[] memory arr) public pure returns (uint256) {
    uint256 total = 0;
    uint256 len = arr.length;
    for (uint256 i = 0; i < len; ) {
        total += arr[i];
        unchecked { ++i; }
    }
    return total;
}

8.3 Additional Optimization Techniques

// 1. calldata vs memory (read-only parameters)
function process(uint256[] calldata data) external pure { /* ... */ }
// calldata: immutable, cheaper Gas
// memory: mutable, more expensive Gas

// 2. Custom Errors (Solidity 0.8.4+)
error Unauthorized(address caller);
error InsufficientBalance(uint256 available, uint256 required);

function withdraw(uint256 amount) external {
    if (msg.sender != owner) revert Unauthorized(msg.sender);
    if (balances[msg.sender] < amount)
        revert InsufficientBalance(balances[msg.sender], amount);
}
// More Gas-efficient than require(string)

// 3. immutable and constant
uint256 public constant MAX_SUPPLY = 10000;       // Compile-time constant
address public immutable deployer;                 // Set at deploy, then immutable
// Both embed directly in code instead of SLOAD = Gas savings

// 4. Bitwise operations
function isEven(uint256 n) pure returns (bool) {
    return n & 1 == 0; // More efficient than n % 2 == 0
}

function multiplyByPowerOf2(uint256 n, uint256 pow) pure returns (uint256) {
    return n << pow; // n * (2**pow)
}

9. Web3 Frontend Integration

9.1 ethers.js / viem

// ethers.js v6 basic usage
import { ethers, BrowserProvider, Contract } from "ethers";

// Wallet connection
async function connectWallet() {
  if (!window.ethereum) {
    throw new Error("MetaMask not installed");
  }

  const provider = new BrowserProvider(window.ethereum);
  const signer = await provider.getSigner();
  const address = await signer.getAddress();
  const balance = await provider.getBalance(address);

  console.log("Address:", address);
  console.log("Balance:", ethers.formatEther(balance), "ETH");
  return signer;
}

// Contract interaction
async function interactWithContract(signer) {
  const contractAddress = "0x...";
  const abi = [
    "function getValue() view returns (uint256)",
    "function setValue(uint256) external",
    "event ValueChanged(address indexed, uint256)"
  ];

  const contract = new Contract(contractAddress, abi, signer);

  // Read
  const value = await contract.getValue();
  console.log("Current value:", value.toString());

  // Write
  const tx = await contract.setValue(42);
  await tx.wait();
  console.log("Transaction confirmed:", tx.hash);
}

9.2 wagmi + viem (React)

// wagmi v2 setup
import { createConfig, http } from "wagmi";
import { mainnet, arbitrum, base } from "wagmi/chains";
import { injected, walletConnect } from "wagmi/connectors";

const config = createConfig({
  chains: [mainnet, arbitrum, base],
  connectors: [
    injected(),
    walletConnect({ projectId: "YOUR_PROJECT_ID" }),
  ],
  transports: {
    [mainnet.id]: http(),
    [arbitrum.id]: http(),
    [base.id]: http(),
  },
});

// React component
function WalletConnect() {
  const { address, isConnected } = useAccount();
  const { connect } = useConnect();
  const { disconnect } = useDisconnect();
  const { data: balance } = useBalance({ address });

  if (isConnected) {
    return (
      <div>
        <p>Connected: {address}</p>
        <p>Balance: {balance?.formatted} {balance?.symbol}</p>
        <button onClick={() => disconnect()}>Disconnect</button>
      </div>
    );
  }

  return (
    <button onClick={() => connect({ connector: injected() })}>
      Connect Wallet
    </button>
  );
}

10. Web3 Career Guide

10.1 Salary by Position (2025)

PositionExperienceSalary Range (USD)
Junior Solidity Dev0-2 years80K-120K
Mid Solidity Dev2-4 years120K-180K
Senior Smart Contract Dev4+ years180K-250K
Smart Contract Auditor3+ years150K-300K+
Protocol Engineer5+ years200K-350K+
DeFi Researcher3+ years150K-250K
Web3 Frontend (React + ethers)2+ years100K-180K
Blockchain Infra Engineer3+ years140K-220K

10.2 Essential Tech Stack

Web3 Developer Roadmap:

Foundation (3-6 months):
├── Solidity syntax and patterns
├── EVM understanding
├── Hardhat or Foundry
├── ethers.js / viem
└── OpenZeppelin library

Intermediate (6-12 months):
├── DeFi protocol understanding (AMM, Lending)
├── Security (common vulnerabilities + auditing)
├── Gas optimization
├── Layer 2 development
├── The Graph (indexing)
└── IPFS / Arweave (distributed storage)

Advanced (12+ months):
├── MEV (Maximal Extractable Value)
├── ZK Proof fundamentals
├── Cross-chain bridges
├── Account Abstraction (ERC-4337)
├── Protocol design
└── Formal Verification

10.3 Portfolio Strategy

The most important thing in the Web3 job market is on-chain evidence.

  1. Open-source GitHub projects: Include tests and documentation
  2. Testnet deployments: Deploy on Sepolia, Base Goerli, etc.
  3. Audit experience: Participate in Code4rena, Sherlock competitions
  4. Contributions: OSS contributions to OpenZeppelin, Uniswap, etc.
  5. Blog/Threads: Share technical analysis articles

11. Practice Quiz

Work through each problem and check your answers.

Q1. What pattern prevents reentrancy attacks?

Checks-Effects-Interactions (CEI) Pattern

Perform state checks (Checks) first, then state changes (Effects), and finally external calls (Interactions). Additionally, you can use OpenZeppelin's ReentrancyGuard (nonReentrant modifier).

Q2. What is the biggest difference between Optimistic and ZK Rollups?

The verification method.

  • Optimistic Rollup: Optimistically assumes transactions are valid, with a 7-day challenge period where fraud proofs can be submitted.
  • ZK Rollup: Generates mathematical validity proofs for every transaction batch and submits them to L1 immediately. Withdrawals are faster.
Q3. How much Gas does SSTORE (new value) cost on the EVM?

20,000 Gas (for writing a value to a new storage slot)

Updating an existing value costs 5,000 Gas. This is why storage optimization matters - use variable packing, constant/immutable declarations, etc. to reduce SSTORE calls.

Q4. What is Uniswap V2's core AMM formula?

x * y = k (Constant Product Formula)

x is the quantity of token A, y is the quantity of token B, and k is a constant. When you input one token, the other is released to maintain k. This formula naturally creates slippage and price impact.

Q5. What should you use instead of require(string) to save Gas in Solidity?

Custom Errors (Solidity 0.8.4+)

Declare with error Unauthorized(); and use with revert Unauthorized();. More Gas-efficient than require with string messages, and can include parameters for better debugging.


12. References

  1. Ethereum Official Docs - Ethereum development fundamentals
  2. Solidity Official Docs - Solidity language reference
  3. OpenZeppelin Contracts - Audited smart contract library
  4. Hardhat Official Docs - Hardhat development environment
  5. Foundry Book - Foundry development tools
  6. Ethereum EVM Illustrated - EVM visual guide
  7. SWC Registry - Smart contract weakness classification
  8. DeFiLlama - DeFi TVL and protocol data
  9. L2Beat - Layer 2 comparison and TVL tracking
  10. Chainlink Official Docs - Oracle solution
  11. EIP-4337: Account Abstraction - Account Abstraction standard
  12. Secureum - Smart contract security learning
  13. Code4rena - Smart contract audit competitions