Skip to content

Latest commit

 

History

History

solidity


Logo

Separated Powers

A role restricted governance protocol for DAOs.

Conceptual overview · What's included · Prerequisites · Getting Started



What's included

  • A fully functional proof-of-concept of the Separated Powers governance protocol.
  • Base electoral laws, that enable different ways to assign roles to accounts.
  • Base executive laws, that enable different ways to role restrict and call external functions.
  • Example constitutions and founders documents needed to initialise DAOs (still a work in progress).
  • Example implementations of DAOs building on the Separated Powers protocol (still a work in progress).
  • Extensive unit, integration, fuzz and invariant tests (still a work in progress).

How it works

The protocol closely mirrors {Governor.sol} and includes code derived from {AccessManager.sol}. Its code layout is inspired by the Hats protocol.

There are several key differences between {Powers.sol} and openZeppelin's {Governor.sol}.

  • Any DAO action needs to be encoded in role restricted external contracts, or laws, that follow the {ILaw.sol} interface.
  • Proposing, voting, cancelling and executing actions are role restricted along the target law that is called.
  • All DAO actions need to run through the governance protocol. Calls to laws that do not need a proposal vote to be executed, still need to be executed through {Powers::execute}.
  • The core protocol uses a non-weighted voting mechanism: one account has one vote.
  • The core protocol is minimalistic. Any complexity (timelock, delayed execution, guardian roles, weighted votes, staking, etc.) has to be integrated through laws.

Laws are role restricted contracts that provide the following functionalities:

  • Role restricting DAO actions
  • Transforming a lawCalldata input into an output of targets[], values[], calldatas[] to be executed by the Powers protocol.
  • Adding conditions to the execution of the law. Any conditional logic can be added to a law, but the standard implementation supports the following:
    • a vote quorum, threshold and period in case the law needs a proposal vote to pass before being executed.
    • a parent law that needs to be completed before the law can be executed.
    • a parent law that needs to NOT be completed before the law can be executed.
    • a vote delay: an amount of time in blocks that needs to have passed since the proposal vote ended before the law can be executed.
    • a minimum amount of blocks that need to have passed since the previous execution before the law can be executed again.

The combination of checks and execution logics allows for creating almost any type of governance infrastructure with a minimum number of laws. For example implementations of DAOs, see the implementations/daos folder.

Directory Structure

.
├── lib                                         # Installed dependencies. 
│    ├── forge-std                              # Forge  
│    └── openZeppelin-contracts                 # openZeppelin contracts  
|
├── script                                      # Deployment scripts  
│    └── DeployAlignedDao.s.sol              # Deploys the AgDao example implementation of Powers. Also deploys laws that make up AgDao's governance. 
|
├── src                                         # Protocol resources
│    ├── implementations                        # AgDao example resources.
│    │    ├── daos                              # 
│    │    │    ├── aligned-grants               # An example dao that revolves around setting and enforcing community values.  
│    │    │    │    ├── aligned-grants.sol      # The core DAO contract.  
│    │    │    │    ├── Constitution.sol        # The initial laws of the DAO.  
│    │    │    │    └── Founders.sol            # The initial founders and their role assignments. 
│    │    │    ├── arb-aips                     # An example DAO that is inspired by the constitution of Arbitrum DAO. 
│    │    │    │    ├── aligned-grants.sol      # The core DAO contract.  
│    │    │    │    ├── Constitution.sol        # The initial laws of the DAO.  
│    │    │    │    └── Founders.sol            # The initial founders and their role assignments. 
│    │    │    ├── core-dao                     # A minimalistic DAO that provides all core functionality for an initial DAO and that allows for future growth. 
│    │    │    │    └── ...                     # 
│    │    │    ├── opt-two-houses               # An example DAO inspired by the two houses governance process of the Optimism Collective.   
│    │    │    │    └── ...                     #  
│    │    │    ├── nouns-dao                    # An example DAO inspired by the NounsDAO governance structure.
│    │    │    │    └── ...                     # 
│    │    │    └── ...   
│    │    │     
│    │    └── laws                              # 
│    │         ├── electoral                    # See description of laws above. 
│    │         │    ├── DelegateSelect.sol      # Assign nominated accounts to a roleId through delegated votes. Uses OpenZeppelin's ERC20Votes.sol 
│    │         │    ├── DirectSelect.sol        # Assigns a single account to a roleId.  
│    │         │    ├── RandomlySelect.sol      # Assigns nominated accounts randomly to a roleId.  
│    │         │    └── TokensSelect.sol        # Assigns nominated accounts to a roleId on the amount of tokens held. 
│    │         └── executive   
│    │              ├── BespokeAction.sol       # Preset the contract and function that can be called, takes the (abi.encoded) input of the target function as its own input.  
│    │              ├── OpenAction.sol          # Takes targets[], values[] and calldatas[] as input, and gives them as output. 
│    │              ├── PresetAction.sol        # Gives a present targets[], values[] and calldatas[] as output, following a bool 'true' input. 
│    │              └── ProposalOnly.sol        # Outputs an empty array, following any input. 
│    │   
│    ├── interfaces                             # Interfaces of the protocol. 
│    │    ├── ILaw.sol                          # Interface for Law.sol.  Includes detailed description of functions. 
│    │    ├── IPowers.sol              # Interface for Powers.sol. Includes detailed description of functions. 
│    │    ├── LawErrors.sol                     # Law.sol errors. 
│    │    ├── PowersErrors.sol         # Powerserrors.   
│    │    ├── PowersEvents.sol         # Powersevents.   
│    │    └── PowersTypes.sol          # Powers data Types. 
│    │     
│    ├── Law.sol                                # The core Law (abstract) contract. It needs to be inherited by law implementations to function. 
│    └── Powers.sol                    # The core protocol. It needs to be inherited by DAO implementations. 
|
├── test                                        # Tests 
│    ├── fuzz                                   # Fuzz tests on example implementation (wip) 
│    │    └── SettingLaw_fuzz.t.t.sol           # 
│    ├── integration-dao                        # Integration tests. 
│    │    ├── AlignedGrants.t.sol               # Integration tests using the AlignedGrants DAO example. 
|    │    ├── ArbAips.t.sol                     # Integration tests using the Arbitrum AIPs example. 
│    │    └── ...                               # 
│    ├── mocks                                  # Mocks. 
│    │    ├── ConstitutionMock.sol              # A mock constitution to initiate laws in a new DAO. 
|    │    ├── DaoMock.sol                       # A mock DAO to be used in testing. 
|    │    ├── FoundersMock.sol                  # A mock founders document to be used in initiating a DAO.
│    │    └── ...                               # 
│    ├── unit                                   # Unit tests.  
│    │    ├── AlignedGrants.t.sol               # Integration tests using the AlignedGrants DAO example. 
|    │    ├── ArbAips.t.sol                     # Integration tests using the Arbitrum AIPs example. 
│    │    └── ...                               # 
│    └── TestSetup.t.sol                        # Dynamic setup of the various tests environments. 
│ 
├── .env.example                   
├── foundry.toml                   
├── LICENSE                                     # MIT license 
├── README.md                                   # This file
├── Makefile.md                                 # Commands to deploy contracts on mainnet sepolia and optimism sepolia.  
├── remappings.txt
└── ...

Prerequisites

Foundry

Getting Started

  1. Clone this repo locally and move to the solidity folder:
git clone https://github.com/7Cedars/separated-powers
cd separated-powers/solidity 
  1. Copy .env.example to .env and update the variables.
cp env.example .env
  1. run make. This will install all dependencies and run the tests.
make
  1. Run the tests without installing packages:
forge test 

Acknowledgements

Code is derived from OpenZeppelin's Governor.sol and AccessManager contracts, in addition to Haberdasher Labs Hats protocol.