Wearable Health Data Monetization

What it does:
Allows users to monetize anonymized health data collected from wearable devices by granting paid, permissioned access to verified data buyers.

Why it matters:
Shifts data ownership from platforms to individuals, enabling fair compensation, consent-based access, and transparent tracking of how personal health data is used.

How it works:

  • Users register wearable data streams as on-chain assets

  • Data is stored off-chain with encrypted references

  • Buyers request access to specific data types and time ranges

  • Users approve access and set pricing and duration

  • Payment is escrowed and released upon access activation

  • All data permissions and payments are auditable on-chain

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

/**
 * @title WearableHealthDataMonetization
 * @author Nam
 * @notice Monetize wearable health data through permissioned access
 */
contract WearableHealthDataMonetization {

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

    struct DataStream {
        string dataReference; // IPFS / encrypted storage pointer
        uint256 price;        // ETH price per access
        bool active;
    }

    struct AccessGrant {
        bool granted;
        uint256 expiry;
    }

    // -------------------- STORAGE --------------------

    // user => streamId => DataStream
    mapping(address => mapping(uint256 => DataStream)) public dataStreams;

    // user => streamId => buyer => AccessGrant
    mapping(address => mapping(uint256 => mapping(address => AccessGrant))) public accessGrants;

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

    event DataStreamRegistered(address indexed user, uint256 indexed streamId);
    event AccessRequested(address indexed buyer, address indexed user, uint256 indexed streamId);
    event AccessGranted(
        address indexed user,
        uint256 indexed streamId,
        address indexed buyer,
        uint256 expiry
    );
    event PaymentReleased(address indexed user, uint256 amount);

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

    modifier onlyOwner(address _owner) {
        require(msg.sender == _owner, "Not data owner");
        _;
    }

    // -------------------- DATA STREAM MANAGEMENT --------------------

    /**
     * @notice Register a wearable data stream
     */
    function registerDataStream(
        uint256 _streamId,
        string calldata _dataReference,
        uint256 _price
    )
        external
        onlyOwner(msg.sender)
    {
        require(!dataStreams[msg.sender][_streamId].active, "Stream already exists");

        dataStreams[msg.sender][_streamId] = DataStream({
            dataReference: _dataReference,
            price: _price,
            active: true
        });

        emit DataStreamRegistered(msg.sender, _streamId);
    }

    // -------------------- ACCESS REQUEST --------------------

    /**
     * @notice Buyer requests access by paying the data price
     */
    function requestAccess(address _user, uint256 _streamId)
        external
        payable
    {
        DataStream memory stream = dataStreams[_user][_streamId];

        require(stream.active, "Inactive data stream");
        require(msg.value == stream.price, "Incorrect payment");

        emit AccessRequested(msg.sender, _user, _streamId);
    }

    /**
     * @notice User grants access to buyer
     */
    function grantAccess(
        uint256 _streamId,
        address _buyer,
        uint256 _duration
    )
        external
        onlyOwner(msg.sender)
    {
        require(dataStreams[msg.sender][_streamId].active, "Stream inactive");
        require(_duration > 0, "Invalid duration");

        accessGrants[msg.sender][_streamId][_buyer] = AccessGrant({
            granted: true,
            expiry: block.timestamp + _duration
        });

        payable(msg.sender).transfer(dataStreams[msg.sender][_streamId].price);

        emit AccessGranted(
            msg.sender,
            _streamId,
            _buyer,
            block.timestamp + _duration
        );
        emit PaymentReleased(msg.sender, dataStreams[msg.sender][_streamId].price);
    }

    // -------------------- VIEW --------------------

    /**
     * @notice Check if buyer has active access
     */
    function hasAccess(
        address _user,
        uint256 _streamId,
        address _buyer
    )
        external
        view
        returns (bool)
    {
        AccessGrant memory grant =
            accessGrants[_user][_streamId][_buyer];

        return grant.granted && block.timestamp <= grant.expiry;
    }

    /**
     * @notice Get data reference if access is valid
     */
    function getDataReference(
        address _user,
        uint256 _streamId
    )
        external
        view
        returns (string memory)
    {
        require(
            accessGrants[_user][_streamId][msg.sender].granted &&
            block.timestamp <= accessGrants[_user][_streamId][msg.sender].expiry,
            "Access denied"
        );

        return dataStreams[_user][_streamId].dataReference;
    }
}