Local Community DAO
What it does:
Empowers local communities to self-govern, propose projects, vote on initiatives, and manage community funds transparently on-chain.
Why it matters:
Enhances civic engagement at the neighborhood or city level, ensures funds and decisions reflect community priorities, and reduces reliance on centralized authorities.
How it works:
-
Residents join the DAO and are registered with verified identities
-
Members propose local projects or initiatives with budgets and timelines
-
Voting determines which projects receive funding
-
Smart contracts manage treasury and disbursements automatically
-
Milestone tracking ensures projects are executed before funds are fully released
-
Public dashboards track proposals, votes, spending, and outcomes
-
Can integrate with reputation, referendum, and civic participation systems for enhanced governance
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title LocalCommunityDAO
* @author Nam
* @notice On-chain DAO for local community governance and project funding
*/
contract LocalCommunityDAO is Ownable {
struct Member {
bool registered;
string metadataURI;
}
struct Proposal {
address payable proposer;
string description;
uint256 requestedAmount;
uint256 votesFor;
uint256 votesAgainst;
bool executed;
}
mapping(address => Member) public members;
mapping(uint256 => Proposal) public proposals;
mapping(address => mapping(uint256 => bool)) public hasVoted;
uint256 public proposalCount;
// -------------------- EVENTS --------------------
event MemberRegistered(address indexed member, string metadataURI);
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 {}
// -------------------- MEMBER MANAGEMENT --------------------
function registerMember(string calldata _metadataURI) external {
require(!members[msg.sender].registered, "Already registered");
members[msg.sender] = Member({
registered: true,
metadataURI: _metadataURI
});
emit MemberRegistered(msg.sender, _metadataURI);
}
function isMember(address _user) public view returns (bool) {
return members[_user].registered;
}
// -------------------- PROPOSALS --------------------
function createProposal(string calldata _description, uint256 _requestedAmount) external {
require(isMember(msg.sender), "Not a member");
require(_requestedAmount > 0, "Invalid amount");
require(address(this).balance >= _requestedAmount, "Insufficient funds");
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 {
require(isMember(msg.sender), "Not a member");
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.requestedAmount, "Insufficient funds");
p.executed = true;
p.proposer.transfer(p.requestedAmount);
emit ProposalExecuted(_proposalId, p.requestedAmount);
}
}