Skill-Based Micro-Credential Contract

What it does:
Issues and verifies micro-credentials or badges for specific skills, allowing learners to showcase verified abilities without full degrees.

Why it matters:
Provides granular, verifiable proof of skills for employment, gig work, or continuing education, increasing transparency and trust in skill verification.

How it works:

  • Accredited issuers or trainers are registered on-chain

  • Learners complete skill assessments or courses

  • Issuers create micro-credential records (hash / metadata)

  • Learners receive verified credentials on-chain

  • Employers or other institutions can verify credentials instantly

  • Credentials can be revoked if invalidated or updated

  • All issuance and verification actions are auditable

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

/**
 * @title SkillMicroCredential
 * @author Nam
 * @notice On-chain issuance and verification of skill-based micro-credentials
 */
contract SkillMicroCredential {

    // -------------------- ROLES --------------------

    address public admin;
    mapping(address => bool) public authorizedIssuers;

    // -------------------- STRUCTS --------------------

    struct Credential {
        string metadataHash; // IPFS / encrypted skill credential
        address issuer;
        uint256 issuedAt;
        bool valid;
    }

    mapping(address => Credential[]) public learnerCredentials;

    // -------------------- EVENTS --------------------

    event IssuerAuthorized(address indexed issuer);
    event CredentialIssued(address indexed learner, uint256 credentialId, address indexed issuer);
    event CredentialRevoked(address indexed learner, uint256 credentialId);

    // -------------------- MODIFIERS --------------------

    modifier onlyAdmin() {
        require(msg.sender == admin, "Not admin");
        _;
    }

    modifier onlyIssuer() {
        require(authorizedIssuers[msg.sender], "Not authorized issuer");
        _;
    }

    // -------------------- CONSTRUCTOR --------------------

    constructor() {
        admin = msg.sender;
    }

    // -------------------- ISSUER MANAGEMENT --------------------

    function authorizeIssuer(address _issuer) external onlyAdmin {
        require(_issuer != address(0), "Invalid issuer");
        authorizedIssuers[_issuer] = true;
        emit IssuerAuthorized(_issuer);
    }

    // -------------------- CREDENTIAL MANAGEMENT --------------------

    function issueCredential(address _learner, string calldata _metadataHash) external onlyIssuer {
        require(_learner != address(0), "Invalid learner");

        learnerCredentials[_learner].push(Credential({
            metadataHash: _metadataHash,
            issuer: msg.sender,
            issuedAt: block.timestamp,
            valid: true
        }));

        emit CredentialIssued(_learner, learnerCredentials[_learner].length - 1, msg.sender);
    }

    function revokeCredential(address _learner, uint256 _credentialId) external onlyIssuer {
        require(_credentialId < learnerCredentials[_learner].length, "Invalid credential ID");
        Credential storage c = learnerCredentials[_learner][_credentialId];
        require(c.valid, "Already revoked");

        c.valid = false;
        emit CredentialRevoked(_learner, _credentialId);
    }

    // -------------------- VERIFICATION --------------------

    function verifyCredential(address _learner, uint256 _credentialId) external view returns (
        string memory metadataHash,
        address issuer,
        bool valid
    ) {
        require(_credentialId < learnerCredentials[_learner].length, "Invalid credential ID");
        Credential memory c = learnerCredentials[_learner][_credentialId];
        return (c.metadataHash, c.issuer, c.valid);
    }
}