From baa40aae457bc2cb3f298b053b3050d2503a6d43 Mon Sep 17 00:00:00 2001
From: 0xRaccoon <112493530+0xRaccoon@users.noreply.github.com>
Date: Wed, 20 Dec 2023 10:41:14 -0300
Subject: [PATCH] feat: add support for proposal types

Signed-off-by: 0xRaccoon <raccoon@defi.sucks>
---
 .../contracts/governance/WonderGovernor.sol   | 156 ++++++++++++------
 .../interfaces/governance/IWonderGovernor.sol |  39 ++++-
 .../governance/utils/IWonderVotes.sol         |   5 +
 3 files changed, 139 insertions(+), 61 deletions(-)

diff --git a/solidity/contracts/governance/WonderGovernor.sol b/solidity/contracts/governance/WonderGovernor.sol
index d5f2fdc..db3fca8 100644
--- a/solidity/contracts/governance/WonderGovernor.sol
+++ b/solidity/contracts/governance/WonderGovernor.sol
@@ -11,8 +11,7 @@ import {DoubleEndedQueue} from '@openzeppelin/contracts/utils/structs/DoubleEnde
 import {Address} from '@openzeppelin/contracts/utils/Address.sol';
 import {Context} from '@openzeppelin/contracts/utils/Context.sol';
 import {Nonces} from '@openzeppelin/contracts/utils/Nonces.sol';
-import {IGovernor} from '@openzeppelin/contracts/governance/IGovernor.sol';
-import {IERC6372} from '@openzeppelin/contracts/interfaces/IERC6372.sol';
+import {IWonderGovernor, IERC6372} from '../../interfaces/governance/IWonderGovernor.sol';
 
 /**
  * @dev Core of the governance system, designed to be extended through various modules.
@@ -23,7 +22,15 @@ import {IERC6372} from '@openzeppelin/contracts/interfaces/IERC6372.sol';
  * - A voting module must implement {_getVotes}
  * - Additionally, {votingPeriod} must also be implemented
  */
-abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor, IERC721Receiver, IERC1155Receiver {
+abstract contract WonderGovernor is
+  Context,
+  ERC165,
+  EIP712,
+  Nonces,
+  IWonderGovernor,
+  IERC721Receiver,
+  IERC1155Receiver
+{
   using DoubleEndedQueue for DoubleEndedQueue.Bytes32Deque;
 
   bytes32 public constant BALLOT_TYPEHASH =
@@ -32,6 +39,7 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
     keccak256('ExtendedBallot(uint256 proposalId,uint8 support,address voter,uint256 nonce,string reason,bytes params)');
 
   struct ProposalCore {
+    uint8 proposalType;
     address proposer;
     uint48 voteStart;
     uint32 voteDuration;
@@ -66,6 +74,16 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
     _;
   }
 
+  /**
+   * @dev Checks if the proposalType is supported by the governor
+   */
+  modifier validProposalType(uint8 proposalType) {
+    if (!_isValidProposalType(proposalType)) {
+      revert InvalidProposalType(proposalType);
+    }
+    _;
+  }
+
   /**
    * @dev Sets the value for {name} and {version}
    */
@@ -86,26 +104,26 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
    * @dev See {IERC165-supportsInterface}.
    */
   function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
-    return interfaceId == type(IGovernor).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId
+    return interfaceId == type(IWonderGovernor).interfaceId || interfaceId == type(IERC1155Receiver).interfaceId
       || super.supportsInterface(interfaceId);
   }
 
   /**
-   * @dev See {IGovernor-name}.
+   * @dev See {IWonderGovernor-name}.
    */
   function name() public view virtual returns (string memory) {
     return _name;
   }
 
   /**
-   * @dev See {IGovernor-version}.
+   * @dev See {IWonderGovernor-version}.
    */
   function version() public view virtual returns (string memory) {
     return '1';
   }
 
   /**
-   * @dev See {IGovernor-hashProposal}.
+   * @dev See {IWonderGovernor-hashProposal}.
    *
    * The proposal id is produced by hashing the ABI encoded `targets` array, the `values` array, the `calldatas` array
    * and the descriptionHash (bytes32 which itself is the keccak256 hash of the description string). This proposal id
@@ -118,16 +136,17 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
    * governor) the proposer will have to change the description in order to avoid proposal id conflicts.
    */
   function hashProposal(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
     bytes32 descriptionHash
   ) public pure virtual returns (uint256) {
-    return uint256(keccak256(abi.encode(targets, values, calldatas, descriptionHash)));
+    return uint256(keccak256(abi.encode(proposalType, targets, values, calldatas, descriptionHash)));
   }
 
   /**
-   * @dev See {IGovernor-state}.
+   * @dev See {IWonderGovernor-state}.
    */
   function state(uint256 proposalId) public view virtual returns (ProposalState) {
     // We read the struct fields into the stack at once so Solidity emits a single SLOAD
@@ -169,42 +188,42 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   }
 
   /**
-   * @dev See {IGovernor-proposalThreshold}.
+   * @dev See {IWonderGovernor-proposalThreshold}.
    */
-  function proposalThreshold() public view virtual returns (uint256) {
+  function proposalThreshold(uint8 proposalType) public view virtual returns (uint256) {
     return 0;
   }
 
   /**
-   * @dev See {IGovernor-proposalSnapshot}.
+   * @dev See {IWonderGovernor-proposalSnapshot}.
    */
   function proposalSnapshot(uint256 proposalId) public view virtual returns (uint256) {
     return _proposals[proposalId].voteStart;
   }
 
   /**
-   * @dev See {IGovernor-proposalDeadline}.
+   * @dev See {IWonderGovernor-proposalDeadline}.
    */
   function proposalDeadline(uint256 proposalId) public view virtual returns (uint256) {
     return _proposals[proposalId].voteStart + _proposals[proposalId].voteDuration;
   }
 
   /**
-   * @dev See {IGovernor-proposalProposer}.
+   * @dev See {IWonderGovernor-proposalProposer}.
    */
   function proposalProposer(uint256 proposalId) public view virtual returns (address) {
     return _proposals[proposalId].proposer;
   }
 
   /**
-   * @dev See {IGovernor-proposalEta}.
+   * @dev See {IWonderGovernor-proposalEta}.
    */
   function proposalEta(uint256 proposalId) public view virtual returns (uint256) {
     return _proposals[proposalId].etaSeconds;
   }
 
   /**
-   * @dev See {IGovernor-proposalNeedsQueuing}.
+   * @dev See {IWonderGovernor-proposalNeedsQueuing}.
    */
   function proposalNeedsQueuing(uint256) public view virtual returns (bool) {
     return false;
@@ -236,10 +255,25 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
    */
   function _voteSucceeded(uint256 proposalId) internal view virtual returns (bool);
 
+  /**
+   * @dev Is the proposalType valid or not
+   */
+  function _isValidProposalType(uint8 proposalType) internal view virtual returns (bool);
+
+  /**
+   * @dev Returns the `proposalTypes` supported.
+   */
+  function _proposalTypes() internal view virtual returns (uint8[] memory);
+
   /**
    * @dev Get the voting weight of `account` at a specific `timepoint`, for a vote as described by `params`.
    */
-  function _getVotes(address account, uint256 timepoint, bytes memory params) internal view virtual returns (uint256);
+  function _getVotes(
+    address account,
+    uint8 proposalType,
+    uint256 timepoint,
+    bytes memory params
+  ) internal view virtual returns (uint256);
 
   /**
    * @dev Register a vote for `proposalId` by `account` with a given `support`, voting `weight` and voting `params`.
@@ -265,14 +299,15 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   }
 
   /**
-   * @dev See {IGovernor-propose}. This function has opt-in frontrunning protection, described in {_isValidDescriptionForProposer}.
+   * @dev See {IWonderGovernor-propose}. This function has opt-in frontrunning protection, described in {_isValidDescriptionForProposer}.
    */
   function propose(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
     string memory description
-  ) public virtual returns (uint256) {
+  ) public virtual validProposalType(proposalType) returns (uint256) {
     address proposer = _msgSender();
 
     // check description restriction
@@ -281,28 +316,29 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
     }
 
     // check proposal threshold
-    uint256 proposerVotes = getVotes(proposer, clock() - 1);
-    uint256 votesThreshold = proposalThreshold();
+    uint256 proposerVotes = getVotes(proposer, proposalType, clock() - 1);
+    uint256 votesThreshold = proposalThreshold(proposalType);
     if (proposerVotes < votesThreshold) {
       revert GovernorInsufficientProposerVotes(proposer, proposerVotes, votesThreshold);
     }
 
-    return _propose(targets, values, calldatas, description, proposer);
+    return _propose(proposalType, targets, values, calldatas, description, proposer);
   }
 
   /**
    * @dev Internal propose mechanism. Can be overridden to add more logic on proposal creation.
    *
-   * Emits a {IGovernor-ProposalCreated} event.
+   * Emits a {IWonderGovernor-ProposalCreated} event.
    */
   function _propose(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
     string memory description,
     address proposer
   ) internal virtual returns (uint256 proposalId) {
-    proposalId = hashProposal(targets, values, calldatas, keccak256(bytes(description)));
+    proposalId = hashProposal(proposalType, targets, values, calldatas, keccak256(bytes(description)));
 
     if (targets.length != values.length || targets.length != calldatas.length || targets.length == 0) {
       revert GovernorInvalidProposalLength(targets.length, calldatas.length, values.length);
@@ -315,12 +351,14 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
     uint256 duration = votingPeriod();
 
     ProposalCore storage proposal = _proposals[proposalId];
+    proposal.proposalType = proposalType;
     proposal.proposer = proposer;
     proposal.voteStart = SafeCast.toUint48(snapshot);
     proposal.voteDuration = SafeCast.toUint32(duration);
 
     emit ProposalCreated(
       proposalId,
+      proposalType,
       proposer,
       targets,
       values,
@@ -335,15 +373,16 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   }
 
   /**
-   * @dev See {IGovernor-queue}.
+   * @dev See {IWonderGovernor-queue}.
    */
   function queue(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
     bytes32 descriptionHash
   ) public virtual returns (uint256) {
-    uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash);
+    uint256 proposalId = hashProposal(proposalType, targets, values, calldatas, descriptionHash);
 
     _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Succeeded));
 
@@ -383,15 +422,16 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   }
 
   /**
-   * @dev See {IGovernor-execute}.
+   * @dev See {IWonderGovernor-execute}.
    */
   function execute(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
     bytes32 descriptionHash
   ) public payable virtual returns (uint256) {
-    uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash);
+    uint256 proposalId = hashProposal(proposalType, targets, values, calldatas, descriptionHash);
 
     _validateStateBitmap(
       proposalId, _encodeStateBitmap(ProposalState.Succeeded) | _encodeStateBitmap(ProposalState.Queued)
@@ -442,9 +482,10 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   }
 
   /**
-   * @dev See {IGovernor-cancel}.
+   * @dev See {IWonderGovernor-cancel}.
    */
   function cancel(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
@@ -453,7 +494,7 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
     // The proposalId will be recomputed in the `_cancel` call further down. However we need the value before we
     // do the internal call, because we need to check the proposal state BEFORE the internal `_cancel` call
     // changes it. The `hashProposal` duplication has a cost that is limited, and that we accept.
-    uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash);
+    uint256 proposalId = hashProposal(proposalType, targets, values, calldatas, descriptionHash);
 
     // public cancel restrictions (on top of existing _cancel restrictions).
     _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Pending));
@@ -461,22 +502,23 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
       revert GovernorOnlyProposer(_msgSender());
     }
 
-    return _cancel(targets, values, calldatas, descriptionHash);
+    return _cancel(proposalType, targets, values, calldatas, descriptionHash);
   }
 
   /**
    * @dev Internal cancel mechanism with minimal restrictions. A proposal can be cancelled in any state other than
    * Canceled, Expired, or Executed. Once cancelled a proposal can't be re-submitted.
    *
-   * Emits a {IGovernor-ProposalCanceled} event.
+   * Emits a {IWonderGovernor-ProposalCanceled} event.
    */
   function _cancel(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
     bytes32 descriptionHash
   ) internal virtual returns (uint256) {
-    uint256 proposalId = hashProposal(targets, values, calldatas, descriptionHash);
+    uint256 proposalId = hashProposal(proposalType, targets, values, calldatas, descriptionHash);
 
     _validateStateBitmap(
       proposalId,
@@ -491,25 +533,26 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   }
 
   /**
-   * @dev See {IGovernor-getVotes}.
+   * @dev See {IWonderGovernor-getVotes}.
    */
-  function getVotes(address account, uint256 timepoint) public view virtual returns (uint256) {
-    return _getVotes(account, timepoint, _defaultParams());
+  function getVotes(address account, uint8 proposalType, uint256 timepoint) public view virtual returns (uint256) {
+    return _getVotes(account, proposalType, timepoint, _defaultParams());
   }
 
   /**
-   * @dev See {IGovernor-getVotesWithParams}.
+   * @dev See {IWonderGovernor-getVotesWithParams}.
    */
   function getVotesWithParams(
     address account,
+    uint8 proposalType,
     uint256 timepoint,
     bytes memory params
   ) public view virtual returns (uint256) {
-    return _getVotes(account, timepoint, params);
+    return _getVotes(account, proposalType, timepoint, params);
   }
 
   /**
-   * @dev See {IGovernor-castVote}.
+   * @dev See {IWonderGovernor-castVote}.
    */
   function castVote(uint256 proposalId, uint8 support) public virtual returns (uint256) {
     address voter = _msgSender();
@@ -517,7 +560,7 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   }
 
   /**
-   * @dev See {IGovernor-castVoteWithReason}.
+   * @dev See {IWonderGovernor-castVoteWithReason}.
    */
   function castVoteWithReason(
     uint256 proposalId,
@@ -529,7 +572,7 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   }
 
   /**
-   * @dev See {IGovernor-castVoteWithReasonAndParams}.
+   * @dev See {IWonderGovernor-castVoteWithReasonAndParams}.
    */
   function castVoteWithReasonAndParams(
     uint256 proposalId,
@@ -542,7 +585,7 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   }
 
   /**
-   * @dev See {IGovernor-castVoteBySig}.
+   * @dev See {IWonderGovernor-castVoteBySig}.
    */
   function castVoteBySig(
     uint256 proposalId,
@@ -564,7 +607,7 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   }
 
   /**
-   * @dev See {IGovernor-castVoteWithReasonAndParamsBySig}.
+   * @dev See {IWonderGovernor-castVoteWithReasonAndParamsBySig}.
    */
   function castVoteWithReasonAndParamsBySig(
     uint256 proposalId,
@@ -601,9 +644,9 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
 
   /**
    * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve
-   * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function. Uses the _defaultParams().
+   * voting weight using {IWonderGovernor-getVotes} and call the {_countVote} internal function. Uses the _defaultParams().
    *
-   * Emits a {IGovernor-VoteCast} event.
+   * Emits a {IWonderGovernor-VoteCast} event.
    */
   function _castVote(
     uint256 proposalId,
@@ -616,9 +659,9 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
 
   /**
    * @dev Internal vote casting mechanism: Check that the vote is pending, that it has not been cast yet, retrieve
-   * voting weight using {IGovernor-getVotes} and call the {_countVote} internal function.
+   * voting weight using {IWonderGovernor-getVotes} and call the {_countVote} internal function.
    *
-   * Emits a {IGovernor-VoteCast} event.
+   * Emits a {IWonderGovernor-VoteCast} event.
    */
   function _castVote(
     uint256 proposalId,
@@ -629,7 +672,9 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   ) internal virtual returns (uint256) {
     _validateStateBitmap(proposalId, _encodeStateBitmap(ProposalState.Active));
 
-    uint256 weight = _getVotes(account, proposalSnapshot(proposalId), params);
+    uint8 _proposalType = _proposals[proposalId].proposalType;
+
+    uint256 weight = _getVotes(account, _proposalType, proposalSnapshot(proposalId), params);
     _countVote(proposalId, account, support, weight, params);
 
     if (params.length == 0) {
@@ -826,17 +871,24 @@ abstract contract WonderGovernor is Context, ERC165, EIP712, Nonces, IGovernor,
   function CLOCK_MODE() public view virtual returns (string memory);
 
   /**
-   * @inheritdoc IGovernor
+   * @inheritdoc IWonderGovernor
    */
   function votingDelay() public view virtual returns (uint256);
 
   /**
-   * @inheritdoc IGovernor
+   * @inheritdoc IWonderGovernor
    */
   function votingPeriod() public view virtual returns (uint256);
 
   /**
-   * @inheritdoc IGovernor
+   * @inheritdoc IWonderGovernor
    */
-  function quorum(uint256 timepoint) public view virtual returns (uint256);
+  function quorum(uint256 timepoint, uint8 proposalType) public view virtual returns (uint256);
+
+  /**
+   * @inheritdoc IWonderGovernor
+   */
+  function proposalTypes() public view virtual override returns (uint8[] memory) {
+    return _proposalTypes();
+  }
 }
diff --git a/solidity/interfaces/governance/IWonderGovernor.sol b/solidity/interfaces/governance/IWonderGovernor.sol
index cf6ed59..2e49684 100644
--- a/solidity/interfaces/governance/IWonderGovernor.sol
+++ b/solidity/interfaces/governance/IWonderGovernor.sol
@@ -5,7 +5,7 @@ import {IERC165} from '@openzeppelin/contracts/interfaces/IERC165.sol';
 import {IERC6372} from '@openzeppelin/contracts/interfaces/IERC6372.sol';
 
 /**
- * @dev Interface of the {Governor} core.
+ * @dev Interface of the {WonderGovernor} core.
  */
 interface IWonderGovernor is IERC165, IERC6372 {
   enum ProposalState {
@@ -102,11 +102,17 @@ interface IWonderGovernor is IERC165, IERC6372 {
    */
   error GovernorInvalidSignature(address voter);
 
+  /**
+   * @dev The proposalType is not supported by the governor.
+   */
+  error InvalidProposalType(uint8 proposalType);
+
   /**
    * @dev Emitted when a proposal is created.
    */
   event ProposalCreated(
     uint256 proposalId,
+    uint8 proposalType,
     address proposer,
     address[] targets,
     uint256[] values,
@@ -191,6 +197,7 @@ interface IWonderGovernor is IERC165, IERC6372 {
    * @dev Hashing function used to (re)build the proposal id from the proposal details..
    */
   function hashProposal(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
@@ -205,9 +212,9 @@ interface IWonderGovernor is IERC165, IERC6372 {
 
   /**
    * @notice module:core
-   * @dev The number of votes required in order for a voter to become a proposer.
+   * @dev The number of votes required in order for a voter to become a proposer given a proposalType.
    */
-  function proposalThreshold() external view returns (uint256);
+  function proposalThreshold(uint8 proposalType) external view returns (uint256);
 
   /**
    * @notice module:core
@@ -273,27 +280,32 @@ interface IWonderGovernor is IERC165, IERC6372 {
 
   /**
    * @notice module:user-config
-   * @dev Minimum number of cast voted required for a proposal to be successful.
+   * @dev Minimum number of cast voted required for a proposal type to be successful.
    *
    * NOTE: The `timepoint` 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 timepoint (see {ERC20Votes}).
    */
-  function quorum(uint256 timepoint) external view returns (uint256);
+  function quorum(uint256 timepoint, uint8 proposalType) external view returns (uint256);
 
   /**
    * @notice module:reputation
-   * @dev Voting power of an `account` at a specific `timepoint`.
+   * @dev Voting power of an `account` at a specific `timepoint` for a given `proposalType`.
    *
    * 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 timepoint) external view returns (uint256);
+  function getVotes(address account, uint8 proposalType, uint256 timepoint) external view returns (uint256);
 
   /**
    * @notice module:reputation
-   * @dev Voting power of an `account` at a specific `timepoint` given additional encoded parameters.
+   * @dev Voting power of an `account` at a specific `timepoint` for a given `proposalType` and additional encoded parameters.
    */
-  function getVotesWithParams(address account, uint256 timepoint, bytes memory params) external view returns (uint256);
+  function getVotesWithParams(
+    address account,
+    uint8 proposalType,
+    uint256 timepoint,
+    bytes memory params
+  ) external view returns (uint256);
 
   /**
    * @notice module:voting
@@ -308,6 +320,7 @@ interface IWonderGovernor is IERC165, IERC6372 {
    * Emits a {ProposalCreated} event.
    */
   function propose(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
@@ -322,6 +335,7 @@ interface IWonderGovernor is IERC165, IERC6372 {
    * Emits a {ProposalQueued} event.
    */
   function queue(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
@@ -338,6 +352,7 @@ interface IWonderGovernor is IERC165, IERC6372 {
    * NOTE: Some modules can modify the requirements for execution, for example by adding an additional timelock.
    */
   function execute(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
@@ -351,6 +366,7 @@ interface IWonderGovernor is IERC165, IERC6372 {
    * Emits a {ProposalCanceled} event.
    */
   function cancel(
+    uint8 proposalType,
     address[] memory targets,
     uint256[] memory values,
     bytes[] memory calldatas,
@@ -413,4 +429,9 @@ interface IWonderGovernor is IERC165, IERC6372 {
     bytes memory params,
     bytes memory signature
   ) external returns (uint256 balance);
+
+  /**
+   * @notice Returns the types of proposals that are supported by the governor.
+   */
+  function proposalTypes() external view returns (uint8[] memory);
 }
diff --git a/solidity/interfaces/governance/utils/IWonderVotes.sol b/solidity/interfaces/governance/utils/IWonderVotes.sol
index 28459a3..1ecfbd1 100644
--- a/solidity/interfaces/governance/utils/IWonderVotes.sol
+++ b/solidity/interfaces/governance/utils/IWonderVotes.sol
@@ -56,4 +56,9 @@ interface IWonderVotes {
    * @dev Delegates votes from signer to `delegatee`.
    */
   function delegateBySig(address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s) external;
+
+  /**
+   * @dev Returns the `proposalTypes` supported.
+   */
+  function proposalTypes() external view returns (uint8[] memory);
 }