Cold Chain Monitoring Contract

What it does:
Monitors temperature-sensitive products throughout the supply chain, recording events and deviations on-chain to ensure quality and compliance.

Why it matters:
Prevents spoilage, ensures regulatory compliance, increases consumer trust, and provides auditable data for perishable or sensitive goods like vaccines, food, or pharmaceuticals.

How it works:

  • Each batch/product is registered on-chain with metadata and temperature thresholds

  • IoT sensors or authorized participants log temperature, humidity, or other environmental data

  • Smart contracts validate data against predefined thresholds

  • Alerts are triggered for deviations or breaches in cold chain conditions

  • Ownership and custody changes are recorded immutably

  • Public dashboards provide real-time monitoring and historical audit trails

  • Integrates with Supply Chain Traceability, logistics, and regulatory reporting

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

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

/**
 * @title ColdChainMonitoring
 * @author Nam
 * @notice Tracks temperature-sensitive products and logs environmental data on-chain
 */
contract ColdChainMonitoring is Ownable {

    struct Batch {
        string metadataURI;
        address currentOwner;
        uint256 creationTimestamp;
        uint256 minTemp; // minimum allowed temperature
        uint256 maxTemp; // maximum allowed temperature
        bool exists;
    }

    struct SensorEvent {
        uint256 timestamp;
        int256 temperature;
        int256 humidity;
        address reporter;
    }

    mapping(uint256 => Batch) public batches;
    mapping(uint256 => SensorEvent[]) public batchEvents;
    uint256 public batchCount;

    mapping(address => bool) public authorizedReporters;

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

    event BatchCreated(uint256 indexed batchId, address owner, uint256 minTemp, uint256 maxTemp);
    event SensorEventLogged(uint256 indexed batchId, int256 temperature, int256 humidity, address reporter);
    event BatchTransferred(uint256 indexed batchId, address from, address to);
    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;
    }

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

    function createBatch(string calldata _metadataURI, uint256 _minTemp, uint256 _maxTemp) external {
        require(_minTemp <= _maxTemp, "Invalid temperature range");

        batchCount += 1;
        batches[batchCount] = Batch({
            metadataURI: _metadataURI,
            currentOwner: msg.sender,
            creationTimestamp: block.timestamp,
            minTemp: _minTemp,
            maxTemp: _maxTemp,
            exists: true
        });

        emit BatchCreated(batchCount, msg.sender, _minTemp, _maxTemp);
    }

    function transferBatch(uint256 _batchId, address _to) external {
        require(batches[_batchId].currentOwner == msg.sender, "Not batch owner");
        require(_to != address(0), "Invalid recipient");

        address from = batches[_batchId].currentOwner;
        batches[_batchId].currentOwner = _to;

        emit BatchTransferred(_batchId, from, _to);
    }

    // -------------------- SENSOR DATA LOGGING --------------------

    function logSensorData(uint256 _batchId, int256 _temperature, int256 _humidity) external {
        require(authorizedReporters[msg.sender], "Not an authorized reporter");
        require(batches[_batchId].exists, "Batch does not exist");

        batchEvents[_batchId].push(SensorEvent({
            timestamp: block.timestamp,
            temperature: _temperature,
            humidity: _humidity,
            reporter: msg.sender
        }));

        // Optional: emit alert if temperature out of bounds
        if (_temperature  int256(batches[_batchId].maxTemp)) {
            // Could integrate with alert system
        }

        emit SensorEventLogged(_batchId, _temperature, _humidity, msg.sender);
    }

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

    function getBatchEvents(uint256 _batchId) external view returns (SensorEvent[] memory) {
        return batchEvents[_batchId];
    }

    function getBatchOwner(uint256 _batchId) external view returns (address) {
        return batches[_batchId].currentOwner;
    }
}