Quadratic Funding (QF) is a method to make funding more democratic, in any system where there is a group of people that are interested in a set of proposals, and they all have varying amounts of voting power/money that they are contributing. It makes it more democratic by biasing the funding towards proposals that have a higher number of supporters for it, instead of simply summing the voting power/money each proposal gets and letting that decide, because otherwise one wealthy/influential person could dictate where most of the funding was distributed, instead of the voice of the majority.

QF can have different shapes depending on the who, what, when, where, and why. For example, on Gitcoin, they have funding rounds where the public can donate to certain projects, and then there is a separate pool of money coming from sponsors like the Ethereum Foundation, which gets distributed to the projects based on how the public donated to these projects. The public’s donations can be seen as votes, where the more votes a project received, the more matching it got from the sponsor pool. But crucially, the function that determines how much matching a project received is biased towards projects that had a higher number of individual donors to it, and not simply the amount of money (voting power) it got, which could come from a single person.

In the case of designing Ren’s QF rounds, we already have every Darknode Operator (DNO) providing to the Community Fund, and we already have established DNOs as those with voting power in RIP-000-004, where the voting power also nicely tracks how much a DNO has been contributing to the Community Fund.

So we can simply let DNOs distribute their voting power towards the proposals they support in a Funding Round, and have that dictate how much funding the different proposals receive (with some caveats)! Very elegant.

Below is a proposal for how Quadratic Funding could take place at Ren, with concrete numbers to provide some intuition for how it could turn out in reality. The numbers are made up but ‘realistic’ and designed to be educational. I am also including how it would look like if people were voting randomly, as well as how it would look like if there were a few very popular proposals that most people voted for. And for both of those cases I’ll be showing how the amount of capital in the funding pool would influence the funding for the proposals.


So how does the QF algorithm work:

The QF algorithm works very simply like this:

What you are left with then is a number you can convert to a percentage that it should get from the funding pool.

Here is a simplified example:

##   vote voter proposal
## 1    5     1        1
## 2    3     1        2
## 3    2     1        3
## 4    6     2        1
## 5   10     2        1
## 6    4     3        1
## 7   36     3        3

Take the square root:

example$vote <- sqrt(example$vote) # take the square root of every vote
##       vote voter proposal
## 1 2.236068     1        1
## 2 1.732051     1        2
## 3 1.414214     1        3
## 4 2.449490     2        1
## 5 3.162278     2        1
## 6 2.000000     3        1
## 7 6.000000     3        3

Combine (sum) the votes for each proposal:

##   proposal combinedVotingPower
## 1        1            9.847836
## 2        2            1.732051
## 3        3            7.414214

Square out the values again:

example$combinedVotingPower <- (example$combinedVotingPower)^2 # square the values
##   proposal combinedVotingPower
## 1        1           96.979874
## 2        2            3.000001
## 3        3           54.970569

Then you can convert these to percentages:

##   proposal combinedVotingPower
## 1        1          0.62587671
## 2        2          0.01936103
## 3        3          0.35476226

You can also compare what would happen if you simply summed the votes, so ignoring QF, and then converting to percentages:

##   proposal combinedVotingPower simpleVotingInstead
## 1        1          0.62587671          0.37878788
## 2        2          0.01936103          0.04545455
## 3        3          0.35476226          0.57575758

Compared to simply summing votes, QF gave proposal 1 more weight because there were more people voting for it, and it made proposal 2 less interesting as only one person voted for it while the others had multiple. And proposal 3 had a whale voting for it and would get most funding in a simple funding round, but with QF proposal 1 got more.


So let’s imagine some realistic proposals:

id <- 0:10
target <- c(0, 500, 2000, 3500, 4400, 5000, 9000, 10000, 12000, 18000, 25000) # in USD
min <- target/2
max <- target*2
proposals <- data.frame(id, target, min, max)
proposals
##    id target   min   max
## 1   0      0     0     0
## 2   1    500   250  1000
## 3   2   2000  1000  4000
## 4   3   3500  1750  7000
## 5   4   4400  2200  8800
## 6   5   5000  2500 10000
## 7   6   9000  4500 18000
## 8   7  10000  5000 20000
## 9   8  12000  6000 24000
## 10  9  18000  9000 36000
## 11 10  25000 12500 50000

The first thing you might notice is why are there 11 proposals, not 10? This is because we need a way for DNOs to vote ‘No’, as in ‘I do not want that funding should be going to any of the proposals in this round’.

Second, you might notice that there is something called a target, and a min and a max as well. This is a design decision we are proposing, that makes sure that money is not wasted on a proposal that is unable to lift of the ground, as most projects need a certain amount of funding to be viable. The max is for putting a ceiling on the max amount we can give to a proposal, so we are not overspending on something that only needs a certain amount of funding to work as intended. Here specifically we’ve chosen a range that is half of the target, to twice the target. It means that any proposer will need to provide a target number in the proposal.

You might also notice that targets are not specified in BTC. For the voting outcome not to shift throughout the voting period simply because of price volatility, we also propose that targets are specified in USD and that the Community Fund exchanges some of its assets into a stablecoin like DAI before the Funding Round, and distribute the grants in that stablecoin.


Imagine some voters with their voting powers:

nVoters <- 100
votingPower <- rbeta(nVoters, 1, 4)*40 # random voting power values that are similar to current DNO voting powers
votingPower
##   [1] 11.381434254 13.109636428  0.007316686  6.446772000 14.787482442
##   [6]  4.578120316  6.906559577 11.437504536  3.342890778 13.195024792
##  [11]  3.289363040 15.405751659  4.895058691  3.354535938  1.104670929
##  [16]  5.226015058  8.553705977  2.339464558  2.728144939 29.228919039
##  [21] 18.485324714  2.692869923 19.264901024  0.304212030  3.095006243
##  [26]  6.773281315  1.982136306 21.735177219  3.997641143  8.551554346
##  [31]  7.333546587 11.377955306 13.844816869  8.004629019 12.568894072
##  [36]  0.330210848 18.747441552  4.382342126  0.388400826  0.603477215
##  [41] 14.842017250  3.983426272  0.520764064  6.598891343  0.957389998
##  [46]  3.192134176 16.373225807  9.813951536  6.729539252  4.138074338
##  [51]  3.437872530 20.990387929  6.835689193  1.538328327  0.142624239
##  [56] 19.441895297  6.617161300 15.238640596  3.366923640 21.051880536
##  [61]  7.774297272 12.415112232  5.062479396  7.956076543 13.767410726
##  [66]  6.152018468  8.132727189  7.863869698  0.848843178  6.860341031
##  [71]  3.236693887  7.860096652  3.413806575  6.441228732  6.977800437
##  [76] 26.854311139 11.259198287  0.104366569 18.713945789  5.642455440
##  [81] 12.235018527  3.488482176 16.508668610  4.476638383  3.726026650
##  [86] 18.288356195  1.167020704  0.847463896  3.524267583 10.630716516
##  [91]  4.147342959 10.439263424  3.893990809 17.256288463  8.510819039
##  [96] 16.080248619 13.625663496  8.226829998  5.111318110  9.102187500

Now, since we’ll be using the Snapshot mechanism for voting, and specifically the Scattershot fork as it allows for multiple-choice voting, the way people assign voting power is clicking on the proposals as many times as you want to divide up your voting power:

You can test yourself here: https://scattershot.page/#/ren-project.eth/proposal/QmXFZaWC8uBUMXNTgGyib7YL6QyDWBSVWoTV62kPB6z1DP

So let’s start with the case where people would just be voting randomly:

(if you want to see the code for this, check out the markdown file)

##    voterID votingIDPower voteForProp votingPowerFrac
## 1        1  11.381434254          10     2.845358563
## 2        1  11.381434254           3     2.845358563
## 3        1  11.381434254           4     2.845358563
## 4        1  11.381434254          11     2.845358563
## 5        2  13.109636428           8     6.554818214
## 6        2  13.109636428          10     6.554818214
## 7        3   0.007316686           9     0.002438895
## 8        3   0.007316686           5     0.002438895
## 9        3   0.007316686           9     0.002438895
## 10       4   6.446772000           8     1.289354400

##     voterID votingIDPower voteForProp votingPowerFrac
## 392      97     13.625663          10       3.4064159
## 393      97     13.625663          10       3.4064159
## 394      98      8.226830           2       8.2268300
## 395      99      5.111318           4       0.8518864
## 396      99      5.111318           6       0.8518864
## 397      99      5.111318           3       0.8518864
## 398      99      5.111318           2       0.8518864
## 399      99      5.111318          11       0.8518864
## 400      99      5.111318           8       0.8518864
## 401     100      9.102188           1       9.1021875

As you see there, we have a bunch of rows of votes on different proposals with the voting power amount, and this is similar to the data anyone could grab from Scattershot after the vote is complete.


After doing the QF process, here are the results for our 10 proposals, including the percentages:

##    id target   min   max      QVP fundPercent
## 1   0      0     0     0 1349.016  0.06592356
## 2   1    500   250  1000 2189.864  0.10701405
## 3   2   2000  1000  4000 1615.918  0.07896650
## 4   3   3500  1750  7000 2155.678  0.10534347
## 5   4   4400  2200  8800 1072.804  0.05242566
## 6   5   5000  2500 10000 2212.172  0.10810421
## 7   6   9000  4500 18000 2588.826  0.12651050
## 8   7  10000  5000 20000 2262.595  0.11056827
## 9   8  12000  6000 24000 1234.810  0.06034255
## 10  9  18000  9000 36000 2306.595  0.11271848
## 11 10  25000 12500 50000 1475.053  0.07208275

With those funding percentages per proposal, we can now see how much of the funding pool has been assigned to each proposal. But the proposal’s target will affect if it actually gets funded, and how much money is in the funding pool. If there is little money in the pool, the grant might not get passed the ‘min’ value, and in that case it won’t get funding.

So imagine we have 3 different scenarios:

##    id target   min   max      QVP fundPercent poorPoolAlloc poorPoolPASS
## 1   0      0     0     0 1349.016  0.06592356      1964.522         TRUE
## 2   1    500   250  1000 2189.864  0.10701405      3189.019         TRUE
## 3   2   2000  1000  4000 1615.918  0.07896650      2353.202         TRUE
## 4   3   3500  1750  7000 2155.678  0.10534347      3139.235         TRUE
## 5   4   4400  2200  8800 1072.804  0.05242566      1562.285        FALSE
## 6   5   5000  2500 10000 2212.172  0.10810421      3221.506         TRUE
## 7   6   9000  4500 18000 2588.826  0.12651050      3770.013        FALSE
## 8   7  10000  5000 20000 2262.595  0.11056827      3294.935        FALSE
## 9   8  12000  6000 24000 1234.810  0.06034255      1798.208        FALSE
## 10  9  18000  9000 36000 2306.595  0.11271848      3359.011        FALSE
## 11 10  25000 12500 50000 1475.053  0.07208275      2148.066        FALSE

If there isn’t much money in the pool, and people vote randomly, likely only the proposals asking for small grants will get funded.

##    id target   min   max      QVP fundPercent matchPoolAlloc matchPoolPASS
## 1   0      0     0     0 1349.016  0.06592356       5893.567          TRUE
## 2   1    500   250  1000 2189.864  0.10701405       9567.056          TRUE
## 3   2   2000  1000  4000 1615.918  0.07896650       7059.605          TRUE
## 4   3   3500  1750  7000 2155.678  0.10534347       9417.706          TRUE
## 5   4   4400  2200  8800 1072.804  0.05242566       4686.854          TRUE
## 6   5   5000  2500 10000 2212.172  0.10810421       9664.517          TRUE
## 7   6   9000  4500 18000 2588.826  0.12651050      11310.038          TRUE
## 8   7  10000  5000 20000 2262.595  0.11056827       9884.804          TRUE
## 9   8  12000  6000 24000 1234.810  0.06034255       5394.624         FALSE
## 10  9  18000  9000 36000 2306.595  0.11271848      10077.032          TRUE
## 11 10  25000 12500 50000 1475.053  0.07208275       6444.198         FALSE

If there is matched money in the pool, and people vote randomly, the proposals asking for a lot of money still might not pass their min ask, and then won’t get funded.

##    id target   min   max      QVP fundPercent richPoolAlloc richPoolPASS
## 1   0      0     0     0 1349.016  0.06592356      17680.70         TRUE
## 2   1    500   250  1000 2189.864  0.10701405      28701.17         TRUE
## 3   2   2000  1000  4000 1615.918  0.07896650      21178.82         TRUE
## 4   3   3500  1750  7000 2155.678  0.10534347      28253.12         TRUE
## 5   4   4400  2200  8800 1072.804  0.05242566      14060.56         TRUE
## 6   5   5000  2500 10000 2212.172  0.10810421      28993.55         TRUE
## 7   6   9000  4500 18000 2588.826  0.12651050      33930.11         TRUE
## 8   7  10000  5000 20000 2262.595  0.11056827      29654.41         TRUE
## 9   8  12000  6000 24000 1234.810  0.06034255      16183.87         TRUE
## 10  9  18000  9000 36000 2306.595  0.11271848      30231.10         TRUE
## 11 10  25000 12500 50000 1475.053  0.07208275      19332.59         TRUE

If there is a lot of money in the pool, and people vote randomly, it’s likely that all proposals will be funded.


Conclusion

As we have seen, QF goes for the popular votes, and inhibits influence from whales, and ignores proposals that only one of a few people vote for.

This is a point to consider. If there are a lot of competing proposals, and they ask for a lot of funding relative to what the Community Ecosystem Fund has allocated to the funding round, there is a chance the proposals will inhibit each others in the competition, and might mean none of them get any. But in a rich environment, popular proposals are likely to get funded.

A remaining question I still have is:

Would appreciate any feedback on this question and the whole model overall, and critiques if you have any!