How to Build a Tokenized Farmer's Market on the Celo Blockchain (Part 1)

How to Build a Tokenized Farmer's Market on the Celo Blockchain (Part 1) https://celo.academy/uploads/default/optimized/2X/3/3b566d62bf50bcc179fb8edb7c60be1572118040_2_1024x576.png
none 0.0 0

Introduction

In this article, we will explore the process of building a tokenized farmer’s market on the Celo blockchain. We will leverage JavaScript, Hardhat, and Solidity to develop a smart contract that enables the creation and management of a decentralized marketplace for farmers to sell their produce. The currency used within this marketplace will be cUSD, which is the stablecoin on the Celo network.

Prerequisites:

Before we begin, make sure you have the following installed:

  1. Node.js: https://nodejs.org
  2. Hardhat: https://hardhat.org

Setting Up the Project:

To start, let’s set up our project by creating a new directory and initializing a new Node.js project. Open your terminal and execute the following commands:

mkdir tokenized-farmers-market
cd tokenized-farmers-market
code .
npm init -y

Next, let’s install the required dependencies:

npm install --save-dev hardhat
npm install --save-dev @nomicfoundation/hardhat-toolbox 
npm install ethers@5
npx hardhat

Now, create a new file named hardhat.config.js in the project root and add the following code:

require("@nomiclabs/hardhat-waffle");
require("@celo/hardhat-celo");

module.exports = {
  solidity: "0.8.0",
  networks: {
	hardhat: {},
	celo: {
  	url: "https://forno.celo.org",
  	accounts: ["MNEMONIC_KEY"],
	},
  },
};

Replace "MNEMONIC_KEY" with your actual Celo mnemonic key. Make sure to keep this private key safe and never commit it to a public repository.

Creating the Smart Contract:

Let’s create a new Solidity file named FarmersMarket.sol in the contracts directory. Add the following code to define the smart contract:

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

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

contract FarmersMarket {
	struct Product {
    	uint256 id;
    	address seller;
    	string name;
    	uint256 price;
    	uint256 quantity;
    	bool sold;
	}

	mapping(uint256 => Product) public products;
	uint256 public totalProducts;
	address public admin;
	IERC20 public cUSDToken;

	event ProductAdded(uint256 id, address seller, string name, uint256 price, uint256 quantity);
	event ProductSold(uint256 id, address buyer, uint256 quantity);

	constructor(address _cUSDTokenAddress) {
    	admin = msg.sender;
    	cUSDToken = IERC20(_cUSDTokenAddress);
	}

	modifier onlyAdmin() {
    	require(msg.sender == admin, "Only admin can perform this action");
    	_;
	}

	function addProduct(string memory _name, uint256 _price, uint256 _quantity) external {
    	totalProducts++;
    	products[totalProducts] = Product(totalProducts, msg.sender, _name, _price, _quantity, false);
    	emit ProductAdded(totalProducts, msg.sender, _name, _price, _quantity);
	}

	function buyProduct(uint256 _id, uint256 _quantity) external {
    	require(_id <= totalProducts, "Invalid product ID");
    	Product storage product = products[_id];
    	require(!product.sold, "Product is already sold");
    	require(product.quantity >= _quantity, "Insufficient quantity");

    	uint256 totalPrice = product.price * _quantity;
    	require(cUSDToken.allowance(msg.sender, address(this)) >= totalPrice, "Insufficient allowance");



    	product.quantity -= _quantity;
    	if (product.quantity == 0) {
        	product.sold = true;
    	}

    	cUSDToken.transferFrom(msg.sender, product.seller, totalPrice);
    	emit ProductSold(_id, msg.sender, _quantity);
	}

	function updateProductPrice(uint256 _id, uint256 _newPrice) external onlyAdmin {
    	require(_id <= totalProducts, "Invalid product ID");
    	Product storage product = products[_id];
    	require(!product.sold, "Cannot update price for sold product");

    	product.price = _newPrice;
	}
}

Let’s go through the important parts of the code:

  1. We define a Product struct to represent the details of a product.
  2. The products mapping stores the products, indexed by their IDs.
  3. The totalProducts variable keeps track of the total number of products.
  4. The admin variable represents the address of the contract administrator.
  5. The cUSDToken variable is an instance of the IERC20 interface, representing the cUSD token contract.
  6. The ProductAdded and ProductSold events emit relevant information for external observers.
  7. The constructor initializes the cUSDToken instance with the provided token address.
  8. The onlyAdmin modifier ensures that certain functions can only be called by the contract administrator.
  9. The addProduct function allows sellers to add new products to the marketplace.
  10. The buyProduct function allows buyers to purchase products from the marketplace using cUSD.
  11. The updateProductPrice function enables the administrator to update the price of a product.

Compile and Deploy the Smart Contract:

To compile the smart contract, run the following command in the terminal:

npx hardhat compile

Now, let’s deploy the contract to the Celo network. Create a new file named deploy.js in the project root and add the following code:

async function main() {
  const FarmersMarket = await ethers.getContractFactory("FarmersMarket");
  const cUSDTokenAddress = "CELO_CUSD_TOKEN_ADDRESS";
  const farmersMarket = await FarmersMarket.deploy(cUSDTokenAddress);

  await farmersMarket.deployed();

  console.log("FarmersMarket contract deployed to:", farmersMarket.address);
}

main().catch((error) => {
  console.error(error);
  process.exitCode = 1;
});

Replace "CELO_CUSD_TOKEN_ADDRESS" with the actual address of the cUSD token on the Celo network.

Run the deployment script:

npx hardhat run deploy.js --network celo

Conclusion:

In this article, we have learned how to build a tokenized farmer’s market on the Celo blockchain using JavaScript, Hardhat, and Solidity. We created a complex smart contract that enables the creation, listing, and purchase of products using cUSD. By leveraging the power of blockchain and decentralized finance, we can create transparent and efficient marketplaces that empower farmers and consumers alike.

In our next article, we’ll be building a frontend for our smart contract using Next.js, a React framework. You can check out the Part 2 here

About Us

Joel Obafemi

A marketer, copywriter, and collab manager for web3 brands. You can connect with me on LinkedIn.

References

Source Code

5 Likes

I’m interested in the outcome of your tutorial.

2 Likes

I had to vote for this article, hoping to see it in publish soon🙌

1 Like

Nice idea

1 Like

Looking forward to this.

Fantastic news! Your proposal has landed in this week’s top voted list. As you begin your project journey, remember to align with our community and technical guidelines, ensuring a high quality platform for our developers. Congratulations! :mortar_board: :seedling:

1 Like

I love the idea for tokenized USD listing of products. Good job👍

I will be reviewing this in a day or two, I am having this as my 4’th tutorial, because one of the tutorial has took months to make the changes ,
Thank You
Ishan

1 Like