ProperQF
Title: Proper Quadratic Funding (QF) math and tallying
Author: Golem Foundation
Incremental QF tallying utilities with alpha-weighted quadratic/linear funding.
Provides storage isolation via deterministic slot, input validation helpers, and funding aggregation with well-defined rounding behavior.
Note: security-contact: [email protected]
State Variables
STORAGE_SLOT
Storage slot for ProperQF storage (ERC-7201 namespaced storage)
https://eips.ethereum.org/EIPS/eip-7201
bytes32 private constant STORAGE_SLOT =
bytes32(uint256(keccak256(abi.encode(uint256(keccak256(bytes("proper.qf.storage"))) - 1))) & ~uint256(0xff))
Functions
constructor
Constructor initializes default alpha values in storage
constructor() ;
_getProperQFStorage
Get the storage struct from the predefined slot
function _getProperQFStorage() internal pure returns (ProperQFStorage storage s);
Returns
| Name | Type | Description |
|---|---|---|
s | ProperQFStorage | Storage struct containing all mutable state for ProperQF |
projects
Returns project aggregated sums
function projects(uint256 projectId) public view returns (Project memory);
Parameters
| Name | Type | Description |
|---|---|---|
projectId | uint256 | ID of the project to query |
alphaNumerator
Returns alpha numerator
function alphaNumerator() public view returns (uint256);
alphaDenominator
Returns alpha denominator
function alphaDenominator() public view returns (uint256);
totalQuadraticSum
Returns total quadratic sum across all projects
function totalQuadraticSum() public view returns (uint256);
totalLinearSum
Returns total linear sum across all projects
function totalLinearSum() public view returns (uint256);
totalFunding
Returns alpha-weighted total funding across all projects
function totalFunding() public view returns (uint256);
_processVote
Process a vote and update the tally for the voting strategy
Implements incremental update quadratic funding algorithm with validations:
- contribution > 0 (asset base units)
- voteWeight > 0 and voteWeight^2 == contribution within 10% tolerance
function _processVote(uint256 projectId, uint256 contribution, uint256 voteWeight) internal virtual;
Parameters
| Name | Type | Description |
|---|---|---|
projectId | uint256 | ID of project to update |
contribution | uint256 | Contribution to add in asset base units |
voteWeight | uint256 | Square root of contribution (dimensionless) |
_processVoteUnchecked
Process vote without validation - for trusted callers who have already validated
Skips input validation for gas optimization when caller guarantees correctness
function _processVoteUnchecked(uint256 projectId, uint256 contribution, uint256 voteWeight) internal;
Parameters
| Name | Type | Description |
|---|---|---|
projectId | uint256 | ID of project to update |
contribution | uint256 | Contribution amount (asset base units) |
voteWeight | uint256 | Vote weight (dimensionless; sqrt of contribution) |
_calculateWeightedTotalFunding
Calculate alpha-weighted total funding across all projects
Rounding: per-project integer division makes sum(project funding) ≤ totalFunding. Discrepancy ε is bounded: 0 ≤ ε ≤ 2(|P|-1) where |P| is number of projects. This dust ensures no over-allocation; all funds are still fully distributed.
function _calculateWeightedTotalFunding() internal view returns (uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | totalFunding_ Weighted total funding across all projects (asset base units) |
getTally
Return current funding metrics for a specific project
Aggregates sums and computes alpha-weighted components on-demand.
Rounding: sum of per-project funding ≤ totalFunding() with small bounded dust ε.
function getTally(uint256 projectId)
public
view
returns (uint256 sumContributions, uint256 sumSquareRoots, uint256 quadraticFunding, uint256 linearFunding);
Parameters
| Name | Type | Description |
|---|---|---|
projectId | uint256 | ID of project to tally |
Returns
| Name | Type | Description |
|---|---|---|
sumContributions | uint256 | Total sum of contributions (asset base units) |
sumSquareRoots | uint256 | Sum of square roots of contributions (dimensionless) |
quadraticFunding | uint256 | Alpha-weighted quadratic funding: ⌊α × S_j²⌋ (asset base units) |
linearFunding | uint256 | Alpha-weighted linear funding: ⌊(1-α) × Sum_j⌋ (asset base units) |
_setAlpha
Set alpha parameter determining ratio between quadratic and linear funding
function _setAlpha(uint256 newNumerator, uint256 newDenominator) internal;
Parameters
| Name | Type | Description |
|---|---|---|
newNumerator | uint256 | Numerator of new alpha (0 ≤ numerator ≤ denominator) |
newDenominator | uint256 | Denominator of new alpha (> 0) |
getAlpha
Get current alpha ratio components
function getAlpha() public view returns (uint256, uint256);
Returns
| Name | Type | Description |
|---|---|---|
<none> | uint256 | numerator Current alpha numerator |
<none> | uint256 | denominator Current alpha denominator |
_calculateOptimalAlpha
Calculate optimal alpha for 1:1 shares-to-assets ratio given fixed matching pool amount
Solve α where: α × totalQuadraticSum + (1−α) × totalLinearSum = totalUserDeposits + matchingPoolAmount
function _calculateOptimalAlpha(
uint256 matchingPoolAmount,
uint256 quadraticSum,
uint256 linearSum,
uint256 totalUserDeposits
) internal pure returns (uint256 optimalAlphaNumerator, uint256 optimalAlphaDenominator);
Parameters
| Name | Type | Description |
|---|---|---|
matchingPoolAmount | uint256 | Matching pool amount (asset base units) |
quadraticSum | uint256 | Total quadratic sum across all proposals (dimensionless) |
linearSum | uint256 | Total linear sum across all proposals (asset base units) |
totalUserDeposits | uint256 | Total user deposits in the mechanism (asset base units) |
Returns
| Name | Type | Description |
|---|---|---|
optimalAlphaNumerator | uint256 | Calculated alpha numerator |
optimalAlphaDenominator | uint256 | Calculated alpha denominator |
Events
AlphaUpdated
Emitted when alpha parameters are updated
event AlphaUpdated(uint256 oldNumerator, uint256 oldDenominator, uint256 newNumerator, uint256 newDenominator);
Parameters
| Name | Type | Description |
|---|---|---|
oldNumerator | uint256 | Previous alpha numerator |
oldDenominator | uint256 | Previous alpha denominator |
newNumerator | uint256 | New alpha numerator |
newDenominator | uint256 | New alpha denominator |
Errors
ContributionMustBePositive
error ContributionMustBePositive();
VoteWeightMustBePositive
error VoteWeightMustBePositive();
VoteWeightOverflow
error VoteWeightOverflow();
SquareRootTooLarge
error SquareRootTooLarge();
VoteWeightOutsideTolerance
error VoteWeightOutsideTolerance();
QuadraticSumUnderflow
error QuadraticSumUnderflow();
LinearSumUnderflow
error LinearSumUnderflow();
DenominatorMustBePositive
error DenominatorMustBePositive();
AlphaMustBeLessOrEqualToOne
error AlphaMustBeLessOrEqualToOne();
Structs
Project
Per-project aggregated sums
struct Project {
/// @notice Sum of contributions for this project (asset base units)
uint256 sumContributions;
/// @notice Sum of square roots of all contributions (dimensionless)
uint256 sumSquareRoots;
}
ProperQFStorage
Main storage struct containing all mutable state for ProperQF
struct ProperQFStorage {
/// @notice Mapping of project IDs to project data
mapping(uint256 => Project) projects;
/// @notice Numerator for alpha (dimensionless; 1.0 = denominator)
uint256 alphaNumerator;
/// @notice Denominator for alpha (must be > 0)
uint256 alphaDenominator;
/// @notice Sum of all quadratic terms across projects (dimensionless squared weights)
uint256 totalQuadraticSum;
/// @notice Sum of all linear contributions across projects (asset base units)
uint256 totalLinearSum;
/// @notice Alpha-weighted total funding across all projects (asset base units)
/// @dev Uses uint256 for precision in calculations
uint256 totalFunding;
}