Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DUNA admin comms onchain #877

Draft
wants to merge 5 commits into
base: verbs-auction-sanction-check
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents
error ProposalToUpdateMustBeUpdatable();
error OnlyProposerCanCreateUpdateCandidate();
error UpdateProposalCandidatesOnlyWorkWithProposalsBySigs();
error MustHaveVotes();
error MustBeDunaAdmin();
error MustBeDunaAdminOrOwner();

/**
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
Expand Down Expand Up @@ -73,6 +76,8 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents
mapping(address => mapping(bytes32 => bool)) public propCandidates;
/// @notice The account to send ETH fees to.
address payable public feeRecipient;
/// @notice The account the DUNA admins use to communicate with the DAO onchain.
address public dunaAdmin;

constructor(address nounsToken_, address nounsDao_) initializer {
nounsToken = NounsTokenLike(nounsToken_);
Expand All @@ -89,13 +94,15 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents
address admin,
uint256 createCandidateCost_,
uint256 updateCandidateCost_,
address payable feeRecipient_
address payable feeRecipient_,
address dunaAdmin_
) external initializer {
_transferOwnership(admin);

createCandidateCost = createCandidateCost_;
updateCandidateCost = updateCandidateCost_;
feeRecipient = feeRecipient_;
dunaAdmin = dunaAdmin_;
}

/**
Expand Down Expand Up @@ -304,12 +311,66 @@ contract NounsDAOData is OwnableUpgradeable, UUPSUpgradeable, NounsDAODataEvents
emit CandidateFeedbackSent(msg.sender, proposer, slug, support, reason);
}

/**
* @notice Send a message to DUNA admins onchain. Must have at least one vote `PRIOR_VOTES_BLOCKS_AGO` blocks ago.
* @param message the text content of the message.
* @param relatedProposals IDs of relevant proposals.
*/
function postVoterMessageToDunaAdmin(string memory message, uint256[] memory relatedProposals) external {
if (!isNouner(msg.sender)) revert MustHaveVotes();

emit VoterMessageToDunaAdminPosted(message, relatedProposals);
}

/**
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
* DUNA ADMIN FUNCTIONS
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/

/**
* @notice Send a message from DUNA admins to DAO members onchain. Only `dunaAdmin` account can call this function.
* @param message the text content of the message.
* @param relatedProposals IDs of relevant proposals.
*/
function postDunaAdminMessage(string memory message, uint256[] memory relatedProposals) external {
if (msg.sender != dunaAdmin) revert MustBeDunaAdmin();

emit DunaAdminMessagePosted(message, relatedProposals);
}

/**
* @notice Signal a proposal's compliance status. Only `dunaAdmin` account can call this function.
* @param proposalId the ID of the proposal in question.
* @param signal 0: not compliant; 1: compliant; 2: undetermined.
* @param reason text content to explain the signal decision.
*/
function signalProposalCompliance(uint256 proposalId, uint8 signal, string memory reason) external {
if (msg.sender != dunaAdmin) revert MustBeDunaAdmin();
if (signal > 2) revert InvalidSupportValue();

emit ProposalComplianceSignaled(proposalId, signal, reason);
}

/**
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
* ADMIN (OWNER) FUNCTIONS
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░
*/

/**
* @notice Set the DUNA admin account. Only owner or current DUNA admin can call this function.
* @param newDunaAdmin the new DUNA admin account.
*/
function setDunaAdmin(address newDunaAdmin) external {
if (msg.sender != owner() && msg.sender != dunaAdmin) revert MustBeDunaAdminOrOwner();

address oldDunaAdmin = dunaAdmin;
dunaAdmin = newDunaAdmin;

emit DunaAdminSet(oldDunaAdmin, newDunaAdmin);
}

function setCreateCandidateCost(uint256 newCreateCandidateCost) external onlyOwner {
uint256 oldCreateCandidateCost = createCandidateCost;
createCandidateCost = newCreateCandidateCost;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,8 @@ contract NounsDAODataEvents {
event UpdateCandidateCostSet(uint256 oldUpdateCandidateCost, uint256 newUpdateCandidateCost);
event ETHWithdrawn(address indexed to, uint256 amount);
event FeeRecipientSet(address indexed oldFeeRecipient, address indexed newFeeRecipient);
event DunaAdminSet(address indexed oldDunaAdmin, address indexed newDunaAdmin);
event VoterMessageToDunaAdminPosted(string message, uint256[] relatedProposals);
event DunaAdminMessagePosted(string message, uint256[] relatedProposals);
event ProposalComplianceSignaled(uint256 indexed proposalId, uint8 signal, string reason);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-3.0

/// @title Nouns DAO Data Events

/*********************************
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░██░░░████░░██░░░████░░░ *
* ░░██████░░░████████░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░██░░██░░░████░░██░░░████░░░ *
* ░░░░░░█████████░░█████████░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
* ░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ *
*********************************/

pragma solidity ^0.8.19;

contract NounsDAODataEventsV1 {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eladmallel why do we need the previous contracts version?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll remove it later once we feel like we're done

event ProposalCandidateCreated(
address indexed msgSender,
address[] targets,
uint256[] values,
string[] signatures,
bytes[] calldatas,
string description,
string slug,
uint256 proposalIdToUpdate,
bytes32 encodedProposalHash
);
event ProposalCandidateUpdated(
address indexed msgSender,
address[] targets,
uint256[] values,
string[] signatures,
bytes[] calldatas,
string description,
string slug,
uint256 proposalIdToUpdate,
bytes32 encodedProposalHash,
string reason
);
event ProposalCandidateCanceled(address indexed msgSender, string slug);
event SignatureAdded(
address indexed signer,
bytes sig,
uint256 expirationTimestamp,
address proposer,
string slug,
uint256 proposalIdToUpdate,
bytes32 encodedPropHash,
bytes32 sigDigest,
string reason
);
event FeedbackSent(address indexed msgSender, uint256 proposalId, uint8 support, string reason);
event CandidateFeedbackSent(
address indexed msgSender,
address indexed proposer,
string slug,
uint8 support,
string reason
);
event CreateCandidateCostSet(uint256 oldCreateCandidateCost, uint256 newCreateCandidateCost);
event UpdateCandidateCostSet(uint256 oldUpdateCandidateCost, uint256 newUpdateCandidateCost);
event ETHWithdrawn(address indexed to, uint256 amount);
event FeeRecipientSet(address indexed oldFeeRecipient, address indexed newFeeRecipient);
}
Loading
Loading