From 97040d3b09bcc613906e8bc225c3a16d9efaae8f Mon Sep 17 00:00:00 2001 From: schultztimothy Date: Thu, 16 May 2024 14:01:05 -0600 Subject: [PATCH] feat(app): check and verify possible stamps --- app/components/DashboardScorePanel.tsx | 11 +++- app/hooks/use1ClickVerification.tsx | 90 ++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 2 deletions(-) create mode 100644 app/hooks/use1ClickVerification.tsx diff --git a/app/components/DashboardScorePanel.tsx b/app/components/DashboardScorePanel.tsx index 0411aba8c..de5bcc99d 100644 --- a/app/components/DashboardScorePanel.tsx +++ b/app/components/DashboardScorePanel.tsx @@ -4,6 +4,7 @@ import { ScorerContext } from "../context/scorerContext"; import { Spinner } from "@chakra-ui/react"; import { useCustomization } from "../hooks/useCustomization"; import { isDynamicCustomization } from "../utils/customizationUtils"; +import { use1ClickVerification } from "../hooks/use1ClickVerification"; // Hexagon SVGs generated using https://codepen.io/wvr/pen/WrNgJp // with the values listed below for each ring @@ -103,9 +104,15 @@ export const DashboardScorePanel = ({ className }: { className: string }) => { const customTitle = isDynamicCustomization(customization) ? customization.scorerPanel?.title : undefined; const customText = isDynamicCustomization(customization) ? customization.scorerPanel?.text : undefined; + const { fetchCredentials } = use1ClickVerification(); + + useEffect(() => { + fetchCredentials(); + }, []); + return (
Person Icon @@ -116,7 +123,7 @@ export const DashboardScorePanel = ({ className }: { className: string }) => {
-

+

{customText || "Your Unique Humanity Score is based out of 100 and measures your uniqueness. The current passing threshold is 20. " + "Scores may vary across different apps, especially due to abuse or attacks on the service."} diff --git a/app/hooks/use1ClickVerification.tsx b/app/hooks/use1ClickVerification.tsx new file mode 100644 index 000000000..1fda9664a --- /dev/null +++ b/app/hooks/use1ClickVerification.tsx @@ -0,0 +1,90 @@ +import { PLATFORM_ID, PROVIDER_ID, Passport, StampPatch, ValidResponseBody } from "@gitcoin/passport-types"; +import { useState, useEffect, useCallback, useContext } from "react"; +import { PlatformProps } from "../components/GenericPlatform"; +import { ValidatedPlatform, fetchPossibleEVMStamps } from "../signer/utils"; +import { useDatastoreConnectionContext } from "../context/datastoreConnectionContext"; +import { IAM_SIGNATURE_TYPE, iamUrl } from "../config/stamp_config"; +import { fetchVerifiableCredential } from "@gitcoin/passport-identity"; +import { createSignedPayload } from "../utils/helpers"; +import { CeramicContext } from "../context/ceramicContext"; +import { useWalletStore } from "../context/walletStore"; + +export const use1ClickVerification = () => { + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + const [validatedPlatforms, setValidatedPlatforms] = useState([]); + const { did } = useDatastoreConnectionContext(); + const { passport, allPlatforms } = useContext(CeramicContext); + const address = useWalletStore((state) => state.address); + + const fetchCredentials = useCallback(async () => { + setIsLoading(true); + setError(null); + + if (!did) { + setIsLoading(false); + setError(new Error("No DID found")); + return; + } + + if (!address) { + setIsLoading(false); + setError(new Error("No address")); + return; + } + + try { + const validatedPlatforms = await fetchPossibleEVMStamps(address, allPlatforms, passport); + if (validatedPlatforms.length === 0) { + setIsLoading(false); + // Nothing to do + return; + } + setValidatedPlatforms(validatedPlatforms); + const platformTypes = validatedPlatforms.map((platform) => platform.platformProps.platform.platformId); + const validatedProviderIds = validatedPlatforms + .map((platform) => + platform.platformProps.platFormGroupSpec.map((group) => group.providers.map((provider) => provider.name)) + ) + .flat(2); + + const credentialResponse = await fetchVerifiableCredential( + iamUrl, + { + type: "EVMBulkVerify", + types: platformTypes, + version: "0.0.0", + address: address || "", + proofs: {}, + signatureType: IAM_SIGNATURE_TYPE, + }, + (data: any) => createSignedPayload(did, data) + ); + + // Should be able to assume that all stamps should be patched + const validCredentials = + credentialResponse.credentials?.filter((cred: any): cred is ValidResponseBody => !cred.error) || []; + + // console.log({ patches }); + + // const stampPatches: StampPatch[] = validatedProviderIds + // .map((provider: PROVIDER_ID) => { + // const { credential } = + // validCredentials.find((cred) => cred.credential.credentialSubject.provider === provider) || {}; + // if (credential) return { provider, credential }; + // // shouldn't need this + // // else if (!selectedProviders.includes(provider)) return { provider }; + // else return null; + // }) + // .filter((patch): patch is StampPatch => patch !== null); + + // await handlePatchStamps(stampPatches); + } catch (error) { + setError(error as Error); + } + + setIsLoading(false); + }, [address, allPlatforms, passport, did]); + + return { isLoading, error, validatedPlatforms, fetchCredentials }; +};