How do non-blocking votings work in Thetta?

Copy-on-write trick for ERC20 token balances

Tony Kent
Thetta DAO Framework
3 min readJul 22, 2018

--

The main feature of any Decentralized Autonomous Organization (DAO) besides decentralization and automation is governance.

Governance is a process of continuous improvements. Governance is a process of producing decisions that affect the governed resource.

Governance is needed because one of the main goals of any organization is to adapt to changes. Good “adaptation” can lead to increasing wealth, increasing population, surviving the market, etc.

Example

By using Thetta DAO Framework one can use existing DAO templates or/and write their own on top of them. Here is an example of the real-world DAO template for a podcast — please see this blog post.

DevZenDAO has some custom (specific) actions defined:

Example file is here.

Thetta DAO Framework has a build-in governance subsystem that works effectively with the permission subsystem. During the bootrstrapping of the DevZenDAO template one can customize what governance mechanism each action should use (like DevZen_selectNextHost).

For example, one can set that an action requires 51% quadratic voting.

Different types of votings are currently available in Thetta:

  • ‘1 person = 1 vote’ voting
  • SimpleToken voting (N tokens = N votes)
  • Quadratic voting (N tokens = √N votes)
  • Liquid voting (N tokens = N votes, but with delegation support)

What is a non-blocking voting?

Once voting is selected, Thetta works like that:

  1. A user calls an action that requires voting
  2. New proposal is generated automatically
  3. New voting is created automatically and started
  4. The voting is held
  5. Participants vote, i.e. call vote() methods
  6. The voting ends
  7. The results are calculated.

Voting takes time. But what if a participant wants to transfer or sell their tokens during the voting? One can do that and it won’t affect voting results! All ‘votes’ are calculated as if one didn’t transfer any tokens at all.

So if one has 11 tokens when the voting begins, even if he sells 6 of them, he will still have 11 votes until voting is finished.

How Copy-on-write algorithm works?

  1. In order to preserve balances one should copy the balances mapping of the selected token when a voting begins
  2. But it’s not possible because the gas limit will be reached. Just imagine that the balances mapping contains thousands of entries
  3. Instead, one should use Copy-on-Write (CoW) algorithm to copy the mapping on the fly.

A simplified Copy-on-write algorithm works as follows:

  1. There is a ‘balancesAtTheStartOfVoting’ mapping that is empty
  2. HolderA has 100 tokens currently and HolderB has 20 tokens currently:
  1. Voting1 begins
  2. HolderA transfers to HolderB 30 tokens
  3. BalancesAtTheStartOfVoting[HolderA] is currently empty, so we store there 100
  4. BalancesAtTheStartOfVoting[HolderB] is currently empty, so we store there 20
  5. We update token balances just as usual
  6. Any exchange or wallet is still working as usual and show these balances:

Any voting can always read from the balancesAtTheStartOfVoting mapping and get:

As a result, token transfers during the voting won’t affect the voting power.

But how to clear the “balancesAtTheStartOfVoting” mapping for future use?

Imagine Voting1 is finished and now one wants to start new Voting2.
Current mapping state is as follows:

A naive approach is to use ‘for-each’ and to clear the balancesAtTheStartOfVoting mapping after Voting1 is finished. But the gas limit will be reached again, so this is not an option.

Instead, one can use an additional mapping and time labels to signal if balancesAtTheStartOfVoting is “dirty”:

  1. When voting is started the current time is stored to the votingStartTime
  2. When balancesAtTheStartOfVoting is updated the current time is stored to lastUpdateTime
  3. Once tokens are transferred one should check If the lastUpdateTime is bigger than balancesAtTheStartOfVoting then it is up-to-date, otherwise mapping is dirty and should be updated.

OpenZeppelin pull request #1100

Thetta added new feature request (pull request) to the OpenZeppelin library: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1100

If you have ideas/thought — please feel free to write any comments directly on the github. We are kindly asking you to support this PullRequest so the community will be able to use it through the OpenZeppelin library!

--

--