Standalone

Quadratic Public Goods

close button

Part I

Quadratic Voting

Download quests in Questplay

In the majority of DAOs, voting power is distributed among voters through tokens. These tokens can be distributed through airdrops, ICOs, or exchanged on the open market.

Traditional Voting

In conventional governance systems, 1 token = 1 vote, and each token has equal weight. However, this can lead to the asymmetrical distribution of voting power, and results often being determined by individual whales.

Let us look at an example. Imagine that we have a DAO with 5 members, each holding some governance tokens:

Participant

Vote Tokens

Vote Power

1

100

100

2

9

9

3

9

9

4

4

4

5

4

4

In the case of a 1 token = 1 vote system, the first participant alone could decide the result of any voting process. This means that there is no real incentive for other participants to vote for their preferred option.

Alternatively, a DAO can adopt a system where 1 participant = 1 vote. However, this system has no incentive for users to acquire more tokens. For example, if a DAO distributes vote tokens to contributors who participate in building the DAO, there is no incentive for builders to contribute more than once:

Participant

Vote Power

1

1

2

1

3

1

4

1

5

1

Quadratic Voting

One solution that aims to encourage flatter democracies, while maintaining a token economy, is quadratic voting. Unlike the previous two mechanisms, tokens and vote power in this system share a quadratic relationship, where nn tokens = n\sqrt{n} votes.

This means that for any one participant, the cost of allocating additional votes to a particular option increases quadratically.

Using quadratic voting in our example DAO would look something like this:

Participant

Vote Tokens

Vote Power

1

100

10

2

9

3

3

9

3

4

4

2

5

4

2

As we can see, the first participant still dominates the decision-making process. However, if the others collaborate, they can potentially tie a vote despite having a fifth of all vote tokens.

A quadratically increasing cost also encourages participants to distribute their votes between proposals and signal their alternative preferences, while still placing emphasis on their most preferred option.

Village Governance

A small village wants your help to build a quadratic voting system for them. The system can be broken into three phases.

  1. Setup Phase.
    The village DAO has some members, each holding some governance tokens. The DAO is presented with several proposals (each represented by a uint256 id), and has to vote on a winning proposal.

  2. Voting Phase.
    The villagers will then vote, to signal their preferred proposal. Each villager can only vote once per round and can distribute their vote tokens into different active proposals.

  3. Counting Phase.
    After the voting round ends, the deployer will count the votes for each proposal. The proposal with the most votes will be declared the winner.
    However, if two or more proposals tie, then a new voting round is initiated. In the new round, villagers can only vote for the previously tied proposals.

All votes must be made before the voting round ends.

VillagerVoting.sol

In the contracts/ folder, you will find a contract called VillagerVoting, that needs to implement the following ABI.

Function

Description

constructor(...)

Initializes a new VillagerVoting contract.

vote(uint256[] proposalIds, uint256[] amounts)

Villagers call this function to vote for their preferred proposals with the corresponding amounts of vote tokens. Proposals must be active and the villager must have a sufficient amount of tokens. Each villager can only vote once per round and before the voting round ends.

countVotes()

Decides the winner or start a new voting round if there is a tie. This can only be called by the deployer and when the voting round ends.

View Function

Description

getActiveProposals()

Returns the proposal IDs that users can vote on in the current round. Returns an empty array if the winner has been decided.

getRoundInfo()

Returns information about the current round: the winner, the current round, and the end time.

balanceOf(address villager)

Returns the amount of tokens held by the given villager.

getproposalVotePower(uint256 proposalId, uint256 round)

Returns the sum of the vote power contributed to a proposal with the given ID at the given round.

The detailed interface can be found in interfaces/IVillagerVoting.sol.

Your Task

Implement all the functions listed above in contracts/VillagerVoting.sol.

Run tests in Questplay

Set up a fair system for the townsfolk to vote on which building they repair first…