Skip to content

Commit 082e4bb

Browse files
committed
fix(sdk): smart wallet account switching
1 parent 149ee05 commit 082e4bb

File tree

3 files changed

+107
-21
lines changed

3 files changed

+107
-21
lines changed

biome.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"noRestrictedGlobals": {
3030
"options": { "deniedGlobals": ["Buffer"] },
3131
"level": "error"
32-
}
32+
},
33+
"noUselessElse": "off"
3334
}
3435
}
3536
},
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { beforeEach, describe, expect, it, vi } from "vitest";
2+
import { TEST_CLIENT } from "../../../test/src/test-clients.js";
3+
import { TEST_ACCOUNT_A } from "../../../test/src/test-wallets.js";
4+
import { sepolia } from "../../chains/chain-definitions/sepolia.js";
5+
import type { ThirdwebClient } from "../../client/client.js";
6+
import type { AsyncStorage } from "../../utils/storage/AsyncStorage.js";
7+
import type { Account, Wallet } from "../interfaces/wallet.js";
8+
import type { SmartWalletOptions } from "../smart/types.js";
9+
import { createConnectionManager } from "./index.js";
10+
11+
describe.runIf(process.env.TW_SECRET_KEY)("Connection Manager", () => {
12+
let storage: AsyncStorage;
13+
let client: ThirdwebClient;
14+
let wallet: Wallet;
15+
let account: Account;
16+
let smartWalletOptions: SmartWalletOptions;
17+
18+
beforeEach(() => {
19+
storage = {
20+
getItem: vi.fn(),
21+
setItem: vi.fn(),
22+
removeItem: vi.fn(),
23+
};
24+
client = TEST_CLIENT;
25+
account = TEST_ACCOUNT_A;
26+
wallet = {
27+
id: "wallet-id",
28+
getAccount: vi.fn().mockReturnValue(account),
29+
subscribe: vi.fn(),
30+
disconnect: vi.fn(),
31+
switchChain: vi.fn(),
32+
getChain: vi.fn().mockReturnValue(sepolia),
33+
getConfig: vi.fn(),
34+
} as unknown as Wallet;
35+
smartWalletOptions = {
36+
chain: sepolia,
37+
} as SmartWalletOptions;
38+
});
39+
40+
it("connect should handle connection and call onConnect", async () => {
41+
const manager = createConnectionManager(storage);
42+
const onConnect = vi.fn();
43+
44+
await manager.connect(wallet, { client, onConnect });
45+
46+
expect(onConnect).toHaveBeenCalledWith(wallet);
47+
expect(storage.setItem).toHaveBeenCalledWith(expect.any(String), wallet.id);
48+
});
49+
50+
it("handleConnection should connect smart wallet", async () => {
51+
const manager = createConnectionManager(storage);
52+
53+
const smartWallet = await manager.handleConnection(wallet, {
54+
client,
55+
accountAbstraction: smartWalletOptions,
56+
});
57+
58+
expect(manager.activeWalletStore.getValue()).toBe(smartWallet);
59+
});
60+
61+
it("handleConnection should add wallet to connected wallets", async () => {
62+
const manager = createConnectionManager(storage);
63+
64+
await manager.handleConnection(wallet, { client });
65+
66+
expect(manager.connectedWallets.getValue()).toContain(wallet);
67+
});
68+
});

packages/thirdweb/src/wallets/manager/index.ts

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -128,37 +128,54 @@ export function createConnectionManager(storage: AsyncStorage) {
128128
throw new Error("Can not set a wallet without an account as active");
129129
}
130130

131-
const personalWallet = wallet;
132-
let activeWallet = personalWallet;
133-
const isInAppSmartAccount = hasSmartAccount(wallet);
134-
if (options?.accountAbstraction && !isInAppSmartAccount) {
135-
activeWallet = smartWallet(options.accountAbstraction);
136-
await activeWallet.connect({
137-
personalAccount: wallet.getAccount(),
138-
client: options.client,
139-
});
140-
}
131+
const activeWallet = await (async () => {
132+
if (options?.accountAbstraction && !hasSmartAccount(wallet)) {
133+
return await handleSmartWalletConnection(
134+
account,
135+
options.client,
136+
options.accountAbstraction,
137+
);
138+
} else {
139+
return wallet;
140+
}
141+
})();
141142

142143
// add personal wallet to connected wallets list
143-
addConnectedWallet(personalWallet);
144+
addConnectedWallet(wallet);
144145

145-
if (personalWallet.id !== "smart") {
146-
await storage.setItem(LAST_ACTIVE_EOA_ID, personalWallet.id);
146+
if (wallet.id !== "smart") {
147+
await storage.setItem(LAST_ACTIVE_EOA_ID, wallet.id);
147148
}
148149

150+
handleSetActiveWallet(activeWallet);
151+
152+
wallet.subscribe("accountChanged", async () => {
153+
connect(wallet, options);
154+
});
155+
149156
return activeWallet;
150157
};
151158

159+
const handleSmartWalletConnection = async (
160+
signer: Account,
161+
client: ThirdwebClient,
162+
options: SmartWalletOptions,
163+
) => {
164+
const wallet = smartWallet(options);
165+
166+
await wallet.connect({
167+
personalAccount: signer,
168+
client: client,
169+
chain: options.chain,
170+
});
171+
172+
return wallet;
173+
};
174+
152175
const connect = async (wallet: Wallet, options?: ConnectManagerOptions) => {
153-
// connectedWallet can be either wallet or smartWallet based on
176+
// connectedWallet can be either wallet or smartWallet
154177
const connectedWallet = await handleConnection(wallet, options);
155178
options?.onConnect?.(connectedWallet);
156-
handleSetActiveWallet(connectedWallet);
157-
wallet.subscribe("accountChanged", async () => {
158-
const newConnectedWallet = await handleConnection(wallet, options);
159-
options?.onConnect?.(newConnectedWallet);
160-
handleSetActiveWallet(newConnectedWallet);
161-
});
162179
return connectedWallet;
163180
};
164181

0 commit comments

Comments
 (0)