Creating a Celo-based Supply Chain Management DApp

Creating a Celo-based Supply Chain Management DApp
none 0.0 0


Cryptocurrency is used widely nowadays in many businesses increasing the growth of Web3. Hence, supply chain management plays an important role in the growth of businesses as well. The traditional or old supply chain management systems still work, but they are less transparent, inefficient, and have many tracing issues. Here comes the DApp or decentralized applications as a great solution to revolutionize supply chain management.

Unlocking the potential of cryptocurrency technology, the supply chain management DApp offers a more transparent framework also more secure than traditional technology. This supply chain management DApp will leverage blockchain technology to fix the issues which occur in traditional supply chain management apps.

This DApp will be transparent, traceable, automated, including smart contracts, secured, and cost-saving. Let’s go on to set up the development environment.

Installation of Tools and Dependencies:

Installation of node.js:

  1. Open the official website to install node.js.
  2. Choose the LTS version for a stable experience.
  3. Select the operating system which you are using. (Windows, macOS, or Linux)
  4. After the installer has been downloaded, you can run it and proceed with the installation.
  5. Read the license agreement and select the installation directory where you want to install it. If it’s the default, leave it as it is.
  6. Once the installation is completed, you need to open the command prompt on Windows or a terminal on macOS or Linux and write the following commands below:


This will show the current version of node.js and npm and it will make sure that node.js has been successfully installed.

It’s time to set up the Celo Development Environment.

Set up the Celo Development Environment:

Celo provides its javascript software development kit that allows everyone to interact with the Celo blockchain.
To configure it, you need to follow the steps below:

  1. Create a new node.js project by using this command:

npm init -y

  1. Now install Celo javascript SDK using this command:

npm install @celo/contractkit

  1. Once it’s done, you need to import the Celo Javascript SDK using the command:

const ContractKit = require('@celo/contractkit');

  1. Now just configure the Celo network provider and you are good to proceed with the next steps as your development environment is ready.

Creation of Smart Contracts:

Smart contacts are required to build a supply chain management DApp as it provides a transparent and secure environment to manage and track the goods across the supply chain.

We will write smart contracts in solidity which will explain the functionalities of our DApp. Solidity is also compatible with Celo so we are good to go with it. We’ll use Remix IDE for our smart contracts.

Follow the steps below to create the smart contracts:

  1. We’ll use Remix IDE which is an online code editor designed for smart contract development. It can be accessed with any browser compatible with the webpage. You just need to visit the URL to access it.
  2. After opening the URL, you need to create a new file with the .sol extension and you can name it whatever you want.
  3. Now define the structure with the following code:
pragma solidity ^0.8.0;

contract SupplyChain {

// Contract code

  1. We’ll declare the variables which are necessary using the code:
contract SupplyChain {

struct Product {

uint256 id;

string name;

address manufacturer;


mapping(uint256 => Product) public products;

  1. To update the product information, track the goods movement, and verify the authenticity, we can use the:
contract SupplyChain {

// ...

function addProduct(uint256 id, string memory name) public {

require(products[id].id == 0, "Product already exists");

products[id] = Product(id, name, msg.sender);

  1. Now compile the code and deploy the contract. Once it shows successful, you can deploy it will the Celo network.

Deploying the Smart Contract on Celo:

  1. Import the smart contract using the “File” tab in the Remix IDE and import it.
  2. Compile the smart contract using the solidity compiler in the Remix IDE.
  3. Select “deploy and run transactions”.
  4. Now select “injected web3” as the environment option which will connect it to the Celo wallet and interact with its test net.
  5. It’s time to confirm the transaction. Once it’s confirmed, the Remix IDE will show the status. You can see the transaction details and hash. It’s done!

Here is the full solidity smart contracts code for your reference:

pragma solidity ^0.8.0;

contract SupplyChain {

enum ProductStatus { Created, Shipped, Delivered }

struct Product {

uint256 id;

string name;

uint256 price;

address seller;

address buyer;

ProductStatus status;


uint256 public productCount;

mapping(uint256 => Product) public products;

event ProductCreated(uint256 id, string name, uint256 price, address seller);

event ProductShip(uint256 id);

event ProductDelivered(uint256 id);

function createProduct(string memory _name, uint256 _price) public {


products[productCount] = Product(productCount, _name, _price, msg.sender, address(0), ProductStatus.Created);

emit ProductCreated(productCount, _name, _price, msg.sender);


function shipProduct(uint256 _id) public {

Product storage product = products[_id];

require(product.status == ProductStatus.Created, "Product is not in the Created status");

require(product.seller == msg.sender, "Only the seller can ship the product");

product.status = ProductStatus.Ship;

emit ProductShip(_id);


function deliverProduct(uint256 _id) public {

Product storage product = products[_id];

require(product.status == ProductStatus.Shipped, "Product is not in the Shipped status");

require(product.buyer == msg.sender, "Only the buyer can deliver the product");

product.status = ProductStatus.Delivered;

emit ProductDelivered(_id);



The ‘addproduct’ function will add new products and if the product already exists it will show ‘ProductAdded’. The function ‘getproduct’ will retrieve the product information using the product ID.

Establishing a connection with the Celo network:

  1. We need to create a new instance of ContractKit and specify the network.
const web3 = new Web3('<RPC_ENDPOINT>');

const kit = ContractKit.newKitFromWeb3(web3);

You need to replace the <RPC_ENDPOINT> with the RPC endpoint URL of Celo Network.

  1. Now load the smart contract instance using ABI:
const contractAddress = '<CONTRACT_ADDRESS>';

const contractABI = require('./path/to/contractABI.json');

const contract = new kit.web3.eth.Contract(contractABI, contractAddress);

You need to replace the <CONTRACT_ADDRESS>’ with the deployed smart contract and give it a correct ABI Path.

  1. Use the below code to interact with the smart contract functions:
async function addProduct(productId, productName) {

const accounts = await kit.web3.eth.getAccounts();

const txObject = await contract.methods.addProduct(productId, productName);

const tx = await txObject.send({ from: accounts[0] });

return tx;


Testing of Supply Chain Management DApp:

Now you need to test your DApp. You can do this by adding some products, tracking goods, and verifying their authenticity.

You can use the below javascript code to test your DApp:

const Web3 = require('web3');

const contractAbi = require('./SupplyChain.abi.json');

const web3 = new Web3(‘replacenetworkurl'); // Replace with your Celo network URL

const contractAddress = ‘replacecontractaddress'; // Replace with your deployed contract address

const supplyChainContract = new web3.eth.Contract(contractAbi, contractAddress);

async function testSupplyChainDApp() {

const accounts = await web3.eth.getAccounts();

const seller = accounts[0];

const buyer = accounts[1];

// Creating a new product

const createProductTx = await supplyChainContract.methods.createProduct('Product A', 100).send({ from: seller });

console.log('Product created:', createProductTx.transactionHash);

const productId =;

const shipProductTx = await supplyChainContract.methods.shipProduct(productId).send({ from: seller });

console.log('Product shipped:', shipProductTx.transactionHash);

const deliverProductTx = await supplyChainContract.methods.deliverProduct(productId).send({ from: buyer });

console.log('Product delivered:', deliverProductTx.transactionHash);



.then(() => console.log('Testing complete'))

.catch(error => console.error('Error:', error));

You need to replace the values with your value. You can install the web3 library using npm.

Frontend HTML & CSS:

We need to create a Frontend for this DApp which we can achieve with this code. For index.html file
<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Supply Chain Management DApp</title>
        body {
            background-color: #C4DFDF;
        h1 {
            color: #070A52;
            text-align: center;
            padding: 100px;
    <link rel="stylesheet" href="styles.css">
    <h1>Supply Chain Management DApp</h1>

    <h2>Create Item</h2>
    <form id="createItemForm">
        <label for="itemName">Item Name:</label>
        <input type="text" id="itemName" required>

        <label for="itemQuantity">Item Quantity:</label>
        <input type="number" id="itemQuantity" required>

        <button type="submit">Create</button>

    <h2>Mark Item as In Transit</h2>
    <form id="markInTransitForm">
        <label for="inTransitItemId">Item ID:</label>
        <input type="number" id="inTransitItemId" required>

        <button type="submit">Mark as In Transit</button>

    <h2>Mark Item as Delivered</h2>
    <form id="markDeliveredForm">
        <label for="deliveredItemId">Item ID:</label>
        <input type="number" id="deliveredItemId" required>

        <button type="submit">Mark as Delivered</button>

    <script src=""></script>
    <script src="app.js"></script>

For style.css design file:

body {
    font-family: Arial, sans-serif;
    margin: 20px;

h1 {
    text-align: center;

h2 {
    margin-top: 30px;

form {
    margin-bottom: 20px;

label {
    display: block;
    margin-bottom: 5px;

input[type="number"] {
    width: 100%;
    padding: 8px;
    margin-bottom: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;

button {
    padding: 8px 16px;
    background: linear-gradient(to right, #64b5f6, #1976d2);
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    transition: background 0.3s ease;

button:hover {
    background: linear-gradient(to right, #1976d2, #64b5f6);

button:disabled {
    background-color: #cccccc;
    cursor: not-allowed;

For app.js

document.addEventListener('DOMContentLoaded', () => {
  const createItemForm = document.getElementById('createItemForm');
  const markInTransitForm = document.getElementById('markInTransitForm');
  const markDeliveredForm = document.getElementById('markDeliveredForm');

  // Event listener for creating an item
  createItemForm.addEventListener('submit', async (event) => {
    event.preventDefault(); // Prevent form submission
    const itemNameInput = document.getElementById('itemName');
    const itemQuantityInput = document.getElementById('itemQuantity');
    const itemName = itemNameInput.value;
    const itemQuantity = itemQuantityInput.value;

    try {
      await createProduct(itemName, itemQuantity);
      console.log('Item created successfully');
      itemNameInput.value = '';
      itemQuantityInput.value = '';
    } catch (error) {
      console.error('Error creating item:', error);

  //  Event listener for marking an item as in transit
  markInTransitForm.addEventListener('submit', async (event) => {
    event.preventDefault(); // Prevent form submission
    const inTransitItemIdInput = document.getElementById('inTransitItemId');
    const inTransitItemId = inTransitItemIdInput.value;

    try {
      await shipProduct(inTransitItemId);
      console.log('Item marked as in transit successfully');
      inTransitItemIdInput.value = '';
    } catch (error) {
      console.error('Error marking item as in transit:', error);

  // Event listener for marking an item as delivered
  markDeliveredForm.addEventListener('submit', async (event) => {
    event.preventDefault(); // Prevent form submission
    const deliveredItemIdInput = document.getElementById('deliveredItemId');
    const deliveredItemId = deliveredItemIdInput.value;

    try {
      await deliverProduct(deliveredItemId);
      console.log('Item marked as delivered successfully');
      deliveredItemIdInput.value = '';
    } catch (error) {
      console.error('Error marking item as delivered:', error);

  async function createProduct(itemName, itemQuantity) {
    try {
      const createProductTx = await supplyChainContract.methods.createProduct(itemName, itemQuantity).send({ from: seller });
      const productId =;
      return productId;
    } catch (error) {
      throw error;

  async function shipProduct(productId) {
    try {
      await supplyChainContract.methods.shipProduct(productId).send({ from: seller });
    } catch (error) {
      throw error;
  async function deliverProduct(productId) {
    try {
      await supplyChainContract.methods.deliverProduct(productId).send({ from: buyer });
    } catch (error) {
      throw error;


We have successfully built a Supply Chain management DApp using Celo Network real quick.

First, we set up the development environment, created smart contracts using solidity and used Remix IDE, tested the contracts and we’re done.


Github: Source Code

Looks interesting. I will love to see the outcome.

1 Like

Congratulations on being among the highest voted proposals for this week! I’m moving this to todo so that you can get started on this project. :mortar_board: :seedling:


I will be reviewing this.


Can you also add the code for app.js

1 Like

Added @Kunaldawar


Nice Work.


A nice piece @dhruv . Thanks for this contribution.


great piece! :blush:

1 Like

A good tutorial here , well done bro.

1 Like

Hi @dhruv , you’re doing well here. But I noticed your contract did not compile successfully due to the following error.

The error occurred in the line quoted below. TypeError: Member "Ship" not found or not visible after argument-dependent lookup in type(enum SupplyChain.ProductStatus)

I hope that you fix it as soon as possible.


I’ll look into it shortly.

1 Like