Domain Ownership Verifier on Ethereum Sepolia
Over the past few days, I completed my first Web3 project: a decentralized domain ownership verification tool built on the Ethereum Sepolia testnet. The project allows users to verify that they own a domain name by connecting their Ethereum wallet and uploading a signed proof to their website.
The project is now live at: https://web3-verifier.netlify.app/
🚀 Project Goals
Learn to build and deploy a Solidity smart contract
Interact with the contract via a React + Tailwind frontend
Use Web3 libraries like Ethers.js
Handle off-chain verification via file upload
🛠️ Smart Contract on Sepolia
The contract is written in Solidity 0.8.28 and deployed on the Sepolia testnet. It allows users to:
Add a domain (after checking it's not empty or already verified)
List their verified domains
Remove a previously verified domain
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; contract DomainVerifier { mapping(address => string[]) public domains; function verifyDomain(string calldata domain) external { require(bytes(domain).length > 0, "Domain cannot be empty"); for (uint i = 0; i < domains[msg.sender].length; i++) { require(keccak256(bytes(domains[msg.sender][i])) != keccak256(bytes(domain)), "Domain already exists"); } domains[msg.sender].push(domain); } function getDomains(address owner) external view returns (string[] memory) { return domains[owner]; } function removeDomain(string calldata domain) external { string[] storage list = domains[msg.sender]; uint indexToRemove = list.length; for (uint i = 0; i < list.length; i++) { if (keccak256(bytes(list[i])) == keccak256(bytes(domain))) { indexToRemove = i; break; } } require(indexToRemove < list.length, "Domain not found"); list[indexToRemove] = list[list.length - 1]; list.pop(); } }
💻 Frontend Stack
The frontend was built with:
React + Vite for speed and DX
Tailwind CSS for utility-based styling
Ethers.js for Ethereum interactions
⭐ Features:
Connect wallet via MetaMask
Input a domain name
Sign a message with your wallet
Upload a
wallet-proof.json
file to your domainVerify domain ownership (via
fetch
to your website)Store verified domains on-chain
📁 Deployment
Smart Contract deployed using Hardhat and Infura to Sepolia
Frontend deployed via Netlify
Config included:
.env
for managing private keys and RPC URLshardhat.config.ts
with Sepolia settingsScript for deploying contract
🔁 Upgradeable Smart Contracts with Proxy Pattern
Steps Taken:
-
Installed
@openzeppelin/contracts-upgradeable
and@openzeppelin/hardhat-upgrades
-
Updated the contract to inherit from
Initializable
-
Deployed the first version with:
const contract = await upgrades.deployProxy(DomainVerifier, [], { initializer: "initialize" });
Created DomainVerifierV2 with new features:
- Added timestamps for each verified domain
- Prevent duplicate domain ownership across users
- Allowed fetching who owns which domain
Upgraded with:
await upgrades.upgradeProxy(proxyAddress, DomainVerifierV2);
Now I can keep improving the logic while keeping the same contract address on-chain.
📖 Learnings
How CORS policies affect cross-domain verification
How to display error messages from smart contracts in React
How to use MetaMask
How to persist contract data via mapping in Solidity
How to debug contract behavior via Hardhat
💪 Final Thoughts
Building this project gave me hands-on experience with the full Web3 development cycle: writing a smart contract, deploying to a testnet, building a React frontend, and connecting them together with Ethers.js.
I'm proud to launch web3-verifier.netlify.app and make it easy for anyone to prove domain ownership on Ethereum.
Thanks for reading!
Comments
Post a Comment