Journalism Funding DAO
What it does:
Enables communities to collectively fund, govern, and reward independent journalism through transparent, on-chain proposals, voting, and milestone-based payouts.
Why it matters:
Reduces dependence on advertisers or centralized sponsors, protects editorial independence, aligns journalists with readers, and makes funding decisions auditable and trust-minimized.
How it works:
-
Journalists submit funding proposals describing investigations, budgets, and timelines
-
DAO members fund the treasury and gain voting power through tokens or contributions
-
Members vote on which journalism proposals to fund
-
Approved proposals receive funds in tranches or milestones, not lump sums
-
Journalists submit progress updates or proofs of work on-chain or via references
-
Funds are released automatically when milestones are approved
-
All funding, voting, and payouts are transparent and auditable on-chain
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
/**
* @title JournalismFundingDAO
* @author Nam
* @notice DAO for funding journalism via proposals, voting, and milestone-based payouts
*/
contract JournalismFundingDAO {
uint256 public proposalCount;
uint256 public memberCount;
// -------------------- STRUCTS --------------------
struct Member {
bool active;
uint256 votingPower;
}
struct Milestone {
uint256 amount;
bool released;
}
struct Proposal {
address payable journalist;
string description;
uint256 yesVotes;
uint256 noVotes;
uint256 deadline;
bool approved;
Milestone[] milestones;
}
// -------------------- STORAGE --------------------
mapping(address => Member) public members;
mapping(uint256 => Proposal) public proposals;
// -------------------- EVENTS --------------------
event MemberJoined(address indexed member, uint256 votingPower);
event ProposalSubmitted(uint256 indexed proposalId, address indexed journalist);
event Voted(uint256 indexed proposalId, address indexed voter, bool support, uint256 weight);
event ProposalApproved(uint256 indexed proposalId);
event MilestoneReleased(uint256 indexed proposalId, uint256 milestoneIndex, uint256 amount);
// -------------------- MODIFIERS --------------------
modifier onlyMember() {
require(members[msg.sender].active, "Not a member");
_;
}
// -------------------- MEMBERSHIP --------------------
function joinDAO(uint256 _votingPower) external {
require(!members[msg.sender].active, "Already member");
require(_votingPower > 0, "Invalid voting power");
members[msg.sender] = Member({
active: true,
votingPower: _votingPower
});
memberCount += 1;
emit MemberJoined(msg.sender, _votingPower);
}
// -------------------- PROPOSALS --------------------
function submitProposal(
string calldata _description,
uint256 _votingDuration,
uint256[] calldata _milestoneAmounts
) external {
require(_milestoneAmounts.length > 0, "No milestones");
proposalCount += 1;
Proposal storage p = proposals[proposalCount];
p.journalist = payable(msg.sender);
p.description = _description;
p.deadline = block.timestamp + _votingDuration;
for (uint256 i = 0; i < _milestoneAmounts.length; i++) {
p.milestones.push(
Milestone({
amount: _milestoneAmounts[i],
released: false
})
);
}
emit ProposalSubmitted(proposalCount, msg.sender);
}
function vote(uint256 _proposalId, bool _support) external onlyMember {
Proposal storage p = proposals[_proposalId];
require(block.timestamp <p>= p.deadline, "Voting ongoing");
require(!p.approved, "Already finalized");
require(p.yesVotes > p.noVotes, "Proposal rejected");
p.approved = true;
emit ProposalApproved(_proposalId);
}
// -------------------- TREASURY --------------------
receive() external payable {}
// -------------------- MILESTONE PAYOUTS --------------------
function releaseMilestone(uint256 _proposalId, uint256 _milestoneIndex)
external
onlyMember
{
Proposal storage p = proposals[_proposalId];
require(p.approved, "Not approved");
require(_milestoneIndex <p>= m.amount, "Insufficient treasury");
m.released = true;
p.journalist.transfer(m.amount);
emit MilestoneReleased(_proposalId, _milestoneIndex, m.amount);
}
}