Academic Record NFT

What it does:
Mints diplomas, transcripts, and academic achievements as NFTs, providing tamper-proof, transferable proof of education.

Why it matters:
Enables instant verification of academic records, reduces fraud, and allows students to share achievements easily while retaining ownership and control.

How it works:

  • Universities or accredited institutions are registered as authorized issuers

  • Student academic records are minted as NFTs with metadata pointing to encrypted or IPFS-stored documents

  • Students hold the NFTs in their wallets as verifiable proof of credentials

  • Employers, institutions, or third parties verify the NFT on-chain

  • Institutions can update, revoke, or issue additional academic NFTs

  • All minting, transfers, and revocations are logged immutably

  • NFTs can be used in combination with credential DAOs or micro-credential contracts

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

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

/**
 * @title AcademicRecordNFT
 * @author Nam
 * @notice Mints academic records as NFTs for verifiable, tamper-proof credentials
 */
contract AcademicRecordNFT is ERC721, Ownable {

    uint256 public tokenCount;

    struct Record {
        string metadataHash; // IPFS / encrypted transcript or diploma
        address issuer;
        bool valid;
    }

    mapping(uint256 => Record) public academicRecords;
    mapping(address => bool) public authorizedInstitutions;

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

    event InstitutionAuthorized(address indexed institution);
    event AcademicNFTMinted(uint256 indexed tokenId, address indexed student, address issuer);
    event AcademicNFTRevoked(uint256 indexed tokenId);

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

    constructor() ERC721("AcademicRecordNFT", "ARNFT") {}

    // -------------------- INSTITUTION MANAGEMENT --------------------

    function authorizeInstitution(address _institution) external onlyOwner {
        require(_institution != address(0), "Invalid address");
        authorizedInstitutions[_institution] = true;
        emit InstitutionAuthorized(_institution);
    }

    // -------------------- NFT MANAGEMENT --------------------

    function mintAcademicNFT(address _student, string calldata _metadataHash) external {
        require(authorizedInstitutions[msg.sender], "Not authorized institution");
        require(_student != address(0), "Invalid student");

        tokenCount += 1;
        _mint(_student, tokenCount);

        academicRecords[tokenCount] = Record({
            metadataHash: _metadataHash,
            issuer: msg.sender,
            valid: true
        });

        emit AcademicNFTMinted(tokenCount, _student, msg.sender);
    }

    function revokeAcademicNFT(uint256 _tokenId) external {
        Record storage r = academicRecords[_tokenId];
        require(msg.sender == r.issuer, "Not issuer");
        require(r.valid, "Already revoked");

        r.valid = false;
        emit AcademicNFTRevoked(_tokenId);
    }

    function verifyAcademicNFT(uint256 _tokenId) external view returns (
        string memory metadataHash,
        address issuer,
        bool valid
    ) {
        Record memory r = academicRecords[_tokenId];
        return (r.metadataHash, r.issuer, r.valid);
    }
}