Skip to content

Commit 81e9831

Browse files
feat: add handler for round and application stats (#106)
# 🤖 Linear closes PAR-943 <img width="1640" alt="image" src="https://github.com/user-attachments/assets/63026e3e-5116-4a57-86ab-107dd8ce099d" /> ## Description ## Checklist before requesting a review - [x] I have conducted a self-review of my code. - [x] I have conducted a QA. - [x] If it is a core feature, I have included comprehensive tests. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit - **New Features** - Donation tracking has been enhanced. The system now automatically updates donation statistics for both rounds and individual applications. - **Refactor** - Donation amounts are now uniformly represented as strings for improved clarity. - **Tests** - Additional tests have been added to ensure reliable processing of donation events and statistics updates for both rounds and applications. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
2 parents 816cf69 + 5b89dd8 commit 81e9831

File tree

23 files changed

+230
-11
lines changed

23 files changed

+230
-11
lines changed

.github/pull_request_template.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 🤖 Linear
22

3-
Closes GIT-XXX
3+
Closes PAR-XXX
44

55
## Description
66

packages/data-flow/src/data-loader/handlers/application.handlers.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,13 @@ export const createApplicationHandlers = (
3131
txConnection,
3232
);
3333
}) satisfies ChangesetHandler<"UpdateApplication">,
34+
35+
IncrementApplicationDonationStats: (async (changeset, txConnection): Promise<void> => {
36+
const { chainId, roundId, applicationId, amountInUsd } = changeset.args;
37+
await repository.incrementApplicationDonationStats(
38+
{ chainId, roundId, id: applicationId },
39+
amountInUsd,
40+
txConnection,
41+
);
42+
}) satisfies ChangesetHandler<"IncrementApplicationDonationStats">,
3443
});

packages/data-flow/src/data-loader/handlers/round.handlers.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ export const createRoundHandlers = (repository: IRoundRepository): RoundHandlers
5151
);
5252
}) satisfies ChangesetHandler<"IncrementRoundFundedAmount">,
5353

54+
IncrementRoundDonationStats: (async (changeset, txConnection): Promise<void> => {
55+
const { chainId, roundId, amountInUsd } = changeset.args;
56+
await repository.incrementRoundDonationStats(
57+
{
58+
chainId,
59+
roundId,
60+
},
61+
amountInUsd,
62+
txConnection,
63+
);
64+
}) satisfies ChangesetHandler<"IncrementRoundDonationStats">,
65+
5466
IncrementRoundTotalDistributed: (async (changeset, txConnection): Promise<void> => {
5567
const { chainId, roundId, amount } = changeset.args;
5668
await repository.incrementRoundTotalDistributed(

packages/data-flow/test/data-loader/handlers/application.handlers.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ describe("Application Handlers", () => {
1313
const mockRepository = {
1414
insertApplication: vi.fn(),
1515
updateApplication: vi.fn(),
16+
incrementApplicationDonationStats: vi.fn(),
1617
} as unknown as IApplicationRepository;
1718
const mockTxConnection = { query: vi.fn() } as unknown as TransactionConnection;
1819

@@ -51,4 +52,24 @@ describe("Application Handlers", () => {
5152
mockTxConnection,
5253
);
5354
});
55+
56+
it("handle IncrementApplicationDonationStats changeset", async () => {
57+
const changeset = {
58+
type: "IncrementApplicationDonationStats",
59+
args: {
60+
chainId: 1 as ChainId,
61+
roundId: "round1",
62+
applicationId: "0",
63+
amountInUsd: "1000",
64+
},
65+
} as const;
66+
67+
await handlers.IncrementApplicationDonationStats(changeset);
68+
69+
expect(mockRepository.incrementApplicationDonationStats).toHaveBeenCalledWith(
70+
{ chainId: 1 as ChainId, roundId: "round1", id: "0" },
71+
"1000",
72+
undefined,
73+
);
74+
});
5475
});

packages/data-flow/test/data-loader/handlers/round.handlers.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ describe("Round Handlers", () => {
1919
deleteManyPendingRoundRoles: vi.fn(),
2020
insertRoundRole: vi.fn(),
2121
deleteManyRoundRolesByRoleAndAddress: vi.fn(),
22+
incrementRoundDonationStats: vi.fn(),
2223
} as unknown as IRoundRepository;
2324
const mockTxConnection = { query: vi.fn() } as unknown as TransactionConnection;
2425

@@ -111,6 +112,25 @@ describe("Round Handlers", () => {
111112
);
112113
});
113114

115+
it("handle IncrementRoundDonationStats changeset", async () => {
116+
const changeset = {
117+
type: "IncrementRoundDonationStats",
118+
args: {
119+
chainId: 1 as ChainId,
120+
roundId: "round-1",
121+
amountInUsd: "1000",
122+
},
123+
} as const;
124+
125+
await handlers.IncrementRoundDonationStats(changeset);
126+
127+
expect(mockRepository.incrementRoundDonationStats).toHaveBeenCalledWith(
128+
{ chainId: 1 as ChainId, roundId: "round-1" },
129+
"1000",
130+
undefined,
131+
);
132+
});
133+
114134
it("handle IncrementRoundTotalDistributed changeset", async () => {
115135
const changeset = {
116136
type: "IncrementRoundTotalDistributed",

packages/data-flow/test/integration/helpers/dependencies.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ export const createMockRepositories = (): Pick<
6060
getRoundMatchTokenAddressById: vi.fn(),
6161
getRoundRoles: vi.fn(),
6262
getPendingRoundRoles: vi.fn(),
63+
incrementRoundDonationStats: vi.fn(),
6364
},
6465
applicationRepository: {
6566
insertApplication: vi.fn(),
@@ -69,6 +70,7 @@ export const createMockRepositories = (): Pick<
6970
getApplicationByAnchorAddress: vi.fn(),
7071
getApplicationByAnchorAddressOrThrow: vi.fn(),
7172
getApplicationsByRoundId: vi.fn(),
73+
incrementApplicationDonationStats: vi.fn(),
7274
},
7375
donationRepository: {
7476
insertDonation: vi.fn(),

packages/data-flow/test/integration/strategy.integration.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ describe("Orchestrator Integration - Strategy Events Processing", () => {
661661
},
662662
],
663663
distributionTransaction: null,
664-
totalAmountDonatedInUsd: 0,
664+
totalAmountDonatedInUsd: "0",
665665
totalDonationsCount: 0,
666666
uniqueDonorsCount: 0,
667667
tags: ["allo-v2"],

packages/processors/src/processors/strategy/directGrantsLite/handlers/registered.handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export class DGLiteRegisteredHandler implements IEventHandler<"Strategy", "Regis
7878
},
7979
],
8080
distributionTransaction: null,
81-
totalAmountDonatedInUsd: 0,
81+
totalAmountDonatedInUsd: "0",
8282
totalDonationsCount: 0,
8383
uniqueDonorsCount: 0,
8484
timestamp: new Date(blockTimestamp),

packages/processors/src/processors/strategy/directGrantsSimple/handlers/registered.handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export class DGSimpleRegisteredHandler
7979
},
8080
],
8181
distributionTransaction: null,
82-
totalAmountDonatedInUsd: 0,
82+
totalAmountDonatedInUsd: "0",
8383
totalDonationsCount: 0,
8484
uniqueDonorsCount: 0,
8585
timestamp: new Date(blockTimestamp),

packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,23 @@ export class DVMDAllocatedHandler implements IEventHandler<"Strategy", "Allocate
108108
type: "InsertDonation",
109109
args: { donation },
110110
},
111+
{
112+
type: "IncrementRoundDonationStats",
113+
args: {
114+
chainId: this.chainId,
115+
roundId: round.id,
116+
amountInUsd,
117+
},
118+
},
119+
{
120+
type: "IncrementApplicationDonationStats",
121+
args: {
122+
chainId: this.chainId,
123+
roundId: round.id,
124+
applicationId: application.id,
125+
amountInUsd,
126+
},
127+
},
111128
];
112129
}
113130

packages/processors/src/processors/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export class DVMDRegisteredHandler implements IEventHandler<"Strategy", "Registe
7373
},
7474
],
7575
distributionTransaction: null,
76-
totalAmountDonatedInUsd: 0,
76+
totalAmountDonatedInUsd: "0",
7777
totalDonationsCount: 0,
7878
uniqueDonorsCount: 0,
7979
timestamp: new Date(blockTimestamp),

packages/processors/src/processors/strategy/easyRetroFunding/handlers/registered.handler.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export class ERFRegisteredHandler implements IEventHandler<"Strategy", "Register
7777
},
7878
],
7979
distributionTransaction: null,
80-
totalAmountDonatedInUsd: 0,
80+
totalAmountDonatedInUsd: "0",
8181
totalDonationsCount: 0,
8282
uniqueDonorsCount: 0,
8383
timestamp: new Date(blockTimestamp),

packages/processors/test/strategy/directGrantsLite/handlers/registered.handler.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ describe("DGLiteRegisteredHandler", () => {
9292
},
9393
],
9494
distributionTransaction: null,
95-
totalAmountDonatedInUsd: 0,
95+
totalAmountDonatedInUsd: "0",
9696
totalDonationsCount: 0,
9797
uniqueDonorsCount: 0,
9898
tags: ["allo-v2"],

packages/processors/test/strategy/directGrantsSimple/handlers/registered.handler.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ describe("DGSimpleRegisteredHandler", () => {
8888
},
8989
],
9090
distributionTransaction: null,
91-
totalAmountDonatedInUsd: 0,
91+
totalAmountDonatedInUsd: "0",
9292
totalDonationsCount: 0,
9393
uniqueDonorsCount: 0,
9494
tags: ["allo-v2"],

packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/allocated.handler.spec.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,23 @@ describe("DVMDAllocatedHandler", () => {
112112
},
113113
},
114114
},
115+
{
116+
type: "IncrementRoundDonationStats",
117+
args: {
118+
chainId,
119+
roundId: "round1",
120+
amountInUsd: "20000",
121+
},
122+
},
123+
{
124+
type: "IncrementApplicationDonationStats",
125+
args: {
126+
chainId,
127+
roundId: "round1",
128+
applicationId: "app1",
129+
amountInUsd: "20000",
130+
},
131+
},
115132
]);
116133
});
117134

@@ -175,6 +192,23 @@ describe("DVMDAllocatedHandler", () => {
175192
}),
176193
},
177194
},
195+
{
196+
type: "IncrementRoundDonationStats",
197+
args: {
198+
chainId,
199+
roundId: "round1",
200+
amountInUsd: "1500",
201+
},
202+
},
203+
{
204+
type: "IncrementApplicationDonationStats",
205+
args: {
206+
chainId,
207+
roundId: "round1",
208+
applicationId: "app1",
209+
amountInUsd: "1500",
210+
},
211+
},
178212
]);
179213
});
180214

packages/processors/test/strategy/donationVotingMerkleDistributionDirectTransfer/handlers/registered.handler.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ describe("DVMDRegisteredHandler", () => {
112112
},
113113
],
114114
distributionTransaction: null,
115-
totalAmountDonatedInUsd: 0,
115+
totalAmountDonatedInUsd: "0",
116116
totalDonationsCount: 0,
117117
uniqueDonorsCount: 0,
118118
tags: ["allo-v2"],

packages/processors/test/strategy/easyRetroFunding/handlers/registered.handler.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ describe("ERFRegisteredHandler", () => {
8888
},
8989
],
9090
distributionTransaction: null,
91-
totalAmountDonatedInUsd: 0,
91+
totalAmountDonatedInUsd: "0",
9292
totalDonationsCount: 0,
9393
uniqueDonorsCount: 0,
9494
tags: ["allo-v2"],

packages/repository/src/interfaces/applicationRepository.interface.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,17 @@ export interface IApplicationRepository<
8989
application: PartialApplication,
9090
tx?: TxConnection,
9191
): Promise<void>;
92+
93+
/**
94+
* Increments the donation stats for an application.
95+
* @param where An object containing the (id, chainId, and roundId) of the application to update.
96+
* @param amountInUsd The amount in USD to increment by.
97+
* @param tx Optional transaction connection
98+
* @returns A promise that resolves when the increment is complete.
99+
*/
100+
incrementApplicationDonationStats(
101+
where: { id: string; chainId: ChainId; roundId: string },
102+
amountInUsd: string,
103+
tx?: TxConnection,
104+
): Promise<void>;
92105
}

packages/repository/src/interfaces/roundRepository.interface.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,22 @@ export interface IRoundRepository<
137137
tx?: TxConnection,
138138
): Promise<void>;
139139

140+
/**
141+
* Increments the donation stats for a specific round.
142+
* @param where An object containing the chainId and roundId of the round to update.
143+
* @param amountInUsd The amount in USD to increment by.
144+
* @param tx Optional transaction connection
145+
* @returns A promise that resolves when the increment is complete.
146+
*/
147+
incrementRoundDonationStats(
148+
where: {
149+
chainId: ChainId;
150+
roundId: string;
151+
},
152+
amountInUsd: string,
153+
tx?: TxConnection,
154+
): Promise<void>;
155+
140156
/**
141157
* Increments the total distributed amount for a specific round.
142158
* @param where An object containing the chainId and roundId of the round to update.

packages/repository/src/kysely/repositories/application.repository.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,35 @@ export class KyselyApplicationRepository implements IApplicationRepository<Kysel
161161
}
162162
}
163163

164+
/* @inheritdoc */
165+
async incrementApplicationDonationStats(
166+
where: { id: string; chainId: ChainId; roundId: string },
167+
amountInUsd: string,
168+
tx?: KyselyTransaction,
169+
): Promise<void> {
170+
try {
171+
const queryBuilder = (tx || this.db).withSchema(this.schemaName);
172+
await queryBuilder
173+
.updateTable("applications")
174+
.set((eb) => ({
175+
totalDonationsCount: eb("totalDonationsCount", "+", 1),
176+
totalAmountDonatedInUsd: eb("totalAmountDonatedInUsd", "+", amountInUsd),
177+
}))
178+
.where("id", "=", where.id)
179+
.where("chainId", "=", where.chainId)
180+
.where("roundId", "=", where.roundId)
181+
.execute();
182+
} catch (error) {
183+
throw handlePostgresError(error, {
184+
className: KyselyApplicationRepository.name,
185+
methodName: "incrementApplicationDonationStats",
186+
additionalData: {
187+
where,
188+
amountInUsd,
189+
},
190+
});
191+
}
192+
}
164193
/**
165194
* Formats the application to ensure that the statusSnapshots are stored as a JSON string.
166195
* Also, properly handles BigInt stringification.

packages/repository/src/kysely/repositories/round.repository.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,35 @@ export class KyselyRoundRepository implements IRoundRepository<KyselyTransaction
205205
}
206206
}
207207

208+
/* @inheritdoc */
209+
async incrementRoundDonationStats(
210+
where: { chainId: ChainId; roundId: string },
211+
amountInUsd: string,
212+
tx?: KyselyTransaction,
213+
): Promise<void> {
214+
try {
215+
const queryBuilder = (tx || this.db).withSchema(this.schemaName);
216+
await queryBuilder
217+
.updateTable("rounds")
218+
.set((eb) => ({
219+
totalDonationsCount: eb("totalDonationsCount", "+", 1),
220+
totalAmountDonatedInUsd: eb("totalAmountDonatedInUsd", "+", amountInUsd),
221+
}))
222+
.where("chainId", "=", where.chainId)
223+
.where("id", "=", where.roundId)
224+
.execute();
225+
} catch (error) {
226+
throw handlePostgresError(error, {
227+
className: KyselyRoundRepository.name,
228+
methodName: "incrementRoundDonationStats",
229+
additionalData: {
230+
where,
231+
amountInUsd,
232+
},
233+
});
234+
}
235+
}
236+
208237
/* @inheritdoc */
209238
async incrementRoundTotalDistributed(
210239
where: { chainId: ChainId; roundId: string },

packages/repository/src/types/application.types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export type Application = {
2323
createdAtBlock: bigint;
2424
statusUpdatedAtBlock: bigint;
2525
totalDonationsCount: number;
26-
totalAmountDonatedInUsd: number;
26+
totalAmountDonatedInUsd: string;
2727
uniqueDonorsCount: number;
2828
timestamp: Date;
2929
tags: string[];

0 commit comments

Comments
 (0)