Skip to content

Commit

Permalink
Handle edge case when wallets aren't present immediately in InjectedW…
Browse files Browse the repository at this point in the history
…indow (#156)
  • Loading branch information
VadimSaveljev authored Aug 30, 2023
1 parent cdaaf2a commit b097e03
Show file tree
Hide file tree
Showing 8 changed files with 51 additions and 17 deletions.
2 changes: 1 addition & 1 deletion examples/react-headless/src/components/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const App = () => {
optionalChainIds: ['polkadot:67f9723393ef76214df0118c34bbbd3d', 'polkadot:7c34d42fc815d392057c78b49f2755c7'],
onSessionDelete: () => {
// do something when session is removed
}
},
};

const walletConnectProvider = new WalletConnectProvider(walletConnectParams, APP_NAME);
Expand Down
2 changes: 1 addition & 1 deletion examples/react-next/components/ConnectContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const ConnectContainer = () => {
optionalChainIds: ['polkadot:67f9723393ef76214df0118c34bbbd3d', 'polkadot:7c34d42fc815d392057c78b49f2755c7'],
onSessionDelete: () => {
// do something when session is removed
}
},
};
let walletConnectProvider = new WalletConnectProvider(walletConnectParams, APP_NAME);
let walletAggregator = new WalletAggregator([injectedWalletProvider, walletConnectProvider]);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export enum WalletType {
}

export interface BaseWalletProvider {
getWallets: () => BaseWallet[];
getWallets: () => Promise<BaseWallet[]>;
}

export interface WalletMetadata {
Expand Down
13 changes: 9 additions & 4 deletions packages/core/src/walletAggregator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import type { BaseWallet, BaseWalletProvider } from './types.js';

export class WalletAggregator {
walletProviders: BaseWalletProvider[];

constructor(providers: BaseWalletProvider[]) {
this.walletProviders = providers;
}
getWallets(): BaseWallet[] {
let wallets: BaseWallet[] = [];
for (let provider of this.walletProviders) {
wallets.push(...provider.getWallets());

async getWallets(): Promise<BaseWallet[]> {
const wallets: BaseWallet[] = [];

for (const provider of this.walletProviders) {
const providedWallets = await provider.getWallets();

wallets.push(...providedWallets);
}
return wallets;
}
Expand Down
33 changes: 30 additions & 3 deletions packages/injected-wallets/src/injectedWallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ const toWalletAccount = (account: InjectedAccount) => {
return account as Account;
};

function isWeb3Injected(injectedWindow: InjectedWindow): boolean {
return Object.values(injectedWindow.injectedWeb3 || {}).filter(({ connect, enable }) => !!(connect || enable)).length !== 0;
}

class InjectedWallet implements BaseWallet {
type = WalletType.INJECTED;
extension: WalletExtension;
Expand Down Expand Up @@ -56,15 +60,35 @@ export class InjectedWalletProvider implements BaseWalletProvider {
config: ExtensionConfiguration;
supportedOnly: boolean;
appName: string;

constructor(config: ExtensionConfiguration, appName: string, supportedOnly: boolean = false) {
this.config = config;
this.supportedOnly = supportedOnly;
this.appName = appName;
}
getExtensions(): { known: WalletExtension[]; other: WalletExtension[] } {

async getExtensions(): Promise<{ known: WalletExtension[]; other: WalletExtension[] }> {
const injectedWindow = window as Window & InjectedWindow;
const knownExtensions: WalletExtension[] = [];
const otherExtensions: WalletExtension[] = [];

if (!isWeb3Injected(injectedWindow)) {
await Promise.any(
[300, 600, 1000].map(
(ms) =>
new Promise((resolve, reject) =>
setTimeout(() => {
if (isWeb3Injected(injectedWindow)) {
resolve('injection complete');
} else {
reject();
}
}, ms),
),
),
).catch(() => {});
}

if (injectedWindow.injectedWeb3) {
Object.keys(injectedWindow.injectedWeb3).forEach((extensionId) => {
if (!this.config.disallowed?.includes(extensionId)) {
Expand All @@ -83,14 +107,17 @@ export class InjectedWalletProvider implements BaseWalletProvider {
return { known: knownExtensions, other: otherExtensions };
}

getWallets(): BaseWallet[] {
async getWallets(): Promise<BaseWallet[]> {
let injectedWallets: InjectedWallet[] = [];
let { known, other } = this.getExtensions();
const { known, other } = await this.getExtensions();
let extensions = [...known];

if (!this.supportedOnly) {
extensions = [...extensions, ...other];
}

injectedWallets = extensions.map((ext) => new InjectedWallet(ext, this.appName));

return injectedWallets;
}
}
6 changes: 4 additions & 2 deletions packages/react/src/PolkadotWalletsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ export const PolkadotWalletsContextProvider = ({
const [wallets, setWallets] = useState<BaseWallet[] | undefined>();

useEffect(() => {
const timeoutId = setTimeout(() => {
setWallets(walletAggregator.getWallets());
const timeoutId = setTimeout(async () => {
const wallets = await walletAggregator.getWallets();
setWallets(wallets);
}, initialWaitMs);

return () => clearTimeout(timeoutId);
}, [walletAggregator]);

Expand Down
4 changes: 2 additions & 2 deletions packages/wallet-connect/src/wallet-connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export class WalletConnectProvider implements BaseWalletProvider {
this.appName = appName;
}

getWallets(): BaseWallet[] {
return [new WalletConnectWallet(this.config, this.appName)];
getWallets(): Promise<BaseWallet[]> {
return new Promise((resolve) => resolve([new WalletConnectWallet(this.config, this.appName)]));
}
}
6 changes: 3 additions & 3 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
"declaration": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"lib": ["dom", "dom.iterable", "ES2020"],
"module": "ES2020",
"lib": ["dom", "dom.iterable", "ES2022"],
"module": "ES2022",
"moduleResolution": "node",
"noImplicitAny": true,
"noUnusedLocals": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"target": "ES2020",
"target": "ES2022",
"types": ["node"]
}
}

0 comments on commit b097e03

Please sign in to comment.