Creative Grant DAO
What it does:
Enables communities or organizations to fund creative projects through a DAO that proposes, votes on, and distributes grants transparently on-chain.
Why it matters:
Removes opaque grant committees, reduces favoritism, ensures fair capital allocation, and gives communities direct power to support creators they believe in.
How it works:
-
Creators submit grant proposals with funding requests and descriptions
-
DAO members stake or hold governance tokens to gain voting power
-
Proposals enter a voting period with on-chain vote tracking
-
Votes are weighted by token balance or stake
-
Approved proposals automatically receive funds from the DAO treasury
-
Grant payouts are executed trustlessly via smart contracts
-
All proposals, votes, and fund flows are transparent and auditable
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
/**
* @title CreativeGrantDAO
* @author Nam
* @notice DAO for proposing, voting, and funding creative grants on-chain
*/
contract CreativeGrantDAO is Ownable {
IERC20 public governanceToken;
uint256 public proposalCount;
uint256 public votingDuration; // seconds
uint256 public quorumPercentage; // e.g. 20 = 20%
struct Proposal {
address payable creator;
string description;
uint256 amountRequested;
uint256 voteStart;
uint256 voteEnd;
uint256 votesFor;
uint256 votesAgainst;
bool executed;
}
mapping(uint256 => Proposal) public proposals;
mapping(uint256 => mapping(address => bool)) public hasVoted;
// -------------------- EVENTS --------------------
event ProposalCreated(
uint256 indexed proposalId,
address indexed creator,
uint256 amountRequested
);
event VoteCast(
uint256 indexed proposalId,
address indexed voter,
bool support,
uint256 weight
);
event ProposalExecuted(uint256 indexed proposalId);
// -------------------- CONSTRUCTOR --------------------
constructor(
address _governanceToken,
uint256 _votingDuration,
uint256 _quorumPercentage
) {
governanceToken = IERC20(_governanceToken);
votingDuration = _votingDuration;
quorumPercentage = _quorumPercentage;
}
// -------------------- TREASURY --------------------
receive() external payable {}
// -------------------- PROPOSALS --------------------
function createProposal(
string calldata _description,
uint256 _amountRequested
) external {
require(_amountRequested > 0, "Invalid amount");
require(_amountRequested = p.voteStart, "Voting not started");
require(block.timestamp 0, "No voting power");
hasVoted[_proposalId][msg.sender] = true;
if (_support) {
p.votesFor += weight;
} else {
p.votesAgainst += weight;
}
emit VoteCast(_proposalId, msg.sender, _support, weight);
}
// -------------------- EXECUTION --------------------
function executeProposal(uint256 _proposalId) external {
Proposal storage p = proposals[_proposalId];
require(block.timestamp > p.voteEnd, "Voting active");
require(!p.executed, "Already executed");
uint256 totalVotes = p.votesFor + p.votesAgainst;
uint256 totalSupply = governanceToken.totalSupply();
require(
totalVotes * 100 / totalSupply >= quorumPercentage,
"Quorum not met"
);
require(p.votesFor > p.votesAgainst, "Proposal rejected");
p.executed = true;
p.creator.transfer(p.amountRequested);
emit ProposalExecuted(_proposalId);
}
// -------------------- ADMIN --------------------
function updateVotingDuration(uint256 _duration) external onlyOwner {
votingDuration = _duration;
}
function updateQuorum(uint256 _quorum) external onlyOwner {
require(_quorum <= 100, "Invalid quorum");
quorumPercentage = _quorum;
}
}