28 lines
995 B
TypeScript
28 lines
995 B
TypeScript
|
import { groupBy, mapValues, sum, sumBy } from 'lodash'
|
||
|
import { Txn } from './txn'
|
||
|
|
||
|
// Returns a map of charity ids to the amount of M$ matched
|
||
|
export function quadraticMatches(
|
||
|
allCharityTxns: Txn[],
|
||
|
matchingPool: number
|
||
|
): Record<string, number> {
|
||
|
// For each charity, group the donations by each individual donor
|
||
|
const donationsByCharity = groupBy(allCharityTxns, 'toId')
|
||
|
const donationsByDonors = mapValues(donationsByCharity, (txns) =>
|
||
|
groupBy(txns, 'fromId')
|
||
|
)
|
||
|
|
||
|
// Weight for each charity = [sum of sqrt(individual donor)] ^ 2
|
||
|
const weights = mapValues(donationsByDonors, (byDonor) => {
|
||
|
const sumByDonor = Object.values(byDonor).map((txns) =>
|
||
|
sumBy(txns, 'amount')
|
||
|
)
|
||
|
const sumOfRoots = sumBy(sumByDonor, Math.sqrt)
|
||
|
return sumOfRoots ** 2
|
||
|
})
|
||
|
|
||
|
// Then distribute the matching pool based on the individual weights
|
||
|
const totalWeight = sum(Object.values(weights))
|
||
|
return mapValues(weights, (weight) => matchingPool * (weight / totalWeight))
|
||
|
}
|