Building a DApp with Ethereum — Full Tutorial
DodaTech
2 min read
In this tutorial, you'll learn about Building a DApp with Ethereum. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
What You'll Learn
Build a complete decentralized application from scratch: a Solidity smart contract, a React frontend, and wallet integration with ethers.js.
Why It Matters
Understanding the full DApp stack makes you a capable Web3 developer. The patterns here apply to any Ethereum-compatible Blockchain.
Prerequisites
- Basic JavaScript and React knowledge
- MetaMask browser extension installed
- Node.js installed
Step 1: The Smart Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract TodoList {
struct Todo {
uint256 id;
string content;
bool completed;
}
mapping(address => Todo[]) private todos;
mapping(address => uint256) private todoCount;
event TodoAdded(address indexed user, uint256 id, string content);
event TodoToggled(address indexed user, uint256 id, bool completed);
function addTodo(string memory content) public {
todoCount[msg.sender]++;
todos[msg.sender].push(Todo(
todoCount[msg.sender],
content,
false
));
emit TodoAdded(msg.sender, todoCount[msg.sender], content);
}
function toggleTodo(uint256 id) public {
Todo storage todo = todos[msg.sender][id - 1];
todo.completed = !todo.completed;
emit TodoToggled(msg.sender, id, todo.completed);
}
function getTodos() public view returns (Todo[] memory) {
return todos[msg.sender];
}
}
Deploy this to Sepolia testnet using Remix (see the Solidity tutorial).
Step 2: Create the React App
npx create-react-app ethereum-todo-dapp
cd ethereum-todo-dapp
npm install ethers
Step 3: Connect to Wallet
// src/web3.js
import { ethers } from "ethers";
export async function getProvider() {
if (!window.ethereum) {
throw new Error("MetaMask not installed");
}
return new ethers.BrowserProvider(window.ethereum);
}
export async function getSigner() {
const provider = await getProvider();
return provider.getSigner();
}
export async function connectWallet() {
const provider = await getProvider();
await provider.send("eth_requestAccounts", []);
const signer = provider.getSigner();
const address = await signer.getAddress();
return address;
}
Step 4: Create the Contract Interface
// src/contract.js
import { ethers } from "ethers";
import { getSigner } from "./web3";
const CONTRACT_ADDRESS = "0xYOUR_DEPLOYED_ADDRESS";
const CONTRACT_ABI = [
// Copy ABI from Remix compilation
"function addTodo(string memory content) public",
"function toggleTodo(uint256 id) public",
"function getTodos() public view returns ((uint256,string,bool)[])"
];
export async function getContract() {
const signer = await getSigner();
return new ethers.Contract(CONTRACT_ADDRESS, CONTRACT_ABI, signer);
}
export async function addTodo(content) {
const contract = await getContract();
const tx = await contract.addTodo(content);
await tx.wait(); // Wait for confirmation
}
export async function getTodos() {
const contract = await getContract();
return contract.getTodos();
}
Step 5: Build the UI
// src/App.js
import { useState, useEffect } from "react";
import { connectWallet } from "./web3";
import { addTodo, getTodos } from "./contract";
function App() {
const [address, setAddress] = useState(null);
const [todos, setTodos] = useState([]);
const [content, setContent] = useState("");
const handleConnect = async () => {
const addr = await connectWallet();
setAddress(addr);
loadTodos();
};
const loadTodos = async () => {
const result = await getTodos();
setTodos(result);
};
const handleAdd = async () => {
await addTodo(content);
setContent("");
loadTodos();
};
return (
<div>
{!address ? (
<button onClick={handleConnect}>Connect Wallet</button>
) : (
<div>
<p>Connected: {address}</p>
<input value={content}
onChange={e => setContent(e.target.value)} />
<button onClick={handleAdd}>Add Todo</button>
<ul>
{todos.map(t => (
<li key={t.id}>{t.content}</li>
))}
</ul>
</div>
)}
</div>
);
}
Complete Flow
- User connects MetaMask
- App reads their todos from the smart contract
- User adds a todo → Transaction sent to Blockchain
- After confirmation (10-20 seconds), the new todo appears
- Every interaction costs a small gas fee
← Previous
What is a DApp? Decentralized Applications Explained
Next →
What is DeFi? Decentralized Finance Explained
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro