From c189514e63d3cfa4387dcdb615340928e887c3c6 Mon Sep 17 00:00:00 2001 From: KONFeature Date: Mon, 9 Dec 2024 18:35:45 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20Update=20components=20to=20handl?= =?UTF-8?q?e=20new=20session=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../context/wallet/smartWallet/connector.ts | 4 +- .../app/i18n/locales/en/translation.json | 6 +- .../app/i18n/locales/fr/translation.json | 6 +- .../authentication/component/Logout/index.tsx | 6 ++ .../authentication/component/Privy/index.tsx | 60 ++++++++----- .../wallet/app/module/common/atoms/session.ts | 13 +++ .../common/hook/useEnforceWagmiConnection.ts | 7 +- .../module/common/hook/useSyncPrivySession.ts | 34 ++++++++ .../module/common/provider/RootProvider.tsx | 5 ++ .../recovery-setup/component/Setup/Step2.tsx | 4 +- .../settings/component/BiometryInfo/index.tsx | 47 ---------- .../settings/component/Recovery/index.tsx | 8 ++ .../index.module.css | 0 .../settings/component/SessionInfo/index.tsx | 86 +++++++++++++++++++ packages/wallet/app/types/Session.ts | 31 ------- packages/wallet/app/types/i18n/resources.d.ts | 6 +- .../wallet/app/views/protected/settings.tsx | 4 +- packages/wallet/package.json | 1 - 18 files changed, 213 insertions(+), 115 deletions(-) create mode 100644 packages/wallet/app/module/common/hook/useSyncPrivySession.ts delete mode 100644 packages/wallet/app/module/settings/component/BiometryInfo/index.tsx rename packages/wallet/app/module/settings/component/{BiometryInfo => SessionInfo}/index.module.css (100%) create mode 100644 packages/wallet/app/module/settings/component/SessionInfo/index.tsx diff --git a/packages/wallet/app/context/wallet/smartWallet/connector.ts b/packages/wallet/app/context/wallet/smartWallet/connector.ts index 259690f73..d6ad64238 100644 --- a/packages/wallet/app/context/wallet/smartWallet/connector.ts +++ b/packages/wallet/app/context/wallet/smartWallet/connector.ts @@ -161,9 +161,7 @@ export function smartAccountConnector< return (await signViaPrivy( message, { - title: "Action confirmation", - description: - "By signing the following hash, you will authorize the current frak action", + showWalletUIs: true, }, address )) as Hex; diff --git a/packages/wallet/app/i18n/locales/en/translation.json b/packages/wallet/app/i18n/locales/en/translation.json index 8a75cb69a..0f6bcad29 100644 --- a/packages/wallet/app/i18n/locales/en/translation.json +++ b/packages/wallet/app/i18n/locales/en/translation.json @@ -125,7 +125,11 @@ }, "wallet": { "activateNotifications": "Enable notifications
to be notified when your gains are paid", - "biometryInfos": "Biometry informations", + "settings": { + "biometryInfo": "Biometry informations", + "privyInfo": "Login informations", + "privyWallet": "Privy wallet" + }, "installWebApp": "Install wallet on home screen
to find your gains at any time", "interaction": { "CREATE_REFERRAL_LINK": "Created share link", diff --git a/packages/wallet/app/i18n/locales/fr/translation.json b/packages/wallet/app/i18n/locales/fr/translation.json index 796881097..e106bead6 100644 --- a/packages/wallet/app/i18n/locales/fr/translation.json +++ b/packages/wallet/app/i18n/locales/fr/translation.json @@ -126,7 +126,11 @@ }, "wallet": { "activateNotifications": "Activer les notifications
pour être prévenu du versement de vos gains", - "biometryInfos": "Informations biométriques", + "settings": { + "biometryInfo": "Informations biométriques", + "privyInfo": "Informations de connection", + "privyWallet": "Portefeuille privy" + }, "installWebApp": "Installer le wallet sur l'écran d'accueil
pour retrouver vos gains à tout moment", "interaction": { "CREATE_REFERRAL_LINK": "Lien de partage créé", diff --git a/packages/wallet/app/module/authentication/component/Logout/index.tsx b/packages/wallet/app/module/authentication/component/Logout/index.tsx index 230af7f7f..840656922 100644 --- a/packages/wallet/app/module/authentication/component/Logout/index.tsx +++ b/packages/wallet/app/module/authentication/component/Logout/index.tsx @@ -2,6 +2,7 @@ import { sdkSessionAtom, sessionAtom } from "@/module/common/atoms/session"; import { Panel } from "@/module/common/component/Panel"; import { jotaiStore } from "@module/atoms/store"; import { Button } from "@module/component/Button"; +import { useLogout } from "@privy-io/react-auth"; import { useQueryClient } from "@tanstack/react-query"; import { RESET } from "jotai/utils"; import { LogOut } from "lucide-react"; @@ -29,6 +30,7 @@ export function Logout() { const { t } = useTranslation(); const navigate = useNavigate(); const queryClient = useQueryClient(); + const { logout: privyLogout } = useLogout(); return ( ); } @@ -47,8 +50,16 @@ function DoPrivyAuthentication() { const { signMessage } = usePrivy(); const { wallets } = useWallets(); const [wallet, setWallet] = useState( - wallets.length > 2 ? undefined : wallets[0] + undefined ); + + // Auto pick the first wallet + useEffect(() => { + if (wallets.length === 1) { + setWallet(wallets[0]); + } + }, [wallets]); + const { mutate: authenticate } = useMutation({ mutationKey: ["privy-login", wallet?.address], async mutationFn() { @@ -97,14 +108,19 @@ function DoPrivyAuthentication() { }, }); - if (!wallet) { - return ; - } - return ( - + <> + {!wallet && wallets.length > 0 && ( + + )} + + ); } diff --git a/packages/wallet/app/module/common/atoms/session.ts b/packages/wallet/app/module/common/atoms/session.ts index 52ac7f752..ba427ffe2 100644 --- a/packages/wallet/app/module/common/atoms/session.ts +++ b/packages/wallet/app/module/common/atoms/session.ts @@ -1,4 +1,5 @@ import type { SdkSession, Session } from "@/types/Session"; +import { atom } from "jotai"; import { atomWithStorage } from "jotai/utils"; export const sessionAtom = atomWithStorage( @@ -6,6 +7,18 @@ export const sessionAtom = atomWithStorage( null ); +export const webauthnSessionAtom = atom((get) => { + const session = get(sessionAtom); + if (!session || typeof session.publicKey !== "object") return null; + return session; +}); + +export const privySessionAtom = atom((get) => { + const session = get(sessionAtom); + if (!session || typeof session.publicKey === "object") return null; + return session; +}); + export const sdkSessionAtom = atomWithStorage( "frak_sdkSession", null diff --git a/packages/wallet/app/module/common/hook/useEnforceWagmiConnection.ts b/packages/wallet/app/module/common/hook/useEnforceWagmiConnection.ts index 5aaf0d81f..acd64a211 100644 --- a/packages/wallet/app/module/common/hook/useEnforceWagmiConnection.ts +++ b/packages/wallet/app/module/common/hook/useEnforceWagmiConnection.ts @@ -2,7 +2,7 @@ import { type FrakWalletConnector, smartAccountConnector, } from "@/context/wallet/smartWallet/connector"; -import { usePrivy } from "@privy-io/react-auth"; +import { useSignMessage } from "@privy-io/react-auth"; import { useEffect, useMemo } from "react"; import { useConfig, useConnect } from "wagmi"; @@ -59,10 +59,9 @@ export function useEnforceWagmiConnection() { }, [connect, frakConnector, isPending, state.current, state.status]); /** - * Get the current privy wallets + * Synchronise the privy sign message with the frak connector */ - const { signMessage } = usePrivy(); - + const { signMessage } = useSignMessage(); useEffect(() => { if (!frakConnector) { return; diff --git a/packages/wallet/app/module/common/hook/useSyncPrivySession.ts b/packages/wallet/app/module/common/hook/useSyncPrivySession.ts new file mode 100644 index 000000000..52f4b385b --- /dev/null +++ b/packages/wallet/app/module/common/hook/useSyncPrivySession.ts @@ -0,0 +1,34 @@ +import { + privySessionAtom, + sdkSessionAtom, + sessionAtom, +} from "@/module/common/atoms/session"; +import { jotaiStore } from "@module/atoms/store"; +import { useWallets } from "@privy-io/react-auth"; +import { useAtomValue } from "jotai"; +import { RESET } from "jotai/utils"; +import { useEffect } from "react"; +import { type Address, isAddressEqual } from "viem"; + +/** + * Hook that synchronise the privy session + */ +export function useSyncPrivySession() { + const privySession = useAtomValue(privySessionAtom); + const { wallets: privyWallets, ready } = useWallets(); + + useEffect(() => { + if (!ready) return; + if (!privySession) return; + + // Find a privy wallets that match the current session + const wallet = privyWallets.find((w) => + isAddressEqual(w.address as Address, privySession.publicKey) + ); + if (wallet) return; + + // If no wallet match, we reset the current user session + jotaiStore.set(sessionAtom, RESET); + jotaiStore.set(sdkSessionAtom, RESET); + }, [privySession, privyWallets, ready]); +} diff --git a/packages/wallet/app/module/common/provider/RootProvider.tsx b/packages/wallet/app/module/common/provider/RootProvider.tsx index a052d5431..e03d2353e 100644 --- a/packages/wallet/app/module/common/provider/RootProvider.tsx +++ b/packages/wallet/app/module/common/provider/RootProvider.tsx @@ -2,6 +2,7 @@ import { currentChain } from "@/context/blockchain/provider"; import { authenticatedBackendApi } from "@/context/common/backendClient"; import { smartAccountConnector } from "@/context/wallet/smartWallet/connector"; import { useEnforceWagmiConnection } from "@/module/common/hook/useEnforceWagmiConnection"; +import { useSyncPrivySession } from "@/module/common/hook/useSyncPrivySession"; import { subscriptionAtom } from "@/module/notification/atom/subscriptionAtom"; import { getTransport } from "@frak-labs/app-essentials/blockchain"; import { jotaiStore } from "@module/atoms/store"; @@ -162,6 +163,7 @@ function WagmiProviderWithDynamicConfig({ children }: PropsWithChildren) { function EnforceWagmiConnection() { useEnforceWagmiConnection(); + useSyncPrivySession(); return null; } @@ -175,11 +177,14 @@ function PrivyProviderWithConfig({ children }: PropsWithChildren) { theme: "light", accentColor: "#676FFF", logo: "https://wallet.frak.id/icon-192.png", + walletChainType: "ethereum-only", }, embeddedWallets: { // Create wallet on login for user who don't have one createOnLogin: "users-without-wallets", }, + supportedChains: [currentChain], + defaultChain: currentChain, }} > {children} diff --git a/packages/wallet/app/module/recovery-setup/component/Setup/Step2.tsx b/packages/wallet/app/module/recovery-setup/component/Setup/Step2.tsx index 6487ad862..c17424b54 100644 --- a/packages/wallet/app/module/recovery-setup/component/Setup/Step2.tsx +++ b/packages/wallet/app/module/recovery-setup/component/Setup/Step2.tsx @@ -1,4 +1,4 @@ -import { sessionAtom } from "@/module/common/atoms/session"; +import { webauthnSessionAtom } from "@/module/common/atoms/session"; import { AccordionRecoveryItem } from "@/module/common/component/AccordionRecoveryItem"; import { useGenerateRecoveryOptions } from "@/module/recovery-setup/hook/useGenerateRecoveryOptions"; import { @@ -21,7 +21,7 @@ export function Step2() { const password = useAtomValue(recoveryPasswordAtom); // Get the current session - const session = useAtomValue(sessionAtom); + const session = useAtomValue(webauthnSessionAtom); // Set the recovery options const setRecoveryOptions = useSetAtom(recoveryOptionsAtom); diff --git a/packages/wallet/app/module/settings/component/BiometryInfo/index.tsx b/packages/wallet/app/module/settings/component/BiometryInfo/index.tsx deleted file mode 100644 index c18191496..000000000 --- a/packages/wallet/app/module/settings/component/BiometryInfo/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { sessionAtom } from "@/module/common/atoms/session"; -import { Panel } from "@/module/common/component/Panel"; -import { Title } from "@/module/common/component/Title"; -import { WalletAddress } from "@module/component/HashDisplay"; -import { useAtomValue } from "jotai"; -import { Fingerprint } from "lucide-react"; -import { useTranslation } from "react-i18next"; -import { useHydrated } from "remix-utils/use-hydrated"; -import { toHex } from "viem"; -import { useAccount } from "wagmi"; -import styles from "./index.module.css"; - -export function BiometryInfo() { - const isHydrated = useHydrated(); - const { t } = useTranslation(); - const { address } = useAccount(); - const wallet = useAtomValue(sessionAtom); - - return ( - - }> - {t("wallet.biometryInfos")} - -
    -
  • - {t("common.authenticator")}{" "} - {isHydrated && ( - - )} -
  • - -
  • - {t("common.wallet")}{" "} - {isHydrated && ( - - )} -
  • -
-
- ); -} diff --git a/packages/wallet/app/module/settings/component/Recovery/index.tsx b/packages/wallet/app/module/settings/component/Recovery/index.tsx index fd3678e79..2fad7ada1 100644 --- a/packages/wallet/app/module/settings/component/Recovery/index.tsx +++ b/packages/wallet/app/module/settings/component/Recovery/index.tsx @@ -1,6 +1,8 @@ +import { webauthnSessionAtom } from "@/module/common/atoms/session"; import { Panel } from "@/module/common/component/Panel"; import { Title } from "@/module/common/component/Title"; import { CurrentRecoverySetupStatus } from "@/module/recovery-setup/component/CurrentSetupStatus"; +import { useAtomValue } from "jotai"; import { Shield } from "lucide-react"; import { useTranslation } from "react-i18next"; import { Link } from "react-router"; @@ -11,6 +13,12 @@ import { Link } from "react-router"; */ export function RecoveryLink() { const { t } = useTranslation(); + const webauthnSession = useAtomValue(webauthnSessionAtom); + + if (!webauthnSession) { + return null; + } + return ( }> diff --git a/packages/wallet/app/module/settings/component/BiometryInfo/index.module.css b/packages/wallet/app/module/settings/component/SessionInfo/index.module.css similarity index 100% rename from packages/wallet/app/module/settings/component/BiometryInfo/index.module.css rename to packages/wallet/app/module/settings/component/SessionInfo/index.module.css diff --git a/packages/wallet/app/module/settings/component/SessionInfo/index.tsx b/packages/wallet/app/module/settings/component/SessionInfo/index.tsx new file mode 100644 index 000000000..b8d3cdc81 --- /dev/null +++ b/packages/wallet/app/module/settings/component/SessionInfo/index.tsx @@ -0,0 +1,86 @@ +import { + privySessionAtom, + webauthnSessionAtom, +} from "@/module/common/atoms/session"; +import { Panel } from "@/module/common/component/Panel"; +import { Title } from "@/module/common/component/Title"; +import { WalletAddress } from "@module/component/HashDisplay"; +import { useAtomValue } from "jotai"; +import { Fingerprint, KeyRound } from "lucide-react"; +import { useTranslation } from "react-i18next"; +import { useHydrated } from "remix-utils/use-hydrated"; +import { toHex } from "viem"; +import { useAccount } from "wagmi"; +import styles from "./index.module.css"; + +export function SessionInfo() { + const isHydrated = useHydrated(); + const { t } = useTranslation(); + const { address } = useAccount(); + const webauthnWallet = useAtomValue(webauthnSessionAtom); + const privyWallet = useAtomValue(privySessionAtom); + + if (webauthnWallet) { + return ( + <Panel size={"small"}> + <Title icon={<Fingerprint size={32} />}> + {t("wallet.settings.biometryInfo")} + +
    +
  • + {t("common.authenticator")}{" "} + {isHydrated && ( + + )} +
  • + +
  • + {t("common.wallet")}{" "} + {isHydrated && ( + + )} +
  • +
+
+ ); + } + + if (privyWallet) { + return ( + + }> + {t("wallet.settings.privyInfo")} + +
    +
  • + {t("wallet.settings.privyWallet")}{" "} + {isHydrated && ( + + )} +
  • + +
  • + {t("common.wallet")}{" "} + {isHydrated && ( + + )} +
  • +
+
+ ); + } + + return null; +} diff --git a/packages/wallet/app/types/Session.ts b/packages/wallet/app/types/Session.ts index d5c9cf71e..25b5c383f 100644 --- a/packages/wallet/app/types/Session.ts +++ b/packages/wallet/app/types/Session.ts @@ -12,37 +12,6 @@ export type PrivyWallet = { transports: undefined; }; -/* - - - Need to generate a session token for the fallback type though - Impact on: - - wagmi connector - - everything that use webauthn directly - - wallet settings page? - - recovery (use privy recovery insteead) - - - how to transmit the signature provider to the wagmi provider? Need to check how the privy custom conenctor is build - - Maybe a privy store? - - - Btw, need to setup google OAuth (so google account) + PWA stuff? - - - For login: - - Privy sign msg, smth like "I accept Frak CGU by signing this message", pushed a new backend routes (login only, no rigstration on privy here) - - Transmit PrivyInstance to the wagmi connector? And then depending on the session type, check for embeded wallets with privy (if none ask to create new one) - - Maybe with privy instance we can get the wallet provider - - Nop, should use the useWallets hook, so LoginFallback should do multiple stuff: - 1. Privy login - 2. Privy wallets check (if none ask to create one) - 3. Sign message for backend login - 4. Transmit the wallets to the wagmi connector - - On logout, need to add the privy logout actions - - */ - export type InteractionSession = { sessionStart: number; sessionEnd: number; diff --git a/packages/wallet/app/types/i18n/resources.d.ts b/packages/wallet/app/types/i18n/resources.d.ts index 16012c5cc..a90c699f3 100644 --- a/packages/wallet/app/types/i18n/resources.d.ts +++ b/packages/wallet/app/types/i18n/resources.d.ts @@ -128,7 +128,11 @@ interface Resources { }; wallet: { activateNotifications: "Enable notifications
to be notified when your gains are paid"; - biometryInfos: "Biometry informations"; + settings: { + biometryInfo: "Biometry informations"; + privyInfo: "Login informations"; + privyWallet: "Privy wallet"; + }; installWebApp: "Install wallet on home screen
to find your gains at any time"; interaction: { CREATE_REFERRAL_LINK: "Created share link"; diff --git a/packages/wallet/app/views/protected/settings.tsx b/packages/wallet/app/views/protected/settings.tsx index 7ae714836..3a22dc8c9 100644 --- a/packages/wallet/app/views/protected/settings.tsx +++ b/packages/wallet/app/views/protected/settings.tsx @@ -1,14 +1,14 @@ import { Logout } from "@/module/authentication/component/Logout"; import { Grid } from "@/module/common/component/Grid"; import { RemoveAllNotification } from "@/module/notification/component/RemoveAllNotification"; -import { BiometryInfo } from "@/module/settings/component/BiometryInfo"; import { CloseSession } from "@/module/settings/component/CloseSession"; import { RecoveryLink } from "@/module/settings/component/Recovery"; +import { SessionInfo } from "app/module/settings/component/SessionInfo"; export default function Settings() { return ( }> - + diff --git a/packages/wallet/package.json b/packages/wallet/package.json index b1572eae2..2592c8fe3 100644 --- a/packages/wallet/package.json +++ b/packages/wallet/package.json @@ -16,7 +16,6 @@ "typecheck": "tsc --noEmit", "bundle:check": "sst shell bunx vite-bundle-visualizer", "i18n:types": "bun run i18next-resources-for-ts interface -i ./app/i18n/locales/en/ -o app/types/i18n/resources.d.ts", - "i18n:pull": "", "sw": "bun run tsup" }, "dependencies": {