Medical Supply Chain Tracking

What it does:
Tracks the lifecycle of medical supplies on-chain from manufacturer to hospital, ensuring authenticity, traceability, and proper handling at every stage.

Why it matters:
Prevents counterfeit drugs and medical equipment, improves recall efficiency, and builds trust across healthcare supply chains through transparent, tamper-proof records.

How it works:

  • Manufacturers register medical products with unique identifiers

  • Each supply batch is tokenized and recorded on-chain

  • Ownership transfers are logged at every handoff

  • Storage and transportation checkpoints update status

  • Hospitals verify authenticity before usage

  • Entire supply history remains auditable and immutable

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

/**
 * @title MedicalSupplyChainTracking
 * @author Nam
 * @notice Tracks medical supplies from production to hospital
 */
contract MedicalSupplyChainTracking {

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

    address public admin;

    mapping(address => bool) public manufacturers;
    mapping(address => bool) public distributors;
    mapping(address => bool) public hospitals;

    // -------------------- SUPPLY STRUCT --------------------

    enum SupplyStatus {
        Manufactured,
        InTransit,
        Delivered,
        Verified
    }

    struct SupplyItem {
        string productName;
        uint256 batchId;
        address currentOwner;
        SupplyStatus status;
        bool exists;
    }

    // supplyId => SupplyItem
    mapping(uint256 => SupplyItem) public supplies;
    uint256 public supplyCounter;

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

    event ManufacturerAuthorized(address indexed manufacturer);
    event DistributorAuthorized(address indexed distributor);
    event HospitalAuthorized(address indexed hospital);
    event SupplyRegistered(uint256 indexed supplyId, string productName);
    event OwnershipTransferred(uint256 indexed supplyId, address indexed to);
    event SupplyVerified(uint256 indexed supplyId, address indexed hospital);

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

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

    modifier onlyManufacturer() {
        require(manufacturers[msg.sender], "Not manufacturer");
        _;
    }

    modifier onlyDistributor() {
        require(distributors[msg.sender], "Not distributor");
        _;
    }

    modifier onlyHospital() {
        require(hospitals[msg.sender], "Not hospital");
        _;
    }

    modifier supplyExists(uint256 _supplyId) {
        require(supplies[_supplyId].exists, "Supply not found");
        _;
    }

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

    constructor() {
        admin = msg.sender;
    }

    // -------------------- ROLE MANAGEMENT --------------------

    function authorizeManufacturer(address _manufacturer)
        external
        onlyAdmin
    {
        manufacturers[_manufacturer] = true;
        emit ManufacturerAuthorized(_manufacturer);
    }

    function authorizeDistributor(address _distributor)
        external
        onlyAdmin
    {
        distributors[_distributor] = true;
        emit DistributorAuthorized(_distributor);
    }

    function authorizeHospital(address _hospital)
        external
        onlyAdmin
    {
        hospitals[_hospital] = true;
        emit HospitalAuthorized(_hospital);
    }

    // -------------------- SUPPLY FLOW --------------------

    /**
     * @notice Manufacturer registers a medical supply batch
     */
    function registerSupply(
        string calldata _productName,
        uint256 _batchId
    )
        external
        onlyManufacturer
    {
        supplyCounter += 1;

        supplies[supplyCounter] = SupplyItem({
            productName: _productName,
            batchId: _batchId,
            currentOwner: msg.sender,
            status: SupplyStatus.Manufactured,
            exists: true
        });

        emit SupplyRegistered(supplyCounter, _productName);
    }

    /**
     * @notice Transfer supply ownership
     */
    function transferSupply(
        uint256 _supplyId,
        address _to
    )
        external
        supplyExists(_supplyId)
    {
        SupplyItem storage s = supplies[_supplyId];

        require(msg.sender == s.currentOwner, "Not owner");

        s.currentOwner = _to;
        s.status = SupplyStatus.InTransit;

        emit OwnershipTransferred(_supplyId, _to);
    }

    /**
     * @notice Hospital verifies supply authenticity
     */
    function verifySupply(uint256 _supplyId)
        external
        onlyHospital
        supplyExists(_supplyId)
    {
        SupplyItem storage s = supplies[_supplyId];

        require(s.currentOwner == msg.sender, "Not holder");

        s.status = SupplyStatus.Verified;
        emit SupplyVerified(_supplyId, msg.sender);
    }
}