diff --git a/src/scripts/syncDataWithJsonReport.ts b/src/scripts/syncDataWithJsonReport.ts index 505502c81..eb2ca64b1 100644 --- a/src/scripts/syncDataWithJsonReport.ts +++ b/src/scripts/syncDataWithJsonReport.ts @@ -6,7 +6,7 @@ import fs from 'fs-extra'; import { Donation } from '../entities/donation'; import { Project } from '../entities/project'; import { AppDataSource } from '../orm'; -import { getStreamDetails } from './helpers'; +import { getRoundByBatchNumber, getStreamDetails } from './helpers'; import { repoLocalDir, getReportsSubDir } from './configs'; async function loadReportFile(filePath: string) { @@ -36,6 +36,8 @@ function getAllReportFiles(dirPath: string) { async function processReportForDonations( donations: Donation[], reportData: any, + round: any, + isEarlyAccess: boolean, ) { try { const participants = reportData.batch.data.participants; @@ -53,64 +55,144 @@ async function processReportForDonations( if (!participantData) { console.error(`No participant data found for donation ${donation.id}`); + await unassociateDonationIfIsForThisRound( + donation, + round, + isEarlyAccess, + ); continue; } - const totalValidContribution = ethers.BigNumber.from( - participantData.validContribution.inCollateral, + await updateDonationRewardsData( + participantData, + donation, + round, + isEarlyAccess, ); - // if issuance allocation is not exist, that mean this user has not any valid contributions - let rewardAmount = 0; - if (participantData.issuanceAllocation) { - const issuanceAllocationRow = ethers.BigNumber.from( - participantData.issuanceAllocation, - ); - const issuanceAllocation = parseFloat( - ethers.utils.formatUnits(issuanceAllocationRow, 18), - ); // Assuming 18 decimal places - - const donationTransaction = participantData.transactions.find( - (tx: any) => - tx.transactionHash.toLowerCase() === - donation.transactionId.toLowerCase(), - ); + } + // todo: can check if there is any transactions that is not in the database + } catch (error) { + console.error( + `Failed to process donations rewards for project ${donations[0].projectId}: ${error.message}`, + ); + } +} - if (!donationTransaction) { - console.error( - `No transaction data found for donation ${donation.id}`, - ); - continue; - } +async function unassociateDonationIfIsForThisRound( + donation: Donation, + round: any, + isEarlyAccess: boolean, +) { + console.info(`Unassociating donation ${donation.id} if the round is same...`); + if (isEarlyAccess && donation.earlyAccessRoundId === round.id) { + donation.earlyAccessRoundId = null; + await donation.save(); + console.info( + `Donation ${donation.id} unassociated form early access round ${round.roundNumber}`, + ); + return; + } + if (!isEarlyAccess && donation.qfRoundId === round.id) { + donation.qfRoundId = null; + await donation.save(); + console.info( + `Donation ${donation.id} unassociated form qacc round ${round.roundNumber}`, + ); + return; + } + console.warn( + `Donation ${donation.id} is not associated to current round!!!\n + Donation qf round id is ${donation.qfRoundId} and donation early access round id is ${donation.earlyAccessRoundId}\n + But report is for ${isEarlyAccess ? 'early access' : 'Qacc'} round with id ${round.id} !!!!`, + ); +} - const donationValidContribution = ethers.BigNumber.from( - donationTransaction.validContribution, - ); - const contributionPercentage = - parseFloat(ethers.utils.formatUnits(donationValidContribution, 18)) / - parseFloat(ethers.utils.formatUnits(totalValidContribution, 18)); +// based the use case of this function, we don't need to save donation in it, because after calling that, we save donation data +function associateDonationToThisRound( + donation: Donation, + round: any, + isEarlyAccess: boolean, +) { + console.info( + `Associating donation ${donation.id} if the round is not matched...`, + ); + if (isEarlyAccess && donation.earlyAccessRoundId !== round.id) { + console.warn( + `Associate donation to current round because donation ${donation.id} is not associated correctly!!!\n + Donation qf round id is ${donation.qfRoundId} and donation early access round id is ${donation.earlyAccessRoundId}\n + But report is for early access round with id ${round.id} !!!!`, + ); + donation.earlyAccessRoundId = round.id; + donation.qfRoundId = null; + return; + } + if (!isEarlyAccess && donation.qfRoundId !== round.id) { + console.warn( + `Associate donation to current round because donation ${donation.id} is not associated correctly!!!\n + Donation qf round id is ${donation.qfRoundId} and donation early access round id is ${donation.earlyAccessRoundId}\n + But report is for Qacc round with id ${round.id} !!!!`, + ); + donation.earlyAccessRoundId = null; + donation.qfRoundId = round.id; + console.info( + `Donation ${donation.id} unassociated form qacc round ${round.roundNumber}`, + ); + return; + } + console.info(`Donation is associated correctly from before`); +} - // Calculate the reward proportionally based on the valid contribution - rewardAmount = issuanceAllocation * contributionPercentage; - } - donation.rewardTokenAmount = rewardAmount || 0; +async function updateDonationRewardsData( + participantData: any, + donation: Donation, + round: any, + isEarlyAccess: boolean, +) { + const totalValidContribution = ethers.BigNumber.from( + participantData.validContribution.inCollateral, + ); + // if issuance allocation is not exist, that mean this user has not any valid contributions + const issuanceAllocationRow = ethers.BigNumber.from( + participantData.issuanceAllocation || '0', + ); + const issuanceAllocation = parseFloat( + ethers.utils.formatUnits(issuanceAllocationRow, 18), + ); // Assuming 18 decimal places - const isEarlyAccessRound = reportData.batch.config.isEarlyAccess; - const vestingInfo = getStreamDetails(isEarlyAccessRound); + const donationTransaction = participantData.transactions.find( + (tx: any) => + tx.transactionHash.toLowerCase() === donation.transactionId.toLowerCase(), + ); - donation.cliff = vestingInfo.CLIFF * 1000; - donation.rewardStreamStart = new Date(vestingInfo.START * 1000); - donation.rewardStreamEnd = new Date(vestingInfo.END * 1000); + if (!donationTransaction) { + console.error(`No transaction data found for donation ${donation.id}`); + await unassociateDonationIfIsForThisRound(donation, round, isEarlyAccess); + return; + } - await donation.save(); - console.debug( - `Reward data for donation ${donation.id} successfully updated`, - ); - } - } catch (error) { - console.error( - `Failed to process donations rewards for project ${donations[0].projectId}: ${error.message}`, - ); + const donationValidContribution = ethers.BigNumber.from( + donationTransaction.validContribution, + ); + const contributionPercentage = + parseFloat(ethers.utils.formatUnits(donationValidContribution, 18)) / + parseFloat(ethers.utils.formatUnits(totalValidContribution, 18)); + + // Calculate the reward proportionally based on the valid contribution + const rewardAmount = issuanceAllocation * contributionPercentage; + donation.rewardTokenAmount = rewardAmount || 0; + + if (donation.rewardTokenAmount) { + const vestingInfo = getStreamDetails(isEarlyAccess); + + donation.cliff = vestingInfo.CLIFF * 1000; + donation.rewardStreamStart = new Date(vestingInfo.START * 1000); + donation.rewardStreamEnd = new Date(vestingInfo.END * 1000); } + + associateDonationToThisRound(donation, round, isEarlyAccess); + + await donation.save(); + console.debug(`Reward data for donation ${donation.id} successfully updated`); } export async function updateRewardsForDonations(batchNumber: number) { @@ -125,6 +207,8 @@ export async function updateRewardsForDonations(batchNumber: number) { ], }); + const { round, isEarlyAccess } = await getRoundByBatchNumber(batchNumber); + const donationsByProjectId = _.groupBy(donations, 'projectId'); const reportFilesDir = path.join(repoLocalDir, getReportsSubDir()); @@ -180,6 +264,8 @@ export async function updateRewardsForDonations(batchNumber: number) { await processReportForDonations( donationsByProjectId[projectId], matchedReportFile, + round, + isEarlyAccess, ); } } catch (error) {