Skip to content

Commit

Permalink
fix: remove namespace from storage on auto connect failure
Browse files Browse the repository at this point in the history
  • Loading branch information
RyukTheCoder authored and yeager-eren committed Jan 26, 2025
1 parent 327255a commit 6b6504f
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 59 deletions.
93 changes: 61 additions & 32 deletions wallets/react/src/hub/autoConnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@ import {

import { HUB_LAST_CONNECTED_WALLETS } from '../legacy/mod.js';

import { sequentiallyRun } from './helpers.js';
import { runSequentiallyWithoutFailure } from './helpers.js';
import { LastConnectedWalletsFromStorage } from './lastConnectedWallets.js';
import { convertNamespaceNetworkToEvmChainId } from './utils.js';

// Getting connected wallets from storage
const lastConnectedWalletsFromStorage = new LastConnectedWalletsFromStorage(
HUB_LAST_CONNECTED_WALLETS
);

/**
* Run `.connect` action on some selected namespaces (passed as param) for a provider.
*/
Expand Down Expand Up @@ -60,21 +65,60 @@ async function eagerConnect(
targetNamespaces.push([namespaceInput, result]);
});

const finalResult = targetNamespaces.map(([info, namespace]) => {
const evmChain = legacyIsEvmNamespace(info)
? convertNamespaceNetworkToEvmChainId(info, allBlockChains || [])
: undefined;
const chain = evmChain || info.network;

return async () => await namespace.connect(chain);
});
const connectNamespacesPromises = targetNamespaces.map(
([info, namespace]) => {
const evmChain = legacyIsEvmNamespace(info)
? convertNamespaceNetworkToEvmChainId(info, allBlockChains || [])
: undefined;
const chain = evmChain || info.network;

return async () =>
await namespace.connect(chain).catch((e) => {
/*
* Since we check for connect failures using `instanceof Error`
* this check is added here to make sure the thrown error always is an instance of `Error`
*/
if (e instanceof Error) {
throw e;
}
throw new Error(e);
});
}
);

/**
* Sometimes calling methods on a instance in parallel, would cause an error in wallet.
* We are running a method at a time to make sure we are covering this.
* e.g. when we are trying to eagerConnect evm and solana on phantom at the same time, the last namespace throw an error.
*/
return await sequentiallyRun(finalResult);
const connectNamespacesResult = await runSequentiallyWithoutFailure(
connectNamespacesPromises
);

const failedNamespaces: LegacyNamespaceInputForConnect[] = [];
connectNamespacesResult.forEach((result, index) => {
if (result instanceof Error) {
failedNamespaces.push(targetNamespaces[index][0]);
}
});

if (failedNamespaces.length > 0) {
lastConnectedWalletsFromStorage.removeNamespacesFromWallet(
type,
failedNamespaces.map((namespace) => namespace.namespace)
);
}

const atLeastOneNamespaceConnectedSuccessfully =
connectNamespacesResult.length - failedNamespaces.length > 0;
if (!atLeastOneNamespaceConnectedSuccessfully) {
throw new Error(`No namespace connected for ${type}`);
}

const successfulResult = connectNamespacesResult.filter(
(result) => !(result instanceof Error)
);
return successfulResult;
}

/*
Expand All @@ -92,11 +136,6 @@ export async function autoConnect(deps: {
wallets?: (WalletType | LegacyProviderInterface)[];
}): Promise<void> {
const { getHub, allBlockChains, getLegacyProvider, wallets } = deps;

// Getting connected wallets from storage
const lastConnectedWalletsFromStorage = new LastConnectedWalletsFromStorage(
HUB_LAST_CONNECTED_WALLETS
);
const lastConnectedWallets = lastConnectedWalletsFromStorage.list();
const walletIds = Object.keys(lastConnectedWallets);

Expand All @@ -123,7 +162,8 @@ export async function autoConnect(deps: {
legacyInstance = legacyProvider.getInstance();
} catch (e) {
console.warn(
"It seems instance isn't available yet. This can happens when extension not loaded yet (sometimes when opening browser for first time) or extension is disabled."
"It seems instance isn't available yet for auto connect. This can happen when extension not loaded yet (sometimes when opening browser for first time) or extension is disabled. Desired wallet:",
providerName
);
return;
}
Expand Down Expand Up @@ -161,26 +201,15 @@ export async function autoConnect(deps: {
providerName,
}).catch((e) => {
walletsToRemoveFromPersistance.push(providerName);
throw e;
console.warn(e);
})
);
});

await Promise.allSettled(eagerConnectQueue);

/*
*After successfully connecting to at least one wallet,
*we will removing the other wallets from persistence.
*If we are unable to connect to any wallet,
*the persistence will not be removed and the eager connection will be retried with another page load.
*/
const canRestoreAnyConnection =
walletIds.length > walletsToRemoveFromPersistance.length;
await Promise.all(eagerConnectQueue);

if (canRestoreAnyConnection) {
lastConnectedWalletsFromStorage.removeWallets(
walletsToRemoveFromPersistance
);
}
lastConnectedWalletsFromStorage.removeWallets(
walletsToRemoveFromPersistance
);
}
}
12 changes: 9 additions & 3 deletions wallets/react/src/hub/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,20 @@ export function fromAccountIdToLegacyAddressFormat(account: string): string {
/**
* Getting a list of (lazy) promises and run them one after another.
*/
export async function sequentiallyRun<T extends () => Promise<unknown>>(
export async function runSequentiallyWithoutFailure<
T extends () => Promise<unknown>
>(
promises: Array<T>
): Promise<Array<T extends () => Promise<infer R> ? R : never>> {
const result = await promises.reduce(async (prev, task) => {
const previousResults = await prev;
const taskResult = await task();
try {
const taskResult = await task();

return [...previousResults, taskResult];
return [...previousResults, taskResult];
} catch (error) {
return [...previousResults, error];
}
}, Promise.resolve([]) as Promise<any>);
return result;
}
Expand Down
36 changes: 12 additions & 24 deletions wallets/react/src/legacy/autoConnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,33 +46,21 @@ export async function autoConnect(
eagerConnectQueue.map(async ({ eagerConnect }) => eagerConnect())
);

const canRestoreAnyConnection = !!result.find(
({ status }) => status === 'fulfilled'
);

/*
*After successfully connecting to at least one wallet,
*we will removing the other wallets from persistence.
*If we are unable to connect to any wallet,
*the persistence will not be removed and the eager connection will be retried with another page load.
*/
if (canRestoreAnyConnection) {
const walletsToRemoveFromPersistance: WalletType[] = [];
result.forEach((settleResult, index) => {
const { status } = settleResult;

if (status === 'rejected') {
walletsToRemoveFromPersistance.push(
eagerConnectQueue[index].walletType
);
}
});
const walletsToRemoveFromPersistance: WalletType[] = [];
result.forEach((settleResult, index) => {
const { status } = settleResult;

if (walletsToRemoveFromPersistance.length) {
lastConnectedWalletsFromStorage.removeWallets(
walletsToRemoveFromPersistance
if (status === 'rejected') {
walletsToRemoveFromPersistance.push(
eagerConnectQueue[index].walletType
);
}
});

if (walletsToRemoveFromPersistance.length) {
lastConnectedWalletsFromStorage.removeWallets(
walletsToRemoveFromPersistance
);
}
}
}

0 comments on commit 6b6504f

Please sign in to comment.