You’ve deployed your first smart contract. Now let’s connect it to a frontend and turn it into a real decentralized app (DApp) you can share with anyone — all on Arbitrum.
🧠 First, What Is a DApp?
A DApp = Decentralized App.
It’s just like any web app you use daily — but with one big difference:
Instead of talking to a server, it talks to a smart contract on the blockchain.
*Example DApps:
*
- Uniswap (swaps tokens)
- Aave (borrows/lends crypto)
- Lens Protocol (decentralized social media)
- DApps = Frontend (HTML/JS) + Smart Contract (Solidity)
🧱 Architecture Breakdown
🧑💻 User clicks button
⬇️
🌐 Frontend (React/Next.js/etc.)
⬇️
🔌 Web3 Provider (ethers.js / wagmi / viem)
⬇️
📜 Smart Contract (Solidity on Arbitrum)
⬇️
📦 Blockchain stores + returns data
⚙️ Let’s Build a Basic DApp UI (React + ethers.js)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
contract MessagePortal {
string private message;
// Event to emit when message is updated
event MessageUpdated(address indexed sender, string newMessage);
// Constructor to set initial message
constructor(string memory _initialMessage) {
message = _initialMessage;
}
// Read current message
function getMessage() public view returns (string memory) {
return message;
}
// Update the message
function updateMessage(string memory _newMessage) public {
message = _newMessage;
emit MessageUpdated(msg.sender, _newMessage);
}
}
Now we’ll build a frontend to read and update that message.
🧰 Tools You’ll Use
- Vite + React for the frontend
- ethers.js to talk to the blockchain
- MetaMask for signing
- Arbitrum Testnet
🚧 Step-by-Step: Build Your DApp Frontend
1. Create your React app
npm create vite@latest hello-dapp --template react
cd hello-dapp
npm install
npm install ethers
2. Add the basic UI
// src/App.jsx
import { useState } from 'react';
import { ethers } from 'ethers';
const CONTRACT_ADDRESS = 'YOUR_DEPLOYED_CONTRACT_ADDRESS';
const ABI = [
'function message() view returns (string)',
'function updateMessage(string memory _newMessage) public',
];
function App() {
const [msg, setMsg] = useState('');
const [newMsg, setNewMsg] = useState('');
const loadMessage = async () => {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, provider);
const current = await contract.message();
setMsg(current);
};
const updateMessage = async () => {
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = new ethers.Contract(CONTRACT_ADDRESS, ABI, signer);
const tx = await contract.updateMessage(newMsg);
await tx.wait();
loadMessage();
};
return (
<div>
<h1>Arbitrum DApp</h1>
<p>Current Message: {msg}</p>
<input
onChange={(e) => setNewMsg(e.target.value)}
placeholder="New message"
/>
<button onClick={updateMessage}>Update</button>
<button onClick={loadMessage}>Refresh</button>
</div>
);
}
export default App;
3. Connect MetaMask to Arbitrum Goerli
- Add Arbitrum testnet if needed: Chainlist
- Grab test ETH from the faucet.
4. Run your app
npm run dev
Now, your DApp:
- Reads the message from the blockchain.
- Sends a transaction to update it.
- Shows the new message on-chain.
Magic. 🔥
🛠️ What Just Happened?
- ethers.js talks to your contract.
- Web3Provider connects to MetaMask.
- signer lets users approve a blockchain transaction.
- You built a Web3 interface — fully functional on Arbitrum testnet.
🧠 Pro Tips
- Use viem or wagmi for advanced state handling.
- Add loading states for transactions.
- Show the transaction hash & link to Arbiscan.
🧪 Next Steps
Now that your frontend talks to your smart contract:
- Add token payments.
- Use a real database for metadata (like IPFS).
- Build real-world apps (chat, voting, DAOs, NFT mints).
📌 TL;DR
- DApps = frontend + smart contract.
- You built a full Web3 app using ethers.js + Arbitrum.
- Next up: storing & using blockchain data better.
Top comments (0)