Skip to content

Commit

Permalink
allocatedGivbacks() endpoint implemented and works
Browse files Browse the repository at this point in the history
  • Loading branch information
mohammadranjbarz committed Sep 11, 2024
1 parent 7535117 commit 05d67d8
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 26 deletions.
123 changes: 120 additions & 3 deletions src/resolvers/donationResolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4970,7 +4970,7 @@ async function donationMetricsTestCases() {
}

async function allocatedGivbacksQueryTestCases() {
it.only('should return correct donation metrics', async () => {
it('should return allocated givbacks correctly', async () => {
// 3 donations with 2 different donor
const project = await saveProjectDirectlyToDb({
...createProjectData(),
Expand Down Expand Up @@ -5039,8 +5039,125 @@ async function allocatedGivbacksQueryTestCases() {
{},
);

const { givbacks } = result.data.data;
assert.isNotNull(givbacks);
const allocatedGivbacks = result.data.data?.allocatedGivbacks;
assert.isNotNull(allocatedGivbacks);
assert.equal(
allocatedGivbacks.usdValueSentAmountInPowerRound,
valueUsd1 * givbackFactor1 + valueUsd2 * givbackFactor2,
);
});
it('should return allocated givbacks correctly when pass refreshCache variable', async () => {
// 3 donations with 2 different donor
const project = await saveProjectDirectlyToDb({
...createProjectData(),
title: String(new Date().getTime()),
slug: String(new Date().getTime()),
});
const donor1 = await saveUserDirectlyToDb(generateRandomEtheriumAddress());
const donor2 = await saveUserDirectlyToDb(generateRandomEtheriumAddress());

const valueUsd1 = 100;
const givbackFactor1 = 0.5;

const valueUsd2 = 200;
const givbackFactor2 = 0.65;

const valueUsd3 = 300;
const givbackFactor3 = 0.7;

const powerRound = 321425;
await setPowerRound(powerRound);

await saveDonationDirectlyToDb(
{
...createDonationData(),
status: 'verified',
valueUsd: valueUsd1,
powerRound,
givbackFactor: givbackFactor1,
isProjectVerified: true,
},
donor1.id,
project.id,
);

await saveDonationDirectlyToDb(
{
...createDonationData(),
status: 'verified',
valueUsd: valueUsd2,
powerRound,
givbackFactor: givbackFactor2,
isProjectVerified: true,
},
donor1.id,
project.id,
);

const result1 = await axios.post(
graphqlUrl,
{
query: allocatedGivbacksQuery,
},
{},
);

const allocatedGivbacks1 = result1.data.data?.allocatedGivbacks;
assert.isNotNull(allocatedGivbacks1);
assert.equal(
allocatedGivbacks1.usdValueSentAmountInPowerRound,
valueUsd1 * givbackFactor1 + valueUsd2 * givbackFactor2,
);

await saveDonationDirectlyToDb(
{
...createDonationData(),
status: 'verified',
valueUsd: valueUsd3,
powerRound,
givbackFactor: givbackFactor3,
isProjectVerified: true,
},
donor2.id,
project.id,
);

const result2 = await axios.post(
graphqlUrl,
{
query: allocatedGivbacksQuery,
},
{},
);

const allocatedGivbacks2 = result2.data.data?.allocatedGivbacks;
// should use the previous result because of cache
assert.equal(
allocatedGivbacks2.usdValueSentAmountInPowerRound,
allocatedGivbacks1.usdValueSentAmountInPowerRound,
);
assert.equal(allocatedGivbacks2.date, allocatedGivbacks1.date);

const result3 = await axios.post(
graphqlUrl,
{
query: allocatedGivbacksQuery,
variables: {
refreshCache: true,
},
},
{},
);

const allocatedGivbacks3 = result3.data.data?.allocatedGivbacks;

// should refresh the cache when pass refreshCache variable
assert.equal(
allocatedGivbacks3.usdValueSentAmountInPowerRound,
allocatedGivbacks1.usdValueSentAmountInPowerRound +
valueUsd3 * givbackFactor3,
);
assert.notEqual(allocatedGivbacks3.date, allocatedGivbacks1.date);
});
}

Expand Down
41 changes: 26 additions & 15 deletions src/resolvers/donationResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import { getTokenPrice } from '../services/priceService';
import { findTokenByNetworkAndSymbol } from '../utils/tokenUtils';

const draftDonationEnabled = process.env.ENABLE_DRAFT_DONATION === 'true';

@ObjectType()
export class AllocatedGivbacks {
@Field()
Expand All @@ -86,7 +87,11 @@ export class AllocatedGivbacks {

@Field()
givPrice: number;

@Field()
date: Date;
}

let allocatedGivbacksCache: AllocatedGivbacks | null;

@ObjectType()
Expand Down Expand Up @@ -444,8 +449,10 @@ export class DonationResolver {
}

@Query(_returns => AllocatedGivbacks, { nullable: true })
async allocatedGivbacks(): Promise<AllocatedGivbacks> {
if (allocatedGivbacksCache) {
async allocatedGivbacks(
@Arg('refreshCache', { nullable: true }) refreshCache?: boolean,
): Promise<AllocatedGivbacks> {
if (allocatedGivbacksCache && !refreshCache) {
return allocatedGivbacksCache;
}
const usdValueSentAmountInPowerRound =
Expand All @@ -457,27 +464,31 @@ export class DonationResolver {
const givPrice = await getTokenPrice(NETWORK_IDS.MAIN_NET, givToken);

const maxSentGivInRound = 1_000_000;
const allocatedGivTokens = Math.min(
maxSentGivInRound,
usdValueSentAmountInPowerRound / givPrice,
const allocatedGivTokens = Math.ceil(
Math.min(maxSentGivInRound, usdValueSentAmountInPowerRound / givPrice),
);
allocatedGivbacksCache = {
allocatedGivTokens,
givPrice,
usdValueSentAmountInPowerRound,
};
const date = new Date();
if (givPrice) {
allocatedGivbacksCache = {
allocatedGivTokens,
givPrice,
usdValueSentAmountInPowerRound,
date,
};

// 10 minute cache
const sentGivbackCacheTimeout = 1000 * 60 * 10;
// 60 minute cache
const sentGivbackCacheTimeout = 1000 * 60 * 60;

setTimeout(() => {
allocatedGivbacksCache = null;
}, sentGivbackCacheTimeout);
setTimeout(() => {
allocatedGivbacksCache = null;
}, sentGivbackCacheTimeout);
}

return {
usdValueSentAmountInPowerRound,
allocatedGivTokens,
givPrice,
date,
};
}

Expand Down
8 changes: 2 additions & 6 deletions src/resolvers/projectResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1785,15 +1785,11 @@ export class ProjectResolver {
// return isWalletAddressSmartContract(address);
// }

/**
* Can a project use this wallet?
* @param address wallet address
* @returns
*/
@Query(_returns => Boolean)
async walletAddressIsValid(
@Arg('address') address: string,
@Arg('chainType', { nullable: true }) chainType?: ChainType,
@Arg('chainType', () => ChainType, { nullable: true })
chainType?: ChainType, // Explicitly set the type of chainType
@Arg('memo', { nullable: true }) memo?: string,
) {
return validateProjectWalletAddress(address, undefined, chainType, memo);
Expand Down
14 changes: 12 additions & 2 deletions test/graphqlQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2250,8 +2250,18 @@ export const getUserProjectPowerQuery = `
`;

export const allocatedGivbacksQuery = `
query {
allocatedGivbacks
query (
$refreshCache: Boolean
) {
allocatedGivbacks(
refreshCache: $refreshCache
) {
usdValueSentAmountInPowerRound
allocatedGivTokens
givPrice
date
}
}
`;

export const getBottomPowerRankQuery = `
Expand Down

0 comments on commit 05d67d8

Please sign in to comment.