Skip to content

Commit f542876

Browse files
feat: metamask sdk connector (#2425)
* fix(wallet): restore metamask connector logic * fix: prefer walletconnect for desktop qr code * fix: metamask sdk options * chore: changeset * fix: explicit metamask provider check
1 parent cbdf578 commit f542876

File tree

2 files changed

+65
-36
lines changed

2 files changed

+65
-36
lines changed

.changeset/two-rats-do.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@rainbow-me/rainbowkit": patch
3+
---
4+
5+
The `metaMaskWallet` wallet connector now utilizes the [MetaMask SDK](https://docs.metamask.io/sdk/) for more reliable, faster connections on mobile

packages/rainbowkit/src/wallets/walletConnectors/metaMaskWallet/metaMaskWallet.ts

Lines changed: 60 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,20 @@
1-
import type { WindowProvider } from '../../../types/utils';
2-
import { isAndroid, isIOS } from '../../../utils/isMobile';
3-
import type { DefaultWalletOptions, Wallet } from '../../Wallet';
4-
import {
5-
getInjectedConnector,
6-
hasInjectedProvider,
7-
} from '../../getInjectedConnector';
1+
import { createConnector } from 'wagmi';
2+
import { metaMask } from 'wagmi/connectors';
3+
import type {
4+
DefaultWalletOptions,
5+
Wallet,
6+
WalletDetailsParams,
7+
} from '../../Wallet';
8+
import { hasInjectedProvider } from '../../getInjectedConnector';
89
import { getWalletConnectConnector } from '../../getWalletConnectConnector';
10+
import { isMobile } from '../../../utils/isMobile';
11+
import type { WindowProvider } from '../../../types/utils';
912

1013
export type MetaMaskWalletOptions = DefaultWalletOptions;
1114

1215
function isMetaMask(ethereum?: WindowProvider['ethereum']): boolean {
13-
// Logic borrowed from wagmi's MetaMaskConnector
14-
// https://github.com/wagmi-dev/references/blob/main/packages/connectors/src/metaMask.ts
16+
// Logic borrowed from wagmi's legacy MetaMaskConnector
17+
// Non-exhaustive list of wallets that try to make themselves look like MetaMask
1518
if (!ethereum?.isMetaMask) return false;
1619
// Brave tries to make itself look like MetaMask
1720
// Could also try RPC `web3_clientVersion` if following is unreliable
@@ -61,22 +64,16 @@ export const metaMaskWallet = ({
6164
projectId,
6265
walletConnectParameters,
6366
}: MetaMaskWalletOptions): Wallet => {
64-
// Not using the explicit isMetaMask fn to check for MetaMask
65-
// so that users can continue to use the MetaMask button
66-
// to interact with wallets compatible with window.ethereum.
67-
// The connector's getProvider will instead favor the real MetaMask
68-
// in window.providers scenarios with multiple wallets injected.
69-
const isMetaMaskInjected = hasInjectedProvider({ flag: 'isMetaMask' });
70-
const shouldUseWalletConnect = !isMetaMaskInjected;
67+
// Custom logic to explicitly detect MetaMask
68+
// Whereas hasInjectedProvider only checks for impersonated `isMetaMask`
69+
// We need this because MetaMask SDK hangs on impersonated wallets
70+
// Previously MetaMask provider would trigger for impersonated wallets
71+
const isMetaMaskInjected =
72+
typeof window !== 'undefined' ? isMetaMask(window.ethereum) : false;
7173

72-
const getUri = (uri: string) => {
73-
return isAndroid()
74-
? uri
75-
: isIOS()
76-
? // currently broken in MetaMask v6.5.0 https://github.com/MetaMask/metamask-mobile/issues/6457
77-
`metamask://wc?uri=${encodeURIComponent(uri)}`
78-
: `https://metamask.app.link/wc?uri=${encodeURIComponent(uri)}`;
79-
};
74+
// TODO: This is a temporary solution to prefer WalletConnect for desktop qr code.
75+
const shouldUseWalletConnect = !isMetaMaskInjected && !isMobile();
76+
const shouldUseMetaMaskConnector = isMetaMaskInjected || isMobile();
8077

8178
return {
8279
id: 'metaMask',
@@ -85,7 +82,7 @@ export const metaMaskWallet = ({
8582
iconUrl: async () => (await import('./metaMaskWallet.svg')).default,
8683
iconAccent: '#f6851a',
8784
iconBackground: '#fff',
88-
installed: !shouldUseWalletConnect ? isMetaMaskInjected : undefined,
85+
installed: isMetaMaskInjected ? isMetaMaskInjected : undefined,
8986
downloadUrls: {
9087
android: 'https://play.google.com/store/apps/details?id=io.metamask',
9188
ios: 'https://apps.apple.com/us/app/metamask/id1438144202',
@@ -98,13 +95,14 @@ export const metaMaskWallet = ({
9895
opera: 'https://addons.opera.com/extensions/details/metamask-10',
9996
browserExtension: 'https://metamask.io/download',
10097
},
101-
10298
mobile: {
103-
getUri: shouldUseWalletConnect ? getUri : undefined,
99+
// MetaMask mobile deep linking handled by wagmi, return URI unchanged.
100+
getUri: shouldUseMetaMaskConnector ? (uri: string) => uri : undefined,
104101
},
105102
qrCode: shouldUseWalletConnect
106103
? {
107-
getUri,
104+
getUri: (uri: string) =>
105+
`https://metamask.app.link/wc?uri=${encodeURIComponent(uri)}`,
108106
instructions: {
109107
learnMoreUrl: 'https://metamask.io/faqs/',
110108
steps: [
@@ -160,13 +158,39 @@ export const metaMaskWallet = ({
160158
projectId,
161159
walletConnectParameters,
162160
})
163-
: getInjectedConnector({
164-
target:
165-
typeof window !== 'undefined'
166-
? (window as WindowProvider).ethereum?.providers?.find(
167-
isMetaMask,
168-
) ?? window.ethereum
169-
: undefined,
170-
}),
161+
: // MetaMask connector
162+
(walletDetails: WalletDetailsParams) => {
163+
return createConnector((config) => {
164+
const metamaskConnector = metaMask({
165+
dappMetadata: {
166+
connector: 'rainbowkit',
167+
name: walletConnectParameters?.metadata?.name,
168+
iconUrl: walletConnectParameters?.metadata?.icons[0],
169+
url: walletConnectParameters?.metadata?.url,
170+
},
171+
headless: true,
172+
checkInstallationImmediately: false,
173+
enableAnalytics: false,
174+
})(config);
175+
176+
/**
177+
* Override getChainId to avoid metamask error
178+
*
179+
* @see https://github.com/rainbow-me/rainbowkit/blob/cdcaa25d66b522119852502f71c8efc02b1abdd9/packages/rainbowkit/src/wallets/useWalletConnectors.ts#L57
180+
* And @see https://github.com/wevm/wagmi/blob/275cccb51437908a2d7d3dab0549c6050b6340d3/packages/connectors/src/metaMask.ts#L154
181+
*/
182+
return {
183+
...metamaskConnector,
184+
...walletDetails,
185+
getChainId: async () => {
186+
try {
187+
return await metamaskConnector.getChainId();
188+
} catch {
189+
return config.chains[0]?.id ?? 1;
190+
}
191+
},
192+
};
193+
});
194+
},
171195
};
172196
};

0 commit comments

Comments
 (0)