feat: add optional wallet.getAdminAccount(), new useAdminWallet() hook and auto auth when using inapp+smart accounts (#4601)
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}`
<!-- end pr-codex -->
This commit is contained in:
@@ -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.
|
||||
@@ -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";
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
}
|
||||
@@ -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<Status>("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 <LoadingScreen />;
|
||||
}
|
||||
|
||||
if (wallet.id === "inApp" || wallet.id === "embedded") {
|
||||
if (
|
||||
wallet.id === "inApp" ||
|
||||
wallet.id === "embedded" ||
|
||||
(wallet.id === "smart" && adminWallet?.id === "inApp")
|
||||
) {
|
||||
return (
|
||||
<HeadlessSignIn
|
||||
signIn={signIn}
|
||||
|
||||
@@ -305,7 +305,6 @@ export class IFrameWallet {
|
||||
return signedMessage as Hex;
|
||||
},
|
||||
async signTypedData(_typedData) {
|
||||
console.log("signTypedData", _typedData);
|
||||
const parsedTypedData = parseTypedData(_typedData);
|
||||
// deleting EIP712 Domain as it results in ambiguous primary type on some cases
|
||||
// this happens when going from viem to ethers via the iframe
|
||||
|
||||
@@ -141,6 +141,12 @@ export type Wallet<TWalletId extends WalletId = WalletId> = {
|
||||
* Can be used to execute any pre-connection actions like showing a modal, etc.
|
||||
*/
|
||||
onConnectRequested?: () => Promise<void>;
|
||||
|
||||
/**
|
||||
* Get the admin account of this wallet
|
||||
* This is useful for smart wallets to get the underlying personal account
|
||||
*/
|
||||
getAdminAccount?: () => Account | undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user