Writing a Smart Contract to Handle Carbon Credits on The Celo Blockchain

Writing a Smart Contract to Handle Carbon Credits on The Celo Blockchain https://celo.academy/uploads/default/optimized/2X/e/e1a14bb534f95104636a8fdf024cdcd8a921be21_2_1024x576.png
none 0.0 0

Introduction

In this tutorial, we will design a smart contract in solidity to establish a Carbon Credit Token, an ERC20 token that will be used to track carbon credits on the Celo blockchain.

This contract creates an ecosystem where users can buy and sell carbon credits, which are represented as tokens. The owner of the contract can mint and burn tokens. These actions increase or decrease the total supply of carbon credits.

You can find the repository for this tutorial Here

Prerequisites

To follow this tutorial, you will need the following:

  • Basic understanding of Solidity and smart contracts.
  • A Development Environment Like Remix.
  • Familiarity with the OpenZeppelin library
  • The Celo Extension Wallet.

Contract Developement

The complete code contract look like this

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

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";

contract CarbonCreditToken is ERC20, Ownable {
    uint256 public totalCarbonCredits;

    event BoughtCredits(address indexed buyer, uint256 amount);
    event SoldCredits(address indexed seller, uint256 amount);
    event TransferredCredits(address indexed from, address indexed to, uint256 amount);

    constructor() ERC20("CarbonCreditToken", "CCT") {
        totalCarbonCredits = 0;
    }

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
        totalCarbonCredits += amount;
    }

    function burn(address from, uint256 amount) public onlyOwner {
        _burn(from, amount);
        totalCarbonCredits -= amount;
    }

    function buyCredits(uint256 amount) public payable {
        require(msg.value >= amount, "Not enough CELO sent");
        _mint(msg.sender, amount);
        totalCarbonCredits += amount;
        emit BoughtCredits(msg.sender, amount);
    }

    function sellCredits(uint256 amount) public {
        require(balanceOf(msg.sender) >= amount, "Not enough credits");
        _burn(msg.sender, amount);
        totalCarbonCredits -= amount;
        payable(msg.sender).transfer(amount);
        emit SoldCredits(msg.sender, amount);
    }

    function transferCredits(address to, uint256 amount) public {
        require(balanceOf(msg.sender) >= amount, "Not enough credits");
        _transfer(msg.sender, to, amount);
        emit TransferredCredits(msg.sender, to, amount);
    }

    function checkBalance(address user) public view returns (uint256) {
        return balanceOf(user);
    }

    function withdrawCELO(uint256 amount) public onlyOwner {
        require(address(this).balance >= amount, "Not enough CELO in the contract");
        payable(owner()).transfer(amount);
    }
}

Code Breakdown

Let’s look at our smart contract in detail.

Imports

import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol";
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/access/Ownable.sol";

The contract imports two contracts from OpenZeppelin, a library that provides secure and community-audited versions of common smart contract functionality.

  • ERC20.sol: This contract provides a full implementation of the ERC20 standard for fungible tokens, an interface for the balance of a certain address and the ability to transfer tokens.
  • Ownable.sol: This contract gives basic authorization control functions. It simplifies the implementation of “user permissions”.

Contract Declaration and Inheritance

contract CarbonCreditToken is ERC20, Ownable {

The CarbonCreditToken contract is declared and it extends the ERC20 and Ownable contracts, meaning that it inherits all their public and internal functions and state variables.

State Variables and Events

uint256 public totalCarbonCredits;

event BoughtCredits(address indexed buyer, uint256 amount);
event SoldCredits(address indexed seller, uint256 amount);
event TransferredCredits(address indexed from, address indexed to, uint256 amount);
  • totalCarbonCredits is a state variable that tracks the total amount of carbon credits minted.
  • BoughtCredits, SoldCredits, and TransferredCredits are events that get emitted when a user buys, sells, or transfers credits. They help external observers, like web applications, track contract activity without needing to examine every single block for transactions involving this contract.

Constructor Function

constructor() ERC20("CarbonCreditToken", "CCT") {
    totalCarbonCredits = 0;
}

The constructor function is called once when the contract is deployed. It initializes the ERC20 token with a name “CarbonCreditToken” and a symbol “CCT”. It also initializes totalCarbonCredits to 0.

Mint Function

function mint(address to, uint256 amount) public onlyOwner {
    _mint(to, amount);
    totalCarbonCredits += amount;
}

The mint function allows the owner of the contract to create new tokens and assigns them to the specified address. The onlyOwner modifier ensures that only the contract owner can call this function. After minting, it increases the totalCarbonCredits by the minted amount.

Burn Function

function burn(address from, uint256 amount) public onlyOwner {
    _burn(from, amount);
    totalCarbonCredits -= amount;
}

The burn function allows the owner of the contract to destroy tokens from a specified address. The totalCarbonCredits is decreased by the burned amount.

Buy Credits Function

function buyCredits(uint256 amount) public payable {
    require(msg.value >= amount, "Not enough CELO sent");
    _mint(msg.sender, amount);
    totalCarbonCredits += amount;
    emit BoughtCredits(msg.sender, amount);
}

This function allows users to buy carbon credits. The payable keyword allows the function to receive Celo. It checks that the Celo sent (msg.value ) is at least the required amount of carbon credits the user wants to buy. If this is true, the function mints the corresponding amount of tokens to the buyer’s address (msg.sender ) and increases the totalCarbonCredits by the amount bought. Lastly, it emits the BoughtCredits event with the buyer’s address and the amount of credits bought.

Sell Credits Function

function sellCredits(uint256 amount) public {
    require(balanceOf(msg.sender) >= amount, "Not enough credits");
    _burn(msg.sender, amount);
    totalCarbonCredits -= amount;
    payable(msg.sender).transfer(amount);
    emit SoldCredits(msg.sender, amount);
}

This function allows users to sell their carbon credits. The function first checks if the seller has enough carbon credits in their balance. If they do, it burns the corresponding amount of tokens from the seller’s address, decreases the totalCarbonCredits by the amount sold, and transfers the corresponding amount of Celo to the seller. Lastly, it emits the SoldCredits event with the seller’s address and the amount of credits sold.

Transfer Credits Function

function transferCredits(address to, uint256 amount) public {
    require(balanceOf(msg.sender) >= amount, "Not enough credits");
    _transfer(msg.sender, to, amount);
    emit TransferredCredits(msg.sender, to, amount);
}

This function allows users to transfer their carbon credits to another address. The function first checks if the sender has enough carbon credits in their balance. If they do, it transfers the specified amount of tokens from the sender’s address to the receiver’s address. Lastly, it emits the TransferredCredits event with the sender’s, receiver’s address, and the amount of credits transferred.

Check Balance Function

function checkBalance(address user) public view returns (uint256) {
    return balanceOf(user);
}

This function allows anyone to check the carbon credit balance of a specified user. It returns the balance of the specified user’s address.

Withdraw CELO Function

function withdrawCELO(uint256 amount) public onlyOwner {
    require(address(this).balance >= amount, "Not enough CELO in the contract");
    payable(owner()).transfer(amount);
}

This function allows the owner of the contract to withdraw Celo from the contract. The function first checks if the contract has enough Celo. If it does, it transfers the specified amount of Celo to the owner’s address. The onlyOwner modifier ensures that only the contract owner can call this function.

Deployment

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

Now, click on the plugin logo at the bottom left corner and search for celo plugin.

Install the plugin and click on the celo logo which will show in the side tab after the plugin is installed.

Next connect your Celo wallet, select the contract you want to deploy and finally click on deploy to deploy your contract.

Conclusion

In conclusion, the CarbonCreditToken contract is a standard ERC20 token with additional functionality for buying, selling, and transferring carbon credits. The contract leverages OpenZeppelin’s ERC20 and Ownable contracts to inherit common functionality. This reduces the complexity of the contract and minimizes potential security risks.

Next Steps

I hope you learned a lot from this tutorial. Here are some relevant links that would aid your learning further.

About the author

I’m Jonathan Iheme, A full stack block-chain Developer from Nigeria.

linkedIn
Twitter

5 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!

4 Likes

Approved By @Kunaldawar.

1 Like

It’s evident that you put effort into creating a valuable resource for developers as the tutorial is well-written, informative, and covers all the essential aspects of building a smart contract for handling carbon credits. Well done!

4 Likes