ProposalTypesConfigurator

Description:

Multi-signature wallet contract requiring multiple confirmations for transaction execution.

Blockchain: Ethereum

Source Code: View Code On The Blockchain

Solidity Source Code:

{{
  "language": "Solidity",
  "sources": {
    "src/ProposalTypesConfigurator.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {IProposalTypesConfigurator} from "src/interfaces/IProposalTypesConfigurator.sol";
import {IAgoraGovernor} from "src/interfaces/IAgoraGovernor.sol";
import {Validator} from "src/lib/Validator.sol";

/**
 * Contract that stores proposalTypes for the Agora Governor.
 * @custom:security-contact security@voteagora.com
 */
contract ProposalTypesConfigurator is IProposalTypesConfigurator {
    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event ScopeCreated(uint8 indexed proposalTypeId, bytes24 indexed scopeKey, bytes4 selector, string description);
    event ScopeDisabled(uint8 indexed proposalTypeId, bytes24 indexed scopeKey);
    event ScopeDeleted(uint8 indexed proposalTypeId, bytes24 indexed scopeKey);

    /*//////////////////////////////////////////////////////////////
                           IMMUTABLE STORAGE
    //////////////////////////////////////////////////////////////*/

    IAgoraGovernor public immutable GOVERNOR;

    /// @notice Max value of `quorum` and `approvalThreshold` in `ProposalType`
    uint16 public constant PERCENT_DIVISOR = 10_000;
    // @notice Max length of the `assignedScopes` array
    uint8 public constant MAX_SCOPE_LENGTH = 5;

    /*//////////////////////////////////////////////////////////////
                                STORAGE
    //////////////////////////////////////////////////////////////*/

    mapping(uint8 proposalTypeId => ProposalType) internal _proposalTypes;
    mapping(uint8 proposalTypeId => mapping(bytes24 key => Scope[])) internal _assignedScopes;
    mapping(bytes24 key => bool) internal _scopeExists;

    /*//////////////////////////////////////////////////////////////
                               MODIFIERS
    //////////////////////////////////////////////////////////////*/

    modifier onlyAdminOrTimelock() {
        if (msg.sender != GOVERNOR.admin() && msg.sender != GOVERNOR.timelock()) revert NotAdminOrTimelock();
        _;
    }

    /*//////////////////////////////////////////////////////////////
                              CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Initialize the contract with the governor and proposal types.
     * @param _governor Address of the governor contract.
     * @param _proposalTypesInit Array of ProposalType structs to initialize the contract with.
     */
    constructor(address _governor, ProposalType[] memory _proposalTypesInit) {
        if (_governor == address(0)) revert InvalidGovernor();

        GOVERNOR = IAgoraGovernor(_governor);

        for (uint8 i = 0; i < _proposalTypesInit.length; i++) {
            _setProposalType(
                i,
                _proposalTypesInit[i].quorum,
                _proposalTypesInit[i].approvalThreshold,
                _proposalTypesInit[i].name,
                _proposalTypesInit[i].description,
                _proposalTypesInit[i].module
            );
        }
    }

    /*//////////////////////////////////////////////////////////////
                               FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    /**
     * @notice Get the parameters for a proposal type.
     * @param proposalTypeId Id of the proposal type.
     * @return ProposalType struct of of the proposal type.
     */
    function proposalTypes(uint8 proposalTypeId) external view returns (ProposalType memory) {
        return _proposalTypes[proposalTypeId];
    }

    /**
     * @notice Get the scope that is assigned to a given proposal type.
     * @param proposalTypeId Id of the proposal type.
     * @param scopeKey The function selector + contract address that is the key for a scope.
     * @return Scope struct of the scope.
     */
    function assignedScopes(uint8 proposalTypeId, bytes24 scopeKey) external view returns (Scope[] memory) {
        return _assignedScopes[proposalTypeId][scopeKey];
    }

    /**
     * @notice Returns a boolean if a scope exists.
     * @param key A function selector and contract address that represent the type hash, i.e. 4byte(keccak256("foobar(uint,address)")) + bytes20(contractAddress).
     * @return boolean returns true if the scope is defined.
     */
    function scopeExists(bytes24 key) external view override returns (bool) {
        return _scopeExists[key];
    }

    /**
     * @notice Sets the scope for a given proposal type.
     * @param proposalTypeId Id of the proposal type.
     * @param key A function selector and contract address that represent the type hash, i.e. 4byte(keccak256("foobar(uint,address)")) + bytes20(contractAddress).
     * @param selector A 4 byte function selector.
     * @param parameters The list of byte represented values to be compared.
     * @param comparators List of enumuerated values represent which comparison to use when enforcing limit checks on parameters.
     * @param types List of enumuerated types that map onto each of the supplied parameters.
     * @param description String that's the describes the scope
     */
    function setScopeForProposalType(
        uint8 proposalTypeId,
        bytes24 key,
        bytes4 selector,
        bytes[] memory parameters,
        Comparators[] memory comparators,
        SupportedTypes[] memory types,
        string calldata description
    ) external override onlyAdminOrTimelock {
        if (!_proposalTypes[proposalTypeId].exists) revert InvalidProposalType();
        if (parameters.length != comparators.length) revert InvalidParameterConditions();
        if (_assignedScopes[proposalTypeId][key].length == MAX_SCOPE_LENGTH) revert MaxScopeLengthReached();

        Scope memory scope = Scope(key, selector, parameters, comparators, types, proposalTypeId, description, true);
        _assignedScopes[proposalTypeId][key].push(scope);
        _scopeExists[key] = true;

        emit ScopeCreated(proposalTypeId, key, selector, description);
    }

    /**
     * @notice Set the parameters for a proposal type. Only callable by the admin or timelock.
     * @param proposalTypeId Id of the proposal type
     * @param quorum Quorum percentage, scaled by `PERCENT_DIVISOR`
     * @param approvalThreshold Approval threshold percentage, scaled by `PERCENT_DIVISOR`
     * @param name Name of the proposal type
     * @param description Describes the proposal type
     * @param module Address of module that can only use this proposal type
     */
    function setProposalType(
        uint8 proposalTypeId,
        uint16 quorum,
        uint16 approvalThreshold,
        string calldata name,
        string calldata description,
        address module
    ) external override onlyAdminOrTimelock {
        _setProposalType(proposalTypeId, quorum, approvalThreshold, name, description, module);
    }

    function _setProposalType(
        uint8 proposalTypeId,
        uint16 quorum,
        uint16 approvalThreshold,
        string memory name,
        string memory description,
        address module
    ) internal {
        if (quorum > PERCENT_DIVISOR) revert InvalidQuorum();
        if (approvalThreshold > PERCENT_DIVISOR) revert InvalidApprovalThreshold();

        _proposalTypes[proposalTypeId] = ProposalType(quorum, approvalThreshold, name, description, module, true);

        emit ProposalTypeSet(proposalTypeId, quorum, approvalThreshold, name, description, module);
    }

    /**
     * @notice Adds an additional scope for a given proposal type.
     * @param proposalTypeId Id of the proposal type
     * @param scope An object that contains the scope for a transaction type hash
     */
    function addScopeForProposalType(uint8 proposalTypeId, Scope calldata scope)
        external
        override
        onlyAdminOrTimelock
    {
        if (!_proposalTypes[proposalTypeId].exists) revert InvalidProposalType();
        if (scope.parameters.length != scope.comparators.length) revert InvalidParameterConditions();
        if (_assignedScopes[proposalTypeId][scope.key].length == MAX_SCOPE_LENGTH) revert MaxScopeLengthReached();

        _scopeExists[scope.key] = true;
        _assignedScopes[proposalTypeId][scope.key].push(scope);

        emit ScopeCreated(proposalTypeId, scope.key, scope.selector, scope.description);
    }

    /**
     * @notice Retrives the function selector of a transaction for a given proposal type.
     * @param proposalTypeId Id of the proposal type
     * @param key A type signature of a function and contract address that has a limit specified in a scope
     */
    function getSelector(uint8 proposalTypeId, bytes24 key) public view returns (bytes4 selector) {
        if (!_scopeExists[key]) revert InvalidScope();
        if (!_proposalTypes[proposalTypeId].exists) revert InvalidProposalType();
        Scope memory validScope = _assignedScopes[proposalTypeId][key][0];
        return validScope.selector;
    }

    /**
     * @notice Disables a scopes for all contract + function signatures.
     * @param proposalTypeId the proposal type ID that has the assigned scope.
     * @param scopeKey the contract and function signature representing the scope key
     * @param idx the index of the assigned scope.
     */
    function disableScope(uint8 proposalTypeId, bytes24 scopeKey, uint8 idx) external override onlyAdminOrTimelock {
        _assignedScopes[proposalTypeId][scopeKey][idx].exists = false;
        emit ScopeDisabled(proposalTypeId, scopeKey);
    }

    /**
     * @notice Deletes a scope inside assignedScopes for a proposal type.
     * @param proposalTypeId the proposal type ID that has the assigned scope.
     * @param scopeKey the contract and function signature representing the scope key
     * @param idx the index of the assigned scope.
     */
    function deleteScope(uint8 proposalTypeId, bytes24 scopeKey, uint8 idx) external override onlyAdminOrTimelock {
        Scope[] storage scopeArr = _assignedScopes[proposalTypeId][scopeKey];

        scopeArr[idx] = scopeArr[scopeArr.length - 1];
        scopeArr.pop();

        emit ScopeDeleted(proposalTypeId, scopeKey);
    }

    /**
     * @notice Validates that a proposed transaction conforms to the scope defined in a given proposal type. Note: This
     *   version only supports functions that have for each parameter 32-byte abi encodings, please see the ABI
     *   specification to see which types are not supported. The types that are supported are as follows:
     *      - Uint
     *      - Address
     *      - Bytes32
     * @param proposedTx The calldata of the proposed transaction
     * @param proposalTypeId Id of the proposal type
     * @param key A type signature of a function and contract address that has a limit specified in a scope
     */
    function validateProposedTx(bytes calldata proposedTx, uint8 proposalTypeId, bytes24 key) public view {
        Scope[] memory scopes = _assignedScopes[proposalTypeId][key];

        for (uint8 i = 0; i < scopes.length; i++) {
            Scope memory validScope = scopes[i];
            if (validScope.selector != bytes4(proposedTx[:4])) revert Invalid4ByteSelector();

            if (validScope.exists) {
                uint256 startIdx = 4;
                uint256 endIdx = startIdx;
                for (uint8 j = 0; j < validScope.parameters.length; j++) {
                    endIdx = endIdx + validScope.parameters[j].length;

                    Validator.determineValidation(
                        proposedTx[startIdx:endIdx],
                        validScope.parameters[j],
                        validScope.types[j],
                        validScope.comparators[j]
                    );

                    startIdx = endIdx;
                }
            }
        }
    }

    /**
     * @notice Validates the proposed transactions against the defined scopes based on the proposal type
     * proposal threshold can propose.
     * @param targets The list of target contract addresses.
     * @param calldatas The list of proposed transaction calldata.
     * @param proposalTypeId The type of the proposal.
     */
    function validateProposalData(address[] memory targets, bytes[] calldata calldatas, uint8 proposalTypeId)
        external
        view
    {
        if (calldatas.length == 0) revert InvalidCalldatasLength();

        for (uint8 i = 0; i < calldatas.length; i++) {
            if (calldatas[i].length < 4) revert InvalidCalldata();

            bytes24 scopeKey = _pack(targets[i], bytes4(calldatas[i]));
            if (_assignedScopes[proposalTypeId][scopeKey].length != 0) {
                validateProposedTx(calldatas[i], proposalTypeId, scopeKey);
            } else {
                if (_scopeExists[scopeKey]) {
                    revert InvalidProposedTxForType();
                }
            }
        }
    }

    /**
     * @notice Generates the scope key defined as the contract address combined with the function selector
     * @param contractAddress Address of the contract to be enforced by the scope
     * @param selector A byte4 function selector on the contract to be enforced by the scope
     */
    function _pack(address contractAddress, bytes4 selector) internal pure returns (bytes24 result) {
        bytes20 left = bytes20(contractAddress);
        assembly ("memory-safe") {
            left := and(left, shl(96, not(0)))
            selector := and(selector, shl(224, not(0)))
            result := or(left, shr(160, selector))
        }
    }
}
"
    },
    "src/interfaces/IProposalTypesConfigurator.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

interface IProposalTypesConfigurator {
    /*//////////////////////////////////////////////////////////////
                                 ERRORS
    //////////////////////////////////////////////////////////////*/

    error InvalidQuorum();
    error InvalidApprovalThreshold();
    error InvalidProposalType();
    error InvalidParameterConditions();
    error InvalidScope();
    error NotAdminOrTimelock();
    error NotAdmin();
    error InvalidGovernor();
    error Invalid4ByteSelector();
    error InvalidParamNotEqual();
    error InvalidParamRange();
    error InvalidProposedTxForType();
    error MaxScopeLengthReached();
    error InvalidCalldatasLength();
    error InvalidCalldata();

    /*//////////////////////////////////////////////////////////////
                                 EVENTS
    //////////////////////////////////////////////////////////////*/

    event ProposalTypeSet(
        uint8 indexed proposalTypeId,
        uint16 quorum,
        uint16 approvalThreshold,
        string name,
        string description,
        address indexed module
    );

    /*//////////////////////////////////////////////////////////////
                                STRUCTS
    //////////////////////////////////////////////////////////////*/

    struct ProposalType {
        uint16 quorum;
        uint16 approvalThreshold;
        string name;
        string description;
        address module;
        bool exists;
    }

    enum Comparators {
        EQUAL,
        LESS_THAN,
        GREATER_THAN
    }

    enum SupportedTypes {
        NONE,
        UINT8,
        UINT16,
        UINT32,
        UINT64,
        UINT128,
        UINT256,
        ADDRESS,
        BYTES32
    }

    struct Scope {
        bytes24 key;
        bytes4 selector;
        bytes[] parameters;
        Comparators[] comparators;
        SupportedTypes[] types;
        uint8 proposalTypeId;
        string description;
        bool exists;
    }

    /*//////////////////////////////////////////////////////////////
                               FUNCTIONS
    //////////////////////////////////////////////////////////////*/

    function proposalTypes(uint8 proposalTypeId) external view returns (ProposalType memory);
    function assignedScopes(uint8 proposalTypeId, bytes24 scopeKey) external view returns (Scope[] memory);
    function scopeExists(bytes24 key) external view returns (bool);

    function setProposalType(
        uint8 proposalTypeId,
        uint16 quorum,
        uint16 approvalThreshold,
        string memory name,
        string memory description,
        address module
    ) external;

    function setScopeForProposalType(
        uint8 proposalTypeId,
        bytes24 key,
        bytes4 selector,
        bytes[] memory parameters,
        Comparators[] memory comparators,
        SupportedTypes[] memory types,
        string memory description
    ) external;

    function getSelector(uint8 proposalTypeId, bytes24 key) external returns (bytes4);
    function addScopeForProposalType(uint8 proposalTypeId, Scope calldata scope) external;
    function disableScope(uint8 proposalTypeId, bytes24 scopeKey, uint8 idx) external;
    function deleteScope(uint8 proposalTypeId, bytes24 scopeKey, uint8 idx) external;
    function validateProposedTx(bytes calldata proposedTx, uint8 proposalTypeId, bytes24 key) external;
    function validateProposalData(address[] memory targets, bytes[] memory calldatas, uint8 proposalTypeId) external;
}
"
    },
    "src/interfaces/IAgoraGovernor.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {IGovernor} from "@openzeppelin/contracts-v4/governance/IGovernor.sol";
import {IVotesUpgradeable} from "@openzeppelin/contracts-upgradeable-v4/governance/utils/IVotesUpgradeable.sol";

abstract contract IAgoraGovernor is IGovernor {
    function manager() external view virtual returns (address);
    function admin() external view virtual returns (address);
    function timelock() external view virtual returns (address);

    function PROPOSAL_TYPES_CONFIGURATOR() external view virtual returns (address);

    function token() external view virtual returns (IVotesUpgradeable);

    function getProposalType(uint256 proposalId) external view virtual returns (uint8);

    function proposalVotes(uint256 proposalId)
        external
        view
        virtual
        returns (uint256 againstVotes, uint256 forVotes, uint256 abstainVotes);
}
"
    },
    "src/lib/Validator.sol": {
      "content": "// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {IProposalTypesConfigurator} from "src/interfaces/IProposalTypesConfigurator.sol";

library Validator {
    error InvalidParamNotEqual();
    error InvalidParamRange();
    error InvalidComparison();

    /**
     * @notice Compares two byte32 values of the represented type and reverts if condition is not met.
     * @param paramA The first parameter, in this case the one extracted from the calldata
     * @param paramB The second parameter, the one stored on the Scope object
     * @param comparison An enumerated type representing which comparison check should be performed
     */
    function compare(bytes32 paramA, bytes32 paramB, IProposalTypesConfigurator.Comparators comparison) internal pure {
        if (comparison == IProposalTypesConfigurator.Comparators.EQUAL) {
            if (paramA != paramB) revert InvalidParamNotEqual();
        } else if (comparison == IProposalTypesConfigurator.Comparators.LESS_THAN) {
            if (paramA >= paramB) revert InvalidParamRange();
        } else if (comparison == IProposalTypesConfigurator.Comparators.GREATER_THAN) {
            if (paramA <= paramB) revert InvalidParamRange();
        } else {
            revert InvalidComparison();
        }
    }

    /**
     * @notice Given the types and comparison enumeration, determine which type check to use prior to validation.
     * @param param The parameter extracted from the calldata
     * @param scopedParam The parameter stored on the Scope object
     * @param supportedType An enumerated type representing the possible supported types for size checks
     * @param comparison An enumerated type representing which comparison check should be performed
     */
    function determineValidation(
        bytes calldata param,
        bytes calldata scopedParam,
        IProposalTypesConfigurator.SupportedTypes supportedType,
        IProposalTypesConfigurator.Comparators comparison
    ) public pure {
        if (supportedType == IProposalTypesConfigurator.SupportedTypes.UINT8) {
            validate_uint8(param, scopedParam, comparison);
        }

        if (supportedType == IProposalTypesConfigurator.SupportedTypes.UINT16) {
            validate_uint16(param, scopedParam, comparison);
        }

        if (supportedType == IProposalTypesConfigurator.SupportedTypes.UINT32) {
            validate_uint32(param, scopedParam, comparison);
        }

        if (supportedType == IProposalTypesConfigurator.SupportedTypes.UINT64) {
            validate_uint64(param, scopedParam, comparison);
        }

        if (supportedType == IProposalTypesConfigurator.SupportedTypes.UINT128) {
            validate_uint128(param, scopedParam, comparison);
        }

        if (supportedType == IProposalTypesConfigurator.SupportedTypes.UINT256) {
            validate_uint256(param, scopedParam, comparison);
        }

        if (supportedType == IProposalTypesConfigurator.SupportedTypes.ADDRESS) {
            validate_address(param, scopedParam, comparison);
        }

        if (supportedType == IProposalTypesConfigurator.SupportedTypes.BYTES32) {
            validate_bytes32(param, scopedParam, comparison);
        }
    }

    /**
     * @dev Conforms the uint8 type to the necessary size considerations prior to comparison
     */
    function validate_uint8(
        bytes calldata param,
        bytes calldata scopedParam,
        IProposalTypesConfigurator.Comparators comparison
    ) internal pure {
        compare(
            bytes32(bytes1(param[param.length - 1:param.length])),
            bytes32(bytes1(scopedParam[scopedParam.length - 1:scopedParam.length])),
            comparison
        );
    }

    /**
     * @dev Conforms the uint16 type to the necessary size considerations prior to comparison
     */
    function validate_uint16(
        bytes calldata param,
        bytes calldata scopedParam,
        IProposalTypesConfigurator.Comparators comparison
    ) internal pure {
        compare(
            bytes32(bytes2(param[param.length - 2:param.length])),
            bytes32(bytes2(scopedParam[scopedParam.length - 2:scopedParam.length])),
            comparison
        );
    }

    /**
     * @dev Conforms the uint32 type to the necessary size considerations prior to comparison
     */
    function validate_uint32(
        bytes calldata param,
        bytes calldata scopedParam,
        IProposalTypesConfigurator.Comparators comparison
    ) internal pure {
        compare(
            bytes32(bytes4(param[param.length - 4:param.length])),
            bytes32(bytes4(scopedParam[scopedParam.length - 4:scopedParam.length])),
            comparison
        );
    }

    /**
     * @dev Conforms the uint64 type to the necessary size considerations prior to comparison
     */
    function validate_uint64(
        bytes calldata param,
        bytes calldata scopedParam,
        IProposalTypesConfigurator.Comparators comparison
    ) internal pure {
        compare(
            bytes32(bytes8(param[param.length - 8:param.length])),
            bytes32(bytes8(scopedParam[scopedParam.length - 8:scopedParam.length])),
            comparison
        );
    }

    /**
     * @dev Conforms the uint128 type to the necessary size considerations prior to comparison
     */
    function validate_uint128(
        bytes calldata param,
        bytes calldata scopedParam,
        IProposalTypesConfigurator.Comparators comparison
    ) internal pure {
        compare(
            bytes32(bytes16(param[param.length - 16:param.length])),
            bytes32(bytes16(scopedParam[scopedParam.length - 16:scopedParam.length])),
            comparison
        );
    }

    /**
     * @dev Conforms the uint256 type to the necessary size considerations prior to comparison
     */
    function validate_uint256(
        bytes calldata param,
        bytes calldata scopedParam,
        IProposalTypesConfigurator.Comparators comparison
    ) internal pure {
        compare(
            bytes32(param[param.length - 32:param.length]),
            bytes32(scopedParam[scopedParam.length - 32:scopedParam.length]),
            comparison
        );
    }

    /**
     * @dev Conforms the address type to the necessary size considerations prior to comparison
     */
    function validate_address(
        bytes calldata param,
        bytes calldata scopedParam,
        IProposalTypesConfigurator.Comparators comparison
    ) internal pure {
        compare(bytes32(bytes20(param[0:20])), bytes32(bytes20(scopedParam[0:20])), comparison);
    }

    /**
     * @dev Conforms the bytes32 type to the necessary size considerations prior to comparison
     */
    function validate_bytes32(
        bytes calldata param,
        bytes calldata scopedParam,
        IProposalTypesConfigurator.Comparators comparison
    ) internal pure {
        compare(bytes32(param[0:32]), bytes32(scopedParam[0:32]), comparison);
    }
}
"
    },
    "lib/openzeppelin-contracts-v4/contracts/governance/IGovernor.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (governance/IGovernor.sol)

pragma solidity ^0.8.0;

import "../utils/introspection/ERC165.sol";

/**
 * @dev Interface of the {Governor} core.
 *
 * _Available since v4.3._
 */
abstract contract IGovernor is IERC165 {
    enum ProposalState {
        Pending,
        Active,
        Canceled,
        Defeated,
        Succeeded,
        Queued,
        Expired,
        Executed
    }

    /**
     * @dev Emitted when a proposal is created.
     */
    event ProposalCreated(
        uint256 proposalId,
        address proposer,
        address[] targets,
        uint256[] values,
        string[] signatures,
        bytes[] calldatas,
        uint256 startBlock,
        uint256 endBlock,
        string description
    );

    /**
     * @dev Emitted when a proposal is canceled.
     */
    event ProposalCanceled(uint256 proposalId);

    /**
     * @dev Emitted when a proposal is executed.
     */
    event ProposalExecuted(uint256 proposalId);

    /**
     * @dev Emitted when a vote is cast without params.
     *
     * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used.
     */
    event VoteCast(address indexed voter, uint256 proposalId, uint8 support, uint256 weight, string reason);

    /**
     * @dev Emitted when a vote is cast with params.
     *
     * Note: `support` values should be seen as buckets. Their interpretation depends on the voting module used.
     * `params` are additional encoded parameters. Their intepepretation also depends on the voting module used.
     */
    event VoteCastWithParams(
        address indexed voter,
        uint256 proposalId,
        uint8 support,
        uint256 weight,
        string reason,
        bytes params
    );

    /**
     * @notice module:core
     * @dev Name of the governor instance (used in building the ERC712 domain separator).
     */
    function name() public view virtual returns (string memory);

    /**
     * @notice module:core
     * @dev Version of the governor instance (used in building the ERC712 domain separator). Default: "1"
     */
    function version() public view virtual returns (string memory);

    /**
     * @notice module:voting
     * @dev A description of the possible `support` values for {castVote} and the way these votes are counted, meant to
     * be consumed by UIs to show correct vote options and interpret the results. The string is a URL-encoded sequence of
     * key-value pairs that each describe one aspect, for example `support=bravo&quorum=for,abstain`.
     *
     * There are 2 standard keys: `support` and `quorum`.
     *
     * - `support=bravo` refers to the vote options 0 = Against, 1 = For, 2 = Abstain, as in `GovernorBravo`.
     * - `quorum=bravo` means that only For votes are counted towards quorum.
     * - `quorum=for,abstain` means that both For and Abstain votes are counted towards quorum.
     *
     * If a counting module makes use of encoded `params`, it should  include this under a `params` key with a unique
     * name that describes the behavior. For example:
     *
     * - `params=fractional` might refer to a scheme where votes are divided fractionally between for/against/abstain.
     * - `params=erc721` might refer to a scheme where specific NFTs are delegated to vote.
     *
     * NOTE: The string can be decoded by the standard
     * https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams[`URLSearchParams`]
     * JavaScript class.
     */
    // solhint-disable-next-line func-name-mixedcase
    function COUNTING_MODE() public pure virtual returns (string memory);

    /**
     * @notice module:core
     * @dev Hashing function used to (re)build the proposal id from the proposal details..
     */
    function hashProposal(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        bytes32 descriptionHash
    ) public pure virtual returns (uint256);

    /**
     * @notice module:core
     * @dev Current state of a proposal, following Compound's convention
     */
    function state(uint256 proposalId) public view virtual returns (ProposalState);

    /**
     * @notice module:core
     * @dev Block number used to retrieve user's votes and quorum. As per Compound's Comp and OpenZeppelin's
     * ERC20Votes, the snapshot is performed at the end of this block. Hence, voting for this proposal starts at the
     * beginning of the following block.
     */
    function proposalSnapshot(uint256 proposalId) public view virtual returns (uint256);

    /**
     * @notice module:core
     * @dev Block number at which votes close. Votes close at the end of this block, so it is possible to cast a vote
     * during this block.
     */
    function proposalDeadline(uint256 proposalId) public view virtual returns (uint256);

    /**
     * @notice module:user-config
     * @dev Delay, in number of block, between the proposal is created and the vote starts. This can be increassed to
     * leave time for users to buy voting power, or delegate it, before the voting of a proposal starts.
     */
    function votingDelay() public view virtual returns (uint256);

    /**
     * @notice module:user-config
     * @dev Delay, in number of blocks, between the vote start and vote ends.
     *
     * NOTE: The {votingDelay} can delay the start of the vote. This must be considered when setting the voting
     * duration compared to the voting delay.
     */
    function votingPeriod() public view virtual returns (uint256);

    /**
     * @notice module:user-config
     * @dev Minimum number of cast voted required for a proposal to be successful.
     *
     * Note: The `blockNumber` parameter corresponds to the snapshot used for counting vote. This allows to scale the
     * quorum depending on values such as the totalSupply of a token at this block (see {ERC20Votes}).
     */
    function quorum(uint256 blockNumber) public view virtual returns (uint256);

    /**
     * @notice module:reputation
     * @dev Voting power of an `account` at a specific `blockNumber`.
     *
     * Note: this can be implemented in a number of ways, for example by reading the delegated balance from one (or
     * multiple), {ERC20Votes} tokens.
     */
    function getVotes(address account, uint256 blockNumber) public view virtual returns (uint256);

    /**
     * @notice module:reputation
     * @dev Voting power of an `account` at a specific `blockNumber` given additional encoded parameters.
     */
    function getVotesWithParams(
        address account,
        uint256 blockNumber,
        bytes memory params
    ) public view virtual returns (uint256);

    /**
     * @notice module:voting
     * @dev Returns whether `account` has cast a vote on `proposalId`.
     */
    function hasVoted(uint256 proposalId, address account) public view virtual returns (bool);

    /**
     * @dev Create a new proposal. Vote start {IGovernor-votingDelay} blocks after the proposal is created and ends
     * {IGovernor-votingPeriod} blocks after the voting starts.
     *
     * Emits a {ProposalCreated} event.
     */
    function propose(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        string memory description
    ) public virtual returns (uint256 proposalId);

    /**
     * @dev Execute a successful proposal. This requires the quorum to be reached, the vote to be successful, and the
     * deadline to be reached.
     *
     * Emits a {ProposalExecuted} event.
     *
     * Note: some module can modify the requirements for execution, for example by adding an additional timelock.
     */
    function execute(
        address[] memory targets,
        uint256[] memory values,
        bytes[] memory calldatas,
        bytes32 descriptionHash
    ) public payable virtual returns (uint256 proposalId);

    /**
     * @dev Cast a vote
     *
     * Emits a {VoteCast} event.
     */
    function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256 balance);

    /**
     * @dev Cast a vote with a reason
     *
     * Emits a {VoteCast} event.
     */
    function castVoteWithReason(
        uint256 proposalId,
        uint8 support,
        string calldata reason
    ) public virtual returns (uint256 balance);

    /**
     * @dev Cast a vote with a reason and additional encoded parameters
     *
     * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params.
     */
    function castVoteWithReasonAndParams(
        uint256 proposalId,
        uint8 support,
        string calldata reason,
        bytes memory params
    ) public virtual returns (uint256 balance);

    /**
     * @dev Cast a vote using the user's cryptographic signature.
     *
     * Emits a {VoteCast} event.
     */
    function castVoteBySig(
        uint256 proposalId,
        uint8 support,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual returns (uint256 balance);

    /**
     * @dev Cast a vote with a reason and additional encoded parameters using the user's cryptographic signature.
     *
     * Emits a {VoteCast} or {VoteCastWithParams} event depending on the length of params.
     */
    function castVoteWithReasonAndParamsBySig(
        uint256 proposalId,
        uint8 support,
        string calldata reason,
        bytes memory params,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual returns (uint256 balance);
}
"
    },
    "lib/openzeppelin-contracts-upgradeable-v4/contracts/governance/utils/IVotesUpgradeable.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (governance/utils/IVotes.sol)
pragma solidity ^0.8.0;

/**
 * @dev Common interface for {ERC20Votes}, {ERC721Votes}, and other {Votes}-enabled contracts.
 *
 * _Available since v4.5._
 */
interface IVotesUpgradeable {
    /**
     * @dev Emitted when an account changes their delegate.
     */
    event DelegateChanged(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);

    /**
     * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes.
     */
    event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance);

    /**
     * @dev Returns the current amount of votes that `account` has.
     */
    function getVotes(address account) external view returns (uint256);

    /**
     * @dev Returns the amount of votes that `account` had at the end of a past block (`blockNumber`).
     */
    function getPastVotes(address account, uint256 blockNumber) external view returns (uint256);

    /**
     * @dev Returns the total supply of votes available at the end of a past block (`blockNumber`).
     *
     * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes.
     * Votes that have not been delegated are still part of total supply, even though they would not participate in a
     * vote.
     */
    function getPastTotalSupply(uint256 blockNumber) external view returns (uint256);

    /**
     * @dev Returns the delegate that `account` has chosen.
     */
    function delegates(address account) external view returns (address);

    /**
     * @dev Delegates votes from the sender to `delegatee`.
     */
    function delegate(address delegatee) external;

    /**
     * @dev Delegates votes from signer to `delegatee`.
     */
    function delegateBySig(
        address delegatee,
        uint256 nonce,
        uint256 expiry,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}
"
    },
    "lib/openzeppelin-contracts-v4/contracts/utils/introspection/ERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}
"
    },
    "lib/openzeppelin-contracts-v4/contracts/utils/introspection/IERC165.sol": {
      "content": "// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
"
    }
  },
  "settings": {
    "remappings": [
      "@openzeppelin/contracts-v4/=lib/openzeppelin-contracts-v4/contracts/",
      "@openzeppelin/contracts-v5/=lib/openzeppelin-contracts-v5/contracts/",
      "@openzeppelin/contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/contracts/",
      "forge-std/=lib/forge-std/src/",
      "@solady/=lib/solady/src/",
      "ERC20VotesPartialDelegationUpgradeable/=lib/ERC20VotesPartialDelegationUpgradeable/src/",
      "@openzeppelin/contracts-upgradeable/=lib/ERC20VotesPartialDelegationUpgradeable/lib/openzeppelin-contracts-upgradeable/contracts/",
      "@openzeppelin/contracts/=lib/openzeppelin-contracts-v5/contracts/",
      "@openzeppelin/foundry-upgrades/=lib/ERC20VotesPartialDelegationUpgradeable/lib/openzeppelin-foundry-upgrades/src/",
      "ds-test/=lib/openzeppelin-contracts-v5/lib/forge-std/lib/ds-test/src/",
      "erc4626-tests/=lib/openzeppelin-contracts-v5/lib/erc4626-tests/",
      "openzeppelin-contracts-upgradeable-v4/=lib/openzeppelin-contracts-upgradeable-v4/",
      "openzeppelin-contracts-upgradeable/=lib/ERC20VotesPartialDelegationUpgradeable/lib/openzeppelin-contracts-upgradeable/",
      "openzeppelin-contracts-v4/=lib/openzeppelin-contracts-v4/",
      "openzeppelin-contracts-v5/=lib/openzeppelin-contracts-v5/",
      "openzeppelin-contracts/=lib/ERC20VotesPartialDelegationUpgradeable/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
      "openzeppelin-foundry-upgrades/=lib/ERC20VotesPartialDelegationUpgradeable/lib/openzeppelin-foundry-upgrades/src/",
      "solady/=lib/solady/src/",
      "solidity-stringutils/=lib/ERC20VotesPartialDelegationUpgradeable/lib/openzeppelin-foundry-upgrades/lib/solidity-stringutils/"
    ],
    "optimizer": {
      "enabled": true,
      "runs": 200
    },
    "metadata": {
      "useLiteralContent": false,
      "bytecodeHash": "ipfs",
      "appendCBOR": true
    },
    "outputSelection": {
      "*": {
        "*": [
          "evm.bytecode",
          "evm.deployedBytecode",
          "devdoc",
          "userdoc",
          "metadata",
          "abi"
        ]
      }
    },
    "evmVersion": "cancun",
    "viaIR": false,
    "libraries": {
      "src/ProposalTypesConfigurator.sol": {
        "Validator": "0x6bfd7add62e94ec38556709cb465b8229772db77"
      }
    }
  }
}}

Tags:
ERC165, Multisig, Voting, Timelock, Upgradeable, Multi-Signature, Factory|addr:0xbfc07a8c9615fe62979f02cd0d975caf61ed0d63|verified:true|block:23477297|tx:0x44060450025fcc6c9b73bafa6a26a48df32198286fe0affc8db232a3f8a5e714|first_check:1759314875

Submitted on: 2025-10-01 12:34:35

Comments

Log in to comment.

No comments yet.