Skip to content

Commit ec27773

Browse files
committed
feat(sdk): add getAdminAccount to ecosystem wallets
1 parent 1b103d7 commit ec27773

File tree

6 files changed

+191
-132
lines changed

6 files changed

+191
-132
lines changed
Lines changed: 115 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,54 @@
11
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";
24
import { baseSepolia } from "../../../../chains/chain-definitions/base-sepolia.js";
3-
import { createThirdwebClient } from "../../../../client/client.js";
45
import { getEcosystemInfo } from "../../../ecosystem/get-ecosystem-wallet-auth-options.js";
5-
import type { Account } from "../../../interfaces/wallet.js";
6+
import { predictSmartAccountAddress } from "../../../smart/lib/calls.js";
7+
import { DEFAULT_ACCOUNT_FACTORY_V0_6 } from "../../../smart/lib/constants.js";
8+
import type { AuthLoginReturnType } from "../authentication/types.js";
69
import type { InAppConnector } from "../interfaces/connector.js";
710
import { createInAppWallet } from "./in-app-core.js";
8-
import { autoConnectInAppWallet, connectInAppWallet } from "./index.js";
11+
import * as InAppWallet from "./index.js";
912

1013
vi.mock("../../../../analytics/track/connect.js", () => ({
1114
trackConnect: vi.fn(),
1215
}));
1316

14-
vi.mock("./index.js", () => ({
15-
autoConnectInAppWallet: vi.fn(),
16-
connectInAppWallet: vi.fn(),
17-
}));
18-
17+
vi.spyOn(InAppWallet, "connectInAppWallet");
18+
vi.spyOn(InAppWallet, "autoConnectInAppWallet");
1919
vi.mock("../../../ecosystem/get-ecosystem-wallet-auth-options.js", () => ({
2020
getEcosystemInfo: vi.fn(),
2121
}));
2222

23-
describe("createInAppWallet", () => {
24-
const mockClient = createThirdwebClient({
25-
clientId: "test-client",
26-
});
23+
describe.runIf(process.env.TW_SECRET_KEY)("createInAppWallet", () => {
24+
const mockClient = TEST_CLIENT;
2725
const mockChain = baseSepolia;
28-
const mockAccount = { address: "0x123" } as Account;
26+
const mockAccount = TEST_ACCOUNT_A;
27+
const mockUser = {
28+
status: "Logged In, Wallet Initialized",
29+
walletAddress: TEST_ACCOUNT_A.address,
30+
authDetails: {
31+
userWalletId: TEST_ACCOUNT_A.address,
32+
recoveryShareManagement: "ENCLAVE",
33+
email: "test@test.com",
34+
},
35+
account: mockAccount,
36+
} as const;
37+
const mockAuthResult: AuthLoginReturnType = {
38+
user: mockUser,
39+
};
2940

3041
const mockConnectorFactory = vi.fn(() =>
3142
Promise.resolve({
32-
connect: vi.fn(),
43+
connect: vi.fn().mockResolvedValue(mockAuthResult),
3344
logout: vi.fn(() => Promise.resolve({ success: true })),
3445
authenticate: vi.fn(),
3546
getAccounts: vi.fn(),
3647
getAccount: vi.fn(),
3748
getProfiles: vi.fn(),
38-
getUser: vi.fn(),
49+
getUser: vi.fn().mockResolvedValue(mockUser),
3950
linkProfile: vi.fn(),
51+
unlinkProfile: vi.fn(),
4052
preAuthenticate: vi.fn(),
4153
} as InAppConnector),
4254
);
@@ -46,8 +58,6 @@ describe("createInAppWallet", () => {
4658
});
4759

4860
it("should connect successfully", async () => {
49-
vi.mocked(connectInAppWallet).mockResolvedValue([mockAccount, mockChain]);
50-
5161
const wallet = createInAppWallet({
5262
connectorFactory: mockConnectorFactory,
5363
});
@@ -61,7 +71,7 @@ describe("createInAppWallet", () => {
6171
});
6272

6373
expect(result).toBe(mockAccount);
64-
expect(connectInAppWallet).toHaveBeenCalledWith(
74+
expect(InAppWallet.connectInAppWallet).toHaveBeenCalledWith(
6575
expect.objectContaining({
6676
client: mockClient,
6777
chain: mockChain,
@@ -72,11 +82,6 @@ describe("createInAppWallet", () => {
7282
});
7383

7484
it("should auto connect successfully", async () => {
75-
vi.mocked(autoConnectInAppWallet).mockResolvedValue([
76-
mockAccount,
77-
mockChain,
78-
]);
79-
8085
const wallet = createInAppWallet({
8186
connectorFactory: mockConnectorFactory,
8287
});
@@ -87,7 +92,7 @@ describe("createInAppWallet", () => {
8792
});
8893

8994
expect(result).toBe(mockAccount);
90-
expect(autoConnectInAppWallet).toHaveBeenCalledWith(
95+
expect(InAppWallet.autoConnectInAppWallet).toHaveBeenCalledWith(
9196
expect.objectContaining({
9297
client: mockClient,
9398
chain: mockChain,
@@ -102,15 +107,13 @@ describe("createInAppWallet", () => {
102107
smartAccountOptions: {
103108
defaultChainId: mockChain.id,
104109
sponsorGas: true,
105-
accountFactoryAddress: "0x456",
110+
accountFactoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
106111
},
107112
authOptions: [],
108113
name: "hello world",
109114
slug: "test-ecosystem",
110115
});
111116

112-
vi.mocked(connectInAppWallet).mockResolvedValue([mockAccount, mockChain]);
113-
114117
const wallet = createInAppWallet({
115118
connectorFactory: mockConnectorFactory,
116119
ecosystem: { id: "ecosystem.test-ecosystem" },
@@ -124,8 +127,14 @@ describe("createInAppWallet", () => {
124127
verificationCode: "",
125128
});
126129

127-
expect(result).toBe(mockAccount);
128-
expect(connectInAppWallet).toHaveBeenCalledWith(
130+
const expectedSmartAccountAddress = await predictSmartAccountAddress({
131+
factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
132+
chain: mockChain,
133+
adminAddress: TEST_ACCOUNT_A.address,
134+
client: mockClient,
135+
});
136+
expect(result.address).toBe(expectedSmartAccountAddress);
137+
expect(InAppWallet.connectInAppWallet).toHaveBeenCalledWith(
129138
expect.objectContaining({
130139
client: mockClient,
131140
chain: mockChain,
@@ -134,7 +143,7 @@ describe("createInAppWallet", () => {
134143
smartAccount: expect.objectContaining({
135144
chain: mockChain,
136145
sponsorGas: true,
137-
factoryAddress: "0x456",
146+
factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
138147
}),
139148
}),
140149
expect.any(Object),
@@ -145,15 +154,13 @@ describe("createInAppWallet", () => {
145154
smartAccountOptions: {
146155
defaultChainId: mockChain.id,
147156
sponsorGas: true,
148-
accountFactoryAddress: "0x456",
157+
accountFactoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
149158
},
150159
authOptions: [],
151160
name: "hello world",
152161
slug: "test-ecosystem",
153162
});
154163

155-
vi.mocked(connectInAppWallet).mockResolvedValue([mockAccount, mockChain]);
156-
157164
const wallet = createInAppWallet({
158165
connectorFactory: mockConnectorFactory,
159166
ecosystem: { id: "ecosystem.test-ecosystem" },
@@ -166,16 +173,22 @@ describe("createInAppWallet", () => {
166173
verificationCode: "",
167174
});
168175

169-
expect(result).toBe(mockAccount);
170-
expect(connectInAppWallet).toHaveBeenCalledWith(
176+
const expectedSmartAccountAddress = await predictSmartAccountAddress({
177+
factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
178+
chain: mockChain,
179+
adminAddress: TEST_ACCOUNT_A.address,
180+
client: mockClient,
181+
});
182+
expect(result.address).toBe(expectedSmartAccountAddress);
183+
expect(InAppWallet.connectInAppWallet).toHaveBeenCalledWith(
171184
expect.objectContaining({
172185
client: mockClient,
173186
}),
174187
expect.objectContaining({
175188
smartAccount: expect.objectContaining({
176189
chain: mockChain,
177190
sponsorGas: true,
178-
factoryAddress: "0x456",
191+
factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
179192
}),
180193
}),
181194
expect.any(Object),
@@ -187,18 +200,13 @@ describe("createInAppWallet", () => {
187200
smartAccountOptions: {
188201
defaultChainId: mockChain.id,
189202
sponsorGas: true,
190-
accountFactoryAddress: "0x456",
203+
accountFactoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
191204
},
192205
authOptions: [],
193206
name: "hello world",
194207
slug: "test-ecosystem",
195208
});
196209

197-
vi.mocked(autoConnectInAppWallet).mockResolvedValue([
198-
mockAccount,
199-
mockChain,
200-
]);
201-
202210
const wallet = createInAppWallet({
203211
connectorFactory: mockConnectorFactory,
204212
ecosystem: { id: "ecosystem.test-ecosystem" },
@@ -209,8 +217,14 @@ describe("createInAppWallet", () => {
209217
chain: mockChain,
210218
});
211219

212-
expect(result).toBe(mockAccount);
213-
expect(autoConnectInAppWallet).toHaveBeenCalledWith(
220+
const expectedSmartAccountAddress = await predictSmartAccountAddress({
221+
factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
222+
chain: mockChain,
223+
adminAddress: TEST_ACCOUNT_A.address,
224+
client: mockClient,
225+
});
226+
expect(result.address).toBe(expectedSmartAccountAddress);
227+
expect(InAppWallet.autoConnectInAppWallet).toHaveBeenCalledWith(
214228
expect.objectContaining({
215229
client: mockClient,
216230
chain: mockChain,
@@ -219,7 +233,7 @@ describe("createInAppWallet", () => {
219233
smartAccount: expect.objectContaining({
220234
chain: mockChain,
221235
sponsorGas: true,
222-
factoryAddress: "0x456",
236+
factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
223237
}),
224238
}),
225239
expect.any(Object),
@@ -231,18 +245,13 @@ describe("createInAppWallet", () => {
231245
smartAccountOptions: {
232246
defaultChainId: mockChain.id,
233247
sponsorGas: true,
234-
accountFactoryAddress: "0x456",
248+
accountFactoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
235249
},
236250
authOptions: [],
237251
name: "hello world",
238252
slug: "test-ecosystem",
239253
});
240254

241-
vi.mocked(autoConnectInAppWallet).mockResolvedValue([
242-
mockAccount,
243-
mockChain,
244-
]);
245-
246255
const wallet = createInAppWallet({
247256
connectorFactory: mockConnectorFactory,
248257
ecosystem: { id: "ecosystem.test-ecosystem" },
@@ -252,19 +261,71 @@ describe("createInAppWallet", () => {
252261
client: mockClient,
253262
});
254263

255-
expect(result).toBe(mockAccount);
256-
expect(autoConnectInAppWallet).toHaveBeenCalledWith(
264+
const expectedSmartAccountAddress = await predictSmartAccountAddress({
265+
factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
266+
chain: mockChain,
267+
adminAddress: TEST_ACCOUNT_A.address,
268+
client: mockClient,
269+
});
270+
expect(result.address).toBe(expectedSmartAccountAddress);
271+
expect(InAppWallet.autoConnectInAppWallet).toHaveBeenCalledWith(
257272
expect.objectContaining({
258273
client: mockClient,
259274
}),
260275
expect.objectContaining({
261276
smartAccount: expect.objectContaining({
262277
chain: mockChain,
263278
sponsorGas: true,
264-
factoryAddress: "0x456",
279+
factoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
265280
}),
266281
}),
267282
expect.any(Object),
268283
);
269284
});
285+
286+
it("should return undefined for getAdminAccount if the account is not a smart account", () => {
287+
const wallet = createInAppWallet({
288+
connectorFactory: mockConnectorFactory,
289+
});
290+
291+
expect(wallet.getAdminAccount?.()).toBeUndefined();
292+
});
293+
294+
it("should return undefined if no account is connected", () => {
295+
const wallet = createInAppWallet({
296+
connectorFactory: mockConnectorFactory,
297+
});
298+
299+
expect(wallet.getAdminAccount?.()).toBeUndefined();
300+
});
301+
302+
it("should return the admin account for a smart account", async () => {
303+
vi.unmock("./index.js");
304+
vi.mocked(getEcosystemInfo).mockResolvedValue({
305+
smartAccountOptions: {
306+
defaultChainId: mockChain.id,
307+
sponsorGas: true,
308+
accountFactoryAddress: DEFAULT_ACCOUNT_FACTORY_V0_6,
309+
},
310+
authOptions: [],
311+
name: "hello world",
312+
slug: "test-ecosystem",
313+
});
314+
315+
const wallet = createInAppWallet({
316+
connectorFactory: mockConnectorFactory,
317+
ecosystem: { id: "ecosystem.test-ecosystem" },
318+
});
319+
320+
const smartAccount = await wallet.connect({
321+
client: mockClient,
322+
strategy: "email",
323+
email: "",
324+
verificationCode: "",
325+
});
326+
327+
const adminAccount = wallet.getAdminAccount?.();
328+
expect(adminAccount).toBeDefined();
329+
expect(adminAccount?.address).not.toBe(smartAccount.address);
330+
});
270331
});

0 commit comments

Comments
 (0)