Introduction
Decentralized applications (dApps) run on blockchain networks, enabling trustless, transparent, and censorship-resistant functionality. In this guide, we’ll build a dApp using React, Solidity, and MetaMask, integrating Web3.js and Ethers.js for blockchain interactions.
What You'll Learn:
✔ Writing smart contracts in Solidity
✔ Deploying contracts on Ethereum testnet
✔ Connecting a dApp to MetaMask using Web3.js & Ethers.js
✔ Executing blockchain transactions from React
- Setting Up the Development Environment
Prerequisites
Ensure you have the following installed:
Node.js (v16 or later)
MetaMask browser extension
Hardhat (Ethereum development environment)
Step 1: Initialize a Hardhat Project
mkdir my-dapp && cd my-dapp
npm init -y
npm install --save-dev hardhat
npx hardhat
Select “Create a basic sample project” and install dependencies when prompted.
- Writing a Smart Contract in Solidity
Step 1: Create a Solidity Contract
Inside contracts/, create a file named MyContract.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
contract MyContract {
uint256 public counter;
function increment() public {
counter++;
}
}
Step 2: Compile the Contract
npx hardhat compile
Step 3: Deploy the Contract
Modify scripts/deploy.js:
const hre = require("hardhat");
async function main() {
const Contract = await hre.ethers.getContractFactory("MyContract");
const contract = await Contract.deploy();
await contract.deployed();
console.log("Contract deployed to:", contract.address);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
Run the deployment script:
npx hardhat run
scripts/deploy.js --network localhost
- Connecting the dApp to MetaMask with Web3.js & Ethers.js
Step 1: Install Web3.js & Ethers.js
npm install web3 ethers
Step 2: Connect React to MetaMask
In App.js, set up MetaMask connection:
import { useState } from "react";
import { ethers } from "ethers";
function App() {
const [account, setAccount] = useState("");
async function connectWallet() {
if (window.ethereum) {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const accounts = await provider.send("eth_requestAccounts", []);
setAccount(accounts[0]);
} else {
alert("MetaMask not found");
}
}
return (
<div>
<button onClick={connectWallet}>Connect Wallet</button>
<p>Connected Account: {account}</p>
</div>
);
}
export default App;
- Interacting with the Smart Contract
Step 1: Load the Contract in React
Create contractABI.js with ABI (after deployment, copy from artifacts/contracts/MyContract.json):
const contractABI = [
{
"inputs": [],
"name": "increment",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "counter",
"outputs": [{"internalType": "uint256", "name": "", "type": "uint256"}],
"stateMutability": "view",
"type": "function"
}
];
export default contractABI;
Step 2: Fetch Contract Data in React
Modify App.js:
import { useState, useEffect } from "react";
import { ethers } from "ethers";
import contractABI from "./contractABI";
const contractAddress = "YOUR_DEPLOYED_CONTRACT_ADDRESS";
function App() {
const [account, setAccount] = useState("");
const [contract, setContract] = useState(null);
const [counter, setCounter] = useState(0);
async function connectWallet() {
if (window.ethereum) {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const accounts = await provider.send("eth_requestAccounts", []);
setAccount(accounts[0]);
const contractInstance = new ethers.Contract(contractAddress, contractABI, signer);
setContract(contractInstance);
fetchCounter(contractInstance);
} else {
alert("MetaMask not found");
}
}
async function fetchCounter(contractInstance) {
const count = await contractInstance.counter();
setCounter(count.toNumber());
}
async function incrementCounter() {
if (contract) {
const tx = await contract.increment();
await tx.wait();
fetchCounter(contract);
}
}
useEffect(() => {
if (contract) fetchCounter(contract);
}, [contract]);
return (
<div>
<button onClick={connectWallet}>Connect Wallet</button>
<p>Connected Account: {account}</p>
<p>Counter Value: {counter}</p>
<button onClick={incrementCounter}>Increment Counter</button>
</div>
);
}
export default App;
- Testing the dApp on a Testnet
Step 1: Get Testnet Funds
Open MetaMask.
Switch to Goerli or Sepolia Testnet.
Get test ETH from a faucet (https://goerlifaucet.com).
Step 2: Deploy to Testnet
Modify hardhat.config.js:
module.exports = {
solidity: "0.8.19",
networks: {
goerli: {
url: "https://eth-goerli.alchemyapi.io/v2/YOUR_ALCHEMY_API_KEY",
accounts: ["YOUR_PRIVATE_KEY"]
}
}
};
Deploy:
npx hardhat run scripts/deploy.js --network goerli
- Enhancing the dApp
✔ Use IPFS or Arweave for decentralized file storage.
✔ Add WalletConnect to support multiple wallets.
✔ Use Moralis API for indexing blockchain data.
✔ Deploy front-end on Vercel or Netlify for easy hosting.
Conclusion
In this guide, we built a React + Solidity dApp that connects to MetaMask, interacts with smart contracts, and runs transactions on Ethereum.
✔ Wrote and deployed a Solidity contract
✔ Connected React with MetaMask using Ethers.js
✔ Interacted with smart contracts from the front end
I am open to collaboration on projects and work. Let's transform ideas into digital reality.
Top comments (0)