diff --git a/.changeset/afraid-mails-sip.md b/.changeset/afraid-mails-sip.md new file mode 100644 index 00000000000..87d44e5d5d5 --- /dev/null +++ b/.changeset/afraid-mails-sip.md @@ -0,0 +1,5 @@ +--- +"thirdweb": minor +--- + +Feature: Adds getAdminAccount to inAppWallet interface for AA ecosystem wallets diff --git a/packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.test.ts b/packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.test.ts index 2dc112387ed..c92dd050060 100644 --- a/packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.test.ts +++ b/packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.test.ts @@ -1,42 +1,54 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; +import { TEST_CLIENT } from "../../../../../test/src/test-clients.js"; +import { TEST_ACCOUNT_A } from "../../../../../test/src/test-wallets.js"; import { baseSepolia } from "../../../../chains/chain-definitions/base-sepolia.js"; -import { createThirdwebClient } from "../../../../client/client.js"; import { getEcosystemInfo } from "../../../ecosystem/get-ecosystem-wallet-auth-options.js"; -import type { Account } from "../../../interfaces/wallet.js"; +import { predictSmartAccountAddress } from "../../../smart/lib/calls.js"; +import { DEFAULT_ACCOUNT_FACTORY_V0_6 } from "../../../smart/lib/constants.js"; +import type { AuthLoginReturnType } from "../authentication/types.js"; import type { InAppConnector } from "../interfaces/connector.js"; import { createInAppWallet } from "./in-app-core.js"; -import { autoConnectInAppWallet, connectInAppWallet } from "./index.js"; +import * as InAppWallet from "./index.js"; vi.mock("../../../../analytics/track/connect.js", () => ({ trackConnect: vi.fn(), })); -vi.mock("./index.js", () => ({ - autoConnectInAppWallet: vi.fn(), - connectInAppWallet: vi.fn(), -})); - +vi.spyOn(InAppWallet, "connectInAppWallet"); +vi.spyOn(InAppWallet, "autoConnectInAppWallet"); vi.mock("../../../ecosystem/get-ecosystem-wallet-auth-options.js", () => ({ getEcosystemInfo: vi.fn(), })); -describe("createInAppWallet", () => { - const mockClient = createThirdwebClient({ - clientId: "test-client", - }); +describe.runIf(process.env.TW_SECRET_KEY)("createInAppWallet", () => { + const mockClient = TEST_CLIENT; const mockChain = baseSepolia; - const mockAccount = { address: "0x123" } as Account; + const mockAccount = TEST_ACCOUNT_A; + const mockUser = { + status: "Logged In, Wallet Initialized", + walletAddress: TEST_ACCOUNT_A.address, + authDetails: { + userWalletId: TEST_ACCOUNT_A.address, + recoveryShareManagement: "ENCLAVE", + email: "test@test.com", + }, + account: mockAccount, + } as const; + const mockAuthResult: AuthLoginReturnType = { + user: mockUser, + }; const mockConnectorFactory = vi.fn(() => Promise.resolve({ - connect: vi.fn(), + connect: vi.fn().mockResolvedValue(mockAuthResult), logout: vi.fn(() => Promise.resolve({ success: true })), authenticate: vi.fn(), getAccounts: vi.fn(), getAccount: vi.fn(), getProfiles: vi.fn(), - getUser: vi.fn(), + getUser: vi.fn().mockResolvedValue(mockUser), linkProfile: vi.fn(), + unlinkProfile: vi.fn(), preAuthenticate: vi.fn(), } as InAppConnector), ); @@ -46,8 +58,6 @@ describe("createInAppWallet", () => { }); it("should connect successfully", async () => { - vi.mocked(connectInAppWallet).mockResolvedValue([mockAccount, mockChain]); - const wallet = createInAppWallet({ connectorFactory: mockConnectorFactory, }); @@ -61,7 +71,7 @@ describe("createInAppWallet", () => { }); expect(result).toBe(mockAccount); - expect(connectInAppWallet).toHaveBeenCalledWith( + expect(InAppWallet.connectInAppWallet).toHaveBeenCalledWith( expect.objectContaining({ client: mockClient, chain: mockChain, @@ -72,11 +82,6 @@ describe("createInAppWallet", () => { }); it("should auto connect successfully", async () => { - vi.mocked(autoConnectInAppWallet).mockResolvedValue([ - mockAccount, - mockChain, - ]); - const wallet = createInAppWallet({ connectorFactory: mockConnectorFactory, }); @@ -87,7 +92,7 @@ describe("createInAppWallet", () => { }); expect(result).toBe(mockAccount); - expect(autoConnectInAppWallet).toHaveBeenCalledWith( + expect(InAppWallet.autoConnectInAppWallet).toHaveBeenCalledWith( expect.objectContaining({ client: mockClient, chain: mockChain, @@ -102,15 +107,13 @@ describe("createInAppWallet", () => { smartAccountOptions: { defaultChainId: mockChain.id, sponsorGas: true, - accountFactoryAddress: "0x456", + accountFactoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, }, authOptions: [], name: "hello world", slug: "test-ecosystem", }); - vi.mocked(connectInAppWallet).mockResolvedValue([mockAccount, mockChain]); - const wallet = createInAppWallet({ connectorFactory: mockConnectorFactory, ecosystem: { id: "ecosystem.test-ecosystem" }, @@ -124,8 +127,14 @@ describe("createInAppWallet", () => { verificationCode: "", }); - expect(result).toBe(mockAccount); - expect(connectInAppWallet).toHaveBeenCalledWith( + const expectedSmartAccountAddress = await predictSmartAccountAddress({ + factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, + chain: mockChain, + adminAddress: TEST_ACCOUNT_A.address, + client: mockClient, + }); + expect(result.address).toBe(expectedSmartAccountAddress); + expect(InAppWallet.connectInAppWallet).toHaveBeenCalledWith( expect.objectContaining({ client: mockClient, chain: mockChain, @@ -134,7 +143,7 @@ describe("createInAppWallet", () => { smartAccount: expect.objectContaining({ chain: mockChain, sponsorGas: true, - factoryAddress: "0x456", + factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, }), }), expect.any(Object), @@ -145,15 +154,13 @@ describe("createInAppWallet", () => { smartAccountOptions: { defaultChainId: mockChain.id, sponsorGas: true, - accountFactoryAddress: "0x456", + accountFactoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, }, authOptions: [], name: "hello world", slug: "test-ecosystem", }); - vi.mocked(connectInAppWallet).mockResolvedValue([mockAccount, mockChain]); - const wallet = createInAppWallet({ connectorFactory: mockConnectorFactory, ecosystem: { id: "ecosystem.test-ecosystem" }, @@ -166,8 +173,14 @@ describe("createInAppWallet", () => { verificationCode: "", }); - expect(result).toBe(mockAccount); - expect(connectInAppWallet).toHaveBeenCalledWith( + const expectedSmartAccountAddress = await predictSmartAccountAddress({ + factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, + chain: mockChain, + adminAddress: TEST_ACCOUNT_A.address, + client: mockClient, + }); + expect(result.address).toBe(expectedSmartAccountAddress); + expect(InAppWallet.connectInAppWallet).toHaveBeenCalledWith( expect.objectContaining({ client: mockClient, }), @@ -175,7 +188,7 @@ describe("createInAppWallet", () => { smartAccount: expect.objectContaining({ chain: mockChain, sponsorGas: true, - factoryAddress: "0x456", + factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, }), }), expect.any(Object), @@ -187,18 +200,13 @@ describe("createInAppWallet", () => { smartAccountOptions: { defaultChainId: mockChain.id, sponsorGas: true, - accountFactoryAddress: "0x456", + accountFactoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, }, authOptions: [], name: "hello world", slug: "test-ecosystem", }); - vi.mocked(autoConnectInAppWallet).mockResolvedValue([ - mockAccount, - mockChain, - ]); - const wallet = createInAppWallet({ connectorFactory: mockConnectorFactory, ecosystem: { id: "ecosystem.test-ecosystem" }, @@ -209,8 +217,14 @@ describe("createInAppWallet", () => { chain: mockChain, }); - expect(result).toBe(mockAccount); - expect(autoConnectInAppWallet).toHaveBeenCalledWith( + const expectedSmartAccountAddress = await predictSmartAccountAddress({ + factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, + chain: mockChain, + adminAddress: TEST_ACCOUNT_A.address, + client: mockClient, + }); + expect(result.address).toBe(expectedSmartAccountAddress); + expect(InAppWallet.autoConnectInAppWallet).toHaveBeenCalledWith( expect.objectContaining({ client: mockClient, chain: mockChain, @@ -219,7 +233,7 @@ describe("createInAppWallet", () => { smartAccount: expect.objectContaining({ chain: mockChain, sponsorGas: true, - factoryAddress: "0x456", + factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, }), }), expect.any(Object), @@ -231,18 +245,13 @@ describe("createInAppWallet", () => { smartAccountOptions: { defaultChainId: mockChain.id, sponsorGas: true, - accountFactoryAddress: "0x456", + accountFactoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, }, authOptions: [], name: "hello world", slug: "test-ecosystem", }); - vi.mocked(autoConnectInAppWallet).mockResolvedValue([ - mockAccount, - mockChain, - ]); - const wallet = createInAppWallet({ connectorFactory: mockConnectorFactory, ecosystem: { id: "ecosystem.test-ecosystem" }, @@ -252,8 +261,14 @@ describe("createInAppWallet", () => { client: mockClient, }); - expect(result).toBe(mockAccount); - expect(autoConnectInAppWallet).toHaveBeenCalledWith( + const expectedSmartAccountAddress = await predictSmartAccountAddress({ + factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, + chain: mockChain, + adminAddress: TEST_ACCOUNT_A.address, + client: mockClient, + }); + expect(result.address).toBe(expectedSmartAccountAddress); + expect(InAppWallet.autoConnectInAppWallet).toHaveBeenCalledWith( expect.objectContaining({ client: mockClient, }), @@ -261,10 +276,56 @@ describe("createInAppWallet", () => { smartAccount: expect.objectContaining({ chain: mockChain, sponsorGas: true, - factoryAddress: "0x456", + factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, }), }), expect.any(Object), ); }); + + it("should return undefined for getAdminAccount if the account is not a smart account", () => { + const wallet = createInAppWallet({ + connectorFactory: mockConnectorFactory, + }); + + expect(wallet.getAdminAccount?.()).toBeUndefined(); + }); + + it("should return undefined if no account is connected", () => { + const wallet = createInAppWallet({ + connectorFactory: mockConnectorFactory, + }); + + expect(wallet.getAdminAccount?.()).toBeUndefined(); + }); + + it("should return the admin account for a smart account", async () => { + vi.unmock("./index.js"); + vi.mocked(getEcosystemInfo).mockResolvedValue({ + smartAccountOptions: { + defaultChainId: mockChain.id, + sponsorGas: true, + accountFactoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6, + }, + authOptions: [], + name: "hello world", + slug: "test-ecosystem", + }); + + const wallet = createInAppWallet({ + connectorFactory: mockConnectorFactory, + ecosystem: { id: "ecosystem.test-ecosystem" }, + }); + + const smartAccount = await wallet.connect({ + client: mockClient, + strategy: "email", + email: "", + verificationCode: "", + }); + + const adminAccount = wallet.getAdminAccount?.(); + expect(adminAccount).toBeDefined(); + expect(adminAccount?.address).not.toBe(smartAccount.address); + }); }); diff --git a/packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.ts b/packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.ts index 751cbcbbf65..2d937a4ee85 100644 --- a/packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.ts +++ b/packages/thirdweb/src/wallets/in-app/core/wallet/in-app-core.ts @@ -48,6 +48,7 @@ export function createInAppWallet(args: { const emitter = createWalletEmitter<"inApp">(); let createOptions = _createOptions; let account: Account | undefined = undefined; + let adminAccount: Account | undefined = undefined; // Admin account if smartAccountOptions were provided with connection let chain: Chain | undefined = undefined; let client: ThirdwebClient | undefined; @@ -98,15 +99,16 @@ export function createInAppWallet(args: { } } - const [connectedAccount, connectedChain] = await autoConnectInAppWallet( - options, - createOptions, - connector, - ); + const { + account: connectedAccount, + chain: connectedChain, + adminAccount: _adminAccount, + } = await autoConnectInAppWallet(options, createOptions, connector); // set the states client = options.client; account = connectedAccount; + adminAccount = _adminAccount; chain = connectedChain; trackConnect({ client: options.client, @@ -151,14 +153,16 @@ export function createInAppWallet(args: { } } - const [connectedAccount, connectedChain] = await connectInAppWallet( - options, - createOptions, - connector, - ); + const { + account: connectedAccount, + chain: connectedChain, + adminAccount: _adminAccount, + } = await connectInAppWallet(options, createOptions, connector); + // set the states client = options.client; account = connectedAccount; + adminAccount = _adminAccount; chain = connectedChain; trackConnect({ client: options.client, @@ -184,6 +188,7 @@ export function createInAppWallet(args: { } } account = undefined; + adminAccount = undefined; chain = undefined; emitter.emit("disconnect", undefined); }, @@ -212,7 +217,11 @@ export function createInAppWallet(args: { } } - const [connectedAccount, connectedChain] = await autoConnectInAppWallet( + const { + account: connectedAccount, + chain: connectedChain, + adminAccount: _adminAccount, + } = await autoConnectInAppWallet( { chain: newChain, client, @@ -220,6 +229,7 @@ export function createInAppWallet(args: { createOptions, connector, ); + adminAccount = _adminAccount; account = connectedAccount; chain = connectedChain; } else { @@ -228,5 +238,6 @@ export function createInAppWallet(args: { } emitter.emit("chainChanged", newChain); }, + getAdminAccount: () => adminAccount, }; } diff --git a/packages/thirdweb/src/wallets/in-app/core/wallet/index.ts b/packages/thirdweb/src/wallets/in-app/core/wallet/index.ts index cd21db10632..accf32262a6 100644 --- a/packages/thirdweb/src/wallets/in-app/core/wallet/index.ts +++ b/packages/thirdweb/src/wallets/in-app/core/wallet/index.ts @@ -37,7 +37,7 @@ export async function connectInAppWallet( | CreateWalletArgs<"inApp">[1] | CreateWalletArgs[1], connector: InAppConnector, -): Promise<[Account, Chain]> { +): Promise<{ account: Account; chain: Chain; adminAccount?: Account }> { if ( // if auth mode is not specified, the default is popup createOptions?.auth?.mode !== "popup" && @@ -65,15 +65,16 @@ export async function connectInAppWallet( "smartAccount" in createOptions && createOptions?.smartAccount ) { - return convertToSmartAccount({ + const [account, chain] = await convertToSmartAccount({ client: options.client, authAccount, smartAccountOptions: createOptions.smartAccount, chain: options.chain, }); + return { account, chain, adminAccount: authAccount }; } - return [authAccount, options.chain || ethereum] as const; + return { account: authAccount, chain: options.chain || ethereum } as const; } /** @@ -87,7 +88,7 @@ export async function autoConnectInAppWallet( | CreateWalletArgs<"inApp">[1] | CreateWalletArgs[1], connector: InAppConnector, -): Promise<[Account, Chain]> { +): Promise<{ account: Account; chain: Chain; adminAccount?: Account }> { if (options.authResult && connector.loginWithAuthToken) { await connector.loginWithAuthToken(options.authResult); } @@ -104,15 +105,16 @@ export async function autoConnectInAppWallet( "smartAccount" in createOptions && createOptions?.smartAccount ) { - return convertToSmartAccount({ + const [account, chain] = await convertToSmartAccount({ client: options.client, authAccount, smartAccountOptions: createOptions.smartAccount, chain: options.chain, }); + return { account, chain, adminAccount: authAccount }; } - return [authAccount, options.chain || ethereum] as const; + return { account: authAccount, chain: options.chain || ethereum } as const; } async function convertToSmartAccount(options: { @@ -121,14 +123,9 @@ async function convertToSmartAccount(options: { smartAccountOptions: CreateWalletArgs<"smart">[1]; chain?: Chain; }) { - const [{ smartWallet }, { connectSmartWallet }] = await Promise.all([ - import("../../../smart/smart-wallet.js"), - import("../../../smart/index.js"), - ]); + const { connectSmartAccount } = await import("../../../smart/index.js"); - const sa = smartWallet(options.smartAccountOptions); - return connectSmartWallet( - sa, + return connectSmartAccount( { client: options.client, personalAccount: options.authAccount, diff --git a/packages/thirdweb/src/wallets/smart/index.ts b/packages/thirdweb/src/wallets/smart/index.ts index f97d8fb386c..98883ab12d5 100644 --- a/packages/thirdweb/src/wallets/smart/index.ts +++ b/packages/thirdweb/src/wallets/smart/index.ts @@ -69,28 +69,26 @@ export function isSmartWallet( } /** - * We can get the personal account for given smart account but not the other way around - this map gives us the reverse lookup + * For in-app wallets, the smart wallet creation is implicit so we track these to be able to retrieve the personal account for a smart account on the wallet API. + * Note: We have to go account to account here and NOT wallet to account because the smart wallet itself is never exposed to the in-app wallet, only the account. * @internal */ -const personalAccountToSmartAccountMap = new WeakMap< - Account, - Wallet<"smart"> ->(); - -const smartWalletToPersonalAccountMap = new WeakMap, Account>(); +const adminAccountToSmartAccountMap = new WeakMap(); +const smartAccountToAdminAccountMap = new WeakMap(); /** * @internal */ -export async function connectSmartWallet( - wallet: Wallet<"smart">, +export async function connectSmartAccount( connectionOptions: SmartWalletConnectionOptions, creationOptions: SmartWalletOptions, ): Promise<[Account, Chain]> { const { personalAccount, client, chain: connectChain } = connectionOptions; if (!personalAccount) { - throw new Error("Personal wallet does not have an account"); + throw new Error( + "No personal account provided for smart account connection", + ); } const options = creationOptions; @@ -177,8 +175,8 @@ export async function connectSmartWallet( client, }); - personalAccountToSmartAccountMap.set(personalAccount, wallet); - smartWalletToPersonalAccountMap.set(wallet, personalAccount); + adminAccountToSmartAccountMap.set(personalAccount, account); + smartAccountToAdminAccountMap.set(account, personalAccount); return [account, chain] as const; } @@ -186,15 +184,13 @@ export async function connectSmartWallet( /** * @internal */ -export async function disconnectSmartWallet( - wallet: Wallet<"smart">, -): Promise { +export async function disconnectSmartAccount(account: Account): Promise { // look up the personalAccount for the smart wallet - const personalAccount = smartWalletToPersonalAccountMap.get(wallet); + const personalAccount = smartAccountToAdminAccountMap.get(account); if (personalAccount) { // remove the mappings - personalAccountToSmartAccountMap.delete(personalAccount); - smartWalletToPersonalAccountMap.delete(wallet); + adminAccountToSmartAccountMap.delete(personalAccount); + smartAccountToAdminAccountMap.delete(account); } } diff --git a/packages/thirdweb/src/wallets/smart/smart-wallet.ts b/packages/thirdweb/src/wallets/smart/smart-wallet.ts index 5110b9dd0f8..0e2e7c6d887 100644 --- a/packages/thirdweb/src/wallets/smart/smart-wallet.ts +++ b/packages/thirdweb/src/wallets/smart/smart-wallet.ts @@ -137,7 +137,7 @@ export function smartWallet( let chain: Chain | undefined = undefined; let lastConnectOptions: WalletConnectionOption<"smart"> | undefined; - const _smartWallet: Wallet<"smart"> = { + return { id: "smart", subscribe: emitter.subscribe, getChain() { @@ -152,9 +152,10 @@ export function smartWallet( getAccount: () => account, getAdminAccount: () => adminAccount, autoConnect: async (options) => { - const { connectSmartWallet } = await import("./index.js"); + const { connectSmartAccount: connectSmartWallet } = await import( + "./index.js" + ); const [connectedAccount, connectedChain] = await connectSmartWallet( - _smartWallet, options, createOptions, ); @@ -172,9 +173,8 @@ export function smartWallet( return account; }, connect: async (options) => { - const { connectSmartWallet } = await import("./index.js"); - const [connectedAccount, connectedChain] = await connectSmartWallet( - _smartWallet, + const { connectSmartAccount } = await import("./index.js"); + const [connectedAccount, connectedChain] = await connectSmartAccount( options, createOptions, ); @@ -194,10 +194,13 @@ export function smartWallet( return account; }, disconnect: async () => { + if (account) { + const { disconnectSmartAccount } = await import("./index.js"); + await disconnectSmartAccount(account); + } account = undefined; + adminAccount = undefined; chain = undefined; - const { disconnectSmartWallet } = await import("./index.js"); - await disconnectSmartWallet(_smartWallet); emitter.emit("disconnect", undefined); }, switchChain: async (newChain: Chain) => { @@ -223,9 +226,8 @@ export function smartWallet( ); } } - const { connectSmartWallet } = await import("./index.js"); - const [connectedAccount, connectedChain] = await connectSmartWallet( - _smartWallet, + const { connectSmartAccount } = await import("./index.js"); + const [connectedAccount, connectedChain] = await connectSmartAccount( { ...lastConnectOptions, chain: newChain }, createOptions, ); @@ -235,6 +237,4 @@ export function smartWallet( emitter.emit("chainChanged", newChain); }, }; - - return _smartWallet; } diff --git a/packages/thirdweb/src/wallets/smart/smart.test.ts b/packages/thirdweb/src/wallets/smart/smart.test.ts index f589ae92777..9622240b13c 100644 --- a/packages/thirdweb/src/wallets/smart/smart.test.ts +++ b/packages/thirdweb/src/wallets/smart/smart.test.ts @@ -2,7 +2,6 @@ import { describe, expect, it } from "vitest"; import { TEST_CLIENT } from "../../../test/src/test-clients.js"; import { defineChain } from "../../chains/utils.js"; import { generateAccount } from "../utils/generateAccount.js"; -import { connectSmartWallet, disconnectSmartWallet } from "./index.js"; import { smartWallet } from "./smart-wallet.js"; describe("Smart Wallet Index", () => { @@ -17,67 +16,48 @@ describe("Smart Wallet Index", () => { gasless: true, }); - const [account, connectedChain] = await connectSmartWallet( - wallet, - { - client, - personalAccount, - }, - { - chain, - gasless: true, - }, - ); + await wallet.connect({ + client, + personalAccount, + }); - expect(account.address).toBeDefined(); - expect(account.address).toMatch(/^0x[a-fA-F0-9]{40}$/); - expect(connectedChain.id).toBe(chain.id); + expect(wallet.getAccount()?.address).toBeDefined(); + expect(wallet.getAccount()?.address).toMatch(/^0x[a-fA-F0-9]{40}$/); + expect(wallet.getChain()?.id).toBe(chain.id); }); }); describe("disconnectSmartWallet", () => { it("should disconnect a smart wallet", async () => { const personalAccount = await generateAccount({ client }); + const wallet = smartWallet({ chain, gasless: true, }); - await connectSmartWallet( - wallet, - { - client, - personalAccount, - }, - { - chain, - gasless: true, - }, - ); + await wallet.connect({ + client, + personalAccount, + }); - await expect(disconnectSmartWallet(wallet)).resolves.not.toThrow(); + await expect(wallet.disconnect()).resolves.not.toThrow(); }); it("should clear wallet mappings on disconnect", async () => { const personalAccount = await generateAccount({ client }); + const wallet = smartWallet({ chain, gasless: true, }); - await connectSmartWallet( - wallet, - { - client, - personalAccount, - }, - { - chain, - gasless: true, - }, - ); + await wallet.connect({ + client, + personalAccount, + }); - await disconnectSmartWallet(wallet); + await wallet.disconnect(); // Verify wallet state is cleared expect(wallet.getAccount()).toBeUndefined();