DEV Community

Cover image for How To Build A Decentralized eCommerce Platform with React and Solidity: (PART ONE)
Gospel Darlington
Gospel Darlington

Posted on • Updated on

How To Build A Decentralized eCommerce Platform with React and Solidity: (PART ONE)

What you will be building, see the live demo and GitHub repo for more info.

Add New Product

Pay With Ethers

Chat With Seller

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.

Prerequisite

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

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. 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.
Enter fullscreen mode Exit fullscreen mode

I recommend you use vs code 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!
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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
);
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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);
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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

The full code looks like this…

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

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
  )
}
Enter fullscreen mode Exit fullscreen mode

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

Testing the Smart Contract

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.

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.

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
Enter fullscreen mode Exit fullscreen mode

You will observe the following result on your terminal.

Migration Result on Terminal

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
Enter fullscreen mode Exit fullscreen mode

You should have something like this on your terminal…

Result on Script Sales

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,
      },
    },
  },
}
Enter fullscreen mode Exit fullscreen mode

Deploying to Alchemy

Alchemy Blockchain Development and Deployment

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 if you already have an account.

Authentication Page

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

Alchemy Dashboard

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

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

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

Web Socket Endpoint

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

Step Two

Step Three

Step Four

ENDPOINT_URL=<YOUR_ALCHEMY_WSS_URL>
SECRET_KEY=<YOUR_METAMASK_SECRET_PHRASE>
DEPLOYER_KEY=<YOUR_METAMASK_PRIVATE_KEY>
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

One: Compiling Smart Contract

Two: Deploying Migration Smart Contract

Three: Deploying Store Smart Contract

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.

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, and you can also check out the git repo here, which you should star.

I'll see you again in PART-TWO 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, Facebook, Github, or on his website.

Top comments (0)