Community Solar Fund Contract

What it does:
Enables communities to collectively fund, own, and benefit from shared solar energy projects through transparent on-chain investment and revenue distribution.

Why it matters:
Lowers the barrier to renewable energy ownership, democratizes access to clean power, and ensures fair, auditable distribution of returns from solar projects.

How it works:

  • Community members contribute funds to a shared solar project

  • Contributions are recorded on-chain and represent ownership shares

  • Funds are used to deploy or expand solar installations

  • Energy revenue or savings are periodically reported via oracles

  • Smart contract distributes收益 to contributors proportional to shares

  • Governance decisions (maintenance, expansion) can be community-voted

  • All funding, ownership, and payouts are transparent and auditable

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

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

/**
 * @title CommunitySolarFund
 * @author Nam
 * @notice Collective funding and revenue sharing for community solar projects
 */
contract CommunitySolarFund is Ownable {

    IERC20 public payoutToken;

    uint256 public totalShares;
    uint256 public totalRevenue;

    mapping(address => uint256) public shares;
    mapping(address => uint256) public claimedRevenue;

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

    event ContributionReceived(address indexed contributor, uint256 amount, uint256 sharesMinted);
    event RevenueReported(uint256 amount);
    event RevenueClaimed(address indexed contributor, uint256 amount);

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

    constructor(address _payoutToken) {
        payoutToken = IERC20(_payoutToken);
    }

    // -------------------- FUNDING --------------------

    function contribute(uint256 _amount) external {
        require(_amount > 0, "Invalid amount");

        payoutToken.transferFrom(msg.sender, address(this), _amount);

        uint256 mintedShares = _amount; // 1:1 for simplicity
        shares[msg.sender] += mintedShares;
        totalShares += mintedShares;

        emit ContributionReceived(msg.sender, _amount, mintedShares);
    }

    // -------------------- REVENUE REPORTING --------------------

    function reportRevenue(uint256 _amount) external onlyOwner {
        require(_amount > 0, "Invalid revenue amount");

        payoutToken.transferFrom(msg.sender, address(this), _amount);
        totalRevenue += _amount;

        emit RevenueReported(_amount);
    }

    // -------------------- REVENUE CLAIM --------------------

    function claimRevenue() external {
        uint256 userShare = shares[msg.sender];
        require(userShare > 0, "No shares owned");

        uint256 entitled = (totalRevenue * userShare) / totalShares;
        uint256 claimable = entitled - claimedRevenue[msg.sender];
        require(claimable > 0, "Nothing to claim");

        claimedRevenue[msg.sender] += claimable;
        payoutToken.transfer(msg.sender, claimable);

        emit RevenueClaimed(msg.sender, claimable);
    }
}