Skip to content

Commit

Permalink
Merge pull request #144 from GeneralMagicio/addGitcoinScorerCheck
Browse files Browse the repository at this point in the history
Add gitcoin scorer check
  • Loading branch information
ae2079 authored Nov 28, 2024
2 parents 024ca74 + b3c2c83 commit 4ec63f8
Show file tree
Hide file tree
Showing 8 changed files with 113 additions and 22 deletions.
1 change: 1 addition & 0 deletions config/example.env
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ MONGO_DB_REPORT_DB_NAME=

# Gitcoin score
GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE=
GITCOIN_PASSPORT_MIN_VALID_SCORER_SCORE=
# 1 day
GITCOIN_PASSPORT_EXPIRATION_PERIOD_MS=86400000
MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD=
Expand Down
2 changes: 2 additions & 0 deletions src/constants/gitcoin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const GITCOIN_PASSPORT_EXPIRATION_PERIOD_MS =
(+config.get('GITCOIN_PASSPORT_EXPIRATION_PERIOD_MS') as number) || 86400000; // 1 day
export const GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE =
(+config.get('GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE') as number) || 50;
export const GITCOIN_PASSPORT_MIN_VALID_SCORER_SCORE =
(+config.get('GITCOIN_PASSPORT_MIN_VALID_SCORER_SCORE') as number) || 15;
export const MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD =
(+config.get('MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD') as number) ||
1000;
13 changes: 12 additions & 1 deletion src/entities/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ import { ProjectVerificationForm } from './projectVerificationForm';
import { ReferredEvent } from './referredEvent';
import { NOTIFICATIONS_EVENT_NAMES } from '../analytics/analytics';
import { PrivadoAdapter } from '../adapters/privado/privadoAdapter';
import { GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE } from '../constants/gitcoin';
import {
GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE,
GITCOIN_PASSPORT_MIN_VALID_SCORER_SCORE,
} from '../constants/gitcoin';

export const publicSelectionFields = [
'user.id',
Expand Down Expand Up @@ -245,6 +248,14 @@ export class User extends BaseEntity {
);
}

@Field(_type => Boolean, { nullable: true })
get hasEnoughGitcoinPassportScore(): boolean {
return !!(
this.passportScore &&
this.passportScore >= GITCOIN_PASSPORT_MIN_VALID_SCORER_SCORE
);
}

@Field(_type => Int, { nullable: true })
async donationsCount() {
return await Donation.createQueryBuilder('donation')
Expand Down
79 changes: 72 additions & 7 deletions src/resolvers/qAccResolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { ProjectRoundRecord } from '../entities/projectRoundRecord';
import { EarlyAccessRound } from '../entities/earlyAccessRound';
import {
GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE,
GITCOIN_PASSPORT_MIN_VALID_SCORER_SCORE,
MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD,
} from '../constants/gitcoin';
import { PrivadoAdapter } from '../adapters/privado/privadoAdapter';
Expand Down Expand Up @@ -281,7 +282,7 @@ function userCapsTestCases() {

sinon.restore();
});
it('should return correct caps for a user with GitcoinPassport', async () => {
it('should return correct caps for a user with analysis score', async () => {
// Save donations
const donationAmount = 100;
await saveDonationDirectlyToDb(
Expand All @@ -295,8 +296,69 @@ function userCapsTestCases() {
project.id,
);

// Simulate valid GitcoinPassport score
// Simulate valid analysis score
user.analysisScore = 80;
user.passportScore = 0;
user.passportScoreUpdateTimestamp = new Date();
await user.save();

const response: ExecutionResult<{
data: {
userCaps: {
qAccCap: number;
gitcoinPassport?: {
unusedCap: number;
};
zkId?: {
unusedCap: number;
};
};
};
}> = await axios.post(
graphqlUrl,
{
query: userCaps,
variables: { projectId: project.id },
},
{
headers: {
Authorization: `Bearer ${accessToken}`,
},
},
);

assert.equal(
response.data?.data.userCaps?.qAccCap,
Number(qfRound1.roundUSDCapPerUserPerProject) /
Number(qfRound1.tokenPrice) -
donationAmount,
);
assert.equal(
response.data?.data.userCaps?.gitcoinPassport?.unusedCap,
MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD /
Number(qfRound1.tokenPrice) -
donationAmount,
);
assert.isNull(response.data?.data.userCaps?.zkId);
});

it('should return correct caps for a user with passport score', async () => {
// Save donations
const donationAmount = 100;
await saveDonationDirectlyToDb(
{
...createDonationData(),
amount: donationAmount,
status: DONATION_STATUS.VERIFIED,
qfRoundId: qfRound1.id,
},
user.id,
project.id,
);

// Simulate valid GitcoinPassport score
user.analysisScore = 0;
user.passportScore = 30;
user.passportScoreUpdateTimestamp = new Date();
await user.save();

Expand Down Expand Up @@ -398,10 +460,12 @@ function userCapsTestCases() {
assert.isNull(response.data?.data.userCaps?.gitcoinPassport);
});

it('should throw an error if the user does not meet the minimum analysis score', async () => {
// Simulate invalid GitcoinPassport score
sinon.stub(user, 'analysisScore').value(40); // Below threshold
sinon.stub(user, 'hasEnoughGitcoinAnalysisScore').value(false);
it('should throw an error if the user does not meet the minimum analysis score and passport score', async () => {
// Simulate invalid GitcoinPassport scores
user.analysisScore = 40;
user.passportScore = 10;
user.passportScoreUpdateTimestamp = new Date();
await user.save();

// Act: Call the resolver through a GraphQL query and expect an error
try {
Expand All @@ -421,7 +485,8 @@ function userCapsTestCases() {
// Assert: Verify the error message
assert.equal(
error.response.data.errors[0].message,
`analysis score is less than ${GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE}`,
`analysis score is less than ${GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE}
and passport score is less than ${GITCOIN_PASSPORT_MIN_VALID_SCORER_SCORE}`,
);
}
});
Expand Down
5 changes: 4 additions & 1 deletion src/resolvers/qAccResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,10 @@ export class QAccResolver {
response.zkId = {
unusedCap: qAccCap,
};
} else if (dbUser.hasEnoughGitcoinAnalysisScore) {
} else if (
dbUser.hasEnoughGitcoinAnalysisScore ||
dbUser.hasEnoughGitcoinPassportScore
) {
const cap = await qAccService.getUserRemainedCapBasedOnGitcoinScore({
projectId,
user: dbUser,
Expand Down
5 changes: 4 additions & 1 deletion src/resolvers/qfRoundResolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import { generateRandomString } from '../utils/utils';
import { OrderDirection } from './projectResolver';
import { QfArchivedRoundsSortType } from '../repositories/qfRoundRepository';

describe('Fetch estimatedMatching test cases', fetchEstimatedMatchingTestCases);
describe.skip(
'Fetch estimatedMatching test cases',
fetchEstimatedMatchingTestCases,
);
describe('Fetch qfRoundStats test cases', fetchQfRoundStatesTestCases);
describe('Fetch archivedQFRounds test cases', fetchArchivedQFRoundsTestCases);
describe('update scoreUserAddress test cases', scoreUserAddressTestCases);
Expand Down
16 changes: 11 additions & 5 deletions src/services/qAccService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import { findActiveEarlyAccessRound } from '../repositories/earlyAccessRoundRepo
import { updateOrCreateProjectRoundRecord } from '../repositories/projectRoundRecordRepository';
import { updateOrCreateProjectUserRecord } from '../repositories/projectUserRecordRepository';
import { findActiveQfRound } from '../repositories/qfRoundRepository';
import { updateUserGitcoinAnalysisScore } from './userService';
import { updateUserGitcoinScores } from './userService';
import {
GITCOIN_PASSPORT_EXPIRATION_PERIOD_MS,
GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE,
GITCOIN_PASSPORT_MIN_VALID_SCORER_SCORE,
MAX_CONTRIBUTION_WITH_GITCOIN_PASSPORT_ONLY_USD,
} from '../constants/gitcoin';

Expand Down Expand Up @@ -210,16 +211,21 @@ const getUserRemainedCapBasedOnGitcoinScore = async ({
user: User;
}): Promise<number> => {
if (
!user.analysisScore ||
user.passportScore === null ||
user.analysisScore === null ||
!user.passportScoreUpdateTimestamp ||
user.passportScoreUpdateTimestamp.getTime() <
Date.now() - GITCOIN_PASSPORT_EXPIRATION_PERIOD_MS
) {
await updateUserGitcoinAnalysisScore(user);
await updateUserGitcoinScores(user);
}
if (!user.hasEnoughGitcoinAnalysisScore) {
if (
!user.hasEnoughGitcoinAnalysisScore &&
!user.hasEnoughGitcoinPassportScore
) {
throw new Error(
`analysis score is less than ${GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE}`,
`analysis score is less than ${GITCOIN_PASSPORT_MIN_VALID_ANALYSIS_SCORE}
and passport score is less than ${GITCOIN_PASSPORT_MIN_VALID_SCORER_SCORE}`,
);
}
const userRecord = await getUserProjectRecord({
Expand Down
14 changes: 7 additions & 7 deletions src/services/userService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,13 @@ export const fetchAdminAndValidatePassword = async (params: {
}
};

export const updateUserGitcoinAnalysisScore = async (user: User) => {
// const passportScore = await getGitcoinAdapter().getWalletAddressScore(
// user.walletAddress as string,
// );
// if (passportScore && passportScore?.score) {
// user.passportScore = Number(passportScore.score);
// }
export const updateUserGitcoinScores = async (user: User) => {
const passportScore = await getGitcoinAdapter().getWalletAddressScore(
user.walletAddress as string,
);
if (passportScore && passportScore?.score) {
user.passportScore = Number(passportScore.score);
}
user.analysisScore = await getGitcoinAdapter().getUserAnalysisScore(
user.walletAddress as string,
);
Expand Down

0 comments on commit 4ec63f8

Please sign in to comment.