Building Your First Web3 DApp: Guide to Ethereum Development

Ramkumar Khubchandani
4 min readDec 31, 2024

--

Ever wondered how to build applications that interact with blockchain? In this guide, I will create a simple decentralized application (DApp) that lets users connect their wallet and interact with a smart contract on the Ethereum network. Don’t worry if you’re new to Web3 — I will break everything down into simple steps!

What We’ll Build

We’re going to create a simple “Message Board” DApp where users can:

  1. Connect their MetaMask wallet
  2. Post messages to the blockchain
  3. Read messages from other users

Prerequisites

Before we start, make sure you have:

  • Node.js installed on your computer
  • MetaMask browser extension installed
  • Basic knowledge of JavaScript
  • Some test ETH on the Sepolia network (we’ll show you how to get this)

Step 1: Setting Up Your Development Environment

First, let’s create a new project and install the necessary dependencies:

mkdir message-board-dapp
cd message-board-dapp
npm init -y
npm install ethers hardhat @nomiclabs/hardhat-waffle ethereum-waffle chai @nomiclabs/hardhat-ethers
npx hardhat init

Step 2: Creating the Smart Contract

Create a new file called MessageBoard.sol in the contracts folder:

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

contract MessageBoard {
struct Message {
address sender;
string content;
uint256 timestamp;
}

Message[] public messages;

event NewMessage(address sender, string content, uint256 timestamp);

function postMessage(string memory _content) public {
messages.push(Message(msg.sender, _content, block.timestamp));
emit NewMessage(msg.sender, _content, block.timestamp);
}

function getMessages() public view returns (Message[] memory) {
return messages;
}
}

Step 3: Setting Up the Frontend

Create a new index.html file in your project root:

<!DOCTYPE html>
<html>
<head>
<title>Message Board DApp</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.message {
border: 1px solid #ddd;
padding: 10px;
margin: 10px 0;
border-radius: 5px;
}
</style>
</head>
<body>
<h1>Blockchain Message Board</h1>
<button id="connectWallet">Connect Wallet</button>
<div id="messageForm" style="display: none;">
<h2>Post a Message</h2>
<input type="text" id="messageInput" placeholder="Enter your message">
<button id="postMessage">Post Message</button>
</div>
<div id="messageBoard">
<h2>Messages</h2>
<div id="messages"></div>
</div>
<script src="app.js"></script>
</body>
</html>

Now create app.js for our frontend logic:


import { ethers } from "https://cdnjs.cloudflare.com/ajax/libs/ethers/6.7.0/ethers.min.js";

class MessageBoardApp {
constructor() {
this.contract = null;
this.provider = null;
this.signer = null;


this.contractAddress = "YOUR_CONTRACT_ADDRESS";

this.init();
}

async init() {
// Setup event listeners
document.getElementById('connectWallet').addEventListener('click', () => this.connectWallet());
document.getElementById('postMessage').addEventListener('click', () => this.postMessage());

// Check if MetaMask is installed
if (typeof window.ethereum !== 'undefined') {
this.provider = new ethers.BrowserProvider(window.ethereum);
await this.loadMessages();
} else {
alert('Please install MetaMask to use this DApp!');
}
}

async connectWallet() {
try {
// Request account access
await window.ethereum.request({ method: 'eth_requestAccounts' });
this.signer = await this.provider.getSigner();

// Show message form once connected
document.getElementById('messageForm').style.display = 'block';
document.getElementById('connectWallet').textContent = 'Connected!';
} catch (error) {
console.error('Error connecting wallet:', error);
}
}

async postMessage() {
if (!this.signer) {
alert('Please connect your wallet first!');
return;
}

const message = document.getElementById('messageInput').value;
if (!message) return;

try {
const contract = new ethers.Contract(this.contractAddress, contractABI, this.signer);
const tx = await contract.postMessage(message);
await tx.wait();

// Clear input and reload messages
document.getElementById('messageInput').value = '';
await this.loadMessages();
} catch (error) {
console.error('Error posting message:', error);
}
}

async loadMessages() {
const contract = new ethers.Contract(this.contractAddress, contractABI, this.provider);
const messages = await contract.getMessages();

const messagesDiv = document.getElementById('messages');
messagesDiv.innerHTML = '';

messages.forEach(msg => {
const messageElement = document.createElement('div');
messageElement.className = 'message';
messageElement.innerHTML = `
<p><strong>From:</strong> ${msg.sender}</p>
<p>${msg.content}</p>
<small>Posted on: ${new Date(msg.timestamp * 1000).toLocaleString()}</small>
`;
messagesDiv.appendChild(messageElement);
});
}
}

// Initialize the app
new MessageBoardApp();

Step 4: Deploying the Smart Contract

  1. Create a deployment script in scripts/deploy.js:
async function main() {
const MessageBoard = await ethers.getContractFactory("MessageBoard");
const messageBoard = await MessageBoard.deploy();
await messageBoard.deployed();

console.log("MessageBoard deployed to:", messageBoard.address);
}

main()
.then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

2. Configure Hardhat for Sepolia network in hardhat.config.js:

require("@nomiclabs/hardhat-waffle");

module.exports = {
solidity: "0.8.0",
networks: {
sepolia: {
url: "YOUR_SEPOLIA_RPC_URL",
accounts: ["YOUR_PRIVATE_KEY"]
}
}
};

3. Deploy the contract:

npx hardhat run scripts/deploy.js --network sepolia

Step 5: Testing Your DApp

  1. Get some test ETH from a Sepolia faucet
  2. Update the contractAddress in app.js with your deployed contract address
  3. Serve your frontend files using a local server:
npx http-server

Common Issues and Solutions

  1. MetaMask not connecting
  • Make sure you’re on the Sepolia network in MetaMask
  • Check if your browser allows pop-ups

2. Transaction failing

  • Ensure you have enough test ETH for gas fees
  • Check the console for specific error messages

3. Messages not loading

  • Verify your contract address is correct
  • Ensure you’re connected to the right network

Next Steps

Now that you have a basic DApp working, here are some ways to expand it:

  • Add the ability to like or reply to messages
  • Store message metadata on IPFS
  • Add user profiles
  • Implement message categories or tags

Conclusion

Congratulations! You’ve built your first Web3 DApp. While this is a simple example, it demonstrates the core concepts of Web3 development:

  • Smart contract development
  • Wallet integration
  • User interaction with the blockchain
  • Frontend integration with Web3 technologies

Remember, the blockchain is immutable, so always test thoroughly on testnets before deploying to mainnet.

--

--

Ramkumar Khubchandani
Ramkumar Khubchandani

Written by Ramkumar Khubchandani

Frontend Developer|Technical Content Writer|React|Angular|React-Native|Corporate Trainer|JavaScript|Trainer|Teacher| Mobile: 7709330265|ramkumarkhub@gmail.com

No responses yet