Skip to content

Commit 520ce54

Browse files
committed
fix(native): fallback to recreate device share if private key recovery fails
1 parent 6a4b776 commit 520ce54

File tree

3 files changed

+41
-5
lines changed

3 files changed

+41
-5
lines changed

packages/thirdweb/src/wallets/in-app/native/helpers/auth/middleware.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ export async function postAuth({
8181
return storedToken;
8282
}
8383

84-
async function getRecoveryCode(args: {
84+
export async function getRecoveryCode(args: {
8585
storedToken: AuthStoredTokenWithCookieReturnType["storedToken"];
8686
client: ThirdwebClient;
8787
storage: ClientScopedStorage;

packages/thirdweb/src/wallets/in-app/native/helpers/wallet/retrieval.ts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ import {
77
import type { Account } from "../../../../interfaces/wallet.js";
88
import { privateKeyToAccount } from "../../../../private-key.js";
99
import type { ClientScopedStorage } from "../../../core/authentication/client-scoped-storage.js";
10-
import type { SetUpWalletRpcReturnType } from "../../../core/authentication/types.js";
10+
import type {
11+
AuthStoredTokenWithCookieReturnType,
12+
SetUpWalletRpcReturnType,
13+
} from "../../../core/authentication/types.js";
1114
import { getUserShares } from "../api/fetchers.js";
15+
import { getRecoveryCode } from "../auth/middleware.js";
1216
import {
1317
DEVICE_SHARE_MISSING_MESSAGE,
1418
ROUTE_GET_USER_SHARES,
@@ -24,8 +28,9 @@ import { decryptShareWeb } from "./encryption.js";
2428
export async function getExistingUserAccount(args: {
2529
client: ThirdwebClient;
2630
storage: ClientScopedStorage;
31+
storedToken?: AuthStoredTokenWithCookieReturnType["storedToken"];
2732
}) {
28-
const { client, storage } = args;
33+
const { client, storage, storedToken } = args;
2934
const { authShare, deviceShare } = await getShares({
3035
client,
3136
authShare: { toRetrieve: true },
@@ -36,6 +41,8 @@ export async function getExistingUserAccount(args: {
3641
return getAccountFromShares({
3742
client,
3843
shares: [authShare, deviceShare],
44+
storage,
45+
storedToken,
3946
});
4047
}
4148

@@ -56,11 +63,34 @@ async function getWalletPrivateKeyFromShares(shares: string[]) {
5663
async function getAccountFromShares(args: {
5764
client: ThirdwebClient;
5865
shares: string[];
66+
storage: ClientScopedStorage;
67+
storedToken?: AuthStoredTokenWithCookieReturnType["storedToken"];
5968
}): Promise<Account> {
60-
const { client, shares } = args;
69+
const { client, shares, storage, storedToken } = args;
70+
const privateKey = await (async () => {
71+
try {
72+
return await getWalletPrivateKeyFromShares(shares);
73+
} catch (e) {
74+
// If the private key reconstruction fails, try to reset the device share
75+
if (storedToken) {
76+
await setUpShareForNewDevice({
77+
client,
78+
recoveryCode: await getRecoveryCode({
79+
storedToken,
80+
client,
81+
storage,
82+
}),
83+
storage,
84+
});
85+
return await getWalletPrivateKeyFromShares(shares);
86+
}
87+
throw e;
88+
}
89+
})();
90+
6191
return privateKeyToAccount({
6292
client,
63-
privateKey: await getWalletPrivateKeyFromShares(shares),
93+
privateKey,
6494
});
6595
}
6696

@@ -179,6 +209,7 @@ async function getShares<
179209
async function getAccountAddressFromShares(args: {
180210
client: ThirdwebClient;
181211
shares: string[];
212+
storage: ClientScopedStorage;
182213
}) {
183214
const wallet = await getAccountFromShares(args);
184215
return wallet.address;
@@ -205,6 +236,7 @@ export async function setUpShareForNewDevice({
205236
const walletAddress = await getAccountAddressFromShares({
206237
client,
207238
shares: [recoveryShare, authShare],
239+
storage,
208240
});
209241

210242
const maybeDeviceShare = await storeShares({

packages/thirdweb/src/wallets/in-app/native/helpers/wallet/sharded-wallet.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import type { Account } from "../../../../interfaces/wallet.js";
33
import type { ClientScopedStorage } from "../../../core/authentication/client-scoped-storage.js";
44
import type {
55
AuthResultAndRecoveryCode,
6+
AuthStoredTokenWithCookieReturnType,
67
GetUser,
78
} from "../../../core/authentication/types.js";
89
import type { IWebWallet } from "../../../core/wallet/web-wallet.js";
@@ -14,6 +15,7 @@ import { getExistingUserAccount } from "./retrieval.js";
1415
export class ShardedWallet implements IWebWallet {
1516
private client: ThirdwebClient;
1617
private storage: ClientScopedStorage;
18+
private storedToken?: AuthStoredTokenWithCookieReturnType["storedToken"];
1719

1820
constructor(args: {
1921
client: ThirdwebClient;
@@ -24,6 +26,7 @@ export class ShardedWallet implements IWebWallet {
2426
}
2527

2628
async postWalletSetUp(authResult: AuthResultAndRecoveryCode): Promise<void> {
29+
this.storedToken = authResult.storedToken;
2730
await postAuth({
2831
storedToken: authResult.storedToken,
2932
client: this.client,
@@ -67,6 +70,7 @@ export class ShardedWallet implements IWebWallet {
6770
return getExistingUserAccount({
6871
client: this.client,
6972
storage: this.storage,
73+
storedToken: this.storedToken,
7074
});
7175
}
7276
}

0 commit comments

Comments
 (0)