# ShareClassGovernor

[Git Source](https://github.com/EntreDevelopers-Lab-Inc/Mezz-Companies/blob/f7a3e84e3dd5bb33c4bd7f77283983f9e8ba20b2/src/core/governance/share-class/ShareClassGovernor.sol)

**Inherits:** StartupGovernor, ProposalGovernor, IShareClassGovernor

**Author:** Daniel Yamagata

A governance contract that enables the execution of arbitrary transactions by a super-majority of a treasury's signers. However, the management of the treasury's board members requires a proposal proccess. A preferred share class can be allocated control of up to three board seats, while the common shares do not have a limit on the number of seats that can be allocated. Once allocated, seats cannot be decreased. For example, if Preferred Shares Class A is allocated control over 2 board seats, its allocation cannot be decreased to 1 board seat. The allocation of seats is done directly by the board of directors. However, the assignment of the allocated board seats is left to the proposal process.

*The following contract is heavily based on OZ's Governor Upgradeable, the Late Stage governor, and the Startup Governor The primary difference is proposals are fragmented by share classes. Therefore, direct inheritance from OZ's governor was not possible*

## State Variables

### BALLOT\_TYPEHASH

```solidity
bytes32 public constant BALLOT_TYPEHASH = _BALLOT_TYPEHASH;
```

### EXTENDED\_BALLOT\_TYPEHASH

```solidity
bytes32 public constant EXTENDED_BALLOT_TYPEHASH = _EXTENDED_BALLOT_TYPEHASH;
```

### ShareClassGovernorStorageLocation

```solidity
bytes32 private constant ShareClassGovernorStorageLocation =
    0x562a9c0a18060dac6c99104dbc22c3187c8da12ab6cbbc0788d567773f540f00;
```

## Functions

### \_getShareClassGovernorStorage

```solidity
function _getShareClassGovernorStorage() internal pure returns (ShareClassGovernorStorage storage $);
```

### constructor

```solidity
constructor(address _mezzHub, address _mezzMigrator) StartupGovernor(_mezzHub, _mezzMigrator);
```

### init

Intializes the Governor's state

```solidity
function init(address initTreasury, bytes memory)
    external
    virtual
    override(StartupGovernor, MezzGovernor, IMezzGovernor)
    initializer;
```

**Parameters**

| Name           | Type      | Description                                                   |
| -------------- | --------- | ------------------------------------------------------------- |
| `initTreasury` | `address` | The address of the Treasury that the Governor is in charge of |
| `<none>`       | `bytes`   |                                                               |

### \_\_ShareClassGovernor\_init

*The 'params' argument is maintained in case future versions require additional initialization parameters*

```solidity
function __ShareClassGovernor_init(address initTreasury, bytes memory) internal virtual onlyInitializing;
```

### state

Returns the state of a proposal associated with 'proposalId' as a ProposalState enum

```solidity
function state(uint256 proposalId)
    public
    view
    virtual
    override(ProposalGovernor, IProposalGovernor)
    returns (IModifiedGovernor.ProposalState);
```

### increaseBoardSeatsForShareClass

Increases the board seats for a given share class.&#x20;

*This function should be called with caution: the number of board seats for a given share class cannot be decreased. Only callable by governance, itself.*

```solidity
function increaseBoardSeatsForShareClass(address shareClass, uint256 increaseAmount)
    external
    virtual
    onlyMezzGovernance
    freezable;
```

**Parameters**

| Name             | Type      | Description                                               |
| ---------------- | --------- | --------------------------------------------------------- |
| `shareClass`     | `address` | The share class to increase the allocated board seats for |
| `increaseAmount` | `uint256` | The amount to increase the allocated board seats by       |

### proposeBoardMemberChange

Proposes a board member change for a given 'shareClass'.  The 'action' must be releated to adding a board member, removing a board member, or swapping a board member. &#x20;

*If the threshold is n, where n is the total number of board members, the new threshold will be n - 1.  Otherwise, the threshold of the treasury will not change.  The 'action' needs to be one that manages the owners of a team. These are defined in \_validateAction(...)*

```solidity
function proposeBoardMemberChange(address shareClass, bytes4 action, bytes memory params, string memory description)
    public
    virtual
    freezable
    returns (uint256);
```

**Parameters**

| Name          | Type      | Description                                          |
| ------------- | --------- | ---------------------------------------------------- |
| `shareClass`  | `address` | The share class to propose a board member change for |
| `action`      | `bytes4`  | The action for managing the treasury's owners        |
| `params`      | `bytes`   | The abi.encoded parameters for the given 'action'    |
| `description` | `string`  | The description of the proposal                      |

**Returns**

| Name     | Type      | Description     |
| -------- | --------- | --------------- |
| `<none>` | `uint256` | The proposal ID |

### cancelProposal

Cancels a pending proposal for 'shareClass'. &#x20;

*The caller must be the Proposal's proposer or the Mezz Hub's owner. The params are solely used to re-create the proposal's ID*

```solidity
function cancelProposal(address shareClass, bytes4 action, bytes memory params, bytes32 descriptionHash)
    public
    virtual
    freezable
    returns (uint256);
```

**Returns**

| Name     | Type      | Description     |
| -------- | --------- | --------------- |
| `<none>` | `uint256` | The proposal ID |

### executeProposal

Executes a proposal that succeeded.

*The caller is not access controlled. However, the proposal must have succeeded and cannot have been executed To succeed, the proposal's for-votes must have reached the quorum and must exceed its against votes. Unless the proposal, has a super-majority, which is 75% in this case, of the votes, it will only be executable once the votiing period has passed. The params and actions are re-validated. The 'target' will also be the treasury*

```solidity
function executeProposal(address shareClass, bytes4 action, bytes memory params, bytes32 descriptionHash)
    public
    virtual
    freezable
    returns (uint256);
```

### executeTx

*Same as StartupGovernor's executeTx(...) except with further data validation. Specifically, the management of the treasury's owners and its threshold are disabled. To change these, the proposal process is required.*

```solidity
function executeTx(address target, uint256 value, bytes memory data, bytes memory signatures, uint256 deadline)
    public
    virtual
    override(StartupGovernor, IStartupGovernor)
    freezable
    returns (bytes memory);
```

### changeTreasuryThreshold

Changes the Treasury's security threshold. Must be called by the governor, itself.

*Meant to be called via the Share Class Governor's executeTx()*

```solidity
function changeTreasuryThreshold(uint256 newTreasuryThreshold) public virtual onlyMezzGovernance freezable;
```

**Parameters**

| Name                   | Type      | Description                        |
| ---------------------- | --------- | ---------------------------------- |
| `newTreasuryThreshold` | `uint256` | The new threshold for the treasury |

### getVotes

Returns the number of votes for an 'account' given a 'shareClass' and 'timepoint'

```solidity
function getVotes(address account, address shareClass, uint256 timepoint) public view virtual returns (uint256);
```

### \_getVotes

*Non-adjusted for voting weight, since all proposals are separated by share classes*

```solidity
function _getVotes(address account, address shareClass, uint256 timepoint) internal view virtual returns (uint256);
```

### quorum

Returns the nominal quorum for a proposal given a 'shareClass' and 'timepoint'.  The nominal quorum is the minimum number of for-votes that a proposal needs to succeed It is based off the quorum percentage, which is set by governance, itself

```solidity
function quorum(address shareClass, uint256 timepoint) public view virtual returns (uint256);
```

### \_quorum

```solidity
function _quorum(address shareClass, uint256 timepoint) internal view virtual returns (uint256);
```

### proposalThreshold

Returns the nominal proposal threshold given a 'shareClass' The nominal proposal threshold is the minimum number of votes that the sender must have for a proposal to be created It is based off the proposal threshold percentage, which is set by governance, itself

```solidity
function proposalThreshold(address shareClass) public view virtual returns (uint256);
```

### \_proposalThreshold

```solidity
function _proposalThreshold(address shareClass) internal view virtual returns (uint256);
```

### superMajority

Returns the nominal super majority given a 'shareClass' and 'timepoint' A super majority in this context is 75% of the total votes for a share class. It a proposal has >75% of for-votes of the outstanding total votes, it is able to skip the voting period and be executed immediately

```solidity
function superMajority(address shareClass, uint256 timepoint) public view virtual returns (uint256);
```

### \_superMajority

```solidity
function _superMajority(address shareClass, uint256 timepoint) internal view virtual returns (uint256);
```

### \_castVote

*'params' are unused outside of event emission*

```solidity
function _castVote(uint256 proposalId, address account, uint8 support, string memory reason, bytes memory params)
    internal
    virtual
    override
    returns (uint256);
```

### hashProposal

Returns the hash of a proposal given a 'shareClass', 'action', 'params', and 'descriptionHash' All of the aforementioned argumetns can be found via events emitted by the Share Class Governor for existing proposals

```solidity
function hashProposal(address shareClass, bytes4 action, bytes memory params, bytes32 descriptionHash)
    public
    pure
    virtual
    returns (uint256);
```

**Returns**

| Name     | Type      | Description                  |
| -------- | --------- | ---------------------------- |
| `<none>` | `uint256` | The proposal ID as a uint256 |

### proposalSnapshot

Returns a proposal's snapshot, which is the time at which votes are counted. Any votes accumulated past this point are not counted towards the proposal

*The snapshot is set during the proposal's and is the sum of the voting delay and block.timestamp*

```solidity
function proposalSnapshot(uint256 proposalId) public view virtual returns (uint256);
```

**Parameters**

| Name         | Type      | Description            |
| ------------ | --------- | ---------------------- |
| `proposalId` | `uint256` | The ID of the proposal |

**Returns**

| Name     | Type      | Description                                                                    |
| -------- | --------- | ------------------------------------------------------------------------------ |
| `<none>` | `uint256` | The snapshot of the proposal, which is measured in seconds from the Unix epoch |

### proposalDeadline

Returns a proposal's deadline, which is the time at which the proposal can no longer be voted on

*The deadline is set during the proposal's creation and is the sum of the voting delay, voting period, and block.timestamp*

```solidity
function proposalDeadline(uint256 proposalId) public view virtual returns (uint256);
```

**Parameters**

| Name         | Type      | Description            |
| ------------ | --------- | ---------------------- |
| `proposalId` | `uint256` | The ID of the proposal |

**Returns**

| Name     | Type      | Description                                                                    |
| -------- | --------- | ------------------------------------------------------------------------------ |
| `<none>` | `uint256` | The deadline of the proposal, which is measured in seconds from the Unix epoch |

### proposalProposer

Returns the proposer of a proposal

```solidity
function proposalProposer(uint256 proposalId) public view virtual returns (address);
```

**Returns**

| Name     | Type      | Description                 |
| -------- | --------- | --------------------------- |
| `<none>` | `address` | The address of the proposer |

### proposalShareClass

Returns the share class associated with a proposal

```solidity
function proposalShareClass(uint256 proposalId) public view virtual returns (address);
```

**Parameters**

| Name         | Type      | Description            |
| ------------ | --------- | ---------------------- |
| `proposalId` | `uint256` | The ID of the proposal |

**Returns**

| Name     | Type      | Description                    |
| -------- | --------- | ------------------------------ |
| `<none>` | `address` | The address of the share class |

### allocatedBoardSeats

Returns the total number of allocated board seats across all share classes

*This does not include the board seats that have been set. For example, company Foo can have 5 allocated seats yet only 4 members set*

```solidity
function allocatedBoardSeats() public view returns (uint256);
```

### \_allocatedBoardSeats

```solidity
function _allocatedBoardSeats(address treasuryCache) internal view returns (uint256);
```

### getAllocatedSeatsByShareClass

Returns the number of allocated board seats for a given share class

```solidity
function getAllocatedSeatsByShareClass(address shareClass) public view returns (uint256);
```

### getBoardMembersByShareClass

Returns the board members that have been set by a given share class

```solidity
function getBoardMembersByShareClass(address shareClass) public view returns (address[] memory);
```

### coreId

Returns the coreId of the implementation as a bytes32

*The core ID is the keccak256 hash of the contract name followed by a version under the following syntax: "mezzanine.coreId.ContractName.vX" For example, the core ID of the 2nd version of the Treasury would be the following: keccak256(abi.encodePacked("mezzanine.coreId.Treasury.v2"))*

```solidity
function coreId() public pure virtual override(StartupGovernor, ProposalGovernor, ICredentialed) returns (bytes32);
```

### version

Returns the version of the implementation as a uint256

```solidity
function version() public pure virtual override(StartupGovernor, ProposalGovernor, ICredentialed) returns (uint256);
```

### COUNTING\_MODE

Returns a URL-encoded sequence of key-value pairs that each describe one aspect of voting

*Mezzanine Proposal Governors use votes in line with Bravo. The quorum also only counts for votes, like in Bravo. Reference: <https://docs.openzeppelin.com/contracts/4.x/api/governance#IGovernor-COUNTING\\_MODE-->*

```solidity
function COUNTING_MODE() public view virtual returns (string memory);
```

**Returns**

| Name     | Type     | Description                                 |
| -------- | -------- | ------------------------------------------- |
| `<none>` | `string` | The URL-encoded sequence of key-value pairs |

### \_updateBoardMembers

*Updates state. Also reconstructs the params for a given proposal such that it includes the Treasury's threshold, if needed*

```solidity
function _updateBoardMembers(address treasuryCache, address shareClass, bytes4 action, bytes memory params)
    internal
    virtual
    returns (bytes memory);
```

**Returns**

| Name     | Type    | Description                                       |
| -------- | ------- | ------------------------------------------------- |
| `<none>` | `bytes` | The calldata for the execution of the transaction |

### \_addOwnerForShareClass

*Adds 'ownerToAdd' to the board members for 'shareClass'*

```solidity
function _addOwnerForShareClass(address shareClass, address ownerToAdd) internal virtual;
```

### \_removeOwnerForShareClass

*Removes 'ownerToRemove' from the board members for 'shareClass'*

```solidity
function _removeOwnerForShareClass(address shareClass, address ownerToRemove) internal virtual;
```

### \_checkInvariants

*Reverts if the Treasury's total number of owners is greater than the allocated number of board seats*

```solidity
function _checkInvariants() internal view virtual;
```

### \_validateShareClass

*Reverts if 'shareClass' is not tracked by 'treasuryCache'*

```solidity
function _validateShareClass(address shareClass, address treasuryCache) internal view virtual;
```

### \_validateAction

*Validates that an action to manage the Treasury's owners. Unlike in TeamLogic's manageOwners(), the params for adding an owner and removing an owner do not include arguments to change the threshold for the treasury. This is to prevent a malicious proposal by a preferred share class that adds or switches an owner and then changes the threshold to 1. This would effectively enable them to control the treasury without the consent of the other signers. The threshold param is reconstructed in \_updateBoardMembers(...) to include the Treasury's current threshold. If the threshold is the same as the number of owners, then the threshold is decreased by 1*

```solidity
function _validateAction(bytes4 action, address shareClass, address treasuryCache, bytes memory params)
    internal
    view
    virtual;
```

### \_encodeStateBitmap

```solidity
function _encodeStateBitmap(IModifiedGovernor.ProposalState proposalState) internal pure virtual returns (bytes32);
```

### \_getTotalVotesAtTimepoint

*Returns the past total votes for the 'shareClass' at timepoint. The voting weight of the shares is ignored*

```solidity
function _getTotalVotesAtTimepoint(address shareClass, uint256 timepoint) internal view virtual returns (uint256);
```

### \_superMajorityReached

*Returns whether or not a super majority has been reached for a given proposal. Only for-votes are counted towards the super majority*

```solidity
function _superMajorityReached(uint256 proposalId) internal view virtual returns (bool);
```

**Returns**

| Name     | Type   | Description                                                                |
| -------- | ------ | -------------------------------------------------------------------------- |
| `<none>` | `bool` | True if the for-votes are greater than the super majority, false otherwise |

### \_quorumReached

*Returns whether or not the quourum has been reached for a given proposal. Only for-votes are counted towards the quorum*

```solidity
function _quorumReached(uint256 proposalId) internal view virtual returns (bool);
```

**Returns**

| Name     | Type   | Description                                                        |
| -------- | ------ | ------------------------------------------------------------------ |
| `<none>` | `bool` | True if the for votes are greater than the quorum, false otherwise |

### supportsInterface

*ERC165 support*

```solidity
function supportsInterface(bytes4 interfaceId)
    public
    view
    virtual
    override(ProposalGovernor, StartupGovernor, IERC165)
    returns (bool);
```

## Structs

### ShareClassGovernorStorage

```solidity
struct ShareClassGovernorStorage {
    mapping(address => EnumerableSet.AddressSet) _boardMembersByShareClass;
    mapping(address => uint256) _numberOfSeatsByShareClass;
    mapping(uint256 => DataTypes.ShareClassProposalCore) _proposals;
}
```
