Community Budget Allocation
What it does:
Enables communities to propose, vote on, and fund public projects using an on-chain participatory budgeting system.
Why it matters:
Increases civic engagement, reduces corruption in public spending, and ensures community funds are allocated according to collective priorities.
How it works:
-
Community treasury holds shared funds on-chain
-
Members submit funding proposals for public projects
-
Proposals include budgets, milestones, and impact descriptions
-
Token-weighted or quadratic voting determines funding approval
-
Approved proposals receive funds automatically or by milestones
-
Spending and progress are transparently tracked on-chain
-
Governance rules can evolve through community voting
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title CommunityBudgetAllocation
* @author Nam
* @notice On-chain participatory budgeting for community funds
*/
contract CommunityBudgetAllocation is Ownable {
struct Proposal {
address payable proposer;
string description;
uint256 requestedAmount;
uint256 votesFor;
uint256 votesAgainst;
bool executed;
}
uint256 public proposalCount;
mapping(uint256 => Proposal) public proposals;
mapping(address => uint256) public votingPower;
// -------------------- EVENTS --------------------
event ProposalCreated(uint256 indexed proposalId, address proposer, uint256 amount);
event Voted(uint256 indexed proposalId, address voter, bool support);
event ProposalExecuted(uint256 indexed proposalId, uint256 amount);
// -------------------- TREASURY --------------------
receive() external payable {}
// -------------------- VOTING POWER --------------------
function setVotingPower(address _member, uint256 _power) external onlyOwner {
votingPower[_member] = _power;
}
// -------------------- PROPOSALS --------------------
function createProposal(
string calldata _description,
uint256 _requestedAmount
) external {
require(_requestedAmount > 0, "Invalid amount");
require(address(this).balance >= _requestedAmount, "Insufficient treasury");
proposalCount += 1;
proposals[proposalCount] = Proposal({
proposer: payable(msg.sender),
description: _description,
requestedAmount: _requestedAmount,
votesFor: 0,
votesAgainst: 0,
executed: false
});
emit ProposalCreated(proposalCount, msg.sender, _requestedAmount);
}
// -------------------- VOTING --------------------
function vote(uint256 _proposalId, bool _support) external {
uint256 power = votingPower[msg.sender];
require(power > 0, "No voting power");
Proposal storage p = proposals[_proposalId];
require(!p.executed, "Already executed");
if (_support) {
p.votesFor += power;
} else {
p.votesAgainst += power;
}
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, "Not approved");
require(address(this).balance >= p.requestedAmount, "Insufficient funds");
p.executed = true;
p.proposer.transfer(p.requestedAmount);
emit ProposalExecuted(_proposalId, p.requestedAmount);
}
}