From 773c621c9108af18ccb5c188f6d1976d9ef96f51 Mon Sep 17 00:00:00 2001 From: Mehdi Torabi <46302001+mehdi-torabiv@users.noreply.github.com> Date: Tue, 27 Aug 2024 11:33:52 +0300 Subject: [PATCH] integrate graphql to getAttestations (#48) * integrate graphql to getAttestations * comment unused libs * remove unused files * remove unused files --- src/components/shared/CustomTable.test.tsx | 40 --- src/libs/oci/index.ts | 23 +- src/pages/Identifiers/Identifiers.tsx | 269 ++++++++------------- src/pages/Permissions/Permissions.tsx | 5 +- src/services/eas/index.ts | 10 + src/services/eas/query.ts | 98 ++++++++ src/utils/contracts/eas/constants.ts | 4 + 7 files changed, 228 insertions(+), 221 deletions(-) delete mode 100644 src/components/shared/CustomTable.test.tsx create mode 100644 src/services/eas/index.ts create mode 100644 src/services/eas/query.ts create mode 100644 src/utils/contracts/eas/constants.ts diff --git a/src/components/shared/CustomTable.test.tsx b/src/components/shared/CustomTable.test.tsx deleted file mode 100644 index 182c6dd..0000000 --- a/src/components/shared/CustomTable.test.tsx +++ /dev/null @@ -1,40 +0,0 @@ -// CustomTable.test.tsx -import { render, screen } from '@testing-library/react'; -import { vi } from 'vitest'; -import CustomTable, { Platform, AccessData } from './CustomTable'; - -// Mock AccessControlButton component -vi.mock('./AccessControlButton', () => ({ - __esModule: true, - default: ({ hasAccess, onToggleAccess }: { hasAccess: boolean, onToggleAccess: () => void }) => ( - - ), -})); - -describe('CustomTable', () => { - const platforms: Platform[] = [ - { name: 'Platform1', icon:
Icon1
}, - { name: 'Platform2', icon:
Icon2
}, - ]; - - const data: AccessData[] = [ - { application: 'App1', Platform1: true, Platform2: false }, - { application: 'App2', Platform1: false, Platform2: true }, - ]; - - it('renders the table with correct headers and data', () => { - render(); - - expect(screen.getByText('Applications \\ Identifiers')).toBeInTheDocument(); - expect(screen.getByText('Platform1')).toBeInTheDocument(); - expect(screen.getByText('Platform2')).toBeInTheDocument(); - - expect(screen.getByText('App1')).toBeInTheDocument(); - expect(screen.getByText('App2')).toBeInTheDocument(); - - expect(screen.getAllByText('Revoke Access').length).toBe(2); - expect(screen.getAllByText('Grant Access').length).toBe(2); - }); -}); diff --git a/src/libs/oci/index.ts b/src/libs/oci/index.ts index e2db7fa..49355a4 100644 --- a/src/libs/oci/index.ts +++ b/src/libs/oci/index.ts @@ -1,13 +1,15 @@ -import { Address, parseAbiItem, WalletClient } from 'viem'; -import { SchemaEncoder } from '@ethereum-attestation-service/eas-sdk'; +import { Address, parseAbiItem } from 'viem'; +import { + SchemaDecodedItem, + SchemaEncoder, +} from '@ethereum-attestation-service/eas-sdk'; +import * as LitJsSdk from '@lit-protocol/lit-node-client'; +import { EncryptToJsonPayload, SessionSigsMap } from '@lit-protocol/types'; import { publicClient } from './client'; import sepoliaChain from '../../utils/contracts/eas/sepoliaChain.json'; -import { LitNetwork } from '@lit-protocol/constants'; -import * as LitJsSdk from '@lit-protocol/lit-node-client'; -import { sepolia } from 'viem/chains'; -import { EncryptToJsonPayload, SessionSigsMap } from '@lit-protocol/types'; +import { SCHEMA_TYPES } from '../../utils/contracts/eas/constants'; export interface IAttestation { uid: `0x${string}`; @@ -76,9 +78,7 @@ export const hasActiveRevocationTime = (attestations: IAttestation[]) => { }; export const getAttestationData = (attestation: IAttestation) => { - const schemaEncoder = new SchemaEncoder( - 'bytes32 key, string provider, string secret' - ); + const schemaEncoder = new SchemaEncoder(SCHEMA_TYPES); const decodedData = schemaEncoder.decodeData(attestation.data); @@ -113,3 +113,8 @@ export const decryptAttestation = async ( return JSON.parse(decryptedData); }; + +export const decodeAttestationData = (data: string): SchemaDecodedItem[] => { + const schemaEncoder = new SchemaEncoder(SCHEMA_TYPES); + return schemaEncoder.decodeData(data); +}; diff --git a/src/pages/Identifiers/Identifiers.tsx b/src/pages/Identifiers/Identifiers.tsx index 9e1b053..45dbaa0 100644 --- a/src/pages/Identifiers/Identifiers.tsx +++ b/src/pages/Identifiers/Identifiers.tsx @@ -10,23 +10,23 @@ import { Paper, Box, Avatar, - CircularProgress, } from '@mui/material'; import VerifiedIcon from '@mui/icons-material/Verified'; import { FaDiscord, FaGoogle } from 'react-icons/fa'; import { useNavigate } from 'react-router-dom'; -import { useEffect, useState } from 'react'; -import { decryptAttestation, getAttestations } from '../../libs/oci'; -import { useAccount } from 'wagmi'; -import useLit from '../../hooks/LitProvider'; -import useSessionSigs from '../../hooks/useSessionSigs'; -import { useSigner } from '../../utils/eas-wagmi-utils'; -import { GraphQLClient, gql } from 'graphql-request'; -import { useQuery } from '@tanstack/react-query'; -import { - SchemaDecodedItem, - SchemaEncoder, -} from '@ethereum-attestation-service/eas-sdk'; +// import { useState } from 'react'; +// import { decryptAttestation, getAttestations } from '../../libs/oci'; +// import { useAccount } from 'wagmi'; +// import useLit from '../../hooks/LitProvider'; +// import useSessionSigs from '../../hooks/useSessionSigs'; +// import { useSigner } from '../../utils/eas-wagmi-utils'; +// import { GraphQLClient, gql } from 'graphql-request'; +// import { useQuery } from '@tanstack/react-query'; +// import { +// SchemaDecodedItem, +// SchemaEncoder, +// } from '@ethereum-attestation-service/eas-sdk'; +import { useGetAttestations } from '../../services/eas/query'; const identifiers = [ { name: 'Discord', icon: FaDiscord, verified: false, color: 'text-blue-500' }, @@ -34,78 +34,17 @@ const identifiers = [ ]; export function Identifiers() { - const graphQLClient = new GraphQLClient( - 'https://sepolia.easscan.org/graphql' - ); - - const SCHEMA_TYPES = 'bytes32 key, string provider, string secret'; - - const decodettestationData = (data: string): SchemaDecodedItem[] => { - const schemaEncoder = new SchemaEncoder(SCHEMA_TYPES); - return schemaEncoder.decodeData(data); - }; - - const useGetAttestations = () => { - return useQuery({ - queryKey: ['getAttestations'], - queryFn: async () => { - const result = await graphQLClient.request(gql` - query Attestations { - attestations( - where: { - attester: { - equals: "0x2d7B3e18D45846DA09D78e3644F15BD4aafa634d" - } - recipient: { - equals: "0x026B727b60D336806B87d60e95B6d7FAd2443dD6" - } - revoked: { equals: false } - schemaId: { - equals: "0x85e90e3e16d319578888790af3284fea8bca549305071531e7478e3e0b5e7d6d" - } - } - ) { - id - attester - recipient - refUID - revocable - revocationTime - expirationTime - data - } - } - `); - - // Decode each attestation's data and log it - result.attestations.forEach((attestation: any) => { - const decodedData = decodettestationData(attestation.data); - console.log({ decodedData }); - }); - - // If you want to return decoded data, you can do something like this: - const decodedAttestations = - result && - result.attestations.map((attestation: any) => ({ - ...attestation, - decodedData: decodettestationData(attestation.data), - })); - - return decodedAttestations; // or return result.attestations if you don't need the decoded data in the result - }, - }); - }; - - const { data, isLoading, error } = useGetAttestations(); + const { data } = useGetAttestations(); console.log({ data }); - const { litNodeClient } = useLit(); - const { chainId } = useAccount(); - const { sessionSigs, createSessionSigs } = useSessionSigs(); - const [decryptedData, setDecryptedData] = useState(null); + // const { litNodeClient } = useLit(); + // const { chainId } = useAccount(); + // const { sessionSigs, createSessionSigs } = useSessionSigs(); + // const [decryptedData, setDecryptedData] = useState(null); + + // const signer = useSigner(); + // const { isConnected, address } = useAccount(); - const signer = useSigner(); - const { isConnected, address } = useAccount(); const navigate = useNavigate(); const handleRevoke = (identifier: string) => { @@ -117,107 +56,101 @@ export function Identifiers() { navigate(`/identifiers/${identifier.toLowerCase()}/attestation`); }; - const fetchAttestations = async () => { - if (!address) throw new Error('No address found'); + // const fetchAttestations = async () => { + // if (!address) throw new Error('No address found'); - const attestations = await getAttestations(address as `0x${string}`); - console.log({ attestations }); + // const attestations = await getAttestations(address as `0x${string}`); + // console.log({ attestations }); - return attestations; - }; + // return attestations; + // }; - useEffect(() => { - if (isConnected && signer && chainId && litNodeClient) { - console.log(litNodeClient, 'litNodeClient'); + // useEffect(() => { + // if (isConnected && signer && chainId && litNodeClient) { + // console.log(litNodeClient, 'litNodeClient'); - createSessionSigs({ signer, chainId, litNodeClient }); - } - }, [signer, isConnected, litNodeClient, chainId, createSessionSigs]); + // createSessionSigs({ signer, chainId, litNodeClient }); + // } + // }, [signer, isConnected, litNodeClient, chainId, createSessionSigs]); - useEffect(() => { - if (!sessionSigs) return; - const decrypt = async () => { - if (!sessionSigs) throw new Error('No sessionSigs found'); + // useEffect(() => { + // if (!sessionSigs) return; + // const decrypt = async () => { + // if (!sessionSigs) throw new Error('No sessionSigs found'); - const attestations = await fetchAttestations(); + // const attestations = await fetchAttestations(); - const decryptedSecrets = await Promise.all( - attestations.map(async (attestation) => { - return decryptAttestation(litNodeClient, attestation, sessionSigs); - }) - ); - setDecryptedData(decryptedSecrets); - }; + // const decryptedSecrets = await Promise.all( + // attestations.map(async (attestation) => { + // return decryptAttestation(litNodeClient, attestation, sessionSigs); + // }) + // ); + // setDecryptedData(decryptedSecrets); + // }; - decrypt(); - }, [sessionSigs]); + // decrypt(); + // }, [sessionSigs]); return (
Identifiers - {isLoading && } - {error && ( - Failed to load attestations - )} - {!isLoading && !error && ( - - - - - - Actions - - - - - {identifiers.map((identifier, index) => ( - - - - - - - - {identifier.verified && ( - - )} - {identifier.name} -
- } - style={{ marginLeft: 16 }} + + + + + + Actions + + + + + {identifiers.map((identifier, index) => ( + + + + + - - {identifier.verified ? ( - - ) : ( - - )} - - - - - ))} - - )} + + + {identifier.verified && ( + + )} + {identifier.name} + + } + style={{ marginLeft: 16 }} + /> + + {identifier.verified ? ( + + ) : ( + + )} + + + + + ))} + ); } diff --git a/src/pages/Permissions/Permissions.tsx b/src/pages/Permissions/Permissions.tsx index b919617..a460beb 100644 --- a/src/pages/Permissions/Permissions.tsx +++ b/src/pages/Permissions/Permissions.tsx @@ -14,10 +14,7 @@ import useSessionSigs from '../../hooks/useSessionSigs'; import useLit from '../../hooks/LitProvider'; import { useSigner } from '../../utils/eas-wagmi-utils'; import { decryptAttestation, getAttestations } from '../../libs/oci'; -import CustomTable, { - AccessData, - Platform, -} from '../../components/shared/CustomTable'; +import CustomTable from '../../components/shared/CustomTable'; interface IProvider { uid: string; diff --git a/src/services/eas/index.ts b/src/services/eas/index.ts new file mode 100644 index 0000000..045fc86 --- /dev/null +++ b/src/services/eas/index.ts @@ -0,0 +1,10 @@ +import { GraphQLClient } from 'graphql-request'; + +export const easBaseUrl = import.meta.env.VITE_API_GRAPHQL_URL; +export const ATTESTER_ADDRESS = import.meta.env.VITE_EAS_ATTESTER_ADDRESS; + +if (!easBaseUrl) { + throw new Error('VITE_API_GRAPHQL_URL is not defined'); +} + +export const graphQLClient = new GraphQLClient(easBaseUrl); diff --git a/src/services/eas/query.ts b/src/services/eas/query.ts new file mode 100644 index 0000000..5592d0e --- /dev/null +++ b/src/services/eas/query.ts @@ -0,0 +1,98 @@ +import { useQuery } from '@tanstack/react-query'; +import { gql } from 'graphql-request'; +import { ATTESTER_ADDRESS, graphQLClient } from '.'; +import { EAS_SCHEMA_ID } from '../../utils/contracts/eas/constants'; + +export const useGetAttestations = () => { + return useQuery({ + queryKey: ['getAttestations'], + queryFn: async () => { + const query = gql` + query Attestations( + $attester: String! + $recipient: String! + $schemaId: String! + ) { + attestations( + where: { + attester: { equals: $attester } + recipient: { equals: $recipient } + revoked: { equals: false } + schemaId: { equals: $schemaId } + } + ) { + id + attester + recipient + refUID + revocable + revocationTime + expirationTime + data + } + } + `; + + const variables = { + attester: ATTESTER_ADDRESS, + recipient: '0x026B727b60D336806B87d60e95B6d7FAd2443dD6', + schemaId: EAS_SCHEMA_ID, + }; + + const attestedResults = await graphQLClient.request(query, variables); + + console.log({ attestedResults }); + + return attestedResults; + }, + }); +}; + +// const useGetAttestations = () => { +// return useQuery({ +// queryKey: ['getAttestations'], +// queryFn: async () => { +// const result = await graphQLClient.request(gql` +// query Attestations { +// attestations( +// where: { +// attester: { equals: "0x2d7B3e18D45846DA09D78e3644F15BD4aafa634d" } +// recipient: { +// equals: "0x026B727b60D336806B87d60e95B6d7FAd2443dD6" +// } +// revoked: { equals: false } +// schemaId: { +// equals: "0x85e90e3e16d319578888790af3284fea8bca549305071531e7478e3e0b5e7d6d" +// } +// } +// ) { +// id +// attester +// recipient +// refUID +// revocable +// revocationTime +// expirationTime +// data +// } +// } +// `); + +// // Decode each attestation's data and log it +// result.attestations.forEach((attestation: any) => { +// const decodedData = decodedAttestations(attestation.data); +// console.log({ decodedData }); +// }); + +// // If you want to return decoded data, you can do something like this: +// const decoded = +// result && +// result.attestations.map((attestation: any) => ({ +// ...attestation, +// decodedData: decodettestationData(attestation.data), +// })); + +// return decoded; // or return result.attestations if you don't need the decoded data in the result +// }, +// }); +// }; diff --git a/src/utils/contracts/eas/constants.ts b/src/utils/contracts/eas/constants.ts new file mode 100644 index 0000000..2311c11 --- /dev/null +++ b/src/utils/contracts/eas/constants.ts @@ -0,0 +1,4 @@ +export const SCHEMA_TYPES = 'bytes32 key, string provider, string secret'; + +export const EAS_SCHEMA_ID = + '0x85e90e3e16d319578888790af3284fea8bca549305071531e7478e3e0b5e7d6d';