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"
}
}
}
}}
Submitted on: 2025-10-01 12:34:35
Comments
Log in to comment.
No comments yet.