Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ ID_HUB_ADDR=
SELF_SCOPE=
SELF_CONFIG_ID=

NEXT_PUBLIC_SELF_APP_NAME=
NODE_ENV = "development"
# this env is read in packages/contract and packages/web
NEXT_PUBLIC_VERIFICATION_DEPLOYED_ADDR=
NEXT_PUBLIC_SELF_SCOPE_SEED=

NEXT_PUBLIC_SELF_SCOPE_SEED="dhkdao-self-prototype"
NEXT_PUBLIC_ALCHEMY_ID=
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=

# DHK Token deployed on op mainnet:
# https://optimistic.etherscan.io/token/0xe85d2c93f7e26b99a46a8bb9350cbfb965fa4f82
NEXT_PUBLIC_DHKTOKEN_ADDR="0xe85d2c93f7e26b99a46a8bb9350cbfb965fa4f82"
NEXT_PUBLIC_DHKTOKEN_THRESHOLD="1"
6 changes: 3 additions & 3 deletions packages/web/src/app/api/verify-successful/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
type Abi,
} from "viem";
import { optimism } from "viem/chains";
import { erc20Abi } from "@/config";
import { erc20Abi, thresholdTokenAmt } from "@/config";

export async function POST(req: NextRequest) {
const body = await req.json();
Expand Down Expand Up @@ -40,8 +40,7 @@ export async function POST(req: NextRequest) {
const balance = BigInt(
(await dhkTokenContract.read.balanceOf([sender])) as bigint,
);
const voteThreshold =
BigInt(process.env.NEXT_PUBLIC_DHKTOKEN_THRESHOLD || "1") * decimals;
const voteThreshold = thresholdTokenAmt * decimals;

// TODO: 3. check user has a DHK subname in https://app.namespace.ninja
const senderHasSubname = true;
Expand All @@ -53,6 +52,7 @@ export async function POST(req: NextRequest) {
status: "success",
sender,
result,
txHash,
aboveTokenThreshold,
hasSubname: senderHasSubname,
});
Expand Down
78 changes: 78 additions & 0 deletions packages/web/src/app/result/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"use client";

import { useEffect, useState } from "react";
import type { VerificationResult } from "@/types";
import {
appName,
alfajoresTxUrlPrefix,
thresholdTokenAmt,
opMainnetAddrUrlPrefix,
} from "@/config";

export default function VerificationResultPage() {
const linkClasses =
"mt-4 bg-transparent text-blue-600 underline hover:text-blue-800 hover:underline p-0 border-0 font-normal";

const [verificationResult, setVerificationResult] =
useState<VerificationResult>();

useEffect(() => {
const _verificationResult = JSON.parse(
localStorage.getItem("verificationResult") || "",
) as VerificationResult;
setVerificationResult(_verificationResult);
}, []);

return (
<div className="verification-result-container flex flex-col items-center">
<h1 className="text-lg/8 font-medium">{appName}</h1>

<section className="flex flex-col items-center my-4">
<h1 className="text-base/8">Result</h1>
<ul>
<li>
User address:{" "}
{verificationResult?.sender && (
<strong>
<a
className={linkClasses}
href={opMainnetAddrUrlPrefix + verificationResult?.sender}
target="_blank"
>
{verificationResult?.sender}
</a>
</strong>
)}
</li>
<li>
User is self.xyz verified?{" "}
{verificationResult?.txHash ? (
<strong>
<a
className={linkClasses}
href={alfajoresTxUrlPrefix + verificationResult?.txHash}
target="_blank"
>
true
</a>
</strong>
) : (
<strong>false</strong>
)}
</li>
<li>
User has threshold amount of DHK token (
{thresholdTokenAmt.toString()})?{" "}
<strong>
{verificationResult?.aboveTokenThreshold ? "true" : "false"}
</strong>
</li>
<li>
User has DHK ID Subname (mocked)?{" "}
<strong>{verificationResult?.hasSubname ? "true" : "false"}</strong>
</li>
</ul>
</section>
</div>
);
}
26 changes: 11 additions & 15 deletions packages/web/src/components/VerificationComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
import React, { useState, useEffect } from "react";
import { getUniversalLink } from "@selfxyz/core";
import { ConnectKitButton } from "connectkit";
import { useRouter } from "next/navigation";
import {
SelfAppBuilder,
SelfQRcodeWrapper,
type SelfApp,
} from "@selfxyz/qrcode";
import { clsx } from "clsx";
import type { Log, Hash } from "viem";
import type { Log } from "viem";
import { useAccount, useConfig, useWatchContractEvent } from "wagmi";
import { watchContractEvent } from "wagmi/actions";
import {
Expand All @@ -22,21 +23,12 @@ import {
} from "@headlessui/react";

import { appName, selfVerificationContract } from "@/config";
import type { Address } from "viem";

type VerificationCompletedEventArgs = {
txHash: Hash;
sender: Address;
nationality: string;
times: number;
userData: string;
};

type EventLog = Log & { args: any };
import type { VerificationCompletedEventArgs, EventLog } from "@/types";

export default function VerificationComponent() {
const account = useAccount();
const config = useConfig();
const router = useRouter();

const [selfApp, setSelfApp] = useState<SelfApp>();
const [universalLink, setUniversalLink] = useState("");
Expand Down Expand Up @@ -144,17 +136,21 @@ export default function VerificationComponent() {

if (!res.ok) throw new Error("API request failed");

console.log("result:", await res.json());
localStorage.setItem(
"verificationResult",
JSON.stringify(await res.json()),
);
router.push("/result");
} catch (err) {
console.error("Error calling verify-successful API:", err);
}
})();
}, [isFNCallback, evReceived]);
}, [isFNCallback, evReceived, router]);

return (
<>
<div className="verification-container flex flex-col items-center">
<h1 className="text-lg/8 font-medium">DHK dao Self Prototype</h1>
<h1 className="text-lg/8 font-medium">{appName}</h1>

<section className="flex flex-col items-center my-4">
<p className="text-base/8">1. Sign in with your wallet</p>
Expand Down
27 changes: 20 additions & 7 deletions packages/web/src/components/Web3Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,28 @@ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ConnectKitProvider, getDefaultConfig } from "connectkit";
import { appName } from "@/config";

const chains =
process.env.NODE_ENV === "development"
? [foundry, celoAlfajores]
: [celoAlfajores];
const transports =
process.env.NODE_ENV === "development"
? {
[foundry.id]: webSocket("http://localhost:8545"),
[celoAlfajores.id]: webSocket(
`https://celo-alfajores.g.alchemy.com/v2/${process.env.NEXT_PUBLIC_ALCHEMY_ID}`,
),
}
: {
[celoAlfajores.id]: webSocket(
`https://celo-alfajores.g.alchemy.com/v2/${process.env.NEXT_PUBLIC_ALCHEMY_ID}`,
),
};

export const ckConfig = getDefaultConfig({
// Your dApps chains
chains: [foundry, celoAlfajores],
transports: {
[foundry.id]: webSocket("http://localhost:8545"),
[celoAlfajores.id]: webSocket(
`https://celo-alfajores.g.alchemy.com/v2/${process.env.NEXT_PUBLIC_ALCHEMY_ID}`,
),
},
chains,
transports,

// Required API Keys
walletConnectProjectId:
Expand Down
10 changes: 9 additions & 1 deletion packages/web/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,13 @@ export const selfVerificationContract = {
};

export const erc20Abi = ERC20ABI_JSON.abi as Abi;

export const appName = "DHK dao Identity Verification";
export const thresholdTokenAmt = BigInt(
process.env.NEXT_PUBLIC_DHKTOKEN_THRESHOLD || "1",
);

export const alfajoresTxUrlPrefix = "https://celo-alfajores.blockscout.com/tx/";
export const alfajoresAddrUrlPrefix =
"https://celo-alfajores.blockscout.com/address/";
export const opMainnetAddrUrlPrefix =
"https://optimistic.etherscan.io/address/";
20 changes: 20 additions & 0 deletions packages/web/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { Address, Log, Hash } from "viem";

export type VerificationCompletedEventArgs = {
txHash: Hash;
sender: Address;
nationality: string;
times: number;
userData: string;
};

export type EventLog = Log & { args: any };

export type VerificationResult = {
status: string;
sender: Address;
result: boolean;
txHash: Hash;
aboveTokenThreshold: boolean;
hasSubname: boolean;
};
Loading