Skip to content

Commit 42d05e6

Browse files
committed
Improve GIVbacks allocatedGivTokens value
1 parent 04ff828 commit 42d05e6

1 file changed

Lines changed: 87 additions & 39 deletions

File tree

src/repositories/donationRepository.ts

Lines changed: 87 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { QfRound } from '../entities/qfRound';
88
import { ChainType } from '../types/network';
99
import { ORGANIZATION_LABELS } from '../entities/organization';
1010
import { AppDataSource } from '../orm';
11-
import { getPowerRound } from './powerRoundRepository';
1211

1312
export const exportClusterMatchingDonationsFormat = async (
1413
qfRoundId: number,
@@ -584,45 +583,94 @@ export const getRecentDonations = async (take: number): Promise<Donation[]> => {
584583
.getMany();
585584
};
586585

587-
export const getSumOfGivbackEligibleDonationsForSpecificRound = async (params: {
588-
powerRound?: number;
589-
}): Promise<number> => {
590-
// This function calculates the total USD value of all donations that are eligible for Givback in a specific PowerRound
591-
592-
try {
593-
// If no powerRound is passed, get the latest one from the PowerRound table
594-
const powerRound = params.powerRound || (await getPowerRound())?.round;
595-
if (!powerRound) {
596-
throw new Error('No powerRound found in the database.');
586+
export const getSumOfGivbackEligibleDonationsForSpecificRound =
587+
async (_params: { powerRound?: number }): Promise<number> => {
588+
// This function calculates the total USD value of all donations eligible for GIVback
589+
// Uses the operational window (16:00 UTC offset) to match givbacks service
590+
// Groups recurring donations and applies minimum thresholds
591+
592+
try {
593+
// Calculate date range for current month with 16:00 UTC offset (matches givbacks service)
594+
const now = new Date();
595+
const year = now.getUTCFullYear();
596+
const month = now.getUTCMonth();
597+
598+
// Start: 1st of current month at 16:00 UTC
599+
const startDate = new Date(Date.UTC(year, month, 1, 16, 0, 0));
600+
// End: Last day of current month at 15:59:59 UTC (or 1st of next month at 15:59:59)
601+
const endDate = new Date(Date.UTC(year, month + 1, 0, 15, 59, 59));
602+
603+
const startDateStr = startDate
604+
.toISOString()
605+
.replace('T', ' ')
606+
.replace('Z', '');
607+
const endDateStr = endDate
608+
.toISOString()
609+
.replace('T', ' ')
610+
.replace('Z', '');
611+
612+
// Minimum threshold: $4 for most projects, $0.05 for community project
613+
const minEligibleValueUsd = 4;
614+
const communityMinValueUsd = 0.05;
615+
const communityProjectSlug = 'the-giveth-community-of-makers';
616+
617+
// Execute query with:
618+
// 1. Date range (operational window)
619+
// 2. Group recurring donations by parent ID
620+
// 3. Apply minimum threshold on grouped totals
621+
// 4. Purple list exclusion
622+
const result = await AppDataSource.getDataSource().query(
623+
`
624+
WITH grouped_donations AS (
625+
SELECT
626+
COALESCE("recurringDonationId"::text, "id"::text) AS group_id,
627+
SUM("valueUsd") AS total_usd,
628+
SUM("valueUsd" * "givbackFactor") AS total_usd_with_factor,
629+
MAX("fromWalletAddress") AS from_address,
630+
MAX("projectId") AS project_id
631+
FROM "donation"
632+
WHERE "status" = 'verified'
633+
AND "isProjectGivbackEligible" = true
634+
AND "createdAt" > $1
635+
AND "createdAt" < $2
636+
GROUP BY COALESCE("recurringDonationId"::text, "id"::text)
637+
)
638+
SELECT COALESCE(SUM(gd.total_usd_with_factor), 0) AS "totalUsdWithGivbackFactor"
639+
FROM grouped_donations gd
640+
JOIN "project" p ON p.id = gd.project_id
641+
WHERE
642+
(
643+
(p.slug = $3 AND gd.total_usd > $4)
644+
OR (p.slug != $3 AND gd.total_usd >= $5)
645+
)
646+
AND NOT EXISTS (
647+
SELECT 1
648+
FROM "project_address" pa
649+
INNER JOIN "project" proj ON proj.id = pa."projectId"
650+
WHERE LOWER(pa.address) = LOWER(gd.from_address)
651+
AND pa."isRecipient" = true
652+
AND proj.verified = true
653+
AND proj."statusId" = 5
654+
);
655+
`,
656+
[
657+
startDateStr,
658+
endDateStr,
659+
communityProjectSlug,
660+
communityMinValueUsd,
661+
minEligibleValueUsd,
662+
],
663+
);
664+
665+
return result?.[0]?.totalUsdWithGivbackFactor ?? 0;
666+
} catch (e) {
667+
logger.error(
668+
'getSumOfGivbackEligibleDonationsForSpecificRound() error',
669+
e,
670+
);
671+
return 0;
597672
}
598-
599-
// Execute the main raw SQL query with the powerRound
600-
const result = await AppDataSource.getDataSource().query(
601-
`
602-
SELECT
603-
SUM("donation"."valueUsd" * "donation"."givbackFactor") AS "totalUsdWithGivbackFactor"
604-
FROM "donation"
605-
WHERE "donation"."status" = 'verified'
606-
AND "donation"."isProjectGivbackEligible" = true
607-
AND "donation"."powerRound" = $1
608-
AND NOT EXISTS (
609-
SELECT 1
610-
FROM "project_address" "pa"
611-
INNER JOIN "project" "p" ON "p"."id" = "pa"."projectId"
612-
WHERE "pa"."address" = "donation"."fromWalletAddress"
613-
AND "pa"."isRecipient" = true
614-
AND "p"."verified" = true
615-
);
616-
`,
617-
[powerRound],
618-
);
619-
620-
return result?.[0]?.totalUsdWithGivbackFactor ?? 0;
621-
} catch (e) {
622-
logger.error('getSumOfGivbackEligibleDonationsForSpecificRound() error', e);
623-
return 0;
624-
}
625-
};
673+
};
626674

627675
export const getPendingDonationsIds = (): Promise<{ id: number }[]> => {
628676
const date = moment()

0 commit comments

Comments
 (0)