Build user interfaces that interact with blockchain
To interact with Ethereum from JavaScript, you need a Web3 library. The two most popular are ethers.js and web3.js.
Modern, lightweight, and well-documented. Most popular choice for new projects.
npm install ethersOlder library, still widely used. Good for legacy projects.
npm install web3Recommendation: Use ethers.js for new projects. It's more modern, has better documentation, and is the industry standard for new dApps.
The first step in any Web3 app is connecting to the user's wallet. Here's how to do it with ethers.js.
import { ethers } from 'ethers';
// Check if MetaMask is installed
if (typeof window.ethereum !== 'undefined') {
console.log('MetaMask is installed!');
}
// Request account access
async function connectWallet() {
try {
// Request accounts from MetaMask
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts'
});
console.log('Connected account:', accounts[0]);
// Create provider
const provider = new ethers.BrowserProvider(window.ethereum);
// Get signer (account that can sign transactions)
const signer = await provider.getSigner();
// Get address
const address = await signer.getAddress();
console.log('Address:', address);
// Get balance
const balance = await provider.getBalance(address);
console.log('Balance:', ethers.formatEther(balance), 'ETH');
return { provider, signer, address };
} catch (error) {
console.error('Error connecting:', error);
}
}import { useState, useEffect } from 'react';
import { ethers } from 'ethers';
function WalletConnect() {
const [account, setAccount] = useState(null);
const [balance, setBalance] = useState(null);
async function connectWallet() {
if (typeof window.ethereum !== 'undefined') {
try {
// Request account access
const accounts = await window.ethereum.request({
method: 'eth_requestAccounts'
});
setAccount(accounts[0]);
// Get balance
const provider = new ethers.BrowserProvider(window.ethereum);
const balance = await provider.getBalance(accounts[0]);
setBalance(ethers.formatEther(balance));
} catch (error) {
console.error('Error:', error);
}
} else {
alert('Please install MetaMask!');
}
}
// Listen for account changes
useEffect(() => {
if (window.ethereum) {
window.ethereum.on('accountsChanged', (accounts) => {
setAccount(accounts[0] || null);
});
}
}, []);
return (
<div>
{!account ? (
<button onClick={connectWallet}>
Connect Wallet
</button>
) : (
<div>
<p>Connected: {account.slice(0, 6)}...{account.slice(-4)}</p>
<p>Balance: {balance} ETH</p>
</div>
)}
</div>
);
}Reading data from the blockchain is free (no gas cost). You can query balances, contract state, and call view functions.
import { ethers } from 'ethers';
// Connect to Ethereum (read-only, no wallet needed)
const provider = new ethers.JsonRpcProvider('https://eth.llamarpc.com');
// Get ETH balance
async function getBalance(address) {
const balance = await provider.getBalance(address);
return ethers.formatEther(balance);
}
// Get current block number
async function getBlockNumber() {
return await provider.getBlockNumber();
}
// Get transaction details
async function getTransaction(txHash) {
return await provider.getTransaction(txHash);
}
// Read from a smart contract
const contractAddress = '0x...';
const abi = [
"function balanceOf(address owner) view returns (uint256)",
"function totalSupply() view returns (uint256)"
];
const contract = new ethers.Contract(contractAddress, abi, provider);
// Call view functions (free, no gas)
async function getTokenBalance(address) {
const balance = await contract.balanceOf(address);
return balance.toString();
}
async function getTotalSupply() {
const supply = await contract.totalSupply();
return supply.toString();
}Writing to the blockchain requires a transaction, which costs gas and needs to be signed by the user.
async function sendETH(toAddress, amount) {
try {
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
// Send transaction
const tx = await signer.sendTransaction({
to: toAddress,
value: ethers.parseEther(amount) // Convert ETH to wei
});
console.log('Transaction sent:', tx.hash);
// Wait for confirmation
const receipt = await tx.wait();
console.log('Transaction confirmed:', receipt);
return receipt;
} catch (error) {
console.error('Error:', error);
}
}// Contract ABI (simplified)
const abi = [
"function transfer(address to, uint256 amount) returns (bool)",
"function approve(address spender, uint256 amount) returns (bool)"
];
async function transferTokens(contractAddress, toAddress, amount) {
try {
const provider = new ethers.BrowserProvider(window.ethereum);
const signer = await provider.getSigner();
// Create contract instance with signer (can write)
const contract = new ethers.Contract(contractAddress, abi, signer);
// Call function (sends transaction)
const tx = await contract.transfer(toAddress, amount);
console.log('Transaction sent:', tx.hash);
// Wait for confirmation
const receipt = await tx.wait();
console.log('Transaction confirmed!');
return receipt;
} catch (error) {
console.error('Error:', error);
// Handle errors (user rejected, insufficient gas, etc.)
}
}parseEther() to convert ETH to weitx.wait()IPFS (InterPlanetary File System) is decentralized storage for files. Perfect for storing NFT images, metadata, and dApp assets.
Storing large files on blockchain is expensive. IPFS stores files off-chain but gives you a content-addressed hash (CID) that you can store on-chain.
// Using Pinata (IPFS pinning service)
async function uploadToIPFS(file) {
const formData = new FormData();
formData.append('file', file);
const response = await fetch('https://api.pinata.cloud/pinning/pinFileToIPFS', {
method: 'POST',
headers: {
'pinata_api_key': 'YOUR_API_KEY',
'pinata_secret_api_key': 'YOUR_SECRET_KEY'
},
body: formData
});
const data = await response.json();
const ipfsHash = data.IpfsHash;
// Access file at: https://gateway.pinata.cloud/ipfs/{ipfsHash}
return ipfsHash;
}
// Store IPFS hash in smart contract
async function mintNFT(ipfsHash) {
const tokenURI = `ipfs://${ipfsHash}`;
const tx = await nftContract.mint(tokenURI);
await tx.wait();
}You now know how to build Web3 frontends! In the final module, we'll explore advanced topics like Layer 2 solutions, NFT marketplaces, DAOs, and the future of blockchain.