Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add confirm guardian view #2

Merged
merged 3 commits into from
Jan 16, 2025
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
26 changes: 26 additions & 0 deletions packages/auth-server/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,35 @@
</template>

<script lang="ts" setup>
import type { AppKitNetwork } from "@reown/appkit/networks";
import { createAppKit } from "@reown/appkit/vue";
import { WagmiAdapter } from "@reown/appkit-adapter-wagmi";

import { supportedChains } from "./stores/client";

// BigInt polyfill
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(BigInt.prototype as any).toJSON = function () {
return this.toString();
};

// AppKit Configuration
const projectId = "9bc5059f6eed355858cc56a3388e9b50";
const metadata = {
name: "ZKsync SSO Auth Server",
description: "ZKsync SSO Auth Server",
url: "https://auth-test.zksync.dev",
icons: ["https://auth-test.zksync.dev/icon-512.png"],
};
const wagmiAdapter = new WagmiAdapter({
networks: supportedChains,
projectId,
});

createAppKit({
adapters: [wagmiAdapter],
networks: supportedChains as unknown as [AppKitNetwork, ...AppKitNetwork[]],
projectId,
metadata,
});
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<template>
<Button
:type="type"
:loading="stateData.open && !accountData.isConnected"
@click="onClick"
>
<div class="flex items-center gap-2">
<UserCircleIcon
v-if="accountData.isConnected"
class="w-4 h-4"
/>
<WalletIcon
v-else
class="w-4 h-4"
/>
<span>{{ text }}</span>
</div>
</Button>
</template>

<script setup lang="ts">
import { UserCircleIcon, WalletIcon } from "@heroicons/vue/24/solid";
import { useAppKit, useAppKitAccount, useAppKitState } from "@reown/appkit/vue";

import Button, { type ButtonTypes } from "~/components/zk/button.vue";

const { open } = useAppKit();
const accountData = useAppKitAccount();
const stateData = useAppKitState();

const onClick = async () => {
if (accountData.value.isConnected) {
await open({ view: "Account" });
} else {
await open({ view: "Connect" });
}
};

const text = computed(() => {
if (accountData.value.isConnected && accountData.value.address) {
return shortenAddress(accountData.value.address);
}
return "Connect Wallet";
});

defineProps<{
type?: ButtonTypes;
}>();
</script>
58 changes: 58 additions & 0 deletions packages/auth-server/components/confirm-guardian/nav.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<template>
<div
class="border border-neutral-200 rounded-zk flex justify-between dark:border-neutral-900 dark:bg-neutral-950 h-[52px]"
>
<div class="flex items-center pl-3">
<NuxtLink to="/">
<app-account-logo
:height="24"
class="dark:text-neutral-100"
/>
</NuxtLink>
</div>
<div
class="flex items-center pr-2"
>
<app-color-mode />
</div>
</div>
</template>

<script setup lang="ts">
import { useWindowSize } from "@vueuse/core";
import { onBeforeUnmount, onMounted, watch } from "vue";

const { width: windowWidth } = useWindowSize();
const menuWrapper = useTemplateRef("menu-wrapper");
const menu = useTemplateRef("menu");
const menuWidth = ref(0);

const showMobileMenu = ref(false);

const checkWidths = () => {
const menuWrapperWidth = menuWrapper.value?.offsetWidth || 0;
if (menuWrapperWidth <= menuWidth.value) {
showMobileMenu.value = true;
} else {
showMobileMenu.value = false;
}
};

onMounted(() => {
menuWidth.value = menu.value?.offsetWidth || 0;
checkWidths();
window.addEventListener("resize", checkWidths);
});

onBeforeUnmount(() => {
window.removeEventListener("resize", checkWidths);
});

watch(windowWidth, checkWidths);
</script>

<style lang="scss" scoped>
.router-link-exact-active {
@apply border-b-neutral-700 text-neutral-900 dark:text-neutral-100 dark:border-b-neutral-200 dark:hover:text-neutral-100
}
</style>
7 changes: 5 additions & 2 deletions packages/auth-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
"@nuxtjs/google-fonts": "^3.2.0",
"@nuxtjs/tailwindcss": "^6.12.0",
"@pinia/nuxt": "^0.5.1",
"@tanstack/vue-query": "^5.59.1",
"@reown/appkit": "^1.6.4",
"@reown/appkit-adapter-wagmi": "^1.6.4",
"@tanstack/vue-query": "^5.59.16",
"@vueuse/core": "^11.1.0",
"@vueuse/nuxt": "^11.1.0",
"@wagmi/core": "^2.13.3",
Expand All @@ -27,7 +29,8 @@
"vue": "latest",
"wagmi": "^2.12.17",
"web3-avatar-vue": "^1.0.4",
"zksync-sso": "workspace:*"
"zksync-sso": "workspace:*",
"zod": "^3.24.1"
},
"devDependencies": {
"tailwindcss": "^3.4.14"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<template>
<div class="min-h-screen">
<header class="max-w-[1920px] mx-auto mb-12">
<Nav />
</header>
<main class="max-w-[900px] mx-auto flex flex-col gap-6">
<div>
<h1 class="text-3xl font-bold text-gray-900 dark:text-white mb-3">
Confirm Guardian Account
</h1>
<p class="text-lg text-gray-600 dark:text-gray-400">
Review and confirm the guardian details below:
</p>
</div>

<div class="space-y-4">
<div class="rounded-2xl bg-neutral-100/50 backdrop-blur-sm dark:bg-gray-800/50 p-6">
<label class="block text-sm font-medium text-gray-600 dark:text-gray-400 mb-2">
Account Address
</label>
<div class=" text-gray-900 dark:text-gray-100 break-all">
<span class="mr-2 font-mono text-lg">
{{ accountAddress.data }}</span>
<CopyToClipboard
class="!inline-flex"
:text="accountAddress.data"
/>
</div>
</div>

<div class="rounded-2xl bg-neutral-100/50 backdrop-blur-sm dark:bg-gray-800/50 p-6">
<label class="block text-sm font-medium text-gray-600 dark:text-gray-400 mb-2">
Guardian Address
</label>
<div class="text-gray-900 dark:text-gray-100 break-all">
<span class="mr-2 font-mono text-lg">
{{ guardianAddress.data }}</span>
<CopyToClipboard
class="!inline-flex"
:text="guardianAddress.data"
/>
</div>
</div>
</div>

<div
v-if="isGuardianConfirmed"
class="rounded-2xl flex gap-4 bg-green-50/80 dark:bg-green-900/30 backdrop-blur-sm p-6 border border-green-200 dark:border-green-700/50"
>
<CheckCircleIcon class="w-6 h-6 text-green-600 dark:text-green-400 flex-shrink-0" />
<div class="flex flex-col flex-1">
<span class="text-lg font-medium text-green-700 dark:text-green-300">Guardian Already Confirmed</span>
<p class="text-green-600 dark:text-green-400">
This guardian has already been confirmed for your account.
</p>
</div>
</div>
<div
v-else
class="rounded-2xl flex gap-4 bg-yellow-50/80 dark:bg-yellow-900/30 backdrop-blur-sm p-6 border border-yellow-200 dark:border-yellow-700/50"
>
<ExclamationTriangleIcon class="w-6 h-6 text-yellow-600 dark:text-yellow-400 flex-shrink-0" />
<div class="flex flex-col flex-1">
<h3 class="text-lg font-semibold text-yellow-800 dark:text-yellow-200 mb-2">
Action Required
</h3>
<p class="text-yellow-700 dark:text-yellow-300">
Connect your wallet to confirm this guardian for your account.
</p>
<ConnectButton
class="w-full lg:w-fit mt-6"
:type="accountData.isConnected ? 'secondary' : 'primary'"
/>
</div>
</div>

<p
v-if="accountData.address &&!isAddressEqual(accountData.address as `0x${string}`, guardianAddress.data)"
class="text-red-500 font-medium"
>
The connected wallet is not the guardian address. Please connect the correct wallet.
</p>
<Button
v-if="accountData.isConnected"
class="w-full lg:w-fit"
>
Confirm Guardian
</Button>
</main>
</div>
</template>

<script setup lang="ts">
import { CheckCircleIcon, ExclamationTriangleIcon } from "@heroicons/vue/24/solid";
import { useAppKitAccount } from "@reown/appkit/vue";
import { isAddressEqual } from "viem";

import { AddressSchema } from "@/utils/schemas";
import CopyToClipboard from "~/components/common/CopyToClipboard.vue";
import ConnectButton from "~/components/confirm-guardian/connect-button.vue";
import Nav from "~/components/confirm-guardian/nav.vue";
import Button from "~/components/zk/button.vue";

const accountData = useAppKitAccount();

const route = useRoute();
const accountAddress = AddressSchema.safeParse(route.params.accountAddress);
const guardianAddress = AddressSchema.safeParse(route.params.guardianAddress);
if (!accountAddress.success || !guardianAddress.success) {
throw createError({
statusCode: 404,
statusMessage: "Page not found",
fatal: true,
});
}

const isGuardianConfirmed = false;

definePageMeta({
layout: "dashboard",
});
</script>
14 changes: 14 additions & 0 deletions packages/auth-server/utils/schemas.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { getAddress } from "viem";
import { z } from "zod";

export const AddressSchema = z.string().transform((val, ctx) => {
try {
return getAddress(val);
} catch {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "Not a valid address",
});
return z.NEVER;
}
});
Loading