Skip to content

Commit

Permalink
chore: type cast window ethereum provider
Browse files Browse the repository at this point in the history
  • Loading branch information
magiziz committed May 7, 2024
1 parent 971635f commit 5577f01
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 62 deletions.
2 changes: 0 additions & 2 deletions packages/create-rainbowkit/templates/next-app/pages/_app.tsx
Expand Up @@ -18,7 +18,6 @@ const config = getDefaultConfig({
appName: 'RainbowKit App',
projectId: 'YOUR_PROJECT_ID',
chains: [
// @ts-ignore - TODO: Fix this typing issue
mainnet,
polygon,
optimism,
Expand All @@ -33,7 +32,6 @@ const client = new QueryClient();

function MyApp({ Component, pageProps }: AppProps) {
return (
// @ts-ignore - TODO: Fix this typing issue
<WagmiProvider config={config}>
<QueryClientProvider client={client}>
<RainbowKitProvider>
Expand Down
2 changes: 0 additions & 2 deletions packages/example/pages/_app.tsx
Expand Up @@ -148,7 +148,6 @@ const config = getDefaultConfig({
appName: 'RainbowKit Demo',
projectId,
chains: [
// @ts-ignore - TODO: Fix this typing issue
mainnet,
polygon,
optimism,
Expand Down Expand Up @@ -730,7 +729,6 @@ export default function App(
</Head>

<SessionProvider refetchInterval={0} session={appProps.pageProps.session}>
{/* @ts-ignore - TODO: Fix this typing issue */}
<WagmiProvider config={config}>
<QueryClientProvider client={queryClient}>
<RainbowKitApp {...appProps} />
Expand Down
89 changes: 89 additions & 0 deletions packages/rainbowkit/src/types/utils.ts
@@ -0,0 +1,89 @@
import { type EIP1193Provider } from 'viem';

/** Combines members of an intersection into a readable type. */
export type Evaluate<type> = { [key in keyof type]: type[key] } & unknown;

/** Removes `readonly` from all properties of an object. */
export type Mutable<type extends object> = {
-readonly [key in keyof type]: type[key];
};

/** Strict version of built-in Omit type */
export type Omit<type, keys extends keyof type> = Pick<
type,
Exclude<keyof type, keys>
>;

// window.ethereum types

export type WalletProviderFlags =
| 'isApexWallet'
| 'isAvalanche'
| 'isBackpack'
| 'isBifrost'
| 'isBitKeep'
| 'isBitski'
| 'isBlockWallet'
| 'isBraveWallet'
| 'isCoinbaseWallet'
| 'isDawn'
| 'isEnkrypt'
| 'isExodus'
| 'isFrame'
| 'isFrontier'
| 'isGamestop'
| 'isHyperPay'
| 'isImToken'
| 'isKuCoinWallet'
| 'isMathWallet'
| 'isMetaMask'
| 'isOkxWallet'
| 'isOKExWallet'
| 'isOneInchAndroidWallet'
| 'isOneInchIOSWallet'
| 'isOpera'
| 'isPhantom'
| 'isPortal'
| 'isRabby'
| 'isRainbow'
| 'isStatus'
| 'isTally'
| 'isTokenPocket'
| 'isTokenary'
| 'isTrust'
| 'isTrustWallet'
| 'isXDEFI'
| 'isZerion'
| 'isTalisman'
| 'isZeal'
| 'isCoin98'
| 'isMEWwallet'
| 'isSafeheron'
| 'isSafePal';

export type WalletProvider = Evaluate<
EIP1193Provider & {
[key in WalletProviderFlags]?: true | undefined;
} & {
providers?: any[] | undefined;
/** Only exists in MetaMask as of 2022/04/03 */
_events?: { connect?: (() => void) | undefined } | undefined;
/** Only exists in MetaMask as of 2022/04/03 */
_state?:
| {
accounts?: string[];
initialized?: boolean;
isConnected?: boolean;
isPermanentlyDisconnected?: boolean;
isUnlocked?: boolean;
}
| undefined;
}
>;

export type WindowProvider = {
coinbaseWalletExtension?: WalletProvider | undefined;
ethereum?: WalletProvider | undefined;
phantom?: { ethereum: WalletProvider } | undefined;
providers?: any[] | undefined; // Adjust the type as needed
};
33 changes: 17 additions & 16 deletions packages/rainbowkit/src/wallets/getInjectedConnector.ts
@@ -1,21 +1,21 @@
import { createConnector } from 'wagmi';
import { injected } from 'wagmi/connectors';
import { WalletProviderFlags, WindowProvider } from '../types/utils';
import { CreateConnector, WalletDetailsParams } from './Wallet';

/*
* Returns the explicit window provider that matches the flag and the flag is true
*/
function getExplicitInjectedProvider(flag: string) {
if (typeof window === 'undefined' || typeof window.ethereum === 'undefined')
function getExplicitInjectedProvider(flag: WalletProviderFlags) {
const _window =
typeof window !== 'undefined' ? (window as WindowProvider) : undefined;
if (typeof _window === 'undefined' || typeof _window.ethereum === 'undefined')
return;
// @ts-ignore - viem/window clash
const providers = window.ethereum.providers;
const providers = _window.ethereum.providers;
return providers
? // @ts-expect-error - some provider flags are not typed in `InjectedProviderFlags`
providers.find((provider) => provider[flag])
: // @ts-ignore - viem/window clash
window.ethereum[flag]
? window.ethereum
? providers.find((provider) => provider[flag])
: _window.ethereum[flag]
? _window.ethereum
: undefined;
}

Expand All @@ -41,7 +41,7 @@ export function hasInjectedProvider({
flag,
namespace,
}: {
flag?: string;
flag?: WalletProviderFlags;
namespace?: string;
}): boolean {
if (namespace && typeof getWindowProviderNamespace(namespace) !== 'undefined')
Expand All @@ -58,24 +58,25 @@ function getInjectedProvider({
flag,
namespace,
}: {
flag?: string;
flag?: WalletProviderFlags;
namespace?: string;
}) {
if (typeof window === 'undefined') return;
const _window =
typeof window !== 'undefined' ? (window as WindowProvider) : undefined;
if (typeof _window === 'undefined') return;
if (namespace) {
// prefer custom eip1193 namespaces
const windowProvider = getWindowProviderNamespace(namespace);
if (windowProvider) return windowProvider;
}
// @ts-ignore - viem/window clash
const providers = window.ethereum?.providers;
const providers = _window.ethereum?.providers;
if (flag) {
const provider = getExplicitInjectedProvider(flag);
if (provider) return provider;
}
if (typeof providers !== 'undefined' && providers.length > 0)
return providers[0];
return window.ethereum;
return _window.ethereum;
}

function createInjectedConnector(provider?: any): CreateConnector {
Expand Down Expand Up @@ -104,7 +105,7 @@ export function getInjectedConnector({
namespace,
target,
}: {
flag?: string;
flag?: WalletProviderFlags;
namespace?: string;
target?: any;
}): CreateConnector {
Expand Down
@@ -1,3 +1,4 @@
import { WindowProvider } from '../../../types/utils';
import { isAndroid, isIOS } from '../../../utils/isMobile';
import { DefaultWalletOptions, Wallet } from '../../Wallet';
import {
Expand All @@ -8,83 +9,48 @@ import { getWalletConnectConnector } from '../../getWalletConnectConnector';

export type MetaMaskWalletOptions = DefaultWalletOptions;

function isMetaMask(ethereum?: (typeof window)['ethereum']): boolean {
function isMetaMask(ethereum?: WindowProvider['ethereum']): boolean {
// Logic borrowed from wagmi's MetaMaskConnector
// https://github.com/wagmi-dev/references/blob/main/packages/connectors/src/metaMask.ts
if (!ethereum?.isMetaMask) return false;
// Brave tries to make itself look like MetaMask
// Could also try RPC `web3_clientVersion` if following is unreliable
// @ts-ignore - viem/window clash
if (ethereum.isBraveWallet && !ethereum._events && !ethereum._state)
return false;
// @ts-ignore - viem/window clash
if (ethereum.isApexWallet) return false;
// @ts-ignore - viem/window clash
if (ethereum.isAvalanche) return false;
// @ts-ignore - viem/window clash
if (ethereum.isBackpack) return false;
// @ts-ignore - viem/window clash
if (ethereum.isBifrost) return false;
// @ts-ignore - viem/window clash
if (ethereum.isBitKeep) return false;
// @ts-ignore - viem/window clash
if (ethereum.isBitski) return false;
// @ts-ignore - viem/window clash
if (ethereum.isBlockWallet) return false;
// @ts-ignore - viem/window clash
if (ethereum.isCoinbaseWallet) return false;
// @ts-ignore - viem/window clash
if (ethereum.isDawn) return false;
// @ts-ignore - viem/window clash
if (ethereum.isEnkrypt) return false;
// @ts-ignore - viem/window clash
if (ethereum.isExodus) return false;
// @ts-ignore - viem/window clash
if (ethereum.isFrame) return false;
// @ts-ignore - viem/window clash
if (ethereum.isFrontier) return false;
// @ts-ignore - viem/window clash
if (ethereum.isGamestop) return false;
// @ts-ignore - viem/window clash
if (ethereum.isHyperPay) return false;
// @ts-ignore - viem/window clash
if (ethereum.isImToken) return false;
// @ts-ignore - viem/window clash
if (ethereum.isKuCoinWallet) return false;
// @ts-ignore - viem/window clash
if (ethereum.isMathWallet) return false;
// @ts-ignore - viem/window clash
if (ethereum.isOkxWallet || ethereum.isOKExWallet) return false;
// @ts-ignore - viem/window clash
if (ethereum.isOneInchIOSWallet || ethereum.isOneInchAndroidWallet)
return false;
// @ts-ignore - viem/window clash
if (ethereum.isOpera) return false;
// @ts-ignore - viem/window clash
if (ethereum.isPhantom) return false;
// @ts-ignore - viem/window clash
if (ethereum.isPortal) return false;
// @ts-ignore - viem/window clash
if (ethereum.isRabby) return false;
// @ts-ignore - viem/window clash
if (ethereum.isRainbow) return false;
// @ts-ignore - viem/window clash
if (ethereum.isStatus) return false;
// @ts-ignore - viem/window clash
if (ethereum.isTalisman) return false;
// @ts-ignore - viem/window clash
if (ethereum.isTally) return false;
// @ts-ignore - viem/window clash
if (ethereum.isTokenPocket) return false;
// @ts-ignore - viem/window clash
if (ethereum.isTokenary) return false;
// @ts-ignore - viem/window clash
if (ethereum.isTrust || ethereum.isTrustWallet) return false;
// @ts-ignore - viem/window clash
if (ethereum.isXDEFI) return false;
// @ts-ignore - viem/window clash
if (ethereum.isZeal) return false;
// @ts-ignore - viem/window clash
if (ethereum.isZerion) return false;
return true;
}
Expand Down Expand Up @@ -195,8 +161,9 @@ export const metaMaskWallet = ({
: getInjectedConnector({
target:
typeof window !== 'undefined'
? // @ts-ignore - viem/window clash
window.ethereum?.providers?.find(isMetaMask) ?? window.ethereum
? (window as WindowProvider).ethereum?.providers?.find(
isMetaMask,
) ?? window.ethereum
: undefined,
}),
};
Expand Down
1 change: 0 additions & 1 deletion packages/rainbowkit/src/window.d.ts

This file was deleted.

3 changes: 0 additions & 3 deletions site/components/Provider/Provider.tsx
Expand Up @@ -42,7 +42,6 @@ const config = getDefaultConfig({
appName: 'rainbowkit.com',
projectId,
chains: [
// @ts-ignore - TODO: Fix this typing issue
mainnet,
polygon,
optimism,
Expand All @@ -53,7 +52,6 @@ const config = getDefaultConfig({
zora,
blast,
],
// @ts-ignore - TODO: Fix this typing issue
transports,
wallets: [
...wallets,
Expand All @@ -75,7 +73,6 @@ const client = new QueryClient();

export function Provider({ children }: { children: React.ReactNode }) {
return (
// @ts-ignore - TODO: Fix this typing issue
<WagmiProvider config={config}>
<QueryClientProvider client={client}>{children}</QueryClientProvider>
</WagmiProvider>
Expand Down

0 comments on commit 5577f01

Please sign in to comment.