Introduction
Building decentralized applications requires specialized tools. This guide covers the essential Web3 development tools and resources.
Smart Contract Development
Frameworks
# Hardhat - Ethereum development environment
npm install --save-dev hardhat
# Create project
npx hardhat init
// hardhat.config.js
module.exports = {
solidity: "0.8.19",
networks: {
mainnet: {
url: process.env.MAINNET_RPC,
accounts: [process.env.PRIVATE_KEY]
}
}
};
// Deploy script
const hre = require("hardhat");
async function main() {
const Contract = await hre.ethers.getContractFactory("MyContract");
const contract = await Contract.deploy();
await contract.deployed();
console.log("Deployed to:", contract.address);
}
main();
Solidity Libraries
// OpenZeppelin Contracts
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyNFT is ERC721, Ownable {
uint256 public tokenCount;
constructor() ERC721("MyNFT", "MNFT") {}
function mint(address to) external onlyOwner {
_mint(to, tokenCount);
tokenCount++;
}
}
Blockchain SDKs
Ethers.js
import { ethers } from 'ethers';
// Connect to wallet
const provider = new ethers.JsonRpcProvider('https://eth-mainnet.g.alchemy.com/v2/KEY');
const wallet = new ethers.Wallet(privateKey, provider);
// Read contract
const contract = new ethers.Contract(contractAddress, abi, provider);
const balance = await contract.balanceOf(address);
// Write contract
const contractWithSigner = contract.connect(wallet);
const tx = await contractWithSigner.mint(address, amount);
await tx.wait();
Web3.js
import Web3 from 'web3';
const web3 = new Web3('https://eth-mainnet.g.alchemy.com/v2/KEY');
// Get accounts
const accounts = await web3.eth.getAccounts();
// Send transaction
await web3.eth.sendTransaction({
from: accounts[0],
to: '0x...',
value: web3.utils.toWei('0.1', 'ether')
});
Testing Tools
Smart Contract Testing
const { expect } = require("chai");
describe("MyToken", function() {
let token;
let owner;
let addr1;
beforeEach(async function() {
const Token = await ethers.getContractFactory("MyToken");
token = await Token.deploy();
[owner, addr1] = await ethers.getSigners();
});
it("Should mint tokens to owner", async function() {
await token.mint(owner.address, 100);
expect(await token.balanceOf(owner.address)).to.equal(100);
});
});
Frontend Integration
Wallet Connection
// Connect wallet
async function connectWallet() {
if (window.ethereum) {
const provider = new ethers.BrowserProvider(window.ethereum);
const accounts = await provider.send("eth_requestAccounts", []);
return accounts[0];
}
throw new Error("No wallet found");
}
// Listen for account changes
window.ethereum.on('accountsChanged', (accounts) => {
if (accounts.length === 0) {
// Disconnected
} else {
// Account changed
}
});
Framework Comparison
| Feature | Hardhat | Foundry | Truffle |
|---|---|---|---|
| Language | JavaScript/TypeScript | Solidity (native) | JavaScript |
| Speed | Moderate | Fast (Rust-based) | Slow |
| Testing | Mocha/Chai | Solidity fuzz tests | Mocha |
| Forking | Built-in | Built-in (anvil) | Ganache |
| Debugging | console.log | cast + forge debug | Truffle Debugger |
| Gas Reporting | Hardhat-gas-reporter | forge snapshot | Built-in |
| Mainnet Simulation | Hardhat Network | anvil | Ganache |
| EVM Equivalence | Full | Full | Full |
Hardhat remains the most popular choice for its mature plugin ecosystem and extensive documentation. It’s ideal for teams comfortable with JavaScript tooling and complex deployment workflows.
Foundry has gained significant adoption for its blazing-fast compilation and testing (written in Rust), native fuzz testing in Solidity, and first-class mainnet forking. Its forge test command is significantly faster than Hardhat for large test suites.
Truffle has declined in popularity but still powers many legacy projects. Its suite includes Ganache (local blockchain) and Drizzle (frontend integration).
SDK Deep Dive: ethers.js v6
import { ethers, JsonRpcProvider, Wallet, Contract } from 'ethers';
// Provider setup
const provider = new JsonRpcProvider(
'https://eth-mainnet.g.alchemy.com/v2/YOUR_API_KEY'
);
// Wallet operations
const wallet = new Wallet(process.env.PRIVATE_KEY, provider);
const balance = await provider.getBalance(wallet.address);
console.log(`Balance: ${ethers.formatEther(balance)} ETH`);
// Contract interaction
const abi = [
'function balanceOf(address owner) view returns (uint256)',
'function transfer(address to, uint256 amount) returns (bool)',
];
const contract = new Contract('0x...', abi, wallet);
const tx = await contract.transfer('0x...', ethers.parseEther('1.0'));
await tx.wait();
// Event listening
contract.on('Transfer', (from, to, value, event) => {
console.log(`Transfer: ${from} -> ${to}: ${ethers.formatEther(value)} ETH`);
});
SDK Comparison
// viem - Modern TypeScript-first library
import { createPublicClient, http, parseAbi } from 'viem';
import { mainnet } from 'viem/chains';
const client = createPublicClient({
chain: mainnet,
transport: http()
});
const balance = await client.getBalance({
address: '0x...'
});
// web3.js v4 - Legacy but still maintained
import Web3 from 'web3';
const web3 = new Web3('https://eth-mainnet.g.alchemy.com/v2/KEY');
const accounts = await web3.eth.getAccounts();
Testing Tools Comparison
| Tool | Focus | Key Features |
|---|---|---|
| Waffle | Contract testing | Matchers, chai integration |
| Hardhat Chai Matchers | Hardhat-native | Ethers compatibility |
| Foundry Forge | Solidity testing | Fuzz, invariant, differential |
| Echidna | Fuzzing | Property-based,Slither integration |
| Mythril | Security analysis | Symbolic execution |
| Slither | Static analysis | Vulnerability detection |
# Forge fuzz testing
forge test --fuzz-runs 10000
# Run specific test
forge test --match-contract MyContract --match-test testFunction
# Gas report
forge snapshot
# Coverage
forge coverage
Frontend Integration Libraries
// wagmi - React hooks for Ethereum
import { createConfig, WagmiConfig, useAccount, useConnect } from 'wagmi';
import { mainnet, base } from 'wagmi/chains';
import { injected, metaMask, walletConnect } from 'wagmi/connectors';
const config = createConfig({
chains: [mainnet, base],
connectors: [
injected(),
metaMask(),
walletConnect({ projectId: 'YOUR_PROJECT_ID' }),
],
transports: {
[mainnet.id]: http(),
[base.id]: http(),
},
});
function WalletInfo() {
const { address, isConnected } = useAccount();
const { connect } = useConnect();
return (
<div>
{isConnected ? (
<p>Connected: {address}</p>
) : (
<button onClick={() => connect({ connector: metaMask() })}>
Connect Wallet
</button>
)}
</div>
);
}
// RainbowKit - Beautiful wallet UI
import { RainbowKitProvider, getDefaultConfig } from '@rainbow-me/rainbowkit';
Deployment and Node Infrastructure
| Provider | Free Tier | Supported Chains | Features |
|---|---|---|---|
| Infura | 100K req/day | 10+ EVM | Reliable, IPFS |
| Alchemy | 300M CU/month | 10+ EVM | Enhanced APIs, WebSocket |
| QuickNode | 300K req/month | 16+ EVM | Multi-chain, DDoS protection |
| Moralis | 40K req/month | 10+ EVM | Web3 auth, NFT APIs |
Development Workflow Best Practices
# Setup project with modern stack
mkdir my-dapp && cd my-dapp
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox
# Foundry alternative
forge init my-dapp
# Install SDKs
npm install ethers viem wagmi @rainbow-me/rainbowkit
# Environment variables
echo "PRIVATE_KEY=0x..." >> .env
echo "ALCHEMY_API_KEY=..." >> .env
# Hardhat compile and test
npx hardhat compile
npx hardhat test
npx hardhat coverage
# Verify contract
npx hardhat verify --network mainnet DEPLOYED_CONTRACT_ADDRESS
Starter Templates
# Scaffold-ETH 2
npx create-eth@latest
cd my-eth-app
# Foundry template
forge init --template https://github.com/Foundry-Forge/hardhat-foundry-template
# Next.js + wagmi template
npx create-wagmi@latest
cd my-wagmi-app
# Web3Modal
npm install @web3modal/ethers @web3modal/react
Smart Contract Development Tips
- Use OpenZeppelin Contracts as your base for ERC-20, ERC-721, and access control
- Test on Hardhat Network first, then deploy to testnets before mainnet
- Use Slither for static analysis before each deployment
- Maintain separate env files for development, staging, and production
- Set up CI/CD with Hardhat using GitHub Actions for automated testing
- Use deterministic deployment (CREATE2) for predictable contract addresses
- Implement upgradeable contracts using OpenZeppelin Upgrades plugin for iterative development
Indexing and Data
The Graph
# Subgraph schema
type Transfer @entity {
id: ID!
from: Bytes!
to: Bytes!
value: BigInt!
timestamp: BigInt!
}
type _Schema_
@fulltext(name: "tokenSearch", fields: [{name: "id"}])
Deployment Best Practices
Before deploying to mainnet, follow this checklist:
- Run static analysis with Slither and Mythril
- Perform fuzz testing with Foundry or Echidna
- Audit the contract with a reputable firm
- Verify contract source code on Etherscan
- Set up monitoring with Tenderly or Dune Analytics
- Implement emergency pause and upgrade mechanisms
- Test on testnet with realistic conditions for at least one week
- Run a bug bounty program before significant TVL
Conclusion
Web3 development tools have matured significantly. These tools enable professional-grade dApp development.
Comments