What you will be building, see the live demo and GitHub repo for more info.
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;
- NodeJs installed on your machine.
- Yarn package manager installed.
- Truffle installed.
- Ganache installed.
- Git CLI 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. 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 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…
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.
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
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
You will observe the following result on your 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
You should have something like this on your terminal…
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
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.
When you log in, you will see the dashboard page, which allows you to create a new blockchain application.
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.
After you've created the app, you can view its information by clicking on the app's name or the view the details button.
Copy the WSS URL as shown in the image below by clicking on the VIEW KEY button.
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.
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.
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)