How To Build A Decentralized eCommerce Platform with React and Solidity: (PART ONE)
Tags: web3, react, solidity, blockchain
Published: 2022-03-23 16:03:00

What you will be building, see the [live demo](https://fresher-a5113.web.app/) and [GitHub repo](https://github.com/Daltonic/freshers) for more info.

![Add New Product](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1647957013361_freshers-add-product.gif)



![Pay With Ethers](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1647957404131_freshers-pay-with-eth.gif)



![Chat With Seller](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1647957929071_freshers-chat.gif)



## Introduction

The demand for Web3.0 solutions is at an all-time high, but there isn't enough material available to usher in the army of developers required to fill the job openings. To assist other web developers, I've created this tutorial to help you understand how to build a decentralized eCommerce platform that transacts Ethers. You will be able to do the following by the end of this tutorial:


- Build an eCommerce app.
- Integrate Web3.0 Payment solution.
- Incorporate Customer Chat functionality.
- Interact with a Database using Firebase v9.
- Code and Deploy a Solidity Smart Contract.
- Hookup Smart Contract with React App.
- Lot’s more.

This is tutorial is PART-ONE of a two-part series, we will begin with developing the solidity smart contract. So If you are pumped for this build, then let’s get coding…

[Check out my YouTube channel for FREE web3 tutorials now](https://www.youtube.com/channel/UCQteXYZ5mC-cuTxplzM4Hlw?sub_confirmation=1).


## Prerequisite

For PART-ONE of this tutorial, you will need the following items to build along with me;


- [NodeJs](https://nodejs.org/en/download/) installed on your machine.
- [Yarn package manager](https://classic.yarnpkg.com/en/docs/install#windows-stable) installed.
- [Truffle](https://trufflesuite.com/docs/truffle/getting-started/installation.html) installed.
- [Ganache](https://trufflesuite.com/ganache/index.html) installed.
- [Git CLI](https://git-scm.com/download/) installed.
- And an agile determination to learn.


## Installing App Dependencies

To save you the pain of installing one dependency after another, I’ve prepared you a [starter kit on my git repo](https://github.com/Daltonic/truffle-starter-kit). Clone and install the dependencies with the instructions below. And… don’t forget to star the project.

On your terminal, navigate to the location of your project and run the code below:


    # Make sure you have the above prerequisites installed already!
    git clone https://github.com/Daltonic/truffle-starter-kit.git freshers
    cd frehsers # Navigate to the new folder.
    yarn install # Installs all the dependencies.

I recommend you use [**vs code**](https://code.visualstudio.com/download) for the tutorial, it has everything you will need for coding.

If you’ve done that, you’re awesome, let’s proceed to the next step…


## Coding the Smart Contract

Open the project in VS code and head on to the contracts directory, you will see an existing contract named **Migration.sol**. 

Create a new solidity contract named **Store.sol**. Inside of the store, define the following structures.


    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    
    contract Store {
      // All codes goes in here!
    }

This is a typical structure of a solidity smart contract, let’s code this smart contract one step at a time.


    // Defining store variables
    address public immutable storeOwner;
    uint256 public storeAcc;
    string public storeName;
    uint256 public immutable feePercent;
    uint256 public storeSales;

These are the variables our smart contract will use to perform store sales. The **store owner** and **fee percent** variables are **immutable**, once the smart contract is deployed it can no longer be changed in the course of the program.

Variables with address type mean that they can only hold data types of wallet address. Whereas variables with **uint** or **uint256** mean unsigned integers, they can be used to hold only positive numbers with or without decimals.


    // Tracking users number of sales
    mapping(address => uint256) public salesOf;

The code above describes a solidity variable with a key-value type of association. It's similar to the python hash method in that it returns a value if the argument passed in the parameter finds a match.


    // Declaring Events within each sale
    event Sale(
        address indexed buyer,
        address indexed seller,
        uint256 amount,
        uint256 timestamp
    );
    event Withdrawal(
        address indexed receiver,
        uint256 amount,
        uint256 timestamp
    );

Events are useful for storing the arguments passed into the smart contract on the blockchain network. It’s an essential ingredient for writing a professional smart contract.


    // Structuring the sales object
    struct SalesStruct {
        address buyer;
        address seller;
        uint256 amount;
        string purpose;
        uint256 timestamp;
    }
    SalesStruct[] sales;

We're describing a structure for collecting sales data in the code above. We want to collect the buyer and seller's addresses, the number of ethers transacted, the purpose of the transaction, and the time the transaction was completed for each sale made through our smart contract. Solidity provides us with a struct method, which is the best practice for ensuring that these records are correctly entered.


    // Initializing the store
    constructor(
        string memory _storeName,
        address _storeOwner,
        uint256 _feePercent
    ) {
        storeName = _storeName;
        storeOwner = _storeOwner;
        feePercent = _feePercent;
        storeAcc = 0;
    }

These are the information passed during the deployment of the smart contract.


    // Performing sales payment
    function payNow(address seller, string memory purpose)
        public
        payable
        returns (bool success)
    {
        // Validating payments
        require(msg.value > 0, "Ethers cannot be zerro!");
        require(msg.sender != storeOwner, "Sale Not allowed");
    
        // Calculating up cost and fee
        uint256 fee = (msg.value / 100) * feePercent;
        uint256 cost = msg.value - fee;
    
        // Assigning sales and payment to store and product owner
        storeAcc += msg.value;
        storeSales += 1;
        salesOf[seller] += 1;
    
        // Cashing out to sales party
        withdrawMoneyTo(storeOwner, fee);
        withdrawMoneyTo(seller, cost);
    
        // Recording sales in smart contract
        sales.push(
            SalesStruct(msg.sender, seller, cost, purpose, block.timestamp)
        );
    
        // Captures sales data on event
        emit Sale(msg.sender, seller, cost, block.timestamp);
        return true;
    }

This function collects payment from a buyer and sends the seller **90%** of the sales and **10%** to the store owner as the fee for utilizing their platform.


    // Sends ethers to a specified address
    function _payTo(address _to, uint256 _amount) internal {
        (bool success1, ) = payable(_to).call{value: _amount}("");
        require(success1);
    }

This is an internal method for transferring ethers to a specified address, it works in conjunction with the withdrawal function. It can only be called by another function within our smart contract.


    // Performs ethers transfer
    function withdrawMoneyTo(address receiver, uint256 amount)
        internal
        returns (bool success)
    {
        require(storeAcc >= amount, "Insufficent Fund!");
        _payTo(receiver, amount);
        storeAcc -= amount;
    
        // Captures transfer data on event
        emit Withdrawal(receiver, amount, block.timestamp);
        return true;
    }

This is a function that performs the sending of money to a specified address. It makes sure that it checks for balances before carrying out the transaction.


    // Retreives all processed sales from smart contract
    function getAllSales() public view returns (SalesStruct[] memory) {
        return sales;
    }

Lastly, this function returns an array of all the sales that have taken place on our smart contract.

The full code looks like this…


{% gist https://gist.github.com/Daltonic/15d3bcc2f223e32b1b22ec67d6bc27d2 %}


Now that we are done with coding this smart contract, it's time to test it programmatically.


## Setting up the Migration Scripts

Before we proceed with testing out the smart contract, let’s set up the migration script in the **migrations** folder.

![Migrations Folder](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1648036743504_screenshoteasy+28.png)


Head to the migrations folder and create a new file called **2_deploy_contracts.js**. Paste the following codes inside the *2_deploy_contracts.js* file.


    const Store = artifacts.require('Store')
    module.exports = async (deployer) => {
      const [_feeAccount] = await web3.eth.getAccounts()
      const _name = 'Fresher'
      const _feePercent = 10
      await deployer.deploy(
        Store,
        _name,
        _feeAccount,
        _feePercent
      )
    }

This will be necessary when we start testing out the smart contract.


## Testing the Smart Contract
![](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1648037915696_Screenshot+249.png)


Spin up Ganache and ensure that it’s live and accessible. Next, locate the **test** folder and create a file called **Store.test.js**.

Paste the code snippet inside of it.


{% gist https://gist.github.com/Daltonic/cc8dcb6081f015dd1c1e9cbf2efaa4d6 %}


The above test is designed to check that our smart contract can perform sales. An extra measure to ensure that your smart contract runs accordingly is to write a script that will interact with it. Let’s do that next.


## Interacting with the Smart Contract

This is the best way to validate the functionalities of your smart contract. We want to write a script to simulate the sales process.

Head to the **scripts folder** and create a file called **performSales.js**. Next, paste the following codes inside of it.


{% gist https://gist.github.com/Daltonic/0643dc927361b712da089cc9115d9062 %}


Cool, after creating and pasting the codes above, run the following command on the terminal. Please make sure that your ganache is up and running.


    truffle migrate --reset

You will observe the following result on your terminal.

![Migration Result on Terminal](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1648038738525_Screenshot+250.png)


If you reached here, you’re awesome, let’s run the **perfomSales** script by running this code on the terminal.


    truffle exec scripts/performSales.js

You should have something like this on your terminal…

![Result on Script Sales](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1648039023844_Screenshot+251.png)


Fantastic, we can be happy that our smart contract is certified and fully functional. Let’s deploy it to the **rinkeby test net**.


## Deploying the Smart Contract

To do this deployment, configure your truffle config file in the order below:


    require('dotenv').config()
    const HDWalletProvider = require('@truffle/hdwallet-provider')
    module.exports = {
      // Configure networks (Localhost, Kovan, etc.)
      networks: {
        development: {
          host: '127.0.0.1',
          port: 7545,
          network_id: '*', // Match any network id
        },
        rinkeby: {
          provider: () =>
            new HDWalletProvider(process.env.SECRET_KEY, process.env.ENDPOINT_URL),
          network_id: 4, // Rinkeby's id
          gas: 5500000, // Rinkeby has a lower block limit than mainnet
          confirmations: 2, // # of confs to wait between deployments. (default: 0)
          timeoutBlocks: 200, // # of blocks before a deployment times out  (minimum/default: 50)
          skipDryRun: true, // Skip dry run before migrations? (default: false for public nets )
        },
      },
      contracts_directory: './contracts/',
      contracts_build_directory: './src/shared/abis/',
      // Configure your compilers
      compilers: {
        solc: {
          version: '0.8.11',
          optimizer: {
            enabled: true,
            runs: 200,
          },
        },
      },
    }


**Deploying to Alchemy**

![Alchemy Blockchain Development and Deployment](https://paper-attachments.dropbox.com/s_80FE02C51945E8808FE82A228922BC93294E036898C1D5C62FBCFC631D57D794_1642323006875_screenshoteasy+19.png)


At the moment, our smart contract can only run on our computer, and no one else can connect to it. We will use alchemy to make it available to everyone at no cost.

Sign up with them now, or [**log in**](https://auth.alchemyapi.io/?redirectUrl=https%3A%2F%2Fdashboard.alchemyapi.io) if you already have an account.


![Authentication Page](https://paper-attachments.dropbox.com/s_80FE02C51945E8808FE82A228922BC93294E036898C1D5C62FBCFC631D57D794_1642323341163_screenshoteasy+20.png)


When you log in, you will see the dashboard page, which allows you to create a new blockchain application.


![Alchemy Dashboard](https://paper-attachments.dropbox.com/s_80FE02C51945E8808FE82A228922BC93294E036898C1D5C62FBCFC631D57D794_1642323555226_screenshoteasy+22.png)


**Creating an Alchemy App**
Click on the **CREATE APP** button and enter the information shown in the image below, making sure to include the **Rinkeby test** network.


![Create New App Popup](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1648042815270_screenshoteasy+32.png)


After you've created the app, you can view its information by clicking on the app's name or the view the details button.

![Created App](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1648042900212_screenshoteasy+33.png)


Copy the **WSS URL** as shown in the image below by clicking on the **VIEW KEY** button.

![Web Socket Endpoint](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1648042628712_screenshoteasy+31.png)


Amazing, now proceed as shown in the images below to obtain your **Rinkeby** account. Please keep in mind that we are not using the regular account address, but rather the private key to that account.


![Step One](https://paper-attachments.dropbox.com/s_80FE02C51945E8808FE82A228922BC93294E036898C1D5C62FBCFC631D57D794_1642325264360_Screenshot+244.png)



![Step Two](https://paper-attachments.dropbox.com/s_80FE02C51945E8808FE82A228922BC93294E036898C1D5C62FBCFC631D57D794_1642325264934_Screenshot+246.png)




![Step Three](https://paper-attachments.dropbox.com/s_80FE02C51945E8808FE82A228922BC93294E036898C1D5C62FBCFC631D57D794_1642325264802_Screenshot+245.png)

![Step Four](https://paper-attachments.dropbox.com/s_80FE02C51945E8808FE82A228922BC93294E036898C1D5C62FBCFC631D57D794_1642325264304_Screenshot+247.png)



    ENDPOINT_URL=<YOUR_ALCHEMY_WSS_URL>
    SECRET_KEY=<YOUR_METAMASK_SECRET_PHRASE>
    DEPLOYER_KEY=<YOUR_METAMASK_PRIVATE_KEY>

Please do not use your real **Metamask details**; these keys must be kept secret. That's why we put them in the environment file and tell git to ignore them.

After you've entered the above keys into their respective variables, execute the commands below.


    truffle migrate --reset --network rinkeby

As we can see below, your smart contract will be deployed on the Rinkeby test net.

![One: Compiling Smart Contract](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1648044203469_Screenshot+256.png)

![Two: Deploying Migration Smart Contract](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1648044174418_Screenshot+255.png)

![Three: Deploying Store Smart Contract](https://paper-attachments.dropbox.com/s_D720F64E38BC9DEB85A924EA9228240E9E0724DBBDD5C2A1518C2F4F4FE8CAB0_1648044152557_Screenshot+254.png)


Wow, you've worked hard to get to this point. You've just finished deploying an eye-catching smart contract to the Ethereum blockchain network. We'll connect it to a ReactJs frontend in PART TWO of this tutorial.

[Watch my FREE web3 tutorials on Youtube now](https://www.youtube.com/channel/UCQteXYZ5mC-cuTxplzM4Hlw?sub_confirmation=1).

## Conclusion

You've completed the first part of this tutorial; next, we'll learn how to connect the solidity smart contract we just deployed to our React frontend.

You can see the finished version of this application [**live here**](https://fresher-a5113.web.app/), and you can also check out the [**git repo here**](https://github.com/Daltonic/freshers), which you should star.

I'll see you again in [PART-TWO](https://dev.to/daltonic/how-to-build-a-decentralized-ecommerce-platform-with-react-and-solidity-part-two-42gk) of this tutorial.


## About the Author

Gospel Darlington kick-started his journey as a software engineer in 2016. Over the years, he has grown full-blown skills in JavaScript stacks such as React, ReactNative, VueJs, and more.

He is currently freelancing, building apps for clients, and writing technical tutorials teaching others how to do what he does.

Gospel Darlington is open and available to hear from you. You can reach him on [LinkedIn](https://www.linkedin.com/in/darlington-gospel-aa626b125/), [Facebook](https://www.facebook.com/darlington.gospel01), [Github](https://github.com/Daltonic), or on his [website](https://daltonic.github.io/).