class: center, middle, inverse, title-slide .title[ # Quadratic Funding in the Wild
A Post-Round Analysis of Gitcoin’s
Fund Matching Mechanism
] .author[ ### Omni Analytics Group ] --- ## Introduction Quadratic Funding is defined by wtfisqf.com as “the mathematically optimal way to fund public goods in a democratic community.” The Gitcoin team further refers to it as the Wisdom of the Crowds. Gitcoin allocates donations from larger donators based on a Quadratic Funding formula, weighting grants which receive many small donations over those that receive a few large ones. Formulaically, Quadratic Funding can be described in such a manner that the amount received by a given is equal to the square of the sum of the square roots of contributions received, multiplied by some constant factor (Buterin, Hitzig, Weyl, 2018). This can be quantified in the formula below: <img src="images/im1.png" width="1288" style="display: block; margin: auto;" /> --- ## Optimality While the core details of this mechanism are not the focus of this article, Quadratic Funding has been shown to be the optimal allocation method, despite the fact that very little research has been conducted on how matching allocations based on this method behave when implemented and applied in a true, real-world environment. In this case study, we will give a visual description of the capital allocation resulting from Gitcoin’s implementation of the Quadratic Funding mechanism, using data from Gitcoin Grants Round 14. --- ## Data We’ve pulled Round 14 Gitcoin Grants data. The data contains the following variables: - *grant_id* – Grant name - *sub_round_slug* – Eco-system Round Name - *clr_match* – Total Funds Available for that Round - *round_num* – Round ID - *grant_title* – Grant Title - *match_amount* – Total Match from that Round - *num_contributions* – Number of Contributors to the Grant - *num_unique_contributors* – Unique Contributors to the Grant - *crowdfund_amount_contributions_usd* – Funding Amount in USD - *total_usd* – Total Amount in USD --- ## Data Preview A previous of the first 15 rows of this data is given in the image below: <img src="images/im2.png" width="2731" style="display: block; margin: auto;" /> --- ## Reading the Data in R The code for loading the data here is quite simple, and reproduced below: ```r library(tidyverse) library(ggrepel) library(ggthemes) library(omnitheme) raw_gr14 <- read_csv("data/GR14 Final Results - 6 29 2022.csv") raw_gr14 %>% select(grant_id, sub_round_slug, clr_match, round_num, grant_title, match_amount, num_contributions, num_unique_contributors, crowdfund_amount_contributions_usd, total_usd) %>% head(n = 20) %>% kable ``` --- <table class="table" style="font-size: 8px; margin-left: auto; margin-right: auto;"> <thead> <tr> <th style="text-align:right;"> grant_id </th> <th style="text-align:left;"> sub_round_slug </th> <th style="text-align:right;"> clr_match </th> <th style="text-align:right;"> round_num </th> <th style="text-align:left;"> grant_title </th> <th style="text-align:right;"> match_amount </th> <th style="text-align:right;"> num_contributions </th> <th style="text-align:right;"> num_unique_contributors </th> <th style="text-align:right;"> crowdfund_amount_contributions_usd </th> <th style="text-align:right;"> total_usd </th> </tr> </thead> <tbody> <tr> <td style="text-align:right;"> 5688 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> JediSwap: First AMM on StarkNet ebling instantaneous gasless swapping of assets </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 36723 </td> <td style="text-align:right;"> 27847 </td> <td style="text-align:right;"> 113862.40 </td> <td style="text-align:right;"> 138862.40 </td> </tr> <tr> <td style="text-align:right;"> 5007 </td> <td style="text-align:left;"> gr14-web3social </td> <td style="text-align:right;"> 1500 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Lenster </td> <td style="text-align:right;"> 36500 </td> <td style="text-align:right;"> 31821 </td> <td style="text-align:right;"> 24180 </td> <td style="text-align:right;"> 87377.30 </td> <td style="text-align:right;"> 123877.30 </td> </tr> <tr> <td style="text-align:right;"> 5007 </td> <td style="text-align:left;"> gr14-polygon </td> <td style="text-align:right;"> 10000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Lenster </td> <td style="text-align:right;"> 36500 </td> <td style="text-align:right;"> 31821 </td> <td style="text-align:right;"> 24180 </td> <td style="text-align:right;"> 87377.30 </td> <td style="text-align:right;"> 123877.30 </td> </tr> <tr> <td style="text-align:right;"> 5007 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Lenster </td> <td style="text-align:right;"> 36500 </td> <td style="text-align:right;"> 31821 </td> <td style="text-align:right;"> 24180 </td> <td style="text-align:right;"> 87377.30 </td> <td style="text-align:right;"> 123877.30 </td> </tr> <tr> <td style="text-align:right;"> 4268 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> zkRollups.xyz </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 25100 </td> <td style="text-align:right;"> 19687 </td> <td style="text-align:right;"> 87054.18 </td> <td style="text-align:right;"> 112054.20 </td> </tr> <tr> <td style="text-align:right;"> 37 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Connext Network </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 21880 </td> <td style="text-align:right;"> 17966 </td> <td style="text-align:right;"> 58739.96 </td> <td style="text-align:right;"> 83739.96 </td> </tr> <tr> <td style="text-align:right;"> 3591 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> DefiLlama </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 18808 </td> <td style="text-align:right;"> 14775 </td> <td style="text-align:right;"> 53617.34 </td> <td style="text-align:right;"> 78617.34 </td> </tr> <tr> <td style="text-align:right;"> 5288 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Tally Ho! - Open Source and Community Owned Wallet </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 16537 </td> <td style="text-align:right;"> 13471 </td> <td style="text-align:right;"> 41804.06 </td> <td style="text-align:right;"> 66804.06 </td> </tr> <tr> <td style="text-align:right;"> 4665 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Via Protocol [Web3 Mastercard] - Best UX among any-to-any cross-chain swaps </td> <td style="text-align:right;"> 50000 </td> <td style="text-align:right;"> 15347 </td> <td style="text-align:right;"> 12312 </td> <td style="text-align:right;"> 35032.35 </td> <td style="text-align:right;"> 85032.35 </td> </tr> <tr> <td style="text-align:right;"> 4665 </td> <td style="text-align:left;"> gr14-aurora </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Via Protocol [Web3 Mastercard] - Best UX among any-to-any cross-chain swaps </td> <td style="text-align:right;"> 50000 </td> <td style="text-align:right;"> 15347 </td> <td style="text-align:right;"> 12312 </td> <td style="text-align:right;"> 35032.35 </td> <td style="text-align:right;"> 85032.35 </td> </tr> <tr> <td style="text-align:right;"> 821 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Umbra: Privacy Preserving Stealth Payments </td> <td style="text-align:right;"> 35000 </td> <td style="text-align:right;"> 14886 </td> <td style="text-align:right;"> 12189 </td> <td style="text-align:right;"> 29929.44 </td> <td style="text-align:right;"> 64929.44 </td> </tr> <tr> <td style="text-align:right;"> 821 </td> <td style="text-align:left;"> gr14-polygon </td> <td style="text-align:right;"> 10000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Umbra: Privacy Preserving Stealth Payments </td> <td style="text-align:right;"> 35000 </td> <td style="text-align:right;"> 14886 </td> <td style="text-align:right;"> 12189 </td> <td style="text-align:right;"> 29929.44 </td> <td style="text-align:right;"> 64929.44 </td> </tr> <tr> <td style="text-align:right;"> 5051 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> DeFrag </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 11775 </td> <td style="text-align:right;"> 9578 </td> <td style="text-align:right;"> 28274.18 </td> <td style="text-align:right;"> 53274.18 </td> </tr> <tr> <td style="text-align:right;"> 4858 </td> <td style="text-align:left;"> gr14-zktech </td> <td style="text-align:right;"> 14500 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Zk Block - Boilerplate & Tools to Bootstrap Zk Dapps </td> <td style="text-align:right;"> 39500 </td> <td style="text-align:right;"> 10004 </td> <td style="text-align:right;"> 8539 </td> <td style="text-align:right;"> 22782.21 </td> <td style="text-align:right;"> 62282.21 </td> </tr> <tr> <td style="text-align:right;"> 4858 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Zk Block - Boilerplate & Tools to Bootstrap Zk Dapps </td> <td style="text-align:right;"> 39500 </td> <td style="text-align:right;"> 10004 </td> <td style="text-align:right;"> 8539 </td> <td style="text-align:right;"> 22782.21 </td> <td style="text-align:right;"> 62282.21 </td> </tr> <tr> <td style="text-align:right;"> 4830 </td> <td style="text-align:left;"> gr14-polygon </td> <td style="text-align:right;"> 10000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Punk Domains (Domains for DAOs) </td> <td style="text-align:right;"> 35000 </td> <td style="text-align:right;"> 9508 </td> <td style="text-align:right;"> 8293 </td> <td style="text-align:right;"> 15804.94 </td> <td style="text-align:right;"> 50804.94 </td> </tr> <tr> <td style="text-align:right;"> 4830 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Punk Domains (Domains for DAOs) </td> <td style="text-align:right;"> 35000 </td> <td style="text-align:right;"> 9508 </td> <td style="text-align:right;"> 8293 </td> <td style="text-align:right;"> 15804.94 </td> <td style="text-align:right;"> 50804.94 </td> </tr> <tr> <td style="text-align:right;"> 4019 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> RainbowDAO Protocol </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 9109 </td> <td style="text-align:right;"> 7742 </td> <td style="text-align:right;"> 17032.73 </td> <td style="text-align:right;"> 42032.73 </td> </tr> <tr> <td style="text-align:right;"> 25 </td> <td style="text-align:left;"> gr14-gitcoin-main </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Lighthouse: Ethereum Consensus Client </td> <td style="text-align:right;"> 75000 </td> <td style="text-align:right;"> 8293 </td> <td style="text-align:right;"> 6836 </td> <td style="text-align:right;"> 22821.97 </td> <td style="text-align:right;"> 97821.97 </td> </tr> <tr> <td style="text-align:right;"> 25 </td> <td style="text-align:left;"> gr14-eth-infra </td> <td style="text-align:right;"> 50000 </td> <td style="text-align:right;"> 14 </td> <td style="text-align:left;"> Lighthouse: Ethereum Consensus Client </td> <td style="text-align:right;"> 75000 </td> <td style="text-align:right;"> 8293 </td> <td style="text-align:right;"> 6836 </td> <td style="text-align:right;"> 22821.97 </td> <td style="text-align:right;"> 97821.97 </td> </tr> </tbody> </table> --- ## Variable Derivation The next step was to derive some important statistics based on the available data above. Specifically, we derive the following variables: - **Average Contribution Amount per Unique Contributor** – This value represents a ratio of the overall contributions, divided by the number of unique contributors, to roughly estimate the per-unique-contributor contribution value for each grant. - **Min-Max Scaled Number of Unique Contributors** – We apply a min-max scaling routine, subtracting the minimum value across all grants and dividing by the range, in order to scale the number of unique contributors to a range where 0 represents the grant with the fewest number, and 1 represents the grant with the largest number. - **Min-Max Scaled Average Contribution Amount per Unique Contributor** – The same procedure from above is applied, but to the first derived variable. In this instance, 0 represents the grant with the lowest average contribution amount per unique contributor, while 1 represents the grant with the highest. - **Equal Weight Score** – We derive this equal weight score by the two above derived variables, taking the Min-Max Scaled Number of Unique Contributors and adding the Min-Max Scaled Average Contribution Amount per Unique Contributor, which yields a variable that ranges from 0 (lowest on both of the derived metrics) to 2 (highest on both). --- ## Data Transformation The last step is to produce a tall or long version of this dataset, suitable for plotting using standard analysis tools such as R and ggplot2. The tall version eschews the one-row-per-grant format of the previous data and instead produces one row per grant and variable combination, across the variables of interest. In the following slides, we walk through the basic `dplyr` routines to perform these data transformations, and show a preview of the resulting dataset. --- ## Variable Derivation Code We use some simple dplyr transformations in order to produce these and rename some variables to help with analysis later on: ```r processed_gr14 <- raw_gr14 %>% rename(`Unique Contributors` = num_unique_contributors, `Crowdfunded Contributions ($)` = crowdfund_amount_contributions_usd, `Avg $ Per Contributor` = avg_contramt_per_ucontr, `Equal Weight Score` = eql_weight_score, `Round Matching Funds ($)` = clr_match) %>% gather(key = Variable, value = Value, `Unique Contributors`, `Crowdfunded Contributions ($)`, `Avg $ Per Contributor`, `Equal Weight Score`) %>% mutate(Variable = factor(Variable, levels = c("Unique Contributors", "Crowdfunded Contributions ($)", "Avg $ Per Contributor", "Equal Weight Score")), sub_round_slug = gsub("gr14-", "", tools::toTitleCase(sub_round_slug))) %>% select(Variable, Value, `Round Matching Funds ($)`, grant_id, sub_round_slug) ``` --- The key feature of this dataset is we now have one row per grant and variable combination, which matches a “third-normal form” in the SQL world, which is suitable for analyzing via plotting and visualization methods in ggplot2. <table> <thead> <tr> <th style="text-align:left;"> Variable </th> <th style="text-align:right;"> Value </th> <th style="text-align:right;"> Round Matching Funds ($) </th> <th style="text-align:right;"> grant_id </th> <th style="text-align:left;"> sub_round_slug </th> </tr> </thead> <tbody> <tr> <td style="text-align:left;"> Unique Contributors </td> <td style="text-align:right;"> 27847 </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 5688 </td> <td style="text-align:left;"> Gr14-Gitcoin-Main </td> </tr> <tr> <td style="text-align:left;"> Unique Contributors </td> <td style="text-align:right;"> 24180 </td> <td style="text-align:right;"> 1500 </td> <td style="text-align:right;"> 5007 </td> <td style="text-align:left;"> Gr14-Web3social </td> </tr> <tr> <td style="text-align:left;"> Unique Contributors </td> <td style="text-align:right;"> 24180 </td> <td style="text-align:right;"> 10000 </td> <td style="text-align:right;"> 5007 </td> <td style="text-align:left;"> Gr14-Polygon </td> </tr> <tr> <td style="text-align:left;"> Unique Contributors </td> <td style="text-align:right;"> 24180 </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 5007 </td> <td style="text-align:left;"> Gr14-Gitcoin-Main </td> </tr> <tr> <td style="text-align:left;"> Unique Contributors </td> <td style="text-align:right;"> 19687 </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 4268 </td> <td style="text-align:left;"> Gr14-Gitcoin-Main </td> </tr> <tr> <td style="text-align:left;"> Unique Contributors </td> <td style="text-align:right;"> 17966 </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 37 </td> <td style="text-align:left;"> Gr14-Gitcoin-Main </td> </tr> <tr> <td style="text-align:left;"> Unique Contributors </td> <td style="text-align:right;"> 14775 </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 3591 </td> <td style="text-align:left;"> Gr14-Gitcoin-Main </td> </tr> <tr> <td style="text-align:left;"> Unique Contributors </td> <td style="text-align:right;"> 13471 </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 5288 </td> <td style="text-align:left;"> Gr14-Gitcoin-Main </td> </tr> <tr> <td style="text-align:left;"> Unique Contributors </td> <td style="text-align:right;"> 12312 </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 4665 </td> <td style="text-align:left;"> Gr14-Gitcoin-Main </td> </tr> <tr> <td style="text-align:left;"> Unique Contributors </td> <td style="text-align:right;"> 12312 </td> <td style="text-align:right;"> 25000 </td> <td style="text-align:right;"> 4665 </td> <td style="text-align:left;"> Gr14-Aurora </td> </tr> </tbody> </table> --- ## Visualization With this dataset, we are ready to write our `ggplot2` code to produce a matrix highlighting our derived variables across all the ecosystem rounds. Let's take a look: ```r ggplot(processed_gr14, aes(x = Value, y = `Round Matching Funds ($)`)) + geom_point(colour = "#0F0132", size = 1) + geom_smooth() + geom_text_repel(aes(label = grant_id)) + scale_x_continuous(breaks = scales::pretty_breaks(n = 10), labels = scales::comma) + scale_y_continuous(breaks = scales::pretty_breaks(n = 5), labels = scales::dollar, expand = expansion(mult = c(0, 0.25))) + facet_wrap(sub_round_slug~Variable, scales = "free", ncol = 4) + theme( axis.text.x = element_text(angle = 20, hjust = 1), axis.title = element_text(size = 45), plot.title = element_text(size = 40, hjust = .5), plot.subtitle = element_text(size = 16, hjust = .5) ) + labs( title = 'Gitcoin Grants 14 Eco-System Round Quadratic Funding Analysis', subtitle = 'A Scatterplot Matrix of per Grant Matching allocations as a Function of the Number of Unique Contributors and Average per Donor Contribution Amount', x = "Value" ) ``` --- This plot is far too large to display on a single slide. Please click the thumbnail below for a full size version: <a target='_blank' href='https://crypto.omnianalytics.org/wp-content/uploads/2023/01/smoother_and_labels.png'> <img src="images/smoother_and_labels.png" width="125" height="500" style="display: block; margin: auto;" /> </a> --- ## Analysis Particular attention should be paid to the Equal Weight Score (the far right column). The idea of the equal weight score is to identify those grants which both have a high average contribution, but also a large number of unique contributors. In the chart, this is plotted along the x axis, with a theoretical maximum of 2 as mentioned (for a grant that was best on both metrics). The Y axis provides the Round Matching Funds. In an ideal world, our Equal Weighting Score would be correlated, in the sense that the grants that had the highest matching values were ones that both had a higher average contribution, but also and in particular a large number of unique donors. Indeed, that pattern presents itself strongly, though the pattern varies across ecosystem rounds. In sound rounds, such as GR14-Aurora, one grant overwhelms the others – in this case, Grant ID 4665, Via Protocol [Web3 Mastercard] - Best UX among any-to-any cross-chain swaps – This grant had over 12,000 unique contributors, with an average per-contributor contribution of nearly $3. It’s equal weight score reached 1.43771, while no other grant in this round achieved even 1.1. In some other rounds, there was not a clear “winner”, but a pattern emerged where generally higher equal weight scores were correlated with higher matching amounts. For instance, GR14-Protocollabs exhibits a distinct upward trend, though not linear – the highest equal weighting score actually had a slightly lower matching amount than the second highest. One thing to note as you analyze this matrix of charts is that the X axis varies as a function of the round, it is not fixed across rounds. This is to aid in the interpretation of the per-round trend. Note for example, GR14-Web3social has a Grant ID 5007 that gets quite close to the theoretical maximum of 2. This grant, Lenster, had over 24,000 unique contributors at $3.6136 per contributor, putting it towards the top of the list. In other rounds, the scale doesn’t reach nearly that high, as most grants have more modest figures in terms of contributors and the average contribution. --- ## Conclusion While the per-round pattern varies quite distinctively, the clear trend is that the equal weighting score (which provides 50% weight to the number of unique contributors and a 50% weight to the average contribution amount) was positively correlated with the matching amount. This lends credence to the idea that we began this article with – Quadratic funding is an effective Wisdom of the Crowds approach, which doesn’t punish grants that happen to have smaller, but more frequent donations. This type of approach helps the Gitcoin Grants Program provide meaningful matching contributions to projects that have a disproportionately positive impact on a large number of users, even if those users don’t have the financial means or wherewithal to donate large sums at once.