Skip to content

Governance Overview

Georgi Zlatarev edited this page Oct 6, 2021 · 9 revisions

This is just my current intepretation of the Polkadot governance system. The document will most likely change as my understanding evolves. I have drawn from the following resources:

Video Resources

  1. Governance on Polkadot by Bill Laboon
  2. Governance with FRAME
  3. Polkadot Decoded 2020: The Power of Polkadot’s On-Chain Governance & Treasury
  4. Gavin Wood - A Walkthrough of Polkadot's Governance

Blog Resources

  1. Polkadot Governance
  2. Kusama Governance
  3. Kusama Treasury

Wiki Resources

  1. Learn Governance
  2. Participate In Governance

Code

  1. Substrate Node Runtime
  2. Polkadot + Kusama Runtime

The high-level idea

The system wants to be governed by the majority of the stake in it. This is not a democractic 1 person 1 vote system. We have the concept of proposals that can be turned into a referenda and voted on in a stake weighted manner. After these referenda are passed by a majority of the stake, they will be enacted autonomously with a delay period. So we can see three distinct periods here:

  1. Launch Period - when a proposal is proposed and turned into a referendum.
  2. Voting Period - the actual voting on the referendum by all the token holders.
  3. Enactment Period - the period between the end of the voting and the actual exection. Necessary so stake holders can either prepare for the change or leave the system if they are not happy with it.

Now that we are familiar with the different periods let's go through the lifetime of a proposal.

Launch Period

We mentioned this is the period where a proposal gets turned into a referendum. First we need to establish there are 2 ways to generate proposals:

  1. Public Token Holders using the democracy pallet
  2. Council using a pallet_collective instance

In both cases first a pre-image hash of the proposal is created. Once we have that let's walk through each of them separately:

  1. Any public token holder can submit a pre-image hash as a proposal, which goes into the public proposal queue. Such proposals need to be seconded (with more stake) by other users during the launch period. There can be multiple proposals but ultimately only one, with the most backing, will be pushed to referendum at the end of the period.

  2. Council can submit their own proposals, aka external proposals, aka council motions. There are three types of external proposals:

    • democracy.externalPropose()
    • democracy.externalProposeMajority()
    • democracy.externalProposeDefault()

Once such motions are put to internal vote each councilor has one vote and there's a threshold that needs to be reached. If the threshold is reached the proposal will be moved to the external proposal queue where it will wait to be bumped to a referendum.

It's important to pause and mention that even though we have described two independent mechanisms to create proposals only 1 at a time will be pushed to be voted on as a referendum. The reason for having 1 referendum at a time is to avoid situations where we vote for 2 completely opposite actions and both passing. In order for things to be fair, the public token holders and council will rotate who gets to make the proposal each launch period.

Both types of proposals can be cancelled during this period by the Technical Committee.

Furthermore it is possible for the Technical Committee to fast track the launch period and table a referendum immediately. Works only for external proposals created by democracy.externalPropose() or democracy.externalProposeDefault().

Voting Period

At this point a referendum has been tabled either from the external proposal queue or the public proposal queue. Token holder need to make a decision by voting. They can either vote to pass the referendum with aye or reject the referendum with nay. No matter what, if 51% of the total stake votes either way, that will be executed.

In the case of public proposals, as well external proposals generated by democracy.externalPropose(), require a super-majority to be approved, which starts high but decreases as turnout increases. For example at 25% turnout it needs 66% ayes to pass. At 75% turnout it needs 52% ayes to pass. As turnout increases threshold decreases approaching simple-majority of 50% + 1.

In the case of external proposals generated by democracy.externalProposeDefault() require a super-majority to be rejected that decreases as turnout increases. In other words the threshold for approval starts low but increases as turnout increases. For example at 25% turnout it needs 34% ayes to pass, at 75% turnout needs 46% of ayes to pass. as turnout increases it becomes harder to pass approaching simple-majority of 50% + 1 of the turnout.

These above mechanisms are called Adaptive Quorum Biasing.

In the case of external proposals generated by democracy.externalProposeMajority() the threshold is a simple-majority of 50% + 1 of the turnout.

This period can be fast-tracked similarly to how the Launch Period could be fast tracked. This will work only for external proposals created by democracy.externalPropose() or democracy.externalProposeDefault(). A unanimous Technical Committee can make it instant or if not unanimous but in agreement, they can drastically reduce it.

Finally referendums can be canceled during the voting period by the Council submitting and passing a motion. However referendums can only be cancelled once, and then can then be resubmitted.

Enactment Period

At this point the system has autonomy and simply executes the passed referendum using pallet_scheduler. As we mentioned before the reason for the delay is for stake holders to either prepare for the change or leave the system if they are not ok with it.

This period can be fast-tracked similarly to how the Launch Period and Voting Period could be fast tracked. A unanimous Technical Committee can make it instant or if not unanimous but in agreement, then can drastically reduce it. Again this will work only for external proposals created by democracy.externalPropose() or democracy.externalProposeDefault().