DEV Community

Cover image for Building a Blockchain-Based Blog dApp with Hardhat: A Step-by-Step Guide
Nick L.
Nick L.

Posted on

Building a Blockchain-Based Blog dApp with Hardhat: A Step-by-Step Guide

Blockchain technology is revolutionizing many industries, and blogging is no exception. Imagine a decentralized blogging platform where content creators can post articles, receive votes, and even earn tips directly from their readers, all powered by blockchain. This is the power of decentralized applications (dApps).

In this guide, we’ll walk through the process of developing a decentralized blog application using Hardhat, a popular Ethereum development environment. By the end of this tutorial, you’ll have a basic dApp where bloggers can post content, users can vote on their favorite posts, and readers can tip bloggers directly in cryptocurrency.

Prerequisites

Before we begin, make sure you have the following installed on your machine:

  • Node.js (v12.x or later)
  • npm (Node Package Manager)
  • Metamask extension installed in your web browser
  • Basic knowledge of JavaScript, Solidity, and Ethereum concepts

Step 1: Setting Up the Hardhat Project

First, create a new directory for your project and navigate into it:

mkdir blockchain-blog
cd blockchain-blog
Enter fullscreen mode Exit fullscreen mode

Initialize a new Node.js project:

npm init -y
Enter fullscreen mode Exit fullscreen mode

Install Hardhat:

npm install --save-dev hardhat
Enter fullscreen mode Exit fullscreen mode

Set up a new Hardhat project:

npx hardhat
Enter fullscreen mode Exit fullscreen mode

Select “Create a basic sample project” when prompted. This will generate a basic Hardhat project structure with some sample files.

Step 2: Writing the Smart Contract

Our decentralized blog dApp will have a smart contract that handles the core functionalities: posting articles, voting on posts, and tipping bloggers.

Create a new contract file called Blog.sol in the contracts directory:

touch contracts/Blog.sol
Enter fullscreen mode Exit fullscreen mode

Open Blog.sol and add the following Solidity code:

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

contract Blog {
    struct Post {
        uint256 id;
        string content;
        address payable author;
        uint256 votes;
        uint256 tips;
    }

    uint256 public postCount = 0;
    mapping(uint256 => Post) public posts;

    event PostCreated(uint256 id, string content, address payable author);
    event PostVoted(uint256 id, uint256 votes);
    event PostTipped(uint256 id, uint256 tips);

    function createPost(string memory _content) public {
        postCount++;
        posts[postCount] = Post(postCount, _content, payable(msg.sender), 0, 0);
        emit PostCreated(postCount, _content, payable(msg.sender));
    }

    function votePost(uint256 _id) public {
        require(_id > 0 && _id <= postCount, "Invalid post ID");
        Post storage post = posts[_id];
        post.votes++;
        emit PostVoted(_id, post.votes);
    }

    function tipPost(uint256 _id) public payable {
        require(_id > 0 && _id <= postCount, "Invalid post ID");
        Post storage post = posts[_id];
        post.tips += msg.value;
        post.author.transfer(msg.value);
        emit PostTipped(_id, post.tips);
    }
}
Enter fullscreen mode Exit fullscreen mode

Breakdown of the Smart Contract

  • Post Structure: We define a Post structure containing fields like id, content, author, votes, and tips.
  • Create Post: The createPost function allows bloggers to create new posts.
  • Vote Post: The votePost function lets users vote for their favorite posts.
  • Tip Post: The tipPost function allows readers to send ETH directly to the post's author.

Step 3: Compiling the Smart Contract

To compile your smart contract, run the following command:

npx hardhat compile
Enter fullscreen mode Exit fullscreen mode

This command will compile your smart contract and generate the necessary artifacts in the artifacts directory.

Step 4: Writing the Deployment Script

We need to deploy our smart contract to a blockchain network. Create a new deployment script in the scripts directory called deploy.js:

touch scripts/deploy.js
Enter fullscreen mode Exit fullscreen mode

Open deploy.js and add the following deployment script:

const hre = require("hardhat");

async function main() {
  const [deployer] = await hre.ethers.getSigners();

  console.log("Deploying contracts with the account:", deployer.address);

  const Blog = await hre.ethers.getContractFactory("Blog");
  const blog = await Blog.deploy();

  await blog.deployed();

  console.log("Blog contract deployed to:", blog.address);
}

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

This script deploys the Blog contract and logs the contract's address after successful deployment.

Step 5: Deploying the Contract Locally

To deploy the contract on a local Ethereum network, first, start the Hardhat node:

npx hardhat node
Enter fullscreen mode Exit fullscreen mode

In a separate terminal, run the deployment script:

npx hardhat run scripts/deploy.js --network localhost
Enter fullscreen mode Exit fullscreen mode

This deploys the Blog contract on your local blockchain. You’ll see the deployment address in the terminal output.

Step 6: Building the Front-End

Now that we have our smart contract deployed, we’ll build a simple front-end to interact with it.

Step 6.1: Setting Up React

Set up a React app using Create React App:

npx create-react-app blog-frontend
cd blog-frontend
npm install ethers
Enter fullscreen mode Exit fullscreen mode

Step 6.2: Connecting to the Smart Contract

Create a new file called App.js in the src directory and add the following code:

import React, { useEffect, useState } from "react";
import { ethers } from "ethers";
import BlogABI from "./BlogABI.json";

const contractAddress = "your_contract_address_here";

function App() {
  const [posts, setPosts] = useState([]);
  const [content, setContent] = useState("");

  useEffect(() => {
    const loadPosts = async () => {
      if (window.ethereum) {
        const provider = new ethers.providers.Web3Provider(window.ethereum);
        await provider.send("eth_requestAccounts", []);
        const signer = provider.getSigner();
        const blogContract = new ethers.Contract(contractAddress, BlogABI, signer);

        const postCount = await blogContract.postCount();
        let postsArray = [];
        for (let i = 1; i <= postCount; i++) {
          const post = await blogContract.posts(i);
          postsArray.push(post);
        }
        setPosts(postsArray);
      }
    };

    loadPosts();
  }, []);

  const createPost = async () => {
    if (window.ethereum) {
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const signer = provider.getSigner();
      const blogContract = new ethers.Contract(contractAddress, BlogABI, signer);

      const transaction = await blogContract.createPost(content);
      await transaction.wait();
      setContent("");
      window.location.reload();
    }
  };

  const votePost = async (id) => {
    if (window.ethereum) {
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const signer = provider.getSigner();
      const blogContract = new ethers.Contract(contractAddress, BlogABI, signer);

      const transaction = await blogContract.votePost(id);
      await transaction.wait();
      window.location.reload();
    }
  };

  const tipPost = async (id) => {
    if (window.ethereum) {
      const provider = new ethers.providers.Web3Provider(window.ethereum);
      const signer = provider.getSigner();
      const blogContract = new ethers.Contract(contractAddress, BlogABI, signer);

      const transaction = await blogContract.tipPost(id, { value: ethers.utils.parseEther("0.1") });
      await transaction.wait();
      window.location.reload();
    }
  };

  return (
    <div>
      <h1>Blockchain Blog</h1>
      <input
        type="text"
        value={content}
        onChange={(e) => setContent(e.target.value)}
        placeholder="Write your post"
      />
      <button onClick={createPost}>Post</button>
      <div>
        {posts.map((post, index) => (
          <div key={index}>
            <p>{post.content}</p>
            <p>Author: {post.author}</p>
            <p>Votes: {post.votes}</p>
            <p>Tips: {ethers.utils.formatEther(post.tips)} ETH</p>
            <button onClick={() => votePost(post.id)}>Vote</button>
            <button onClick={() => tipPost(post.id)}>Tip</button>
          </div>
        ))}
      </div>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Step 6.3: Understanding the Front-End

  • Fetching Posts: The loadPosts function fetches all posts from the blockchain and stores them in the state.
  • Creating a Post: The createPost function sends a transaction to create a new post on the blockchain.
  • Voting for a Post: The votePost function allows users to vote for a specific post.
  • Tipping a Post: The tipPost function allows users to send ETH to the post’s author as a tip.

Step 6.4: Running the Front-End

Now

, let's run the front-end to interact with our deployed smart contract.

First, make sure you are in the blog-frontend directory and run:

npm start
Enter fullscreen mode Exit fullscreen mode

This command will start the React development server and open the application in your default web browser. You should now see a simple interface where you can create blog posts, vote on them, and tip the authors.

Conclusion

Congratulations! You’ve built a decentralized blog application that leverages blockchain technology for posting content, voting, and tipping bloggers. This guide covered the entire process from setting up your environment with Hardhat, writing and deploying smart contracts, to building a front-end interface using React.

While this is a basic implementation, it lays the foundation for more advanced features like user authentication, content moderation, and decentralized storage for blog content. As you continue to explore blockchain development, consider experimenting with other Ethereum tools and expanding the functionality of your dApp.

Blockchain is a rapidly evolving field with endless possibilities. By mastering tools like Hardhat and integrating smart contracts with user-friendly interfaces, you’re well on your way to creating innovative and decentralized applications that could shape the future of the web. Happy coding!

Top comments (0)