Creating a Tokenized Rewards Program for a Fitness and Wellness Center on Celo

Creating a Tokenized Rewards Program for a Fitness and Wellness Center on Celo https://celo.academy/uploads/default/optimized/2X/7/7ab198f568264e8baad04094979a0c9c01bd317f_2_1024x576.png
none 4.0 1

Introduction

Welcome to this tutorial! Today, we will be diving into the world of Solidity and blockchain by building a tokenized rewards program for a fitness and wellness center.

Our task is to create a system where fitness center members earn tokens by attending classes or purchasing services. These tokens can later be redeemed for rewards. This encourages regular engagement with the fitness center and provides a fun and interactive experience for members.

To accomplish this, we’ll create two Celo smart contracts: one for the token itself (FitnessToken ), which will follow the ERC20 standard, and another (FitnessRewards ) to manage the fitness center’s rewards program.

Here’s the GitHub repo of our code. source code

Prerequisites

To follow this tutorial, you will need the following:

  • Solidity programming language.
  • Remix IDE.
  • The celo Extension Wallet.

SmartContract

Complete contracts.

pragma solidity ^0.8.6;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract FitnessToken is ERC20, Ownable {
    constructor() ERC20("FitnessToken", "FT") {}

    function mint(address recipient, uint256 amount) external onlyOwner {
        _mint(recipient, amount);
    }

    function burnFrom(address account, uint256 amount) external onlyOwner {
        _burn(account, amount);
    }
}

contract FitnessRewards is Ownable {
    FitnessToken private fitnessToken;

    struct Member {
        uint256 totalAttendedClasses;
        uint256 totalPurchasedServices;
    }

    mapping(address => Member) private members;

    event ClassAttended(address indexed member, uint256 totalAttendedClasses, uint256 totalTokens);
    event ServicePurchased(address indexed member, uint256 totalPurchasedServices, uint256 totalTokens);
    event RewardRedeemed(address indexed member, uint256 tokensBurned);

    constructor(FitnessToken _fitnessToken) {
        fitnessToken = _fitnessToken;
    }

    function attendClass(address memberAddress) external onlyOwner {
        members[memberAddress].totalAttendedClasses += 1;
        uint256 tokensToMint = 10;  // Award 10 FTs for each class
        fitnessToken.mint(memberAddress, tokensToMint);
        
        emit ClassAttended(memberAddress, members[memberAddress].totalAttendedClasses, tokensToMint);
    }

    function purchaseService(address memberAddress) external payable onlyOwner {
        members[memberAddress].totalPurchasedServices += 1;
        uint256 tokensToMint = 50;  // Award 50 FTs for each service purchased
        fitnessToken.mint(memberAddress, tokensToMint);
        
        emit ServicePurchased(memberAddress, members[memberAddress].totalPurchasedServices, tokensToMint);
    }

    function redeemRewards(address memberAddress, uint256 tokenAmount) external {
        require(tokenAmount <= fitnessToken.balanceOf(memberAddress), "Not enough FTs to redeem");
        fitnessToken.burnFrom(memberAddress, tokenAmount);
        
        emit RewardRedeemed(memberAddress, tokenAmount);
    }

    function getTotalAttendedClasses(address memberAddress) external view returns (uint256) {
        return members[memberAddress].totalAttendedClasses;
    }

    function getTotalPurchasedServices(address memberAddress) external view returns (uint256) {
        return members[memberAddress].totalPurchasedServices;
    }
}

Understanding the FitnessToken Contract

Pragma and Imports

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

The pragma solidity ^0.8.6; line specifies the compiler version to use. Here we’re using 0.8.6 or any newer version that doesn’t break functionality.

The import statements import code from the OpenZeppelin library, a library of secure and tested contract standards.

FitnessToken Contract Declaration

contract FitnessToken is ERC20, Ownable {

Here we’re declaring a new contract FitnessToken which inherits from the ERC20 and Ownable contracts.

Constructor

    constructor() ERC20("FitnessToken", "FT") {}

The constructor is a special function that is called when the contract is first deployed. Here we’re calling the ERC20 constructor with two parameters: the name and the symbol of the token.

Mint Function

   function mint(address recipient, uint256 amount) external onlyOwner {
    _mint(recipient, amount);
}

This function allows the contract owner to “mint” or create new tokens. The onlyOwner modifier ensures that only the owner of the contract can call this function.

Burn Function

function burnFrom(address account, uint256 amount) external onlyOwner {
    _burn(account, amount);
}

This function allows the contract owner to “burn” or destroy tokens from a specific account. Again, the onlyOwner modifier ensures that only the contract owner can call this function.

Understanding the FitnessRewards Contract

The FitnessRewards contract handles the reward logic for the fitness center.

FitnessToken and Member Struct

     FitnessToken private fitnessToken;

struct Member {
    uint256 totalAttendedClasses;
    uint256 totalPurchasedServices;
}

Here we’re declaring a private instance of the FitnessToken contract, and a Member struct that keeps track of how many classes a member has attended and how many services they’ve purchased.

Members Mapping and Events

mapping(address => Member) private members;

event ClassAttended(address indexed member, uint256 totalAttendedClasses, uint256 totalTokens);
event ServicePurchased(address indexed member, uint256 totalPurchasedServices, uint256 totalTokens);
event RewardRedeemed(address indexed member, uint256 tokensBurned);

The mapping assigns a Member struct to each address (each member). The events are emitted when a member attends a class, purchases a service, or redeems a reward. Events are a way for smart contracts to communicate that something has happened on the blockchain to external listeners.

Constructor

constructor(FitnessToken _fitnessToken) {
    fitnessToken = _fitnessToken;
}

The constructor has one parameter: _fitnessToken, which is an instance of the FitnessToken contract. The passed in FitnessToken instance is then assigned to the fitnessToken state variable of the FitnessRewards contract.

With this setup, the FitnessRewards contract can interact with the FitnessToken contract (for example, minting or burning tokens) because it now holds a reference to the FitnessToken contract.

attendClass Function

function attendClass(address memberAddress) external onlyOwner {
    members[memberAddress].totalAttendedClasses += 1;
    uint256 tokensToMint = 10;  // Award 10 FTs for each class
    fitnessToken.mint(memberAddress, tokensToMint);
    
    emit ClassAttended(memberAddress, members[memberAddress].totalAttendedClasses, tokensToMint);
}

This function is called when a member attends a class. It increases the total count of attended classes by the member, mints new tokens for the member, and emits an event. The onlyOwner modifier ensures that only the contract owner can call this function.

purchaseService Function

function purchaseService(address memberAddress) external payable onlyOwner {
    members[memberAddress].totalPurchasedServices += 1;
    uint256 tokensToMint = 50;  // Award 50 FTs for each service purchased
    fitnessToken.mint(memberAddress, tokensToMint);
    
    emit ServicePurchased(memberAddress, members[memberAddress].totalPurchasedServices, tokensToMint);
}

This function is similar to the attendClass function. It increases the total count of purchased services by the member, mints new tokens for the member, and emits an event. The onlyOwner modifier again ensures that only the contract owner can call this function.

redeemRewards Function

function redeemRewards(address memberAddress, uint256 tokenAmount) external {
    require(tokenAmount <= fitnessToken.balanceOf(memberAddress), "Not enough FTs to redeem");
    fitnessToken.burnFrom(memberAddress, tokenAmount);
    
    emit RewardRedeemed(memberAddress, tokenAmount);
}

This function is called when a member wants to redeem their rewards. It first checks if the member has enough tokens to redeem, then burns the tokens from the member’s balance, and emits an event.

getTotalAttendedClasses and getTotalPurchasedServices Functions

function getTotalAttendedClasses(address memberAddress) external view returns (uint256) {
    return members[memberAddress].totalAttendedClasses;
}

function getTotalPurchasedServices(address memberAddress) external view returns (uint256) {
    return members[memberAddress].totalPurchasedServices;
}

These are “view” functions, which means they don’t change the state of the contract but allow anyone to view the total number of classes attended and services purchased by a member.

Deployment

Install the Celo Plugin

First, you’ll need to install the Celo Plugin for Remix. To do this, open Remix and click on the Plugin Manager icon on the left-hand side. Search for Celo and click the Install button next to the Celo Plugin. Once the installation is complete, you’ll see a new Celo tab appear in the sidebar.

Connect to the Celo Alfajores Testnet

To deploy our smart contract successfully, we need the celo extention wallet which can be downloaded from here

Next, we need to fund our newly created wallet which can done using the celo alfojares faucet here

Next, you’ll need to connect Remix to the Celo Testnet. Click on the Celo tab in the sidebar and then click on the Connect to Network button.

Compile Contract

Open the contract file in Remix and click on the Solidity Compiler tab in the sidebar. Click the `Compile button to compile the contract.

Deploy the Contract

Click on the Deploy & Run Transactions tab in the sidebar. In the Contract dropdown menu, select the contract.

Interact with the Contract

Once the contract is deployed, you can interact with it using the functions in the Deployed Contracts section of the Deploy & Run Transactions tab. You’ll need to connect to the contract using the At Address button and entering the contract address. From there, you can call the various functions of the contract.

Conclusion

Congratulations on completing this tutorial! You have now successfully developed a tokenized rewards program using Solidity. You’ve learned how to create an ERC20 token, implement a system to reward user behavior with tokens, and provide a mechanism for redeeming those tokens.

Extra Resources

Learn more by following these links.

About the author

I’ am a passionate web3 developer who loves to write and learn new skills

7 Likes

Approved for you to get started. You can manage the tutorial here by changing the category to Proposals > In Progress then Proposals > Review as you complete the tutorial. Thanks!

3 Likes

@kingokonn i will be reviewing this

2 Likes

@kingokonn you did not explain the constructor for the fitness reward contract, please do that and you’ll be set for publish.

4 Likes

@4undRaiser i have done that.

4 Likes

Alright…looks good, you can go ahead and move to publish

2 Likes

@4undRaiser please how do i do that?

2 Likes

@kingokonn when you click on edit title, you will see the field under the title, click on it and select publish, then save.

3 Likes

I will love to see this become an actual In Real Life Use Case , will be really exciting to see.

1 Like

This tutorial on creating a tokenized rewards program for a fitness and wellness center on Celo is incredibly detailed and informative. The step-by-step breakdown of the Solidity code and the explanation of each function provides a clear understanding of how the rewards program works. The tutorial covers all the necessary prerequisites and provides the complete contract code, making it easy to follow along and implement. It’s a valuable resource for developers looking to leverage Celo’s capabilities for building reward-based applications. Great job on creating such a comprehensive and insightful tutorial!

4 Likes

Nice content. Thanks for this contribution.

3 Likes

fixing the capital “H”

1 Like

This tutorial is exceptional! It provides a clear and comprehensive guide to creating a tokenized rewards program for a fitness and wellness center on the Celo blockchain. Looking forward to more of your tutorial!

2 Likes

Tutorial is straight forward and easy to understand. Thanks

2 Likes

This post is ok! and good for the beginners as well. So I added the beginner tag for you.

10 Likes

This is very good and well structured. Keep up the good job.

3 Likes