Skip to content

Commit fc33919

Browse files
authored
add whitelist (#3725)
implement different statuses fix test fix icon color fix collection size (#3723) * fix collection size * fix height * slice string * add description to collection details * add cols * edit slice length * remove log added copy functionality to project owner address on ViewProjectDetails page. (#3724) * added copy functionality * Update package.json add verified filter
1 parent 8f89823 commit fc33919

File tree

13 files changed

+237
-46
lines changed

13 files changed

+237
-46
lines changed

packages/common/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,3 +488,4 @@ export function isLitUnavailable(chainId: number) {
488488
}
489489

490490
export * from "./chains";
491+
export * from "./programWhitelist";
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
export type WhitelistStatus = "Accepted" | "Rejected" | "Pending";
2+
3+
interface ProgramData {
4+
programId: string;
5+
whitelistStatus: WhitelistStatus;
6+
}
7+
8+
async function fetchProgramsData(): Promise<ProgramData[]> {
9+
try {
10+
const response = await fetch(
11+
"https://docs.google.com/spreadsheets/d/e/2PACX-1vQxC34V_N3ubt3ycs7LvMya_zYeBmAqTxPczt0yDbLSfpI-kMp6o5E08fC0BxQG4uMp7EPV5bxP-64a/pub?gid=0&single=true&output=csv"
12+
);
13+
14+
if (!response.ok) {
15+
throw new Error(`HTTP error! status: ${response.status}`);
16+
}
17+
const csvText = await response.text();
18+
19+
const stringArray = csvText
20+
.split(/\r?\n/)
21+
.filter((line) => line.trim() !== "");
22+
23+
const programsData = stringArray.map((line) => {
24+
const [programId, whitelistStatus] = line.split(",") as [
25+
string,
26+
WhitelistStatus,
27+
];
28+
return { programId, whitelistStatus };
29+
});
30+
31+
return programsData;
32+
} catch (error) {
33+
console.error("Failed to fetch or process the CSV:", error);
34+
return [];
35+
}
36+
}
37+
38+
export async function getWhitelistedPrograms(): Promise<string[]> {
39+
const programsData = await fetchProgramsData();
40+
return programsData
41+
.filter((program) => program.whitelistStatus === "Accepted")
42+
.map((program) => program.programId);
43+
}
44+
45+
export async function isProgramWhitelisted(
46+
programId: string
47+
): Promise<boolean> {
48+
const whitelistedPrograms = await getWhitelistedPrograms();
49+
return whitelistedPrograms.includes(programId);
50+
}
51+
52+
export async function getAllProgramsData(): Promise<ProgramData[]> {
53+
return await fetchProgramsData();
54+
}
55+
56+
export async function getProgramWhitelistStatus(
57+
programId: string
58+
): Promise<WhitelistStatus | null> {
59+
const programsData = await fetchProgramsData();
60+
const program = programsData.find(
61+
(program) => program.programId === programId
62+
);
63+
return program ? program.whitelistStatus : null;
64+
}

packages/data-layer/src/data-layer.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -942,18 +942,25 @@ export class DataLayer {
942942
first,
943943
orderBy,
944944
filter,
945+
whitelistedPrograms,
945946
}: {
946947
chainIds: number[];
947948
first: number;
948949
orderBy?: OrderByRounds;
949950
orderDirection?: "asc" | "desc";
950951
filter?: RoundsQueryVariables["filter"];
952+
whitelistedPrograms?: string[];
951953
}): Promise<{ rounds: RoundGetRound[] }> {
952954
return await request(this.gsIndexerEndpoint, getRoundsQuery, {
953955
orderBy: orderBy ?? "NATURAL",
954956
chainIds,
955957
first,
956-
filter,
958+
filter: whitelistedPrograms
959+
? {
960+
...filter,
961+
projectId: { in: whitelistedPrograms },
962+
}
963+
: filter,
957964
});
958965
}
959966

@@ -1011,8 +1018,8 @@ export class DataLayer {
10111018
async getAttestationCount({
10121019
attestationChainIds,
10131020
}: {
1014-
attestationChainIds: number[]
1021+
attestationChainIds: number[];
10151022
}): Promise<number> {
1016-
return this.attestationService.getAttestationCount({attestationChainIds});
1023+
return this.attestationService.getAttestationCount({ attestationChainIds });
10171024
}
10181025
}

packages/grant-explorer/src/features/api/rounds.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,31 @@
1+
import { getWhitelistedPrograms } from "common";
12
import useSWR, { SWRResponse } from "swr";
23
import { createISOTimestamp } from "../discovery/utils/createRoundsStatusFilter";
34
import { RoundGetRound, RoundsQueryVariables, useDataLayer } from "data-layer";
45

56
export const useRounds = (
67
variables: RoundsQueryVariables,
7-
chainIds: number[]
8+
chainIds: number[],
9+
onlywWhitelistedPrograms = false
810
): SWRResponse<RoundGetRound[]> => {
911
const dataLayer = useDataLayer();
1012

1113
const query = useSWR(
1214
// Cache requests on chainIds and variables as keys (when these are the
1315
// same, cache will be used instead of new requests)
14-
["rounds", chainIds, variables],
16+
["rounds", chainIds, variables, onlywWhitelistedPrograms],
1517
async () => {
18+
const whitelistedPrograms = onlywWhitelistedPrograms
19+
? await getWhitelistedPrograms()
20+
: undefined;
21+
1622
const [spamRounds, { rounds }] = await Promise.all([
1723
fetchSpamRounds(),
1824
dataLayer.getRounds({
1925
...variables,
2026
first: 500,
2127
chainIds,
28+
whitelistedPrograms,
2229
}),
2330
]);
2431

@@ -64,8 +71,9 @@ const OVERRIDE_PRIVATE_ROUND_IDS = [
6471
export const filterOutPrivateRounds = (rounds: RoundGetRound[]) => {
6572
return rounds.filter(
6673
(round) =>
67-
(round.roundMetadata && round.roundMetadata.roundType) &&
68-
round.roundMetadata.roundType !== "private" ||
74+
(round.roundMetadata &&
75+
round.roundMetadata.roundType &&
76+
round.roundMetadata.roundType !== "private") ||
6977
OVERRIDE_PRIVATE_ROUND_IDS.includes(round.id.toLowerCase())
7078
);
7179
};

packages/grant-explorer/src/features/discovery/ExploreRoundsPage.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,23 @@ import { useMemo } from "react";
1515
const ExploreRoundsPage = () => {
1616
const [params] = useSearchParams();
1717
const filter = getRoundSelectionParamsFromUrlParams(params);
18-
1918
// Pass the filter from the search params and build the graphql query
20-
const rounds = useFilterRounds(filter, getEnabledChains());
19+
const rounds = useFilterRounds(
20+
filter,
21+
getEnabledChains(),
22+
filter.status.includes("verified")
23+
);
2124

22-
const publicRounds = useMemo(() => rounds.data?.filter(round => (round.roundMetadata && round.roundMetadata.roundType) && round.roundMetadata.roundType?.toLowerCase() !== "private"), [rounds]);
25+
const publicRounds = useMemo(
26+
() =>
27+
rounds.data?.filter(
28+
(round) =>
29+
round.roundMetadata &&
30+
round.roundMetadata.roundType &&
31+
round.roundMetadata.roundType?.toLowerCase() !== "private"
32+
),
33+
[rounds]
34+
);
2335
rounds.data = publicRounds;
2436

2537
const sectionTitle = getExplorerPageTitle(filter);

packages/grant-explorer/src/features/discovery/FilterDropdown.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,14 @@ export const FILTER_OPTIONS: RoundFilterUiOption[] = [
4141
},
4242
],
4343
},
44-
4544
{
4645
label: "Status",
4746
value: "status",
4847
children: [
48+
{
49+
label: "Verified",
50+
value: "verified",
51+
},
4952
{
5053
label: "Active",
5154
value: RoundStatus.active,
@@ -75,7 +78,6 @@ export function FilterDropdown() {
7578

7679
const filter = getRoundSelectionParamsFromUrlParams(params);
7780
const { status = "", type = "", network = "" } = filter;
78-
7981
const selected = getFilterLabel({ status, type, network });
8082
return (
8183
<Dropdown
@@ -133,7 +135,7 @@ export function FilterDropdown() {
133135
>
134136
<Disclosure.Panel
135137
static
136-
className=" mt-1 w-full overflow-auto p-2"
138+
className="mt-1 w-full overflow-auto p-2"
137139
>
138140
{children
139141
?.filter((child) => !child.hide)

packages/grant-explorer/src/features/discovery/LandingPage.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@ import { CollectionsGrid } from "../collections/CollectionsGrid";
2222
const LandingPage = () => {
2323
const activeRounds = useFilterRounds(
2424
ACTIVE_ROUNDS_FILTER,
25-
getEnabledChains()
25+
getEnabledChains(),
26+
true
2627
);
2728
const roundsEndingSoon = useFilterRounds(
2829
ROUNDS_ENDING_SOON_FILTER,
29-
getEnabledChains()
30+
getEnabledChains(),
31+
true
3032
);
3133

3234
const filteredActiveRounds = useMemo(() => {
@@ -81,7 +83,7 @@ const LandingPage = () => {
8183
<ViewAllLink
8284
to={`/rounds?${toQueryString({
8385
orderBy: ROUNDS_ENDING_SOON_FILTER.orderBy,
84-
status: RoundStatus.active,
86+
status: `${RoundStatus.active},verified`,
8587
})}`}
8688
>
8789
View all

packages/grant-explorer/src/features/discovery/LandingTabs.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ export default function LandingTabs() {
3131
{
3232
to: `/rounds?${toQueryString({
3333
orderBy: "MATCH_AMOUNT_IN_USD_DESC",
34-
status: [RoundStatus.active, RoundStatus.taking_applications].join(","),
34+
status: [
35+
RoundStatus.active,
36+
RoundStatus.taking_applications,
37+
"verified",
38+
].join(","),
3539
})}`,
3640
activeRegExp: /^\/rounds/,
3741
children: isDesktop ? "Explore rounds" : "Rounds",

packages/grant-explorer/src/features/discovery/__tests__/LandingPage.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ vi.mock("common", async () => {
1919
return {
2020
...actual,
2121
renderToPlainText: vi.fn().mockReturnValue((str = "") => str),
22+
getWhitelistedPrograms: vi.fn().mockResolvedValue(undefined),
2223
};
2324
});
2425

@@ -60,7 +61,6 @@ vi.mock("wagmi", async () => {
6061
});
6162

6263
describe("LandingPage", () => {
63-
6464
it("renders landing page", () => {
6565
renderWithContext(<LandingPage />);
6666
});

packages/grant-explorer/src/features/discovery/hooks/useFilterRounds.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export enum RoundStatus {
5757

5858
export const ACTIVE_ROUNDS_FILTER: RoundSelectionParams = {
5959
orderBy: "MATCH_AMOUNT_IN_USD_DESC",
60-
status: RoundStatus.active,
60+
status: `${RoundStatus.active},verified`,
6161
type: "allov2.DonationVotingMerkleDistributionDirectTransferStrategy,allov1.QF",
6262
network: "",
6363
};
@@ -69,12 +69,13 @@ export const ROUNDS_ENDING_SOON_FILTER: RoundSelectionParams & {
6969
orderBy: "DONATIONS_END_TIME_ASC",
7070
type: "",
7171
network: "",
72-
status: RoundStatus.ending_soon,
72+
status: `${RoundStatus.ending_soon},verified`,
7373
};
7474

7575
export const useFilterRounds = (
7676
where: RoundSelectionParams,
77-
chains: TChain[]
77+
chains: TChain[],
78+
onlywWhitelistedPrograms?: boolean
7879
): SWRResponse<RoundGetRound[]> => {
7980
const chainIds =
8081
where.network === undefined || where.network.trim() === ""
@@ -102,7 +103,7 @@ export const useFilterRounds = (
102103
const orderBy =
103104
where.orderBy === undefined ? "CREATED_AT_BLOCK_DESC" : where.orderBy;
104105
const vars = { orderBy, filter };
105-
return useRounds(vars, chainIds);
106+
return useRounds(vars, chainIds, onlywWhitelistedPrograms);
106107
};
107108

108109
const createRoundWhereFilter = (

0 commit comments

Comments
 (0)