Skip to content

Commit c6c3cd7

Browse files
Default to in-memory storage for inAppWallet outside browser
1 parent 1c31a1e commit c6c3cd7

File tree

5 files changed

+76
-23
lines changed

5 files changed

+76
-23
lines changed

.changeset/thin-rockets-walk.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Default to in-memory storage when creating inapp wallets outside the browser

packages/thirdweb/src/wallets/in-app/web/in-app.ts

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import type { ThirdwebClient } from "../../../client/client.js";
2+
import type { AsyncStorage } from "../../../utils/storage/AsyncStorage.js";
3+
import { inMemoryStorage } from "../../../utils/storage/inMemoryStorage.js";
4+
import { webLocalStorage } from "../../../utils/storage/webStorage.js";
25
import type { Wallet } from "../../interfaces/wallet.js";
36
import { createInAppWallet } from "../core/wallet/in-app-core.js";
47
import type { InAppWalletCreationOptions } from "../core/wallet/types.js";
@@ -23,23 +26,29 @@ import type { InAppWalletCreationOptions } from "../core/wallet/types.js";
2326
* const account = await wallet.connect({
2427
* client,
2528
* chain,
26-
* strategy: "google",
29+
* strategy: "google", // or "apple", "facebook","discord", "github", "twitch", "x", "telegram", "line", "coinbase", etc
2730
* });
2831
* ```
2932
*
3033
* [View all available social auth methods](https://portal.thirdweb.com/connect/wallet/sign-in-methods/configure)
3134
*
3235
* ### Enable smart accounts and sponsor gas for your users:
3336
*
37+
* With the `executionMode` option, you can enable smart accounts and sponsor gas for your users.
38+
*
39+
* **Using EIP-7702** (recommended):
40+
*
41+
* On chains with EIP-7702 enabled, you can upgrade the inapp wallet to a smart account, keeping the same address and performance as the regular EOA.
42+
*
3443
* ```ts
3544
* import { inAppWallet } from "thirdweb/wallets";
3645
* import { sepolia } from "thirdweb/chains";
3746
*
3847
* const wallet = inAppWallet({
39-
* smartAccount: {
40-
* chain: sepolia,
48+
* executionMode: {
49+
* mode: "EIP7702",
4150
* sponsorGas: true,
42-
* },
51+
* },
4352
* });
4453
*
4554
* // account will be a smart account with sponsored gas enabled
@@ -49,8 +58,28 @@ import type { InAppWalletCreationOptions } from "../core/wallet/types.js";
4958
* });
5059
* ```
5160
*
61+
* **Using EIP-4337**:
62+
*
63+
* On chains without EIP-7702 enabled, you can still use smart accounts using EIP-4337, this will return a different address (the smart contract address) than the regular EOA.
64+
*
65+
* ```ts
66+
* import { inAppWallet } from "thirdweb/wallets/in-app";
67+
*
68+
* const wallet = inAppWallet({
69+
* executionMode: {
70+
* mode: "EIP4337",
71+
* smartAccount: {
72+
* chain: sepolia, // chain required for EIP-4337
73+
* sponsorGas: true,
74+
* }
75+
* },
76+
* });
77+
* ```
78+
*
5279
* ### Login with email
5380
*
81+
* To login with email, you can use the `preAuthenticate` function to first send a verification code to the user's email, then login with the verification code.
82+
*
5483
* ```ts
5584
* import { inAppWallet, preAuthenticate } from "thirdweb/wallets/in-app";
5685
*
@@ -73,22 +102,10 @@ import type { InAppWalletCreationOptions } from "../core/wallet/types.js";
73102
* });
74103
* ```
75104
*
76-
* ### Login with SIWE
77-
* ```ts
78-
* import { inAppWallet, createWallet } from "thirdweb/wallets";
105+
* ### Login with phone number
79106
*
80-
* const rabby = createWallet("io.rabby");
81-
* const inAppWallet = inAppWallet();
107+
* Similar to email, you can login with a phone number by first sending a verification code to the user's phone number, then login with the verification code.
82108
*
83-
* const account = await inAppWallet.connect({
84-
* strategy: "wallet",
85-
* chain: mainnet,
86-
* wallet: rabby,
87-
* client: MY_CLIENT
88-
* });
89-
* ```
90-
*
91-
* ### Login with phone number
92109
* ```ts
93110
* import { inAppWallet, preAuthenticate } from "thirdweb/wallets/in-app";
94111
*
@@ -111,8 +128,28 @@ import type { InAppWalletCreationOptions } from "../core/wallet/types.js";
111128
* });
112129
* ```
113130
*
131+
* ### Login with another wallet (SIWE)
132+
*
133+
* You can also login to the in-app wallet with another existing wallet by signing a standard Sign in with Ethereum (SIWE) message.
134+
*
135+
* ```ts
136+
* import { inAppWallet, createWallet } from "thirdweb/wallets";
137+
*
138+
* const rabby = createWallet("io.rabby");
139+
* const inAppWallet = inAppWallet();
140+
*
141+
* const account = await inAppWallet.connect({
142+
* strategy: "wallet",
143+
* chain: mainnet,
144+
* wallet: rabby,
145+
* client: MY_CLIENT
146+
* });
147+
* ```
148+
*
114149
* ### Login with passkey
115150
*
151+
* You can also login with a passkey. This mode requires specifying whether it should create a new passkey, or sign in with an existing passkey. We recommend checking if the user has a passkey stored in their browser to automatically login with it.
152+
*
116153
* ```ts
117154
* import { inAppWallet, hasStoredPasskey } from "thirdweb/wallets/in-app";
118155
*
@@ -128,6 +165,11 @@ import type { InAppWalletCreationOptions } from "../core/wallet/types.js";
128165
* ```
129166
*
130167
* ### Connect to a guest account
168+
*
169+
* You can also connect to a guest account, this will create a new account for the user instantly and store it in the browser's local storage.
170+
*
171+
* You can later "upgrade" this account by linking another auth method, like email or phone for example. This will preserve the account's address and history.
172+
*
131173
* ```ts
132174
* import { inAppWallet } from "thirdweb/wallets";
133175
*
@@ -264,8 +306,16 @@ export function inAppWallet(
264306
return new InAppWebConnector({
265307
client,
266308
passkeyDomain: createOptions?.auth?.passkeyDomain,
267-
storage: createOptions?.storage,
309+
storage: createOptions?.storage ?? getDefaultStorage(),
268310
});
269311
},
270312
}) as Wallet<"inApp">;
271313
}
314+
315+
function getDefaultStorage(): AsyncStorage {
316+
if (typeof window !== "undefined" && window.localStorage) {
317+
return webLocalStorage;
318+
}
319+
// default to in-memory storage if we're not in the browser
320+
return inMemoryStorage;
321+
}

packages/thirdweb/src/wallets/in-app/web/lib/in-app-backend.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { describe, expect, it } from "vitest";
22
import { TEST_CLIENT } from "~test/test-clients.js";
33
import { sepolia } from "../../../../chains/chain-definitions/sepolia.js";
4-
import { inMemoryStorage } from "../../../../utils/storage/inMemoryStorage.js";
54
import { inAppWallet } from "../in-app.js";
65

76
describe("InAppWallet", () => {
@@ -11,7 +10,6 @@ describe("InAppWallet", () => {
1110
chain: sepolia,
1211
sponsorGas: true,
1312
},
14-
storage: inMemoryStorage,
1513
});
1614
const account = await wallet.connect({
1715
client: TEST_CLIENT,

packages/thirdweb/src/wallets/in-app/web/lib/web-connector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export class InAppWebConnector implements InAppConnector {
8686
this.ecosystem = ecosystem;
8787
this.passkeyDomain = passkeyDomain;
8888
this.storage = new ClientScopedStorage({
89-
storage: storage ?? webLocalStorage,
89+
storage,
9090
clientId: client.clientId,
9191
ecosystem: ecosystem,
9292
});

packages/thirdweb/src/wallets/in-app/web/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export type InAppWalletConstructorType = ClientIdConstructorType & {
3333
/**
3434
* The storage to use for storing wallet state
3535
*/
36-
storage?: AsyncStorage;
36+
storage: AsyncStorage;
3737
};
3838

3939
export type ClientIdWithQuerierType = ClientIdConstructorType & {

0 commit comments

Comments
 (0)