Skip to content
Merged
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 @@ -40,17 +40,6 @@ interface IProposalValidator is ISemver {
CouncilBudget
}

event ProposalSubmitted(
bytes32 indexed proposalHash,
address indexed proposer,
address[] targets,
uint256[] values,
bytes[] calldatas,
string description,
ProposalType proposalType,
uint8 proposalVotingModule
);

event ProposalApproved(
bytes32 indexed proposalHash,
address indexed approver
Expand Down Expand Up @@ -78,15 +67,6 @@ interface IProposalValidator is ISemver {

event Initialized(uint8 version);

function submitProposal(
address[] memory _targets,
uint256[] memory _values,
bytes[] memory _calldatas,
string memory _description,
ProposalType _proposalType,
bytes32 _attestationUid
) external returns (bytes32 proposalHash_);

function approveProposal(bytes32 _proposalHash) external;

function moveToVote(
Expand Down
99 changes: 0 additions & 99 deletions packages/contracts-bedrock/snapshots/abi/ProposalValidator.json
Original file line number Diff line number Diff line change
Expand Up @@ -357,50 +357,6 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address[]",
"name": "_targets",
"type": "address[]"
},
{
"internalType": "uint256[]",
"name": "_values",
"type": "uint256[]"
},
{
"internalType": "bytes[]",
"name": "_calldatas",
"type": "bytes[]"
},
{
"internalType": "string",
"name": "_description",
"type": "string"
},
{
"internalType": "enum ProposalValidator.ProposalType",
"name": "_proposalType",
"type": "uint8"
},
{
"internalType": "bytes32",
"name": "_attestationUid",
"type": "bytes32"
}
],
"name": "submitProposal",
"outputs": [
{
"internalType": "bytes32",
"name": "proposalHash_",
"type": "bytes32"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down Expand Up @@ -552,61 +508,6 @@
"name": "ProposalMovedToVote",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "bytes32",
"name": "proposalHash",
"type": "bytes32"
},
{
"indexed": true,
"internalType": "address",
"name": "proposer",
"type": "address"
},
{
"indexed": false,
"internalType": "address[]",
"name": "targets",
"type": "address[]"
},
{
"indexed": false,
"internalType": "uint256[]",
"name": "values",
"type": "uint256[]"
},
{
"indexed": false,
"internalType": "bytes[]",
"name": "calldatas",
"type": "bytes[]"
},
{
"indexed": false,
"internalType": "string",
"name": "description",
"type": "string"
},
{
"indexed": false,
"internalType": "enum ProposalValidator.ProposalType",
"name": "proposalType",
"type": "uint8"
},
{
"indexed": false,
"internalType": "uint8",
"name": "proposalVotingModule",
"type": "uint8"
}
],
"name": "ProposalSubmitted",
"type": "event"
},
{
"anonymous": false,
"inputs": [
Expand Down
4 changes: 2 additions & 2 deletions packages/contracts-bedrock/snapshots/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@
"sourceCodeHash": "0x18f43b227decd0f2a895b8b55e23fa6a47706697c272bbf2482b3f912be446e1"
},
"src/governance/ProposalValidator.sol:ProposalValidator": {
"initCodeHash": "0x553e9a5abda992f985f23d02f07c169be7ee39063d6dbd00742b4298089d3602",
"sourceCodeHash": "0xe3649d1d6a51572d2f6a0f82683d54eb3717dae3373f9a0c2a3648c392e66433"
"initCodeHash": "0xdcec7b9d2e1d4a7c7849e0b06fe1142fd743fd5927edceb1fc22466bf139d33c",
"sourceCodeHash": "0xf9bed487efd2ee53ab19814bbc32af947a6cb23f891b0a9af9059077155b64dd"
},
"src/legacy/DeployerWhitelist.sol:DeployerWhitelist": {
"initCodeHash": "0x53099379ed48b87f027d55712dbdd1da7d7099925426eb0531da9c0012e02c29",
Expand Down
128 changes: 14 additions & 114 deletions packages/contracts-bedrock/src/governance/ProposalValidator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -106,26 +106,6 @@ contract ProposalValidator is OwnableUpgradeable, ReinitializableBase, ISemver {
EVENTS
//////////////////////////////////////////////////////////////*/

/// @notice Emitted when a new proposal is submitted to the validator contract.
/// @param proposalHash The hash of the submitted proposal.
/// @param proposer The address that submitted the proposal.
/// @param targets Target addresses for proposal calls.
/// @param values ETH values for proposal calls.
/// @param calldatas Function data for proposal calls.
/// @param description Description of the proposal.
/// @param proposalType Type of the proposal.
/// @param proposalVotingModule Voting module specific to the proposal type.
event ProposalSubmitted(
bytes32 indexed proposalHash,
address indexed proposer,
address[] targets,
uint256[] values,
bytes[] calldatas,
string description,
ProposalType proposalType,
uint8 proposalVotingModule
);

/// @notice Emitted when a delegate approves a proposal.
/// @param proposalHash The hash of the approved proposal.
/// @param approver The address of the delegate who approved the proposal.
Expand Down Expand Up @@ -247,51 +227,6 @@ contract ProposalValidator is OwnableUpgradeable, ReinitializableBase, ISemver {
transferOwnership(_owner);
}

/// @notice Submit a proposal for delegate approval
/// @param _targets Target addresses for proposal calls
/// @param _values ETH values for proposal calls
/// @param _calldatas Function data for proposal calls
/// @param _description Description of the proposal
/// @param _proposalType Type of the proposal
/// @return proposalHash_ The hash of the submitted proposal
function submitProposal(
address[] memory _targets,
uint256[] memory _values,
bytes[] memory _calldatas,
string memory _description,
ProposalType _proposalType,
bytes32 _attestationUid
)
external
returns (bytes32 proposalHash_)
{
_validateProposal(_targets, _values, _calldatas, _proposalType, _attestationUid);

proposalHash_ = bytes32(0); // TODO: Implement hashProposalWithModule
ProposalData storage proposal = _proposals[proposalHash_];

if (proposal.proposer != address(0)) {
revert ProposalValidator_ProposalAlreadySubmitted();
}

ProposalTypeData memory proposalTypeData = proposalTypesData[_proposalType];

proposal.proposer = msg.sender;
proposal.proposalType = _proposalType;
proposal.inVoting = false;

emit ProposalSubmitted(
proposalHash_,
msg.sender,
_targets,
_values,
_calldatas,
_description,
_proposalType,
proposalTypeData.proposalVotingModule
);
}

/// @notice Approve a proposal (only callable by delegates with sufficient voting power)
/// @param _proposalHash The hash of the proposal to approve
function approveProposal(bytes32 _proposalHash) external {
Expand Down Expand Up @@ -401,57 +336,22 @@ contract ProposalValidator is OwnableUpgradeable, ReinitializableBase, ISemver {
_setProposalTypeData(_proposalType, _proposalTypeData);
}

/// @notice Validates a proposal before submission.
/// @dev Checks if the proposal requires approval and validates the attestation.
/// @param _targets Target addresses for proposal calls.
/// @param _values ETH values for proposal calls.
/// @param _calldatas Function data for proposal calls.
/// @param _proposalType Type of the proposal.
/// @param _attestationUid The UID of the attestation proving eligibility.
function _validateProposal(
address[] memory _targets,
uint256[] memory _values,
bytes[] memory _calldatas,
ProposalType _proposalType,
bytes32 _attestationUid
)
private
view
{
if (_requiresAttestation(_proposalType)) {
Attestation memory attestation = IEAS(Predeploys.EAS).getAttestation(_attestationUid);
if (
attestation.attester != owner() || attestation.schema != ATTESTATION_SCHEMA_UID
|| !_isValidAttestationData(attestation.data, _proposalType)
) {
revert ProposalValidator_InvalidAttestation();
}
}
}

/// @notice Determines if a proposal type requires approval via attestation.
/// @param _proposalType The type of proposal to check.
/// @return requiresAttestation_ True if the proposal type requires approval, false otherwise.
function _requiresAttestation(ProposalType _proposalType) private pure returns (bool requiresAttestation_) {
return _proposalType == ProposalType.ProtocolOrGovernorUpgrade
|| _proposalType == ProposalType.MaintenanceUpgrade || _proposalType == ProposalType.CouncilMemberElections;
}

/// @notice Validates the attestation data for a proposal.
/// @dev Checks that the sender is the approved delegate and that the proposal type is correct.
/// @param _data The attestation data to validate.
/// @dev Checks that the attester is the owner, the schema is correct,
/// the sender is the approved delegate, and that the proposal type is correct.
/// Reverts with ProposalValidator_InvalidAttestation if validation fails.
/// @param _attestationUid The UID of the attestation to validate.
/// @param _expectedProposalType The expected proposal type from the attestation.
/// @return isValid_ True if the attestation data is valid, false otherwise.
function _isValidAttestationData(
bytes memory _data,
ProposalType _expectedProposalType
)
private
view
returns (bool isValid_)
{
(address approvedDelegate, uint8 proposalType) = abi.decode(_data, (address, uint8));
isValid_ = approvedDelegate == msg.sender && proposalType == uint8(_expectedProposalType);
function _validateAttestation(bytes32 _attestationUid, ProposalType _expectedProposalType) internal view {
Attestation memory attestation = IEAS(Predeploys.EAS).getAttestation(_attestationUid);
(address approvedDelegate, uint8 proposalType) = abi.decode(attestation.data, (address, uint8));

if (
attestation.attester != owner() || attestation.schema != ATTESTATION_SCHEMA_UID
|| approvedDelegate != msg.sender || proposalType != uint8(_expectedProposalType)
) {
revert ProposalValidator_InvalidAttestation();
}
}

/// @notice Calculate `proposalId` hashing similarly to `hashProposal` but based on `module` and `proposalData`.
Expand Down
Loading