-
Notifications
You must be signed in to change notification settings - Fork 66
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #392 from privacy-scaling-explorations/integration…
…/eas Add EAS provider with default `EAS_ATTESTATIONS` validator
- Loading branch information
Showing
11 changed files
with
268 additions
and
13 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
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,6 +1,6 @@ | ||
import { Provider } from "./types" | ||
import { github, twitter, blockchain } from "./providers/index" | ||
import { github, twitter, blockchain, eas } from "./providers/index" | ||
|
||
const providers: Provider[] = [github, twitter, blockchain] | ||
const providers: Provider[] = [github, twitter, blockchain, eas] | ||
|
||
export default providers |
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,22 @@ | ||
import { EASProvider, EASNetworks } from "../.." | ||
import queryGraph from "../../queryGraph" | ||
|
||
// Graph endpoint for ethereum mainnet. | ||
const easDefaultEndpoint = `https://easscan.org/graphql` | ||
const easNetworkEndpoint = (network: EASNetworks) => | ||
`https://${network}.easscan.org/graphql` | ||
|
||
const provider: EASProvider = { | ||
name: "eas", | ||
|
||
async queryGraph(network: EASNetworks, query: string) { | ||
return queryGraph( | ||
network === EASNetworks.ETHEREUM | ||
? easDefaultEndpoint | ||
: easNetworkEndpoint(network), | ||
query | ||
) | ||
} | ||
} | ||
|
||
export default provider |
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,5 +1,6 @@ | ||
import github from "./github" | ||
import twitter from "./twitter" | ||
import blockchain from "./blockchain" | ||
import eas from "./eas" | ||
|
||
export { github, twitter, blockchain } | ||
export { github, twitter, blockchain, eas } |
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,18 @@ | ||
import { request } from "@bandada/utils" | ||
|
||
/** | ||
* It returns a function that can be used to query graphs | ||
* data using GraphQL style queries for the EAS provider supported by Bandada. | ||
* @param endpoint The endpoint of the graph. | ||
* @param query The query to execute to fetch the data. | ||
* @returns The function to query the graph. | ||
*/ | ||
export default function queryGraph(endpoint: string, query: string) { | ||
request(endpoint, { | ||
method: "POST", | ||
headers: { "Content-Type": "application/json" }, | ||
data: JSON.stringify({ | ||
query | ||
}) | ||
}) | ||
} |
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
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
139 changes: 139 additions & 0 deletions
139
libs/credentials/src/validators/easAttestations/index.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,139 @@ | ||
import { validateCredentials } from "../.." | ||
import easAttestations from "./index" | ||
|
||
describe("EASAttestations", () => { | ||
const queryGraphMocked = { | ||
queryGraph: jest.fn() | ||
} | ||
|
||
it("Should return true if an account has greater than or equal to 3 attestations", async () => { | ||
queryGraphMocked.queryGraph.mockReturnValue([ | ||
{ | ||
id: "0x52561c95029d9f2335839ddc96a69ee9737a18e2a781e64659b7bd645ccb8efc", | ||
recipient: "0x9aB3971e1b065701C72C5f3cAFbF33118dC51ae8" | ||
}, | ||
{ | ||
id: "0xee06a022c7d55f67bac213d6b2cd384a899ef79a57f1f5f148e45c313b4fdebe", | ||
recipient: "0x9aB3971e1b065701C72C5f3cAFbF33118dC51ae8" | ||
}, | ||
{ | ||
id: "0xfbc0f1aac4379c18fa9a5b6493825234a8ca82a2a296148465d150c2e64c6202", | ||
recipient: "0x0000000000000000000000000000000000000000" | ||
}, | ||
{ | ||
id: "0x227510204bcfe7b543388b82c6e02aafe7b0d0a20e4f159794e8121611aa601b", | ||
recipient: "0x9aB3971e1b065701C72C5f3cAFbF33118dC51ae8" | ||
} | ||
]) | ||
|
||
const result = await validateCredentials( | ||
{ | ||
id: easAttestations.id, | ||
criteria: { | ||
minAttestations: 3 | ||
} | ||
}, | ||
{ | ||
recipient: "0x9aB3971e1b065701C72C5f3cAFbF33118dC51ae8", | ||
queryGraph: queryGraphMocked.queryGraph | ||
} | ||
) | ||
|
||
expect(result).toBeTruthy() | ||
}) | ||
|
||
it("Should return false if an account has less than 3 attestations", async () => { | ||
queryGraphMocked.queryGraph.mockReturnValue([ | ||
{ | ||
id: "0x52561c95029d9f2335839ddc96a69ee9737a18e2a781e64659b7bd645ccb8efc", | ||
recipient: "0x0000000000000000000000000000000000000000" | ||
}, | ||
{ | ||
id: "0xee06a022c7d55f67bac213d6b2cd384a899ef79a57f1f5f148e45c313b4fdebe", | ||
recipient: "0x0000000000000000000000000000000000000000" | ||
}, | ||
{ | ||
id: "0xfbc0f1aac4379c18fa9a5b6493825234a8ca82a2a296148465d150c2e64c6202", | ||
recipient: "0x0000000000000000000000000000000000000000" | ||
}, | ||
{ | ||
id: "0x227510204bcfe7b543388b82c6e02aafe7b0d0a20e4f159794e8121611aa601b", | ||
recipient: "0x9aB3971e1b065701C72C5f3cAFbF33118dC51ae8" | ||
} | ||
]) | ||
|
||
const result = await validateCredentials( | ||
{ | ||
id: easAttestations.id, | ||
criteria: { | ||
minAttestations: 3 | ||
} | ||
}, | ||
{ | ||
recipient: "0x9aB3971e1b065701C72C5f3cAFbF33118dC51ae8", | ||
queryGraph: queryGraphMocked.queryGraph | ||
} | ||
) | ||
|
||
expect(result).toBeFalsy() | ||
}) | ||
|
||
it("Should throw an error if a criteria parameter is missing", async () => { | ||
const fun = () => | ||
validateCredentials( | ||
{ | ||
id: easAttestations.id, | ||
criteria: {} | ||
}, | ||
{ | ||
recipient: "0x9aB3971e1b065701C72C5f3cAFbF33118dC51ae9", | ||
queryGraph: queryGraphMocked.queryGraph | ||
} | ||
) | ||
|
||
await expect(fun).rejects.toThrow( | ||
"Parameter 'minAttestations' has not been defined" | ||
) | ||
}) | ||
|
||
it("Should throw an error if a criteria parameter should not exist", async () => { | ||
const fun = () => | ||
validateCredentials( | ||
{ | ||
id: easAttestations.id, | ||
criteria: { | ||
minAttestations: 1, | ||
test: 123 | ||
} | ||
}, | ||
{ | ||
recipient: "0x9aB3971e1b065701C72C5f3cAFbF33118dC51ae9", | ||
queryGraph: queryGraphMocked.queryGraph | ||
} | ||
) | ||
|
||
await expect(fun).rejects.toThrow( | ||
"Parameter 'test' should not be part of the criteria" | ||
) | ||
}) | ||
|
||
it("Should throw a type error if a criteria parameter has the wrong type", async () => { | ||
const fun = () => | ||
validateCredentials( | ||
{ | ||
id: easAttestations.id, | ||
criteria: { | ||
minAttestations: "1" | ||
} | ||
}, | ||
{ | ||
recipient: "0x9aB3971e1b065701C72C5f3cAFbF33118dC51ae9", | ||
queryGraph: queryGraphMocked.queryGraph | ||
} | ||
) | ||
|
||
await expect(fun).rejects.toThrow( | ||
"Parameter 'minAttestations' is not a number" | ||
) | ||
}) | ||
}) |
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,46 @@ | ||
import { Context, EASContext, Validator } from "../.." | ||
|
||
export type Criteria = { | ||
minAttestations: number | ||
} | ||
|
||
const validator: Validator = { | ||
id: "EAS_ATTESTATIONS", | ||
|
||
criteriaABI: { | ||
minAttestations: "number" | ||
}, | ||
|
||
/** | ||
* It checks if a user has greater than or equal to 'minAttestations' attestations. | ||
* @param criteria The criteria used to check user's credentials. | ||
* @param context Context variables. | ||
* @returns True if the user meets the criteria. | ||
*/ | ||
async validate(criteria: Criteria, context: Context) { | ||
if ("recipient" in context) { | ||
const { recipient } = context as EASContext | ||
|
||
const getAttestations = (context as EASContext).queryGraph | ||
|
||
const attestations = await getAttestations(` | ||
query { | ||
attestations { | ||
id | ||
recipient | ||
} | ||
} | ||
`) | ||
|
||
const recipientAttestations = attestations.filter( | ||
(attestation: any) => attestation.recipient === recipient | ||
) | ||
|
||
return recipientAttestations.length >= criteria.minAttestations | ||
} | ||
|
||
throw new Error("No recipient value found") | ||
} | ||
} | ||
|
||
export default validator |
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