Renewable Energy Credit System

What it does:
Creates, tracks, and trades Renewable Energy Credits (RECs) on-chain, where each credit represents a verified unit of renewable electricity generated.

Why it matters:
Prevents double-counting of green energy, increases trust in sustainability claims, and enables open, global markets for renewable energy credits.

How it works:

  • Renewable energy producers register generation facilities on-chain

  • Verified oracles submit energy production data (kWh / MWh)

  • Smart contract mints REC tokens based on verified output

  • Credits can be transferred, traded, or retired (burned) to offset emissions

  • Corporations or individuals retire RECs to prove green energy usage

  • All issuance, transfers, and retirements are transparent and auditable

  • Integrates with carbon markets, ESG reporting, and energy DAOs

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

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

/**
 * @title RenewableEnergyCredit
 * @author Nam
 * @notice On-chain Renewable Energy Credit (REC) issuance and retirement
 */
contract RenewableEnergyCredit is ERC20, Ownable {

    mapping(address => bool) public approvedProducers;
    mapping(address => bool) public approvedOracles;

    uint256 public creditsPerMWh; // tokens per MWh

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

    event ProducerApproved(address producer);
    event OracleApproved(address oracle);
    event CreditsMinted(address indexed producer, uint256 amount);
    event CreditsRetired(address indexed account, uint256 amount);

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

    constructor(uint256 _creditsPerMWh)
        ERC20("Renewable Energy Credit", "REC")
    {
        creditsPerMWh = _creditsPerMWh;
    }

    // -------------------- ROLE MANAGEMENT --------------------

    function approveProducer(address _producer) external onlyOwner {
        approvedProducers[_producer] = true;
        emit ProducerApproved(_producer);
    }

    function approveOracle(address _oracle) external onlyOwner {
        approvedOracles[_oracle] = true;
        emit OracleApproved(_oracle);
    }

    // -------------------- CREDIT ISSUANCE --------------------

    function mintCredits(
        address _producer,
        uint256 _mwhGenerated
    ) external {
        require(approvedOracles[msg.sender], "Not authorized oracle");
        require(approvedProducers[_producer], "Not approved producer");
        require(_mwhGenerated > 0, "Invalid amount");

        uint256 credits = _mwhGenerated * creditsPerMWh;
        _mint(_producer, credits);

        emit CreditsMinted(_producer, credits);
    }

    // -------------------- CREDIT RETIREMENT --------------------

    function retireCredits(uint256 _amount) external {
        require(balanceOf(msg.sender) >= _amount, "Insufficient credits");

        _burn(msg.sender, _amount);
        emit CreditsRetired(msg.sender, _amount);
    }
}