Recall Management Contract

What it does:
Registers and manages product recalls, tracking affected batches, notifying stakeholders, and ensuring compliance with safety regulations.

Why it matters:
Reduces risk to consumers, ensures timely recall actions, prevents fraud, and provides auditable evidence of recall management.

How it works:

  • Manufacturers register recalled batches or products on-chain

  • Batch IDs and affected product details are logged immutably

  • Notifications are sent to distributors, retailers, and consumers (off-chain integration possible)

  • Ownership and custody of recalled items are tracked for proper handling

  • Smart contracts maintain historical recall records for compliance and auditing

  • Integrates with Supply Chain Traceability, Inventory Management, and marketplaces

  • Public dashboards display recalled products and their status

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

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

/**
 * @title RecallManagement
 * @author Nam
 * @notice Manages product recalls on-chain with batch tracking and event logging
 */
contract RecallManagement is Ownable {

    struct Batch {
        string metadataURI;
        bool exists;
        bool recalled;
    }

    struct RecallEvent {
        uint256 timestamp;
        string reason;
        address reporter;
    }

    mapping(uint256 => Batch) public batches; // batchId => Batch
    mapping(uint256 => RecallEvent[]) public recallEvents; // batchId => events
    uint256 public batchCount;

    mapping(address => bool) public authorizedReporters;

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

    event BatchRegistered(uint256 indexed batchId, string metadataURI);
    event RecallEventLogged(uint256 indexed batchId, string reason, address reporter);
    event BatchRecalled(uint256 indexed batchId);
    event ReporterApproved(address reporter);

    // -------------------- REPORTER MANAGEMENT --------------------

    function approveReporter(address _reporter) external onlyOwner {
        authorizedReporters[_reporter] = true;
        emit ReporterApproved(_reporter);
    }

    function revokeReporter(address _reporter) external onlyOwner {
        authorizedReporters[_reporter] = false;
    }

    modifier onlyReporter() {
        require(authorizedReporters[msg.sender], "Not an authorized reporter");
        _;
    }

    // -------------------- BATCH MANAGEMENT --------------------

    function registerBatch(string calldata _metadataURI) external onlyReporter {
        batchCount += 1;
        batches[batchCount] = Batch({
            metadataURI: _metadataURI,
            exists: true,
            recalled: false
        });

        emit BatchRegistered(batchCount, _metadataURI);
    }

    // -------------------- RECALL MANAGEMENT --------------------

    function logRecallEvent(uint256 _batchId, string calldata _reason) external onlyReporter {
        require(batches[_batchId].exists, "Batch does not exist");

        recallEvents[_batchId].push(RecallEvent({
            timestamp: block.timestamp,
            reason: _reason,
            reporter: msg.sender
        }));

        batches[_batchId].recalled = true;

        emit RecallEventLogged(_batchId, _reason, msg.sender);
        emit BatchRecalled(_batchId);
    }

    // -------------------- VIEW FUNCTIONS --------------------

    function getRecallEvents(uint256 _batchId) external view returns (RecallEvent[] memory) {
        return recallEvents[_batchId];
    }

    function isBatchRecalled(uint256 _batchId) external view returns (bool) {
        return batches[_batchId].recalled;
    }
}