// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {Governor} from "../Governor.sol"; /** * @dev Extension of {Governor} that implements storage of proposal details. This modules also provides primitives for * the enumerability of proposals. * * Use cases for this module include: * - UIs that explore the proposal state without relying on event indexing. * - Using only the proposalId as an argument in the {Governor-queue} and {Governor-execute} functions for L2 chains where storage is cheap compared to calldata. */ abstract contract GovernorStorage is Governor { struct ProposalDetails { address[] targets; uint256[] values; bytes[] calldatas; bytes32 descriptionHash; } uint256[] private _proposalIds; mapping(uint256 proposalId => ProposalDetails) private _proposalDetails; /** * @dev Hook into the proposing mechanism */ function _propose( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, string memory description, address proposer ) internal virtual override returns (uint256) { uint256 proposalId = super._propose(targets, values, calldatas, description, proposer); // store _proposalIds.push(proposalId); _proposalDetails[proposalId] = ProposalDetails({ targets: targets, values: values, calldatas: calldatas, descriptionHash: keccak256(bytes(description)) }); return proposalId; } /** * @dev Version of {IGovernorTimelock-queue} with only `proposalId` as an argument. */ function queue(uint256 proposalId) public virtual { // here, using storage is more efficient than memory ProposalDetails storage details = _proposalDetails[proposalId]; queue(details.targets, details.values, details.calldatas, details.descriptionHash); } /** * @dev Version of {IGovernor-execute} with only `proposalId` as an argument. */ function execute(uint256 proposalId) public payable virtual { // here, using storage is more efficient than memory ProposalDetails storage details = _proposalDetails[proposalId]; execute(details.targets, details.values, details.calldatas, details.descriptionHash); } /** * @dev ProposalId version of {IGovernor-cancel}. */ function cancel(uint256 proposalId) public virtual { // here, using storage is more efficient than memory ProposalDetails storage details = _proposalDetails[proposalId]; cancel(details.targets, details.values, details.calldatas, details.descriptionHash); } /** * @dev Returns the number of stored proposals. */ function proposalCount() public view virtual returns (uint256) { return _proposalIds.length; } /** * @dev Returns the details of a proposalId. Reverts if `proposalId` is not a known proposal. */ function proposalDetails( uint256 proposalId ) public view virtual returns (address[] memory, uint256[] memory, bytes[] memory, bytes32) { // here, using memory is more efficient than storage ProposalDetails memory details = _proposalDetails[proposalId]; if (details.descriptionHash == 0) { revert GovernorNonexistentProposal(proposalId); } return (details.targets, details.values, details.calldatas, details.descriptionHash); } /** * @dev Returns the details (including the proposalId) of a proposal given its sequential index. */ function proposalDetailsAt( uint256 index ) public view virtual returns (uint256, address[] memory, uint256[] memory, bytes[] memory, bytes32) { uint256 proposalId = _proposalIds[index]; ( address[] memory targets, uint256[] memory values, bytes[] memory calldatas, bytes32 descriptionHash ) = proposalDetails(proposalId); return (proposalId, targets, values, calldatas, descriptionHash); } }