Medical Research Funding DAO

What it does:
Pools capital from donors and institutions to fund medical research projects through transparent, community-governed decision-making.

Why it matters:
Reduces bias in research funding, increases accountability, and ensures capital is allocated to scientifically valuable and socially impactful studies.

How it works:

  • Donors contribute funds to the research pool

  • Researchers submit funding proposals

  • Proposal details and requested budgets are stored on-chain

  • DAO members vote on which projects receive funding

  • Approved funds are released to researchers

  • Spending and milestones are transparently tracked

  • Unused funds can be reclaimed or reallocated

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

/**
 * @title MedicalResearchFundingDAO
 * @author Nam
 * @notice DAO for funding medical research projects
 */
contract MedicalResearchFundingDAO {

    // -------------------- DAO CORE --------------------

    address public admin;
    uint256 public proposalCount;

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

    struct Proposal {
        address researcher;
        string metadataHash;      // IPFS research proposal
        uint256 requestedAmount;
        uint256 votesFor;
        uint256 votesAgainst;
        bool executed;
        uint256 deadline;
    }

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

    mapping(uint256 => Proposal) public proposals;
    mapping(uint256 => mapping(address => bool)) public hasVoted;

    mapping(address => uint256) public votingPower; // donation-based

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

    event Funded(address indexed donor, uint256 amount);
    event ProposalSubmitted(uint256 indexed proposalId, address researcher);
    event VoteCast(uint256 indexed proposalId, address voter, bool support);
    event FundsReleased(uint256 indexed proposalId, uint256 amount);

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

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

    modifier proposalActive(uint256 _id) {
        require(block.timestamp  0, "No funds sent");
        votingPower[msg.sender] += msg.value;

        emit Funded(msg.sender, msg.value);
    }

    // -------------------- PROPOSALS --------------------

    /**
     * @notice Submit a research proposal
     */
    function submitProposal(
        string calldata _metadataHash,
        uint256 _requestedAmount,
        uint256 _votingDuration
    )
        external
    {
        require(_requestedAmount > 0, "Invalid amount");
        require(_votingDuration > 0, "Invalid duration");

        proposalCount += 1;
        proposals[proposalCount] = Proposal({
            researcher: msg.sender,
            metadataHash: _metadataHash,
            requestedAmount: _requestedAmount,
            votesFor: 0,
            votesAgainst: 0,
            executed: false,
            deadline: block.timestamp + _votingDuration
        });

        emit ProposalSubmitted(proposalCount, msg.sender);
    }

    // -------------------- VOTING --------------------

    /**
     * @notice Vote on a proposal
     */
    function vote(
        uint256 _proposalId,
        bool _support
    )
        external
        proposalActive(_proposalId)
    {
        require(votingPower[msg.sender] > 0, "No voting power");
        require(!hasVoted[_proposalId][msg.sender], "Already voted");

        hasVoted[_proposalId][msg.sender] = true;

        if (_support) {
            proposals[_proposalId].votesFor += votingPower[msg.sender];
        } else {
            proposals[_proposalId].votesAgainst += votingPower[msg.sender];
        }

        emit VoteCast(_proposalId, msg.sender, _support);
    }

    // -------------------- EXECUTION --------------------

    /**
     * @notice Release funds if proposal passes
     */
    function releaseFunds(uint256 _proposalId)
        external
    {
        Proposal storage p = proposals[_proposalId];
        require(!p.executed, "Already executed");
        require(block.timestamp > p.deadline, "Voting not ended");
        require(p.votesFor > p.votesAgainst, "Proposal rejected");
        require(address(this).balance >= p.requestedAmount, "Insufficient funds");

        p.executed = true;
        payable(p.researcher).transfer(p.requestedAmount);

        emit FundsReleased(_proposalId, p.requestedAmount);
    }

    // -------------------- TREASURY --------------------

    receive() external payable {}
}