Building a Decentralized E-commerce Platform with QuickNode and Ethereum

Building a Decentralized E-commerce Platform with QuickNode and Ethereum

Introduction

Decentralized finance (DeFi) and blockchain technology have been revolutionizing various industries, and e-commerce is no exception. In this tutorial, we will walk you through the process of building a decentralized e-commerce platform using QuickNode, a leading blockchain-as-a-service provider, and Ethereum, a popular programmable blockchain. By the end of this tutorial, you'll have a functional platform that enables users to list and purchase products securely and transparently.

Prerequisites

To follow this tutorial, you'll need the following:

  • Basic knowledge of blockchain concepts

  • Node.js and npm installed on your machine

  • An Ethereum wallet and MetaMask browser extension

  • Solidity and web development knowledge (JavaScript, React)

Setting Up the Development Environment

Let's begin by setting up the development environment for our decentralized e-commerce platform.

Step 1: Install Truffle and Create a New Project

npm install -g truffle
truffle init

Step 2: Create Smart Contracts

In the contracts directory, create a new file called Marketplace.sol to define the smart contract for the marketplace.

// contracts/Marketplace.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Marketplace {
    // Contract implementation here
}

Implementing the Smart Contract

In this section, we'll implement the smart contract with the necessary functions to list products and make purchases.

Step 1: Define Data Structures and State Variables

Add the following data structures and state variables to the Marketplace contract:

// contracts/Marketplace.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Marketplace {
    struct Product {
        uint256 id;
        string name;
        string description;
        uint256 price;
        uint256 stock;
        address seller;
    }

    uint256 public productCount;
    mapping(uint256 => Product) public products;
}

Step 2: Implement Listing Products

Add a function to the Marketplace contract that allows users to list their products for sale.

// contracts/Marketplace.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Marketplace {
    // ... (previous code)

    event ProductListed(uint256 id, string name, uint256 price, uint256 stock);

    function listProduct(string memory _name, string memory _description, uint256 _price, uint256 _stock) public {
        // Implement the listing logic here
        // Ensure only authenticated users can list products
        // Add the product to the products mapping and emit the ProductListed event
    }
}

Step 3: Implementing Purchasing Products

Next, add a function to the Marketplace a contract that allows users to purchase products.

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

contract Marketplace {
    struct Product {
        uint256 id;
        address seller;
        string name;
        string description;
        uint256 price;
        uint256 stock;
    }

    uint256 public productCounter;
    mapping(uint256 => Product) public products;

    // Events for product listing and purchase
    event ProductListed(uint256 id, string name, uint256 price, uint256 stock);
    event ProductPurchased(uint256 id, string name, uint256 price, uint256 quantity);

    // Function to list a new product for sale
    function listProduct(string memory _name, string memory _description, uint256 _price, uint256 _stock) public {
        productCounter++;
        products[productCounter] = Product(productCounter, msg.sender, _name, _description, _price, _stock);
        emit ProductListed(productCounter, _name, _price, _stock);
    }

    // Function to purchase a product
    function purchaseProduct(uint256 _productId, uint256 _quantity) public payable {
        Product memory product = products[_productId];
        require(product.id > 0 && product.id <= productCounter, "Product not found");
        require(_quantity > 0 && _quantity <= product.stock, "Invalid quantity");
        require(msg.value >= product.price * _quantity, "Insufficient funds");

        product.stock -= _quantity;
        products[_productId] = product;

        emit ProductPurchased(product.id, product.name, product.price, _quantity);
    }
}

Deploying the Smart Contract

Now, let's deploy the smart contract to the Ethereum blockchain using Truffle.

Step 1: Configure Truffle

In the truffle-config.js file, import the required packages and use the @truffle/hdwallet-provider as the provider. Replace NETWORK_NAME with the desired network name (e.g., ropsten, mainnet) and make sure to replace YOUR_MNEMONIC with your Ethereum wallet's mnemonic or private key:

require('dotenv').config();
const HDWalletProvider = require('@truffle/hdwallet-provider');

const mnemonic = 'YOUR_MNEMONIC'; // Replace this with your Ethereum wallet's mnemonic or private key
const quicknodeApiKey = process.env.QUICKNODE_API_KEY;
const quicknodeEndpoint = process.env.QUICKNODE_ENDPOINT;

module.exports = {
  networks: {
    development: {
      host: '127.0.0.1',
      port: 8545,
      network_id: '*',
    },
    ropsten: {
      provider: () => new HDWalletProvider(mnemonic, quicknodeEndpoint),
      network_id: 3,
      gas: 5500000,
      gasPrice: 20000000000, // 20 gwei (in wei)
    },
    // Add more networks as needed (e.g., mainnet)
  },
  // ... (other Truffle configurations)
};

Step 2: Deploy the Smart Contract

Run the following command to deploy the smart contract to the desired network:

truffle migrate --network NETWORK_NAME

Building the Frontend with React

Set up a React application in a new directory called client. Install necessary dependencies and design the basic structure of the frontend.

npx create-react-app client
cd client
npm install web3 @truffle/hdwallet-provider dotenv

Create a new file web3.js in the src folder to connect the frontend with the Ethereum blockchain using Web3.

// src/web3.js
import Web3 from 'web3';

const getWeb3 = async () => {
  if (window.ethereum) {
    window.web3 = new Web3(window.ethereum);
    await window.ethereum.enable();
    return window.web3;
  } else if (window.web3) {
    window.web3 = new Web3(window.web3.currentProvider);
    return window.web3;
  } else {
    console.log('Non-Ethereum browser detected. You should consider trying MetaMask!');
    return null;
  }
};

export default getWeb3;

In the App.js file, import the Authenticate component and implement the authentication logic using state.

// src/App.js
import React, { useState, useEffect } from 'react';
import getWeb3 from './web3';
import MarketplaceContract from './contracts/Marketplace.json';
import Authenticate from './components/Authenticate';
import Marketplace from './components/Marketplace';

const App = () => {
  const [web3, setWeb3] = useState(null);
  const [contract, setContract] = useState(null);
  const [user, setUser] = useState(null);

  const authenticateUser = async (username) => {
    try {
      const isAuthenticated = await contract.methods.authenticateUser(username).call();
      if (isAuthenticated) {
        setUser(username);
      } else {
        console.error('User not authenticated.');
      }
    } catch (error) {
      console.error('Error authenticating user: ', error);
    }
  };

  useEffect(() => {
    const initWeb3 = async () => {
      const web3Instance = await getWeb3();
      if (web3Instance) {
        setWeb3(web3Instance);
        const networkId = await web3Instance.eth.net.getId();
        const deployedNetwork = MarketplaceContract.networks[networkId];
        if (deployedNetwork) {
          const marketplaceInstance = new web3Instance.eth.Contract(
            MarketplaceContract.abi,
            deployedNetwork.address
          );
          setContract(marketplaceInstance);
        } else {
          console.error('Marketplace contract not deployed to the current network.');
        }
      }
    };
    initWeb3();
  }, []);

  return (
    <div>
      {user ? (
        <Marketplace contract={contract} user={user} />
      ) : (
        <Authenticate authenticateUser={authenticateUser} />
      )}
    </div>
  );
};

export default App;

Frontend for Product Listing

Let's add the frontend to list products on the marketplace. In the Marketplace.js file, implement a form to input product details and a button to list the product.

// src/components/Marketplace.js
import React, { useState } from 'react';

const Marketplace = ({ contract, user }) => {
  const [productName, setProductName] = useState('');
  const [productDescription, setProductDescription] = useState('');
  const [productPrice, setProductPrice] = useState('');
  const [productStock, setProductStock] = useState('');

  const handleListProduct = async () => {
    if (productName && productDescription && productPrice && productStock) {
      try {
        await contract.methods.listProduct(productName, productDescription, productPrice, productStock).send({
          from: user,
        });
        console.log('Product listed successfully.');
        // Update product listing UI or perform other actions after successful listing
      } catch (error) {
        console.error('Error listing product: ', error);
        // Handle the error and display an appropriate message to the user
      }
    }
  };

  return (
    <div>
      <h2>Marketplace</h2>
      <h3>List a Product</h3>
      <input
        type="text"
        placeholder="Product Name"
        value={productName}
        onChange={(e) => setProductName(e.target.value)}
      />
      <textarea
        placeholder="Product Description"
        value={productDescription}
        onChange={(e) => setProductDescription(e.target.value)}
      ></textarea>
      <input
        type="number"
        placeholder="Price (in ETH)"
        value={productPrice}
        onChange={(e) => setProductPrice(e.target.value)}
      />
      <input
        type="number"
        placeholder="Stock"
        value={productStock}
        onChange={(e) => setProductStock(e.target.value)}
      />
      <button onClick={handleListProduct}>List Product</button>
    </div>
  );
};

export default Marketplace;

Conclusion

Congratulations! You've built a decentralized e-commerce platform using QuickNode and Ethereum. Users can now authenticate themselves and list products securely on the platform. This tutorial provides a foundation for further enhancements, such as implementing secure payment mechanisms, real-time updates, and improving the user interface. You can explore more features like searching for products, product details, and purchasing products from the marketplace.

Remember to enhance security measures and thoroughly test your application before deploying it to a production environment. Building decentralized applications (dApps) is an exciting journey that offers transparency, security, and opportunities for innovative business models. Enjoy exploring the vast world of blockchain technology and DeFi applications!


Require assistance with your project or have inquiries? Feel free to reach out to us through this form, connect with us on Twitter @QuickNode, or ping us on Discord! We're here to help and support you every step of the way.

I'd love to connect with you on Twitter | LinkedIn | Portfolio.

Resources

Create A Free Account

QuickNode Developers Documentation

QuickNode Developers Guides

About QuickNode

QuickNode is building infrastructure to support the future of Web3. Since 2017, we've worked with hundreds of developers and companies, helping scale dApps and providing high-performance access to 23+ blockchains. Subscribe to our newsletter for more content like this, and stay in the loop with what's happening in Web3!