forked from passportxyz/passport
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(platforms): allo stamp (passportxyz#1579)
* feat(platforms): base allo stamp * feat(app, platforms, types): allo -> grantsstack stamp * feat(app): allo stamp credential logic * feat(app, platforms): add logo and banner for grants stack stamp * chore(platforms): test grantsStack provider * feat(platforms): use datakey to index allo count response * chore(app): remove feature flag
- Loading branch information
1 parent
a5942d8
commit 0bb096c
Showing
10 changed files
with
261 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { AppContext, ProviderPayload } from "../types"; | ||
import { Platform } from "../utils/platform"; | ||
|
||
export class GrantsStackPlatform extends Platform { | ||
platformId = "GrantsStack"; | ||
path = "GrantsStack"; | ||
clientId: string = null; | ||
redirectUri: string = null; | ||
|
||
banner = { | ||
heading: | ||
"Note: Only Alpha and Beta rounds run by Gitcoin are included. For the Alpha program, only donations larger than $1 are counted. For the Beta program, only matching-eligible contributions are counted.", | ||
}; | ||
|
||
async getProviderPayload(appContext: AppContext): Promise<ProviderPayload> { | ||
const result = await Promise.resolve({}); | ||
return result; | ||
} | ||
|
||
getOAuthUrl(state: string): Promise<string> { | ||
throw new Error("Method not implemented."); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { PlatformSpec, PlatformGroupSpec, Provider } from "../types"; | ||
import { GrantsStackProvider } from "./Providers/GrantsStack"; | ||
|
||
export const PlatformDetails: PlatformSpec = { | ||
icon: "./assets/grantsStackLogo.svg", | ||
platform: "GrantsStack", | ||
name: "GrantsStack", | ||
description: "Connect your existing GrantsStack Account to verify", | ||
connectMessage: "Connect Account", | ||
}; | ||
|
||
export const ProviderConfig: PlatformGroupSpec[] = [ | ||
{ | ||
platformGroup: "Projects Contributed To:", | ||
providers: [ | ||
{ title: "Supported 3+ unique projects", name: "GrantsStack3Projects" }, | ||
{ title: "Supported 5+ unique projects", name: "GrantsStack5Projects" }, | ||
{ title: "Supported 7+ unique projects", name: "GrantsStack7Projects" }, | ||
], | ||
}, | ||
{ | ||
platformGroup: "Matching Fund Programs Participation:", | ||
providers: [ | ||
{ title: "Contributed to 2+ unique programs.", name: "GrantsStack2Programs" }, | ||
{ title: "Contributed to 4+ unique programs.", name: "GrantsStack4Programs" }, | ||
{ title: "Contributed to 6+ unique programs.", name: "GrantsStack6Programs" }, | ||
], | ||
}, | ||
]; | ||
|
||
export const providers: Provider[] = [ | ||
new GrantsStackProvider({ | ||
type: "GrantsStack3Projects", | ||
dataKey: "projectCount", | ||
threshold: 3, | ||
}), | ||
new GrantsStackProvider({ | ||
type: "GrantsStack5Projects", | ||
dataKey: "projectCount", | ||
threshold: 5, | ||
}), | ||
new GrantsStackProvider({ | ||
type: "GrantsStack7Projects", | ||
dataKey: "projectCount", | ||
threshold: 7, | ||
}), | ||
new GrantsStackProvider({ | ||
type: "GrantsStack2Programs", | ||
dataKey: "programCount", | ||
threshold: 2, | ||
}), | ||
new GrantsStackProvider({ | ||
type: "GrantsStack4Programs", | ||
dataKey: "programCount", | ||
threshold: 4, | ||
}), | ||
new GrantsStackProvider({ | ||
type: "GrantsStack6Programs", | ||
dataKey: "programCount", | ||
threshold: 6, | ||
}), | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import type { Provider, ProviderOptions } from "../../types"; | ||
import { ProviderContext, PROVIDER_ID, RequestPayload, VerifiedPayload } from "@gitcoin/passport-types"; | ||
import axios from "axios"; | ||
|
||
export type GrantsStackProviderOptions = ProviderOptions & { | ||
type: PROVIDER_ID; | ||
dataKey: keyof GrantsStackCounts; | ||
threshold: number; | ||
}; | ||
|
||
type GrantsStackCounts = { | ||
projectCount?: number; | ||
programCount?: number; | ||
}; | ||
|
||
export type GrantsStackContext = ProviderContext & { | ||
grantsStack?: GrantsStackCounts; | ||
}; | ||
|
||
type StatisticResponse = { | ||
num_grants_contribute_to: number; | ||
num_rounds_contribute_to: number; | ||
total_valid_contribution_amount: number; | ||
num_gr14_contributions: number; | ||
}; | ||
|
||
export const getGrantsStackData = async ( | ||
payload: RequestPayload, | ||
context: GrantsStackContext | ||
): Promise<GrantsStackCounts> => { | ||
try { | ||
if (!context?.grantsStack?.projectCount || !context?.grantsStack?.programCount) { | ||
const grantStatisticsRequest: { | ||
data: StatisticResponse; | ||
} = await axios.get(`${process.env.CGRANTS_API_URL}/allo/contributor_statistics`, { | ||
headers: { Authorization: process.env.CGRANTS_API_TOKEN }, | ||
params: { address: payload.address }, | ||
}); | ||
|
||
if (!context.grantsStack) context.grantsStack = {}; | ||
|
||
context.grantsStack.projectCount = grantStatisticsRequest.data.num_grants_contribute_to; | ||
context.grantsStack.programCount = grantStatisticsRequest.data.num_rounds_contribute_to; | ||
|
||
return context.grantsStack; | ||
} | ||
return context.grantsStack; | ||
} catch (e) { | ||
throw new Error("Error getting GrantsStack data"); | ||
} | ||
}; | ||
|
||
export class GrantsStackProvider implements Provider { | ||
type: PROVIDER_ID; | ||
threshold: number; | ||
dataKey: keyof GrantsStackCounts; | ||
|
||
constructor(options: GrantsStackProviderOptions) { | ||
this.type = options.type; | ||
this.threshold = options.threshold; | ||
this.dataKey = options.dataKey; | ||
} | ||
|
||
async verify(payload: RequestPayload, context: ProviderContext): Promise<VerifiedPayload> { | ||
try { | ||
const grantsStackData = await getGrantsStackData(payload, context); | ||
const count = grantsStackData[this.dataKey]; | ||
const valid = count >= this.threshold; | ||
const errors = !valid ? [`${this.dataKey}: ${count} is less than ${this.threshold}`] : []; | ||
const contributionStatistic = `${this.type}-${this.threshold}-contribution-statistic`; | ||
return { | ||
valid, | ||
errors, | ||
record: { | ||
address: payload.address, | ||
contributionStatistic, | ||
}, | ||
}; | ||
} catch (e) { | ||
throw new Error("Error verifying GrantsStack data"); | ||
} | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
platforms/src/GrantsStack/Providers/__tests__/GrantsStack.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import axios from "axios"; | ||
import { GrantsStackProvider, getGrantsStackData } from "../GrantsStack"; | ||
import { RequestPayload, PROVIDER_ID } from "@gitcoin/passport-types"; | ||
|
||
// Mocking axios | ||
jest.mock("axios"); | ||
|
||
// Common setup | ||
const userAddress = "0x123"; | ||
const requestPayload = { address: userAddress } as RequestPayload; | ||
|
||
describe("GrantsStackProvider", () => { | ||
// Testing getGrantsStackData function | ||
describe("getGrantsStackData", () => { | ||
it("should fetch GrantsStack data successfully", async () => { | ||
// Mock the axios response | ||
(axios.get as jest.Mock).mockResolvedValue({ | ||
data: { num_grants_contribute_to: 10, num_rounds_contribute_to: 5 }, | ||
}); | ||
const context = {}; | ||
const result = await getGrantsStackData(requestPayload, context); | ||
expect(result).toEqual({ projectCount: 10, programCount: 5 }); | ||
}); | ||
|
||
it("should throw error when fetching GrantsStack data fails", async () => { | ||
// Mock an axios error | ||
(axios.get as jest.Mock).mockRejectedValue(new Error("Network Error")); | ||
const context = {}; | ||
await expect(() => getGrantsStackData(requestPayload, context)).rejects.toThrow("Error getting GrantsStack data"); | ||
}); | ||
}); | ||
|
||
// Testing GrantsStackProvider class | ||
describe("verify method", () => { | ||
it("should verify GrantsStack data and return valid true if threshold is met", async () => { | ||
const providerId = "GrantsStack5Projects"; | ||
const threshold = 5; | ||
const provider = new GrantsStackProvider({ type: providerId, threshold, dataKey: "projectCount" }); | ||
// Using the previously tested getGrantsStackData, we'll assume it works as expected | ||
const verifiedPayload = await provider.verify(requestPayload, { | ||
grantsStack: { projectCount: 10, programCount: 1 }, | ||
}); | ||
expect(verifiedPayload).toMatchObject({ | ||
valid: true, | ||
record: { | ||
address: userAddress, | ||
contributionStatistic: `${providerId}-${threshold}-contribution-statistic`, | ||
}, | ||
}); | ||
}); | ||
|
||
it("should verify GrantsStack data and return valid false if threshold is not met", async () => { | ||
const providerId = "GrantsStack5Projects"; | ||
const provider = new GrantsStackProvider({ type: providerId, threshold: 15, dataKey: "projectCount" }); | ||
const verifiedPayload = await provider.verify(requestPayload, { | ||
grantsStack: { projectCount: 10, programCount: 1 }, | ||
}); | ||
expect(verifiedPayload).toMatchObject({ valid: false }); | ||
}); | ||
|
||
it("should throw an error if verification fails", async () => { | ||
const providerId = "GrantsStack5Projects"; | ||
// Mock the axios response to throw an error in getGrantsStackData | ||
(axios.get as jest.Mock).mockRejectedValue(new Error("Network Error")); | ||
const provider = new GrantsStackProvider({ type: providerId, threshold: 5, dataKey: "projectCount" }); | ||
await expect(() => provider.verify(requestPayload, {})).rejects.toThrow("Error verifying GrantsStack data"); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export { GrantsStackProvider } from "./Providers/GrantsStack"; | ||
export { GrantsStackPlatform } from "./App-Bindings"; | ||
export { ProviderConfig, PlatformDetails, providers } from "./Providers-config"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
process.env.ZKSYNC_ERA_MAINNET_ENDPOINT = "https://zksync-era-api-endpoint.io"; | ||
process.env.ZKSYNC_ERA_MAINNET_ENDPOINT = "https://zksync-era-api-endpoint.io"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters