Decentralized Health ID

What it does:
Creates a self-sovereign, on-chain health identity that allows individuals to prove their medical identity and credentials without exposing sensitive personal data.

Why it matters:
Eliminates fragmented patient records, reduces identity fraud, and enables seamless interoperability across hospitals, insurers, and health platforms while preserving privacy.

How it works:

  • Users create a decentralized health identity on-chain

  • Identity links to verifiable credentials (hashes only)

  • Trusted issuers attest medical or insurance credentials

  • Users selectively prove identity ownership

  • Health ID can be used across multiple healthcare contracts

  • Identity updates are auditable without revealing raw data

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

/**
 * @title DecentralizedHealthID
 * @author Nam
 * @notice Self-sovereign health identity on-chain
 */
contract DecentralizedHealthID {

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

    address public admin;

    mapping(address => bool) public trustedIssuers;

    // -------------------- IDENTITY STRUCT --------------------

    struct HealthIdentity {
        bool registered;
        string metadataHash; // IPFS hash / encrypted identity metadata
        uint256 createdAt;
    }

    struct Credential {
        string credentialHash;
        address issuer;
        uint256 issuedAt;
        bool valid;
    }

    // user => identity
    mapping(address => HealthIdentity) public identities;

    // user => credentialId => Credential
    mapping(address => mapping(uint256 => Credential)) public credentials;
    mapping(address => uint256) public credentialCount;

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

    event HealthIDCreated(address indexed user);
    event HealthIDUpdated(address indexed user);
    event IssuerAuthorized(address indexed issuer);
    event CredentialIssued(
        address indexed user,
        uint256 indexed credentialId,
        address indexed issuer
    );
    event CredentialRevoked(
        address indexed user,
        uint256 indexed credentialId
    );

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

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

    modifier onlyIssuer() {
        require(trustedIssuers[msg.sender], "Not trusted issuer");
        _;
    }

    modifier onlyUser(address _user) {
        require(msg.sender == _user, "Not identity owner");
        _;
    }

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

    constructor() {
        admin = msg.sender;
    }

    // -------------------- ISSUER MANAGEMENT --------------------

    /**
     * @notice Authorize a trusted credential issuer
     */
    function authorizeIssuer(address _issuer)
        external
        onlyAdmin
    {
        require(_issuer != address(0), "Invalid issuer");
        trustedIssuers[_issuer] = true;
        emit IssuerAuthorized(_issuer);
    }

    // -------------------- HEALTH ID --------------------

    /**
     * @notice Create a decentralized health ID
     */
    function createHealthID(string calldata _metadataHash)
        external
    {
        require(!identities[msg.sender].registered, "Already registered");

        identities[msg.sender] = HealthIdentity({
            registered: true,
            metadataHash: _metadataHash,
            createdAt: block.timestamp
        });

        emit HealthIDCreated(msg.sender);
    }

    /**
     * @notice Update identity metadata reference
     */
    function updateHealthID(string calldata _metadataHash)
        external
        onlyUser(msg.sender)
    {
        require(identities[msg.sender].registered, "Not registered");

        identities[msg.sender].metadataHash = _metadataHash;
        emit HealthIDUpdated(msg.sender);
    }

    // -------------------- CREDENTIALS --------------------

    /**
     * @notice Issue a verifiable credential
     */
    function issueCredential(
        address _user,
        string calldata _credentialHash
    )
        external
        onlyIssuer
    {
        require(identities[_user].registered, "User not registered");

        credentialCount[_user] += 1;

        credentials[_user][credentialCount[_user]] = Credential({
            credentialHash: _credentialHash,
            issuer: msg.sender,
            issuedAt: block.timestamp,
            valid: true
        });

        emit CredentialIssued(
            _user,
            credentialCount[_user],
            msg.sender
        );
    }

    /**
     * @notice Revoke a credential
     */
    function revokeCredential(
        address _user,
        uint256 _credentialId
    )
        external
    {
        Credential storage c = credentials[_user][_credentialId];

        require(
            msg.sender == c.issuer || msg.sender == admin,
            "Not authorized"
        );
        require(c.valid, "Already revoked");

        c.valid = false;
        emit CredentialRevoked(_user, _credentialId);
    }

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

    /**
     * @notice Verify a credential
     */
    function verifyCredential(
        address _user,
        uint256 _credentialId
    )
        external
        view
        returns (
            string memory credentialHash,
            address issuer,
            bool valid
        )
    {
        Credential memory c = credentials[_user][_credentialId];
        require(c.issuedAt > 0, "Credential not found");

        return (
            c.credentialHash,
            c.issuer,
            c.valid
        );
    }
}