Build an Educational Credential Verification System On the Celo Blockchain

Build an Educational Credential Verification System On the Celo Blockchain https://celo.academy/uploads/default/optimized/2X/d/d69a2352b14438a9dc0b8a4fecbe61cee9411ab3_2_1024x576.png
none 0.0 0

Introduction

In this tutorial, you will learn how to create an educational credential verification system on the Celo Blockchain. We will explore how to leverage blockchain technology for securely storing, validating, and verifying educational credentials such as degrees, diplomas, and certificates. By the end of this tutorial, you will be able to create and deploy your own educational credential verification system and understand the benefits of using blockchain technology for this purpose.

Full source code

Prerequisites

To follow this tutorial, you will need the following:

  • Basic knowledge of Solidity programming language.
  • A Development Environment Like Remix.
  • The celo Extension Wallet.

SmartContract

Let’s begin writing our smart contract in Remix IDE

The completed code Should look like this.

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

contract EducationCredentialVerification is ERC721, AccessControl {
    using Counters for Counters.Counter;

    bytes32 public constant ISSUER_ROLE = keccak256("ISSUER_ROLE");

    struct Credential {
        uint256 tokenId;
        string institution;
        string degree;
        string major;
        string studentName;
        uint256 dateIssued;
        bool isRevoked;
    }

    mapping(uint256 => Credential) public credentials;
    Counters.Counter private _tokenIds;

    event CredentialIssued(uint256 indexed tokenId, string studentName, string degree, string major, string institution, uint256 dateIssued);
    event CredentialRevoked(uint256 indexed tokenId);

    constructor() ERC721("EducationCredential", "EDUC") {
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
    }

    function issueCredential(
        string memory institution,
        string memory degree,
        string memory major,
        string memory studentName,
        uint256 dateIssued,
        address recipient
    ) public onlyRole(ISSUER_ROLE) {
        _tokenIds.increment();
        uint256 tokenId = _tokenIds.current();
        _safeMint(recipient, tokenId);

        Credential memory newCredential = Credential(
            tokenId,
            institution,
            degree,
            major,
            studentName,
            dateIssued,
            false
        );

        credentials[tokenId] = newCredential;

        emit CredentialIssued(tokenId, studentName, degree, major, institution, dateIssued);
    }

    function revokeCredential(uint256 tokenId) public onlyRole(ISSUER_ROLE) {
        require(_exists(tokenId), "Credential not found");

        credentials[tokenId].isRevoked = true;

        emit CredentialRevoked(tokenId);
    }

    function isCredentialValid(uint256 tokenId) public view returns (bool) {
        return _exists(tokenId) && !credentials[tokenId].isRevoked;
    }

    function getCredential(uint256 tokenId) public view returns (Credential memory) {
        require(_exists(tokenId), "Credential not found");

        return credentials[tokenId];
    }

    function grantIssuerRole(address account) public onlyRole(DEFAULT_ADMIN_ROLE) {
        grantRole(ISSUER_ROLE, account);
    }

    function revokeIssuerRole(address account) public onlyRole(DEFAULT_ADMIN_ROLE) {
        revokeRole(ISSUER_ROLE, account);
    }

    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, AccessControl) returns (bool) {
        return super.supportsInterface(interfaceId);
    }
}

Breakdown

First, we declared our license and the solidity version. then we import all the neccessary openzeppelin contracts

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

import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Counters.sol";

The EducationCredentialVerification contract extends the ERC-721 token standard. ERC-721 is a standard for creating unique, non-fungible tokens on the Celo blockchain. In this contract, we will use ERC-721 to create unique educational credentials for students.

The AccessControl library is also imported and utilized in the EducationCredentialVerification contract. AccessControl allows us to define roles for various participants in the system. In this contract, we define the ISSUER_ROLE which is granted to educational institutions that are authorized to issue credentials.

contract EducationCredentialVerification is ERC721, AccessControl {
    using Counters for Counters.Counter;

    bytes32 public constant ISSUER_ROLE = keccak256("ISSUER_ROLE");

    struct Credential {
        uint256 tokenId;
        string institution;
        string degree;
        string major;
        string studentName;
        uint256 dateIssued;
        bool isRevoked;
    }

    mapping(uint256 => Credential) public credentials;
    Counters.Counter private _tokenIds;
}

ISSUER_ROLE: This is a bytes32 constant variable that defines the name of the role granted to educational institutions that are authorized to issue credentials.

We created a struct Credential, which is used to store the details of each educational credential. The Credential struct has the following attributes:

  • tokenId: A unique identifier for the educational credential.
    institution: The name of the educational institution that issued the credential.
  • degree: The degree earned by the student.
    major: The student’s area of study.
  • studentName: The name of the student who earned the credential.
    dateIssued: The date the credential was issued.
  • isRevoked: A boolean value indicating whether the credential has been revoked.

A mapping credentials is used to store the credentials issued by educational institutions. The keys in the mapping are the tokenIds of the educational credentials, and the values are instances of the Credential struct.

We then use the Counters library to manage the unique tokenId assigned to each educational credential.

event CredentialIssued(uint256 indexed tokenId, string studentName, string degree, string major, string institution, uint256 dateIssued);
event CredentialRevoked(uint256 indexed tokenId);

The contract emits two events:

  • CredentialIssued: This event is emitted when an educational credential is issued.
  • CredentialRevoked: This event is emitted when an educational credential is revoked.
constructor() ERC721("EducationCredential", "EDUC") {
        _setupRole(DEFAULT_ADMIN_ROLE, _msgSender());
    }

The constructor sets up the default admin role and initializes the ERC-721 token by setting its name to EducationCredential and its symbol to EDUC.

function issueCredential(
        string memory institution,
        string memory degree,
        string memory major,
        string memory studentName,
        uint256 dateIssued,
        address recipient
    ) public onlyRole(ISSUER_ROLE) {
        _tokenIds.increment();
        uint256 tokenId = _tokenIds.current();
        _safeMint(recipient, tokenId);

        Credential memory newCredential = Credential(
            tokenId,
            institution,
            degree,
            major,
            studentName,
            dateIssued,
            false
        );

        credentials[tokenId] = newCredential;

        emit CredentialIssued(tokenId, studentName, degree, major, institution, dateIssued);
    }

The issueCredential function is used by educational institutions to issue educational credentials. The function takes in several arguments, including the name of the institution, the degree earned by the student, the major of the student, the name of the student, the date the credential was issued, and the recipient address.

The function then creates a new unique tokenId using the Counters library, mints a new ERC-721 token using the _safeMint function, and assigns the token to the recipient address. Finally, the function creates a new instance of the Credential struct, stores it in the credentials mapping, and emits the CredentialIssued event.

  function revokeCredential(uint256 tokenId) public onlyRole(ISSUER_ROLE) {
        require(_exists(tokenId), "Credential not found");

        credentials[tokenId].isRevoked = true;

        emit CredentialRevoked(tokenId);
    }

The revokeCredential function is used by educational institutions to revoke previously issued educational credentials. The function takes in a tokenId as an argument, checks if the credential exists, and sets the isRevoked attribute of the corresponding Credential struct to true. Finally, the function emits the CredentialRevoked event.

function isCredentialValid(uint256 tokenId) public view returns (bool) {
        return _exists(tokenId) && !credentials[tokenId].isRevoked;
    }

The isCredentialValid function is used to verify if a given educational credential is valid. The function takes in a tokenId and checks if the corresponding credential exists and if it has been revoked. If the credential is valid, the function returns true, otherwise, it returns false.

function getCredential(uint256 tokenId) public view returns (Credential memory) {
        require(_exists(tokenId), "Credential not found");

        return credentials[tokenId];
    }

The getCredential function is used to retrieve the details of a given educational credential. The function takes in a tokenId and checks if the corresponding credential exists. If it does, the function returns the corresponding Credential struct.

function grantIssuerRole(address account) public onlyRole(DEFAULT_ADMIN_ROLE) {
    grantRole(ISSUER_ROLE, account);
    }

function revokeIssuerRole(address account) public onlyRole(DEFAULT_ADMIN_ROLE) {
    revokeRole(ISSUER_ROLE, account);
    }

The grantIssuerRole and revokeIssuerRole functions are used to grant or revoke the ISSUER_ROLE to an educational institution. These functions can only be called by the contract’s DEFAULT_ADMIN_ROLE, which is set to the address that deployed the contract.

function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, AccessControl) returns (bool) {
        return super.supportsInterface(interfaceId);
    }

The supportsInterface function is used to check if the EducationCredentialVerification contract supports the ERC-721 and AccessControl interfaces.

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

You can now fund your wallet and deploy your contract using the celo plugin in remix.

Conclusion

The EducationCredentialVerification contract provides a way for educational institutions to issue and verify educational credentials on the blockchain. By using the ERC-721 token standard and the AccessControl library, the contract allows for the creation of unique and verifiable educational credentials. The contract also allows for the granting and revoking of roles to educational institutions.

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.

Thank You!!

4 Likes

Dear fellow learners, enhance transparency, security, and trust in the education sector by following this detailed guide to create a decentralized solution for verifying academic achievements!