thirdweb 5.80.1-nightly-a3f59e50e249d8b4fac765e025fc2cd102093e9c-20250105000328 → 5.81.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/cjs/contract/actions/compiler-metadata.js.map +1 -1
  2. package/dist/cjs/react/core/hooks/wallets/useAutoConnect.js +28 -9
  3. package/dist/cjs/react/core/hooks/wallets/useAutoConnect.js.map +1 -1
  4. package/dist/cjs/version.js +1 -1
  5. package/dist/cjs/version.js.map +1 -1
  6. package/dist/cjs/wallets/in-app/core/wallet/in-app-core.js +9 -3
  7. package/dist/cjs/wallets/in-app/core/wallet/in-app-core.js.map +1 -1
  8. package/dist/cjs/wallets/in-app/core/wallet/index.js +8 -10
  9. package/dist/cjs/wallets/in-app/core/wallet/index.js.map +1 -1
  10. package/dist/cjs/wallets/injected/index.js +2 -1
  11. package/dist/cjs/wallets/injected/index.js.map +1 -1
  12. package/dist/cjs/wallets/smart/index.js +14 -13
  13. package/dist/cjs/wallets/smart/index.js.map +1 -1
  14. package/dist/cjs/wallets/smart/smart-wallet.js +12 -10
  15. package/dist/cjs/wallets/smart/smart-wallet.js.map +1 -1
  16. package/dist/esm/contract/actions/compiler-metadata.js.map +1 -1
  17. package/dist/esm/react/core/hooks/wallets/useAutoConnect.js +27 -9
  18. package/dist/esm/react/core/hooks/wallets/useAutoConnect.js.map +1 -1
  19. package/dist/esm/version.js +1 -1
  20. package/dist/esm/version.js.map +1 -1
  21. package/dist/esm/wallets/in-app/core/wallet/in-app-core.js +9 -3
  22. package/dist/esm/wallets/in-app/core/wallet/in-app-core.js.map +1 -1
  23. package/dist/esm/wallets/in-app/core/wallet/index.js +8 -10
  24. package/dist/esm/wallets/in-app/core/wallet/index.js.map +1 -1
  25. package/dist/esm/wallets/injected/index.js +2 -1
  26. package/dist/esm/wallets/injected/index.js.map +1 -1
  27. package/dist/esm/wallets/smart/index.js +12 -11
  28. package/dist/esm/wallets/smart/index.js.map +1 -1
  29. package/dist/esm/wallets/smart/smart-wallet.js +12 -10
  30. package/dist/esm/wallets/smart/smart-wallet.js.map +1 -1
  31. package/dist/types/contract/actions/compiler-metadata.d.ts +9 -0
  32. package/dist/types/contract/actions/compiler-metadata.d.ts.map +1 -1
  33. package/dist/types/react/core/hooks/connection/types.d.ts +4 -0
  34. package/dist/types/react/core/hooks/connection/types.d.ts.map +1 -1
  35. package/dist/types/react/core/hooks/wallets/useAutoConnect.d.ts +12 -0
  36. package/dist/types/react/core/hooks/wallets/useAutoConnect.d.ts.map +1 -1
  37. package/dist/types/version.d.ts +1 -1
  38. package/dist/types/version.d.ts.map +1 -1
  39. package/dist/types/wallets/in-app/core/wallet/in-app-core.d.ts.map +1 -1
  40. package/dist/types/wallets/in-app/core/wallet/index.d.ts +10 -2
  41. package/dist/types/wallets/in-app/core/wallet/index.d.ts.map +1 -1
  42. package/dist/types/wallets/injected/index.d.ts.map +1 -1
  43. package/dist/types/wallets/smart/index.d.ts +2 -2
  44. package/dist/types/wallets/smart/index.d.ts.map +1 -1
  45. package/package.json +1 -1
  46. package/src/adapters/eip1193/from-eip1193.test.ts +18 -0
  47. package/src/contract/actions/compiler-metadata.ts +5 -0
  48. package/src/react/core/hooks/connection/types.ts +5 -0
  49. package/src/react/core/hooks/wallets/useAutoConnect.ts +41 -12
  50. package/src/react/core/hooks/wallets/useAutoConnectCore.test.tsx +187 -0
  51. package/src/version.ts +1 -1
  52. package/src/wallets/in-app/core/wallet/in-app-core.test.ts +115 -54
  53. package/src/wallets/in-app/core/wallet/in-app-core.ts +22 -11
  54. package/src/wallets/in-app/core/wallet/index.ts +10 -13
  55. package/src/wallets/in-app/web/lib/get-url-token.test.tsx +92 -0
  56. package/src/wallets/injected/index.ts +2 -1
  57. package/src/wallets/smart/index.ts +14 -18
  58. package/src/wallets/smart/smart-wallet.ts +13 -13
  59. package/src/wallets/smart/smart.test.ts +19 -39
@@ -48,6 +48,7 @@ export function createInAppWallet(args: {
48
48
  const emitter = createWalletEmitter<"inApp">();
49
49
  let createOptions = _createOptions;
50
50
  let account: Account | undefined = undefined;
51
+ let adminAccount: Account | undefined = undefined; // Admin account if smartAccountOptions were provided with connection
51
52
  let chain: Chain | undefined = undefined;
52
53
  let client: ThirdwebClient | undefined;
53
54
 
@@ -98,15 +99,16 @@ export function createInAppWallet(args: {
98
99
  }
99
100
  }
100
101
 
101
- const [connectedAccount, connectedChain] = await autoConnectInAppWallet(
102
- options,
103
- createOptions,
104
- connector,
105
- );
102
+ const {
103
+ account: connectedAccount,
104
+ chain: connectedChain,
105
+ adminAccount: _adminAccount,
106
+ } = await autoConnectInAppWallet(options, createOptions, connector);
106
107
 
107
108
  // set the states
108
109
  client = options.client;
109
110
  account = connectedAccount;
111
+ adminAccount = _adminAccount;
110
112
  chain = connectedChain;
111
113
  trackConnect({
112
114
  client: options.client,
@@ -151,14 +153,16 @@ export function createInAppWallet(args: {
151
153
  }
152
154
  }
153
155
 
154
- const [connectedAccount, connectedChain] = await connectInAppWallet(
155
- options,
156
- createOptions,
157
- connector,
158
- );
156
+ const {
157
+ account: connectedAccount,
158
+ chain: connectedChain,
159
+ adminAccount: _adminAccount,
160
+ } = await connectInAppWallet(options, createOptions, connector);
161
+
159
162
  // set the states
160
163
  client = options.client;
161
164
  account = connectedAccount;
165
+ adminAccount = _adminAccount;
162
166
  chain = connectedChain;
163
167
  trackConnect({
164
168
  client: options.client,
@@ -184,6 +188,7 @@ export function createInAppWallet(args: {
184
188
  }
185
189
  }
186
190
  account = undefined;
191
+ adminAccount = undefined;
187
192
  chain = undefined;
188
193
  emitter.emit("disconnect", undefined);
189
194
  },
@@ -212,7 +217,11 @@ export function createInAppWallet(args: {
212
217
  }
213
218
  }
214
219
 
215
- const [connectedAccount, connectedChain] = await autoConnectInAppWallet(
220
+ const {
221
+ account: connectedAccount,
222
+ chain: connectedChain,
223
+ adminAccount: _adminAccount,
224
+ } = await autoConnectInAppWallet(
216
225
  {
217
226
  chain: newChain,
218
227
  client,
@@ -220,6 +229,7 @@ export function createInAppWallet(args: {
220
229
  createOptions,
221
230
  connector,
222
231
  );
232
+ adminAccount = _adminAccount;
223
233
  account = connectedAccount;
224
234
  chain = connectedChain;
225
235
  } else {
@@ -228,5 +238,6 @@ export function createInAppWallet(args: {
228
238
  }
229
239
  emitter.emit("chainChanged", newChain);
230
240
  },
241
+ getAdminAccount: () => adminAccount,
231
242
  };
232
243
  }
@@ -37,7 +37,7 @@ export async function connectInAppWallet(
37
37
  | CreateWalletArgs<"inApp">[1]
38
38
  | CreateWalletArgs<EcosystemWalletId>[1],
39
39
  connector: InAppConnector,
40
- ): Promise<[Account, Chain]> {
40
+ ): Promise<{ account: Account; chain: Chain; adminAccount?: Account }> {
41
41
  if (
42
42
  // if auth mode is not specified, the default is popup
43
43
  createOptions?.auth?.mode !== "popup" &&
@@ -65,15 +65,16 @@ export async function connectInAppWallet(
65
65
  "smartAccount" in createOptions &&
66
66
  createOptions?.smartAccount
67
67
  ) {
68
- return convertToSmartAccount({
68
+ const [account, chain] = await convertToSmartAccount({
69
69
  client: options.client,
70
70
  authAccount,
71
71
  smartAccountOptions: createOptions.smartAccount,
72
72
  chain: options.chain,
73
73
  });
74
+ return { account, chain, adminAccount: authAccount };
74
75
  }
75
76
 
76
- return [authAccount, options.chain || ethereum] as const;
77
+ return { account: authAccount, chain: options.chain || ethereum } as const;
77
78
  }
78
79
 
79
80
  /**
@@ -87,7 +88,7 @@ export async function autoConnectInAppWallet(
87
88
  | CreateWalletArgs<"inApp">[1]
88
89
  | CreateWalletArgs<EcosystemWalletId>[1],
89
90
  connector: InAppConnector,
90
- ): Promise<[Account, Chain]> {
91
+ ): Promise<{ account: Account; chain: Chain; adminAccount?: Account }> {
91
92
  if (options.authResult && connector.loginWithAuthToken) {
92
93
  await connector.loginWithAuthToken(options.authResult);
93
94
  }
@@ -104,15 +105,16 @@ export async function autoConnectInAppWallet(
104
105
  "smartAccount" in createOptions &&
105
106
  createOptions?.smartAccount
106
107
  ) {
107
- return convertToSmartAccount({
108
+ const [account, chain] = await convertToSmartAccount({
108
109
  client: options.client,
109
110
  authAccount,
110
111
  smartAccountOptions: createOptions.smartAccount,
111
112
  chain: options.chain,
112
113
  });
114
+ return { account, chain, adminAccount: authAccount };
113
115
  }
114
116
 
115
- return [authAccount, options.chain || ethereum] as const;
117
+ return { account: authAccount, chain: options.chain || ethereum } as const;
116
118
  }
117
119
 
118
120
  async function convertToSmartAccount(options: {
@@ -121,14 +123,9 @@ async function convertToSmartAccount(options: {
121
123
  smartAccountOptions: CreateWalletArgs<"smart">[1];
122
124
  chain?: Chain;
123
125
  }) {
124
- const [{ smartWallet }, { connectSmartWallet }] = await Promise.all([
125
- import("../../../smart/smart-wallet.js"),
126
- import("../../../smart/index.js"),
127
- ]);
126
+ const { connectSmartAccount } = await import("../../../smart/index.js");
128
127
 
129
- const sa = smartWallet(options.smartAccountOptions);
130
- return connectSmartWallet(
131
- sa,
128
+ return connectSmartAccount(
132
129
  {
133
130
  client: options.client,
134
131
  personalAccount: options.authAccount,
@@ -0,0 +1,92 @@
1
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
2
+ import { getUrlToken } from "./get-url-token.js";
3
+
4
+ describe("getUrlToken", () => {
5
+ let originalLocation: Location;
6
+
7
+ beforeEach(() => {
8
+ originalLocation = window.location;
9
+
10
+ Object.defineProperty(window, "location", {
11
+ value: {
12
+ ...originalLocation,
13
+ search: "",
14
+ },
15
+ writable: true,
16
+ });
17
+ });
18
+
19
+ afterEach(() => {
20
+ // Restore the original location object after each test
21
+ Object.defineProperty(window, "location", {
22
+ value: originalLocation,
23
+ writable: true,
24
+ });
25
+ });
26
+
27
+ it("should return an empty object if not in web context", () => {
28
+ const originalWindow = window;
29
+ // biome-ignore lint/suspicious/noExplicitAny: Test
30
+ (global as any).window = undefined;
31
+
32
+ const result = getUrlToken();
33
+ // biome-ignore lint/suspicious/noExplicitAny: Test
34
+ (global as any).window = originalWindow;
35
+
36
+ expect(result).toEqual({});
37
+ });
38
+
39
+ it("should return an empty object if no parameters are present", () => {
40
+ const result = getUrlToken();
41
+ expect(result).toEqual({});
42
+ });
43
+
44
+ it("should parse walletId and authResult correctly", () => {
45
+ window.location.search =
46
+ "?walletId=123&authResult=%7B%22token%22%3A%22abc%22%7D";
47
+
48
+ const result = getUrlToken();
49
+
50
+ expect(result).toEqual({
51
+ walletId: "123",
52
+ authResult: { token: "abc" },
53
+ authProvider: null,
54
+ authCookie: null,
55
+ });
56
+ });
57
+
58
+ it("should handle authCookie and update URL correctly", () => {
59
+ window.location.search = "?walletId=123&authCookie=myCookie";
60
+
61
+ const result = getUrlToken();
62
+
63
+ expect(result).toEqual({
64
+ walletId: "123",
65
+ authResult: undefined,
66
+ authProvider: null,
67
+ authCookie: "myCookie",
68
+ });
69
+
70
+ // Check if URL has been updated correctly
71
+ expect(window.location.search).toBe("?walletId=123&authCookie=myCookie");
72
+ });
73
+
74
+ it("should handle all parameters correctly", () => {
75
+ window.location.search =
76
+ "?walletId=123&authResult=%7B%22token%22%3A%22xyz%22%7D&authProvider=provider1&authCookie=myCookie";
77
+
78
+ const result = getUrlToken();
79
+
80
+ expect(result).toEqual({
81
+ walletId: "123",
82
+ authResult: { token: "xyz" },
83
+ authProvider: "provider1",
84
+ authCookie: "myCookie",
85
+ });
86
+
87
+ // Check if URL has been updated correctly
88
+ expect(window.location.search).toBe(
89
+ "?walletId=123&authResult=%7B%22token%22%3A%22xyz%22%7D&authProvider=provider1&authCookie=myCookie",
90
+ );
91
+ });
92
+ });
@@ -85,7 +85,8 @@ export async function connectEip1193Wallet({
85
85
  chain && chain.id === chainId ? chain : getCachedChain(chainId);
86
86
 
87
87
  // if we want a specific chainId and it is not the same as the provider chainId, trigger switchChain
88
- if (chain && chain.id !== chainId) {
88
+ // we check for undefined chain ID since some chain-specific wallets like Abstract will not send a chain ID on connection
89
+ if (chain && typeof chain.id !== "undefined" && chain.id !== chainId) {
89
90
  await switchChain(provider, chain);
90
91
  connectedChain = chain;
91
92
  }
@@ -69,28 +69,26 @@ export function isSmartWallet(
69
69
  }
70
70
 
71
71
  /**
72
- * We can get the personal account for given smart account but not the other way around - this map gives us the reverse lookup
72
+ * 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.
73
+ * 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.
73
74
  * @internal
74
75
  */
75
- const personalAccountToSmartAccountMap = new WeakMap<
76
- Account,
77
- Wallet<"smart">
78
- >();
79
-
80
- const smartWalletToPersonalAccountMap = new WeakMap<Wallet<"smart">, Account>();
76
+ const adminAccountToSmartAccountMap = new WeakMap<Account, Account>();
77
+ const smartAccountToAdminAccountMap = new WeakMap<Account, Account>();
81
78
 
82
79
  /**
83
80
  * @internal
84
81
  */
85
- export async function connectSmartWallet(
86
- wallet: Wallet<"smart">,
82
+ export async function connectSmartAccount(
87
83
  connectionOptions: SmartWalletConnectionOptions,
88
84
  creationOptions: SmartWalletOptions,
89
85
  ): Promise<[Account, Chain]> {
90
86
  const { personalAccount, client, chain: connectChain } = connectionOptions;
91
87
 
92
88
  if (!personalAccount) {
93
- throw new Error("Personal wallet does not have an account");
89
+ throw new Error(
90
+ "No personal account provided for smart account connection",
91
+ );
94
92
  }
95
93
 
96
94
  const options = creationOptions;
@@ -177,8 +175,8 @@ export async function connectSmartWallet(
177
175
  client,
178
176
  });
179
177
 
180
- personalAccountToSmartAccountMap.set(personalAccount, wallet);
181
- smartWalletToPersonalAccountMap.set(wallet, personalAccount);
178
+ adminAccountToSmartAccountMap.set(personalAccount, account);
179
+ smartAccountToAdminAccountMap.set(account, personalAccount);
182
180
 
183
181
  return [account, chain] as const;
184
182
  }
@@ -186,15 +184,13 @@ export async function connectSmartWallet(
186
184
  /**
187
185
  * @internal
188
186
  */
189
- export async function disconnectSmartWallet(
190
- wallet: Wallet<"smart">,
191
- ): Promise<void> {
187
+ export async function disconnectSmartAccount(account: Account): Promise<void> {
192
188
  // look up the personalAccount for the smart wallet
193
- const personalAccount = smartWalletToPersonalAccountMap.get(wallet);
189
+ const personalAccount = smartAccountToAdminAccountMap.get(account);
194
190
  if (personalAccount) {
195
191
  // remove the mappings
196
- personalAccountToSmartAccountMap.delete(personalAccount);
197
- smartWalletToPersonalAccountMap.delete(wallet);
192
+ adminAccountToSmartAccountMap.delete(personalAccount);
193
+ smartAccountToAdminAccountMap.delete(account);
198
194
  }
199
195
  }
200
196
 
@@ -137,7 +137,7 @@ export function smartWallet(
137
137
  let chain: Chain | undefined = undefined;
138
138
  let lastConnectOptions: WalletConnectionOption<"smart"> | undefined;
139
139
 
140
- const _smartWallet: Wallet<"smart"> = {
140
+ return {
141
141
  id: "smart",
142
142
  subscribe: emitter.subscribe,
143
143
  getChain() {
@@ -152,9 +152,10 @@ export function smartWallet(
152
152
  getAccount: () => account,
153
153
  getAdminAccount: () => adminAccount,
154
154
  autoConnect: async (options) => {
155
- const { connectSmartWallet } = await import("./index.js");
155
+ const { connectSmartAccount: connectSmartWallet } = await import(
156
+ "./index.js"
157
+ );
156
158
  const [connectedAccount, connectedChain] = await connectSmartWallet(
157
- _smartWallet,
158
159
  options,
159
160
  createOptions,
160
161
  );
@@ -172,9 +173,8 @@ export function smartWallet(
172
173
  return account;
173
174
  },
174
175
  connect: async (options) => {
175
- const { connectSmartWallet } = await import("./index.js");
176
- const [connectedAccount, connectedChain] = await connectSmartWallet(
177
- _smartWallet,
176
+ const { connectSmartAccount } = await import("./index.js");
177
+ const [connectedAccount, connectedChain] = await connectSmartAccount(
178
178
  options,
179
179
  createOptions,
180
180
  );
@@ -194,10 +194,13 @@ export function smartWallet(
194
194
  return account;
195
195
  },
196
196
  disconnect: async () => {
197
+ if (account) {
198
+ const { disconnectSmartAccount } = await import("./index.js");
199
+ await disconnectSmartAccount(account);
200
+ }
197
201
  account = undefined;
202
+ adminAccount = undefined;
198
203
  chain = undefined;
199
- const { disconnectSmartWallet } = await import("./index.js");
200
- await disconnectSmartWallet(_smartWallet);
201
204
  emitter.emit("disconnect", undefined);
202
205
  },
203
206
  switchChain: async (newChain: Chain) => {
@@ -223,9 +226,8 @@ export function smartWallet(
223
226
  );
224
227
  }
225
228
  }
226
- const { connectSmartWallet } = await import("./index.js");
227
- const [connectedAccount, connectedChain] = await connectSmartWallet(
228
- _smartWallet,
229
+ const { connectSmartAccount } = await import("./index.js");
230
+ const [connectedAccount, connectedChain] = await connectSmartAccount(
229
231
  { ...lastConnectOptions, chain: newChain },
230
232
  createOptions,
231
233
  );
@@ -235,6 +237,4 @@ export function smartWallet(
235
237
  emitter.emit("chainChanged", newChain);
236
238
  },
237
239
  };
238
-
239
- return _smartWallet;
240
240
  }
@@ -2,7 +2,6 @@ import { describe, expect, it } from "vitest";
2
2
  import { TEST_CLIENT } from "../../../test/src/test-clients.js";
3
3
  import { defineChain } from "../../chains/utils.js";
4
4
  import { generateAccount } from "../utils/generateAccount.js";
5
- import { connectSmartWallet, disconnectSmartWallet } from "./index.js";
6
5
  import { smartWallet } from "./smart-wallet.js";
7
6
 
8
7
  describe.runIf(process.env.TW_SECRET_KEY)("Smart Wallet Index", () => {
@@ -17,67 +16,48 @@ describe.runIf(process.env.TW_SECRET_KEY)("Smart Wallet Index", () => {
17
16
  gasless: true,
18
17
  });
19
18
 
20
- const [account, connectedChain] = await connectSmartWallet(
21
- wallet,
22
- {
23
- client,
24
- personalAccount,
25
- },
26
- {
27
- chain,
28
- gasless: true,
29
- },
30
- );
19
+ await wallet.connect({
20
+ client,
21
+ personalAccount,
22
+ });
31
23
 
32
- expect(account.address).toBeDefined();
33
- expect(account.address).toMatch(/^0x[a-fA-F0-9]{40}$/);
34
- expect(connectedChain.id).toBe(chain.id);
24
+ expect(wallet.getAccount()?.address).toBeDefined();
25
+ expect(wallet.getAccount()?.address).toMatch(/^0x[a-fA-F0-9]{40}$/);
26
+ expect(wallet.getChain()?.id).toBe(chain.id);
35
27
  });
36
28
  });
37
29
 
38
30
  describe("disconnectSmartWallet", () => {
39
31
  it("should disconnect a smart wallet", async () => {
40
32
  const personalAccount = await generateAccount({ client });
33
+
41
34
  const wallet = smartWallet({
42
35
  chain,
43
36
  gasless: true,
44
37
  });
45
38
 
46
- await connectSmartWallet(
47
- wallet,
48
- {
49
- client,
50
- personalAccount,
51
- },
52
- {
53
- chain,
54
- gasless: true,
55
- },
56
- );
39
+ await wallet.connect({
40
+ client,
41
+ personalAccount,
42
+ });
57
43
 
58
- await expect(disconnectSmartWallet(wallet)).resolves.not.toThrow();
44
+ await expect(wallet.disconnect()).resolves.not.toThrow();
59
45
  });
60
46
 
61
47
  it("should clear wallet mappings on disconnect", async () => {
62
48
  const personalAccount = await generateAccount({ client });
49
+
63
50
  const wallet = smartWallet({
64
51
  chain,
65
52
  gasless: true,
66
53
  });
67
54
 
68
- await connectSmartWallet(
69
- wallet,
70
- {
71
- client,
72
- personalAccount,
73
- },
74
- {
75
- chain,
76
- gasless: true,
77
- },
78
- );
55
+ await wallet.connect({
56
+ client,
57
+ personalAccount,
58
+ });
79
59
 
80
- await disconnectSmartWallet(wallet);
60
+ await wallet.disconnect();
81
61
 
82
62
  // Verify wallet state is cleared
83
63
  expect(wallet.getAccount()).toBeUndefined();