Anti-Corruption Fund Tracking

What it does:
Tracks the allocation, disbursement, and usage of anti-corruption or public integrity funds on-chain to ensure transparency and accountability.

Why it matters:
Prevents misuse of funds, builds public trust, and allows auditors and citizens to verify that allocated resources are used appropriately.

How it works:

  • Funds are deposited into a dedicated anti-corruption treasury on-chain

  • Authorized spenders submit disbursement proposals with recipient, purpose, and metadata

  • Auditors or community members vote to approve or reject proposals

  • Approved funds are automatically released to recipients

  • All transactions and voting are immutably recorded on-chain

  • Public dashboards provide real-time transparency and auditability

  • Can integrate with DAO governance or budgeting systems for broader oversight

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

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

/**
 * @title AntiCorruptionFundTracking
 * @author Nam
 * @notice Tracks and manages anti-corruption funds with on-chain transparency
 */
contract AntiCorruptionFundTracking is Ownable {

    struct Proposal {
        address payable recipient;
        uint256 amount;
        string purpose;
        uint256 votesFor;
        uint256 votesAgainst;
        bool executed;
    }

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

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

    event FundDeposited(address indexed sender, uint256 amount);
    event ProposalCreated(uint256 indexed proposalId, address recipient, uint256 amount);
    event Voted(uint256 indexed proposalId, address voter, bool support);
    event ProposalExecuted(uint256 indexed proposalId, uint256 amount);

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

    receive() external payable {
        emit FundDeposited(msg.sender, msg.value);
    }

    // -------------------- AUDITOR MANAGEMENT --------------------

    function approveAuditor(address _auditor) external onlyOwner {
        auditors[_auditor] = true;
    }

    function revokeAuditor(address _auditor) external onlyOwner {
        auditors[_auditor] = false;
    }

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

    function createProposal(
        address payable _recipient,
        uint256 _amount,
        string calldata _purpose
    ) external {
        require(_amount > 0, "Invalid amount");
        require(address(this).balance >= _amount, "Insufficient treasury");

        proposalCount += 1;
        proposals[proposalCount] = Proposal({
            recipient: _recipient,
            amount: _amount,
            purpose: _purpose,
            votesFor: 0,
            votesAgainst: 0,
            executed: false
        });

        emit ProposalCreated(proposalCount, _recipient, _amount);
    }

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

    function vote(uint256 _proposalId, bool _support) external {
        require(auditors[msg.sender], "Not authorized auditor");
        require(!hasVoted[msg.sender][_proposalId], "Already voted");

        Proposal storage p = proposals[_proposalId];
        require(!p.executed, "Already executed");

        if (_support) {
            p.votesFor += 1;
        } else {
            p.votesAgainst += 1;
        }

        hasVoted[msg.sender][_proposalId] = true;
        emit Voted(_proposalId, msg.sender, _support);
    }

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

    function executeProposal(uint256 _proposalId) external {
        Proposal storage p = proposals[_proposalId];
        require(!p.executed, "Already executed");
        require(p.votesFor > p.votesAgainst, "Proposal not approved");
        require(address(this).balance >= p.amount, "Insufficient funds");

        p.executed = true;
        p.recipient.transfer(p.amount);

        emit ProposalExecuted(_proposalId, p.amount);
    }
}