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 domain

  • Verify 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 URLs

  • hardhat.config.ts with Sepolia settings

  • Script for deploying contract

🔁 Upgradeable Smart Contracts with Proxy Pattern

After launching the initial version, I wanted the flexibility to add features without changing the contract address. I refactored the smart contract using OpenZeppelin’s upgradeable proxy pattern.

Steps Taken:

  1. Installed @openzeppelin/contracts-upgradeable and @openzeppelin/hardhat-upgrades

  2. Updated the contract to inherit from Initializable

  3. Deployed the first version with: 

    const contract = await upgrades.deployProxy(DomainVerifier, [], { initializer: "initialize" });
  4. Created DomainVerifierV2 with new features:

    - Added timestamps for each verified domain

    - Prevent duplicate domain ownership across users

    - Allowed fetching who owns which domain

  5. 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