From a4a41364cd2f1b7b52717f619d70e005edc74edc Mon Sep 17 00:00:00 2001 From: joaquim-verges Date: Sun, 15 Sep 2024 20:34:38 +0000 Subject: [PATCH] feat: add optional wallet.getAdminAccount(), new useAdminWallet() hook and auto auth when using inapp+smart accounts (#4601) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes CNCT-1833 ## PR-Codex overview This PR introduces a new `useAdminWallet()` hook for smart wallets and adds functionality for automatic authentication with in-app and smart accounts. ### Detailed summary - Added `getAdminAccount` method to `Wallet` interface - Created `useAdminWallet()` hook to get admin wallet for smart wallets - Automatic authentication for in-app and smart accounts - Updated various files to implement the new hook and method > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .changeset/five-toys-wait.md | 16 ++++++++++++ packages/thirdweb/src/exports/react.native.ts | 1 + packages/thirdweb/src/exports/react.ts | 1 + .../core/hooks/wallets/useAdminAccount.ts | 25 +++++++++++++++++++ .../ConnectWallet/screens/SignatureScreen.tsx | 14 +++++++---- .../wallets/in-app/web/lib/in-app-account.ts | 1 - .../thirdweb/src/wallets/interfaces/wallet.ts | 6 +++++ .../src/wallets/smart/smart-wallet.ts | 3 +++ 8 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 .changeset/five-toys-wait.md create mode 100644 packages/thirdweb/src/react/core/hooks/wallets/useAdminAccount.ts diff --git a/.changeset/five-toys-wait.md b/.changeset/five-toys-wait.md new file mode 100644 index 000000000..e5ed18918 --- /dev/null +++ b/.changeset/five-toys-wait.md @@ -0,0 +1,16 @@ +--- +"thirdweb": minor +--- + +`useAdminWallet()` Hook + automatically auth when using inapp + smart accounts + +### Add `useAdminWallet()` hook to get the admin wallet for a smart wallet + +```ts +const activeWallet = useActiveWallet(); // smart wallet +const adminWallet = useAdminWallet(); // the personal wallet that controls the smart wallet +``` + +### Automatically auth when using inapp + smart accounts + +When using auth with an inapp + smart wallet, ConnectButton and ConnectEmebed will automatically auth without having to click sign in. diff --git a/packages/thirdweb/src/exports/react.native.ts b/packages/thirdweb/src/exports/react.native.ts index a21829b9a..427eff3bf 100644 --- a/packages/thirdweb/src/exports/react.native.ts +++ b/packages/thirdweb/src/exports/react.native.ts @@ -9,6 +9,7 @@ export type { // wallet hooks export { useActiveWallet } from "../react/core/hooks/wallets/useActiveWallet.js"; +export { useAdminWallet } from "../react/core/hooks/wallets/useAdminAccount.js"; export { useActiveWalletChain } from "../react/core/hooks/wallets/useActiveWalletChain.js"; export { useActiveWalletConnectionStatus } from "../react/core/hooks/wallets/useActiveWalletConnectionStatus.js"; export { useActiveAccount } from "../react/core/hooks/wallets/useActiveAccount.js"; diff --git a/packages/thirdweb/src/exports/react.ts b/packages/thirdweb/src/exports/react.ts index 16784343d..0f2cc6ea8 100644 --- a/packages/thirdweb/src/exports/react.ts +++ b/packages/thirdweb/src/exports/react.ts @@ -40,6 +40,7 @@ export type { MediaRendererProps } from "../react/web/ui/MediaRenderer/types.js" // wallet hooks export { useActiveWallet } from "../react/core/hooks/wallets/useActiveWallet.js"; +export { useAdminWallet } from "../react/core/hooks/wallets/useAdminAccount.js"; export { useActiveWalletChain } from "../react/core/hooks/wallets/useActiveWalletChain.js"; export { useActiveWalletConnectionStatus } from "../react/core/hooks/wallets/useActiveWalletConnectionStatus.js"; export { useActiveAccount } from "../react/core/hooks/wallets/useActiveAccount.js"; diff --git a/packages/thirdweb/src/react/core/hooks/wallets/useAdminAccount.ts b/packages/thirdweb/src/react/core/hooks/wallets/useAdminAccount.ts new file mode 100644 index 000000000..27915f884 --- /dev/null +++ b/packages/thirdweb/src/react/core/hooks/wallets/useAdminAccount.ts @@ -0,0 +1,25 @@ +import { useActiveWallet } from "./useActiveWallet.js"; +import { useConnectedWallets } from "./useConnectedWallets.js"; + +/** + * Get the admin wallet for the active wallet + * Useful for smart wallets to get the underlying personal account + * @returns The admin wallet for the active wallet, or the active wallet if it doesn't have an admin account + */ +export function useAdminWallet() { + const activeWallet = useActiveWallet(); + const connectedWallets = useConnectedWallets(); + const adminAccount = activeWallet?.getAdminAccount?.(); + + if (!adminAccount) { + // If the active wallet doesn't have an admin account, return the active wallet + return activeWallet; + } + + // If the active wallet has an admin account, find the admin wallet in connected wallets and return it + return connectedWallets.find( + (wallet) => + wallet.getAccount()?.address?.toLowerCase() === + adminAccount?.address?.toLowerCase(), + ); +} diff --git a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/SignatureScreen.tsx b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/SignatureScreen.tsx index 226071943..f9ba103f5 100644 --- a/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/SignatureScreen.tsx +++ b/packages/thirdweb/src/react/web/ui/ConnectWallet/screens/SignatureScreen.tsx @@ -13,6 +13,7 @@ import { useSiweAuth } from "../../../../core/hooks/auth/useSiweAuth.js"; import type { ConnectButtonProps } from "../../../../core/hooks/connection/ConnectButtonProps.js"; import { useActiveAccount } from "../../../../core/hooks/wallets/useActiveAccount.js"; import { useActiveWallet } from "../../../../core/hooks/wallets/useActiveWallet.js"; +import { useAdminWallet } from "../../../../core/hooks/wallets/useAdminAccount.js"; import { useDisconnect } from "../../../../core/hooks/wallets/useDisconnect.js"; import { wait } from "../../../../core/utils/wait.js"; import { LoadingScreen } from "../../../wallets/shared/LoadingScreen.js"; @@ -46,12 +47,12 @@ export const SignatureScreen: React.FC<{ connectLocale, } = props; - const activeWallet = useActiveWallet(); + const wallet = useActiveWallet(); + const adminWallet = useAdminWallet(); const activeAccount = useActiveAccount(); - const siweAuth = useSiweAuth(activeWallet, activeAccount, props.auth); + const siweAuth = useSiweAuth(wallet, activeAccount, props.auth); const [status, setStatus] = useState("idle"); const { disconnect } = useDisconnect(); - const wallet = useActiveWallet(); const locale = connectLocale.signatureScreen; const signIn = useCallback(async () => { @@ -66,12 +67,15 @@ export const SignatureScreen: React.FC<{ } }, [onDone, siweAuth]); - // this should not happen if (!wallet) { return ; } - if (wallet.id === "inApp" || wallet.id === "embedded") { + if ( + wallet.id === "inApp" || + wallet.id === "embedded" || + (wallet.id === "smart" && adminWallet?.id === "inApp") + ) { return ( = { * Can be used to execute any pre-connection actions like showing a modal, etc. */ onConnectRequested?: () => Promise; + + /** + * Get the admin account of this wallet + * This is useful for smart wallets to get the underlying personal account + */ + getAdminAccount?: () => Account | undefined; }; /** diff --git a/packages/thirdweb/src/wallets/smart/smart-wallet.ts b/packages/thirdweb/src/wallets/smart/smart-wallet.ts index 21a6ab220..5aa999295 100644 --- a/packages/thirdweb/src/wallets/smart/smart-wallet.ts +++ b/packages/thirdweb/src/wallets/smart/smart-wallet.ts @@ -102,6 +102,7 @@ export function smartWallet( ): Wallet<"smart"> { const emitter = createWalletEmitter<"smart">(); let account: Account | undefined = undefined; + let adminAccount: Account | undefined = undefined; let chain: Chain | undefined = undefined; let lastConnectOptions: WalletConnectionOption<"smart"> | undefined; @@ -118,6 +119,7 @@ export function smartWallet( }, getConfig: () => createOptions, getAccount: () => account, + getAdminAccount: () => adminAccount, autoConnect: async (options) => { const { connectSmartWallet } = await import("./index.js"); const [connectedAccount, connectedChain] = await connectSmartWallet( @@ -145,6 +147,7 @@ export function smartWallet( createOptions, ); // set the states + adminAccount = options.personalAccount; lastConnectOptions = options; account = connectedAccount; chain = connectedChain;