Skip to content

Commit 7ddbe48

Browse files
committed
feat: reset referral rewards after claim (#183)
1 parent 47fd1ec commit 7ddbe48

File tree

3 files changed

+73
-27
lines changed

3 files changed

+73
-27
lines changed

Diff for: migrations/1671299400000-Deposit.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { MigrationInterface, QueryRunner } from "typeorm";
2+
3+
export class Deposit1671299400000 implements MigrationInterface {
4+
name = "Deposit1671299400000";
5+
6+
public async up(queryRunner: QueryRunner): Promise<void> {
7+
await queryRunner.query(`
8+
create index "IX_deposit_srAddress_depositDate_pId_tId_status"
9+
on deposit ("stickyReferralAddress", "depositDate", "priceId", "tokenId", status)
10+
`);
11+
}
12+
13+
public async down(queryRunner: QueryRunner): Promise<void> {
14+
await queryRunner.query(`drop index if exists "IX_deposit_srAddress_depositDate_pId_tId_status"`);
15+
}
16+
}

Diff for: src/modules/referral/services/service.ts

+50-27
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { WindowAlreadySetException } from "./exceptions";
2424
import { DepositsFilteredReferrals } from "../model/DepositsFilteredReferrals.entity";
2525
import { DepositReferralStat } from "../../deposit/model/deposit-referral-stat.entity";
2626
import { splitArrayInChunks } from "../../../utils";
27+
import { Claim } from "../../scraper/model/claim.entity";
2728

2829
const REFERRAL_ADDRESS_DELIMITER = "d00dfeeddeadbeef";
2930
const getReferralsSummaryCacheKey = (address: string) => `referrals:summary:${address}`;
@@ -127,7 +128,6 @@ export class ReferralService {
127128
.where("deposit.rewardsWindowIndex IS NULL")
128129
.andWhere("deposit.depositDate <= :maxDepositDate", { maxDepositDate })
129130
.getMany();
130-
console.log(`found ${deposits.length} deposits`);
131131
const { recipients, rewardsToDeposit } = this.calculateReferralRewards(deposits);
132132

133133
for (const depositsChunk of splitArrayInChunks(deposits, 100)) {
@@ -274,19 +274,17 @@ export class ReferralService {
274274
this.logger.log(`start cumputeReferralStats()`);
275275
const t1 = performance.now();
276276
const window = -1;
277-
278277
const deposits = await entityManager
279278
.createQueryBuilder(DepositsFilteredReferrals, "d")
280279
.select("d.stickyReferralAddress")
281-
.where("d.referralClaimedWindowIndex = :claimedWindowIndex", { claimedWindowIndex: window })
282280
.groupBy("d.stickyReferralAddress")
283281
.getMany();
284282
const referralAddresses = deposits.map((deposit) => deposit.stickyReferralAddress);
285283
this.logger.log(`window ${window}: ${referralAddresses.length} referralAddresses`);
286284
await Bluebird.Promise.map(
287285
referralAddresses,
288286
(address) => {
289-
return this.computeStatsForReferralAddress(entityManager, window, address);
287+
return this.computeStatsForReferralAddress(entityManager, address);
290288
},
291289
{ concurrency: 10 },
292290
);
@@ -296,21 +294,33 @@ export class ReferralService {
296294
});
297295
}
298296

299-
private async computeStatsForReferralAddress(entityManager: EntityManager, window: number, referralAddress: string) {
300-
const depositsResult = await entityManager
297+
private async computeStatsForReferralAddress(entityManager: EntityManager, referralAddress: string) {
298+
const claims = await entityManager
299+
.createQueryBuilder(Claim, "c")
300+
.where("c.account = :account", { account: referralAddress })
301+
.orderBy("c.claimedAt", "ASC")
302+
.getMany();
303+
const deposits = await entityManager
301304
.createQueryBuilder(DepositsFilteredReferrals, "d")
302-
.where("d.referralClaimedWindowIndex = :claimedWindowIndex", { claimedWindowIndex: window })
303305
.andWhere("d.stickyReferralAddress = :referralAddress", { referralAddress })
304306
.getMany();
307+
const sortedDeposits = deposits.sort((d1, d2) => (d1.depositDate.getTime() < d2.depositDate.getTime() ? -1 : 0));
308+
const sortedClaims = claims.sort((c1, c2) => (c1.claimedAt.getTime() < c2.claimedAt.getTime() ? -1 : 0));
309+
const groupedDeposits = this.groupDepositsByClaimDate(sortedDeposits, sortedClaims);
310+
311+
for (const deposits of Object.values(groupedDeposits)) {
312+
await this.computeReferralStatsForDeposits(deposits, entityManager);
313+
}
314+
}
315+
316+
private async computeReferralStatsForDeposits(deposits: DepositsFilteredReferrals[], entityManager: EntityManager) {
305317
const depositorAddrCounts = {};
306318
const depositCounts = {};
307319
const depositVolume = {};
308320
let totalVolume = new BigNumber(0);
309-
310321
let currentCount = 0;
311-
const sortedDeposits = depositsResult.sort((d1, d2) => (d1.depositDate < d2.depositDate ? -1 : 0));
312322

313-
for (const deposit of sortedDeposits) {
323+
for (const deposit of deposits) {
314324
const prevCount = depositorAddrCounts[deposit.depositorAddr];
315325

316326
if (!prevCount) {
@@ -327,22 +337,35 @@ export class ReferralService {
327337
depositVolume[deposit.id] = totalVolume;
328338
}
329339

330-
for (const depositsChunk of splitArrayInChunks(sortedDeposits, 100)) {
331-
const values: Partial<DepositReferralStat>[] = depositsChunk.map((d) => ({
332-
depositId: d.id,
333-
referralCount: depositCounts[d.id],
334-
referralVolume: depositVolume[d.id].toFixed(),
335-
referralClaimedWindowIndex: d.referralClaimedWindowIndex,
336-
}));
337-
await entityManager
338-
.createQueryBuilder(DepositReferralStat, "d")
339-
.insert()
340-
.values(values)
341-
.orUpdate({
342-
conflict_target: ["depositId"],
343-
overwrite: ["referralCount", "referralVolume", "referralClaimedWindowIndex"],
344-
})
345-
.execute();
346-
}
340+
await Promise.all(
341+
splitArrayInChunks(deposits, 100).map((depositsChunk) => {
342+
const values: Partial<DepositReferralStat>[] = depositsChunk.map((d) => ({
343+
depositId: d.id,
344+
referralCount: depositCounts[d.id],
345+
referralVolume: depositVolume[d.id].toFixed(),
346+
referralClaimedWindowIndex: d.referralClaimedWindowIndex,
347+
}));
348+
return entityManager
349+
.createQueryBuilder(DepositReferralStat, "d")
350+
.insert()
351+
.values(values)
352+
.orUpdate({
353+
conflict_target: ["depositId"],
354+
overwrite: ["referralCount", "referralVolume", "referralClaimedWindowIndex"],
355+
})
356+
.execute();
357+
}),
358+
);
359+
}
360+
361+
private groupDepositsByClaimDate(deposits: DepositsFilteredReferrals[], claims: Claim[]) {
362+
return deposits.reduce((acc, deposit) => {
363+
const claim = claims.filter((claim) => claim.claimedAt.getTime() >= deposit.depositDate.getTime())[0];
364+
const windowIndex = claim?.windowIndex || -1;
365+
return {
366+
...acc,
367+
[windowIndex]: [...(acc[windowIndex] || []), deposit],
368+
};
369+
}, {} as Record<string, DepositsFilteredReferrals[]>);
347370
}
348371
}

Diff for: src/modules/scraper/model/deposit.entity.ts

+7
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ export type RequestedSpeedUpDepositTx = {
3131
@Entity()
3232
@Unique("UK_deposit_depositId_sourceChainId", ["depositId", "sourceChainId"])
3333
@Index("IX_deposit_depositorAddr", ["depositorAddr"])
34+
@Index("IX_deposit_srAddress_depositDate_pId_tId_status", [
35+
"stickyReferralAddress",
36+
"depositDate",
37+
"priceId",
38+
"tokenId",
39+
"status",
40+
])
3441
export class Deposit {
3542
@PrimaryGeneratedColumn()
3643
id: number;

0 commit comments

Comments
 (0)