Standalone

Quadratic Public Goods

close button

Part II

Quadratic Funding

Beyond decision-making in governance, the quadratic relationships can also help democratize crowdfunding.

In crowdfunding systems, participants pool together funds to support interesting projects, where the voting power garnered by the project and the funds it receives share a 1:1 relationship. Similar to traditional voting mechanisms, crowdfunding systems can suffer from the problem of “kingmakers”.

Traditional Crowdfunding

A crowdfunding system can use quadratic voting to flatten its governance. Let us get back to our example, but instead of vote tokens, participants donate ETH to a crowdfunding contract.

Participant

ETH

Voting Power

1

100

10

2

9

3

3

9

3

4

4

2

5

4

2

Total

126

20

Imagine that the crowdfund involves two projects, and the first participant supports Project #1, while everyone else supports Project #2. Without any additional mechanism, this means that both projects should receive 63 ETH worth of funds.

Quadratic Funding

The system above does its job, but what if a crowdfund wants to further empower the majority? Then, quadratic funding can be considered.

In quadratic funding, funds are split into two buckets: a main fund and a subsidy fund. Then, fund distribution is calculated with the following equation:

fundi=vpiVPfundmain+ni2n2fundsubfund_i = {{vp_i}\over{VP}} \cdot fund_{main} + {{n_i^2}\over{\sum n^2}} \cdot fund_{sub}

  • fundifund_i : The funds allocated to project ii.

  • fundmainfund_{main}: Main fund

  • fundsubfund_{sub}: Subsidy fund

  • vpivp_i: The sum of voting power allocated to project ii.

  • VPVP:The total voting power.

  • nin_i: The number of unique contributors for project ii.

Let us take a look at our example one last time. Assuming that funds are split 1:1 between the main bucket and subsidy bucket, our fund distribution will look like this:

Project

No. of contributors

Main Fund

Subsidies

1

1

31.5

3.71

2

4

31.5

59.29

As we can see, under this mechanism, the majority of the funds will be allocated to Project #2, thanks to the fact that it has more unique contributors. With this, quadratic funding systems are more likely to back projects that have broader support from the masses.

Village Funding

Our village now wants a crowdfunding system that utilizes both quadratic voting and funding to support its grassroots projects. The system can be broken into three phases.

  1. Setup Phase.
    The village fund has some members. They are presented with several projects that are looking for funding (each represented by a uint256 id).
    Members can donate ETH to the fund and acquire voting power (nn wei = n\sqrt{n} voting power). Members can only donate once. Half of the donation is allocated to the subsidy fund, while the rest goes to the main fund.

  2. Voting Phase.
    The villagers will then vote, to express their preferences for specific projects. Each villager can vote multiple times, provided they have sufficient voting power.

  3. Distribution Phase.
    After the voting round ends, the deployer calculates fund allocation and distributes funds accordingly.

All votes must be made before the voting window closes.

VillageFunding.sol

In the contracts/ folder, you will find a contract called VillageFunding. The contract is responsible for the quadratic funding system and supports the following ABI.

Function

Description

constructor(...)

Initializes a new VillageFunding contract.

donate()

A payable function that villagers call to donate ETH to get a certain amount of vote power. The function should only be callable once per villager and before the voting round ends.

vote(uint256 projectId, uint256 votePower)

Villagers call this function to vote for their preferred project with a specified amount of vote power. Should revert if a villager tries to vote with 0 vote power.

distribute()

Distributes the funds using the quadratic formula. This can only be called by the deployer and after the voting round ends.

View Function

Description

getProjects()

Returns the project IDs.

getVotePower(address villager)

Returns the current vote power of a villager.

getContributions(uint256 projectId)

Returns the amount of contributed vote power and the number of unique contributors to a certain project.

getFunds(uint256 projectId)

Returns the final amount of funds for a certain project.

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

Your Task

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

Run tests in Questplay

Submit work in Questplay

Now a decision has been made, it’s time to figure out a way to fund the repairs…