diff --git a/src/assets/images/coinbaseWalletIcon.svg b/src/assets/images/coinbaseWalletIcon.svg
deleted file mode 100644
index 46dd00f391..0000000000
--- a/src/assets/images/coinbaseWalletIcon.svg
+++ /dev/null
@@ -1,12 +0,0 @@
-
diff --git a/src/assets/images/metamask.svg b/src/assets/images/metamask.svg
deleted file mode 100644
index 057e2d84c7..0000000000
--- a/src/assets/images/metamask.svg
+++ /dev/null
@@ -1,15 +0,0 @@
-
diff --git a/src/assets/images/phantom.png b/src/assets/images/phantom.png
deleted file mode 100644
index 295ef88a30..0000000000
Binary files a/src/assets/images/phantom.png and /dev/null differ
diff --git a/src/assets/images/rainbow.png b/src/assets/images/rainbow.png
deleted file mode 100644
index 52ae9d3620..0000000000
Binary files a/src/assets/images/rainbow.png and /dev/null differ
diff --git a/src/assets/images/walletConnectIcon.svg b/src/assets/images/walletConnectIcon.svg
deleted file mode 100644
index 8557b99694..0000000000
--- a/src/assets/images/walletConnectIcon.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/src/assets/svg/browser-wallet-dark.svg b/src/assets/svg/browser-wallet-dark.svg
deleted file mode 100644
index 5ac423d12d..0000000000
--- a/src/assets/svg/browser-wallet-dark.svg
+++ /dev/null
@@ -1,77 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/svg/browser-wallet-light.svg b/src/assets/svg/browser-wallet-light.svg
deleted file mode 100644
index 98e68b0749..0000000000
--- a/src/assets/svg/browser-wallet-light.svg
+++ /dev/null
@@ -1,78 +0,0 @@
-
\ No newline at end of file
diff --git a/src/assets/svg/phantom-icon.svg b/src/assets/svg/phantom-icon.svg
new file mode 100644
index 0000000000..3d9309fde7
--- /dev/null
+++ b/src/assets/svg/phantom-icon.svg
@@ -0,0 +1,24 @@
+
diff --git a/src/assets/wallets/brave-icon.svg b/src/assets/wallets/brave-icon.svg
new file mode 100644
index 0000000000..b4fb5b6723
--- /dev/null
+++ b/src/assets/wallets/brave-icon.svg
@@ -0,0 +1,18 @@
+
diff --git a/src/assets/wallets/browser-wallet-dark.svg b/src/assets/wallets/browser-wallet-dark.svg
new file mode 100644
index 0000000000..af517ca597
--- /dev/null
+++ b/src/assets/wallets/browser-wallet-dark.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/assets/wallets/browser-wallet-light.svg b/src/assets/wallets/browser-wallet-light.svg
new file mode 100644
index 0000000000..d557a1f4e0
--- /dev/null
+++ b/src/assets/wallets/browser-wallet-light.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/assets/wallets/coinbase-icon.svg b/src/assets/wallets/coinbase-icon.svg
new file mode 100644
index 0000000000..5e2727a43a
--- /dev/null
+++ b/src/assets/wallets/coinbase-icon.svg
@@ -0,0 +1,13 @@
+
diff --git a/src/assets/wallets/ledger-icon.svg b/src/assets/wallets/ledger-icon.svg
new file mode 100644
index 0000000000..078db767dd
--- /dev/null
+++ b/src/assets/wallets/ledger-icon.svg
@@ -0,0 +1,11 @@
+
diff --git a/src/assets/wallets/metamask-icon.svg b/src/assets/wallets/metamask-icon.svg
new file mode 100644
index 0000000000..d574d33e7b
--- /dev/null
+++ b/src/assets/wallets/metamask-icon.svg
@@ -0,0 +1,15 @@
+
diff --git a/src/assets/wallets/phantom-icon.svg b/src/assets/wallets/phantom-icon.svg
new file mode 100644
index 0000000000..c40aa9253a
--- /dev/null
+++ b/src/assets/wallets/phantom-icon.svg
@@ -0,0 +1,24 @@
+
diff --git a/src/assets/wallets/rabby-icon.svg b/src/assets/wallets/rabby-icon.svg
new file mode 100644
index 0000000000..d61f871f70
--- /dev/null
+++ b/src/assets/wallets/rabby-icon.svg
@@ -0,0 +1,25 @@
+
diff --git a/src/assets/wallets/trustwallet-icon.svg b/src/assets/wallets/trustwallet-icon.svg
new file mode 100644
index 0000000000..b574317d99
--- /dev/null
+++ b/src/assets/wallets/trustwallet-icon.svg
@@ -0,0 +1,17 @@
+
diff --git a/src/assets/wallets/uniswap-wallet-icon.png b/src/assets/wallets/uniswap-wallet-icon.png
new file mode 100644
index 0000000000..9f9f89c5d1
Binary files /dev/null and b/src/assets/wallets/uniswap-wallet-icon.png differ
diff --git a/src/assets/wallets/walletconnect-icon.svg b/src/assets/wallets/walletconnect-icon.svg
new file mode 100644
index 0000000000..3f524a4b4b
--- /dev/null
+++ b/src/assets/wallets/walletconnect-icon.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/components/Identicon/__snapshots__/StatusIcon.test.tsx.snap b/src/components/Identicon/__snapshots__/StatusIcon.test.tsx.snap
index 52c1d0258d..7ca05073eb 100644
--- a/src/components/Identicon/__snapshots__/StatusIcon.test.tsx.snap
+++ b/src/components/Identicon/__snapshots__/StatusIcon.test.tsx.snap
@@ -1,14 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`StatusIcon with account renders children in correct order 1`] = `
-.c1 {
- height: 16px;
- width: 16px;
- border-radius: 50%;
- background-color: #98A1C0;
- font-size: initial;
-}
-
.c0 {
position: relative;
display: -webkit-box;
@@ -35,7 +27,7 @@ exports[`StatusIcon with account renders children in correct order 1`] = `
width: 16px;
}
-.c2 {
+.c1 {
position: absolute;
display: -webkit-box;
display: -webkit-flex;
@@ -60,7 +52,7 @@ exports[`StatusIcon with account renders children in correct order 1`] = `
overflow: hidden;
}
-.c4 {
+.c3 {
position: absolute;
display: -webkit-box;
display: -webkit-flex;
@@ -85,7 +77,7 @@ exports[`StatusIcon with account renders children in correct order 1`] = `
overflow: hidden;
}
-.c3 {
+.c2 {
width: 16px;
height: 16px;
}
@@ -100,13 +92,13 @@ exports[`StatusIcon with account renders children in correct order 1`] = `
}
@supports (overflow:clip) {
- .c2 {
+ .c1 {
overflow: clip;
}
}
@supports (overflow:clip) {
- .c4 {
+ .c3 {
overflow: clip;
}
}
@@ -117,60 +109,161 @@ exports[`StatusIcon with account renders children in correct order 1`] = `
size="16"
>
-
-
+
-
+
+
+
@@ -289,9 +382,9 @@ exports[`StatusIcon with no account renders children in correct order 1`] = `
class="c1"
>
!theme.darkMode && `border: 1px solid ${theme.backgroundOutline}`};
+ border-radius: 12px;
+ }
& > img,
span {
height: 40px;
diff --git a/src/components/WalletModal/__snapshots__/Option.test.tsx.snap b/src/components/WalletModal/__snapshots__/Option.test.tsx.snap
index 57eed1eca7..f1ac9404b5 100644
--- a/src/components/WalletModal/__snapshots__/Option.test.tsx.snap
+++ b/src/components/WalletModal/__snapshots__/Option.test.tsx.snap
@@ -86,6 +86,11 @@ exports[`Wallet Option renders default state 1`] = `
justify-content: center;
}
+.c2 img {
+ border: 1px solid #D2D9EE;
+ border-radius: 12px;
+}
+
.c2 > img,
.c2 span {
height: 40px;
diff --git a/src/connection/index.test.tsx b/src/connection/index.test.tsx
index ae58d9deb0..e9f41bf662 100644
--- a/src/connection/index.test.tsx
+++ b/src/connection/index.test.tsx
@@ -1,5 +1,5 @@
-import INJECTED_DARK_ICON from 'assets/svg/browser-wallet-dark.svg'
-import INJECTED_LIGHT_ICON from 'assets/svg/browser-wallet-light.svg'
+import INJECTED_DARK_ICON from 'assets/wallets/browser-wallet-dark.svg'
+import INJECTED_LIGHT_ICON from 'assets/wallets/browser-wallet-light.svg'
import { getConnection, getConnections } from 'connection'
import { ConnectionType } from './types'
@@ -10,6 +10,11 @@ jest.mock('utils/userAgent', () => ({
}))
describe('connection utility/metadata tests', () => {
+ beforeEach(() => {
+ global.window.ethereum = undefined
+ global.window.phantom = undefined
+ })
+
const createWalletEnvironment = (ethereum: Window['window']['ethereum'], isMobile = false) => {
UserAgentMock.isMobile = isMobile
global.window.ethereum = ethereum
@@ -23,11 +28,15 @@ describe('connection utility/metadata tests', () => {
return { displayed, injected, coinbase, uniswap, walletconnect }
}
+ const createPhantomEnviroment = () => {
+ global.window.phantom = { ethereum: { isPhantom: true } }
+ }
+
it('Non-injected Desktop', async () => {
const { displayed, injected } = createWalletEnvironment(undefined)
expect(displayed.includes(injected)).toBe(true)
- expect(injected.getName()).toBe('MetaMask')
+ expect(injected.getName()).toBe('Install MetaMask')
expect(injected.overrideActivate?.()).toBeTruthy()
expect(displayed.length).toEqual(4)
@@ -48,7 +57,7 @@ describe('connection utility/metadata tests', () => {
expect(displayed.includes(coinbase)).toBe(true)
expect(displayed.includes(injected)).toBe(true)
- expect(injected.getName()).toBe('MetaMask')
+ expect(injected.getName()).toBe('Install MetaMask')
expect(injected.overrideActivate?.()).toBeTruthy()
expect(displayed.length).toEqual(4)
@@ -65,38 +74,68 @@ describe('connection utility/metadata tests', () => {
expect(displayed.length).toEqual(4)
})
- it('Generic Injected Desktop', async () => {
- const { displayed, injected } = createWalletEnvironment({ isTrustWallet: true })
+ it('Trust Wallet Injected Desktop', async () => {
+ const { displayed, injected } = createWalletEnvironment({ isTrust: true })
expect(displayed.includes(injected)).toBe(true)
- expect(injected.getName()).toBe('Browser Wallet')
+ expect(injected.getName()).toBe('Trust Wallet')
expect(injected.overrideActivate?.()).toBeFalsy()
expect(displayed.length).toEqual(4)
})
+ it('Rabby Wallet Injected Desktop', async () => {
+ const { displayed, injected } = createWalletEnvironment({ isRabby: true, isMetaMask: true }) // Rabby sets isMetaMask to true
+
+ expect(displayed.includes(injected)).toBe(true)
+ expect(injected.getName()).toBe('Rabby')
+ expect(injected.overrideActivate?.()).toBeFalsy()
+
+ expect(displayed.length).toEqual(4)
+ })
+
+ it('LedgerConnect Wallet Injected Desktop', async () => {
+ const { displayed, injected } = createWalletEnvironment({ isLedgerConnect: true })
+
+ expect(displayed.includes(injected)).toBe(true)
+ expect(injected.getName()).toBe('Ledger')
+ expect(injected.overrideActivate?.()).toBeFalsy()
+
+ expect(displayed.length).toEqual(4)
+ })
+
+ it('Brave Browser Wallet Injected Desktop', async () => {
+ const { displayed, injected } = createWalletEnvironment({ isBraveWallet: true })
+
+ expect(displayed.includes(injected)).toBe(true)
+ expect(injected.getName()).toBe('Brave')
+ expect(injected.overrideActivate?.()).toBeFalsy()
+
+ expect(displayed.length).toEqual(4)
+ })
+
+ it('Phantom Wallet Injected Desktop', async () => {
+ createPhantomEnviroment()
+ const { displayed, injected } = createWalletEnvironment({ isMetaMask: true }) // Phantom sets isMetaMask to true
+
+ expect(displayed.includes(injected)).toBe(true)
+ expect(injected.getName()).toBe('Phantom')
+ expect(injected.overrideActivate?.()).toBeFalsy()
+
+ expect(displayed.length).toEqual(4)
+ })
+
+ const UNKNOWN_MM_INJECTOR = { isRandomWallet: true, isMetaMask: true } as Window['window']['ethereum']
it('Generic Browser Wallet that injects as MetaMask', async () => {
- const { displayed, injected } = createWalletEnvironment({ isRabby: true, isMetaMask: true })
+ const { displayed, injected } = createWalletEnvironment(UNKNOWN_MM_INJECTOR)
expect(displayed.includes(injected)).toBe(true)
- expect(injected.getName()).toBe('Browser Wallet')
+ expect(injected.getName()).toBe('MetaMask')
expect(injected.overrideActivate?.()).toBeFalsy()
expect(displayed.length).toEqual(4)
})
- it('Generic Wallet Browser with delayed injection', async () => {
- const { injected } = createWalletEnvironment(undefined)
-
- expect(injected.getName()).toBe('MetaMask')
- expect(injected.overrideActivate?.()).toBeTruthy()
-
- createWalletEnvironment({ isTrustWallet: true })
-
- expect(injected.getName()).toBe('Browser Wallet')
- expect(injected.overrideActivate?.()).toBeFalsy()
- })
-
const UNKNOWN_INJECTOR = { isRandomWallet: true } as Window['window']['ethereum']
it('Generic Unknown Injected Wallet Browser', async () => {
const { displayed, injected } = createWalletEnvironment(UNKNOWN_INJECTOR, true)
@@ -105,13 +144,25 @@ describe('connection utility/metadata tests', () => {
expect(injected.getName()).toBe('Browser Wallet')
expect(injected.overrideActivate?.()).toBeFalsy()
- expect(injected.getIcon?.(/* isDarkMode */ false)).toBe(INJECTED_LIGHT_ICON)
- expect(injected.getIcon?.(/* isDarkMode */ true)).toBe(INJECTED_DARK_ICON)
+ expect(injected.getIcon?.(/* isDarkMode= */ false)).toBe(INJECTED_LIGHT_ICON)
+ expect(injected.getIcon?.(/* isDarkMode= */ true)).toBe(INJECTED_DARK_ICON)
// Ensures we provide multiple connection options if in an unknown injected browser
expect(displayed.length).toEqual(4)
})
+ it('Generic Wallet Browser with delayed injection', async () => {
+ const { injected } = createWalletEnvironment(undefined)
+
+ expect(injected.getName()).toBe('Install MetaMask')
+ expect(injected.overrideActivate?.()).toBeTruthy()
+
+ createWalletEnvironment(UNKNOWN_INJECTOR)
+
+ expect(injected.getName()).toBe('Browser Wallet')
+ expect(injected.overrideActivate?.()).toBeFalsy()
+ })
+
it('MetaMask Mobile Browser', async () => {
const { displayed, injected } = createWalletEnvironment({ isMetaMask: true }, true)
diff --git a/src/connection/index.ts b/src/connection/index.ts
index d2ffb08a1b..47a6593de5 100644
--- a/src/connection/index.ts
+++ b/src/connection/index.ts
@@ -4,21 +4,18 @@ import { GnosisSafe } from '@web3-react/gnosis-safe'
import { MetaMask } from '@web3-react/metamask'
import { Network } from '@web3-react/network'
import { Connector } from '@web3-react/types'
-import COINBASE_ICON from 'assets/images/coinbaseWalletIcon.svg'
import GNOSIS_ICON from 'assets/images/gnosis.png'
-import METAMASK_ICON from 'assets/images/metamask.svg'
-import UNIWALLET_ICON from 'assets/images/uniwallet.png'
-import WALLET_CONNECT_ICON from 'assets/images/walletConnectIcon.svg'
-import INJECTED_DARK_ICON from 'assets/svg/browser-wallet-dark.svg'
-import INJECTED_LIGHT_ICON from 'assets/svg/browser-wallet-light.svg'
import UNISWAP_LOGO from 'assets/svg/logo.svg'
+import COINBASE_ICON from 'assets/wallets/coinbase-icon.svg'
+import UNIWALLET_ICON from 'assets/wallets/uniswap-wallet-icon.png'
+import WALLET_CONNECT_ICON from 'assets/wallets/walletconnect-icon.svg'
import { SupportedChainId } from 'constants/chains'
import { isMobile, isNonIOSPhone } from 'utils/userAgent'
import { RPC_URLS } from '../constants/networks'
import { RPC_PROVIDERS } from '../constants/providers'
import { Connection, ConnectionType } from './types'
-import { getIsCoinbaseWallet, getIsInjected, getIsMetaMaskWallet } from './utils'
+import { getInjection, getIsCoinbaseWallet, getIsInjected, getIsMetaMaskWallet } from './utils'
import { UniwalletConnect, WalletConnectPopup } from './WalletConnect'
import { WalletConnectV2Popup } from './WalletConnectV2'
@@ -48,13 +45,11 @@ const getIsGenericInjector = () => getIsInjected() && !getIsMetaMaskWallet() &&
const [web3Injected, web3InjectedHooks] = initializeConnector((actions) => new MetaMask({ actions, onError }))
const injectedConnection: Connection = {
- // TODO(WEB-3131) re-add "Install MetaMask" string when no injector is present
- getName: () => (getIsGenericInjector() ? 'Browser Wallet' : 'MetaMask'),
+ getName: () => getInjection().name,
connector: web3Injected,
hooks: web3InjectedHooks,
type: ConnectionType.INJECTED,
- getIcon: (isDarkMode: boolean) =>
- getIsGenericInjector() ? (isDarkMode ? INJECTED_DARK_ICON : INJECTED_LIGHT_ICON) : METAMASK_ICON,
+ getIcon: (isDarkMode: boolean) => getInjection(isDarkMode).icon,
shouldDisplay: () => getIsMetaMaskWallet() || getShouldAdvertiseMetaMask() || getIsGenericInjector(),
// If on non-injected, non-mobile browser, prompt user to install Metamask
overrideActivate: () => {
diff --git a/src/connection/utils.ts b/src/connection/utils.ts
index a70b54b05b..efd1bbc283 100644
--- a/src/connection/utils.ts
+++ b/src/connection/utils.ts
@@ -1,14 +1,54 @@
+import BRAVE_ICON from 'assets/wallets/brave-icon.svg'
+import INJECTED_DARK_ICON from 'assets/wallets/browser-wallet-dark.svg'
+import INJECTED_LIGHT_ICON from 'assets/wallets/browser-wallet-light.svg'
+import LEDGER_ICON from 'assets/wallets/ledger-icon.svg'
+import METAMASK_ICON from 'assets/wallets/metamask-icon.svg'
+import PHANTOM_ICON from 'assets/wallets/phantom-icon.svg'
+import RABBY_ICON from 'assets/wallets/rabby-icon.svg'
+import TRUST_WALLET_ICON from 'assets/wallets/trustwallet-icon.svg'
import { Connection, ConnectionType } from 'connection/types'
export const getIsInjected = () => Boolean(window.ethereum)
-// When using Brave browser, `isMetaMask` is set to true when using the built-in wallet
-// This variable should be true only when using the MetaMask extension
-// https://wallet-docs.brave.com/ethereum/wallet-detection#compatability-with-metamask
-type NonMetaMaskFlag = 'isRabby' | 'isBraveWallet' | 'isTrustWallet' | 'isLedgerConnect'
-const allNonMetamaskFlags: NonMetaMaskFlag[] = ['isRabby', 'isBraveWallet', 'isTrustWallet', 'isLedgerConnect']
-export const getIsMetaMaskWallet = () =>
- Boolean(window.ethereum?.isMetaMask && !allNonMetamaskFlags.some((flag) => window.ethereum?.[flag]))
+const InjectedWalletTable: { [key in keyof NonNullable]?: { name: string; icon: string } } = {
+ isBraveWallet: { name: 'Brave', icon: BRAVE_ICON },
+ isRabby: { name: 'Rabby', icon: RABBY_ICON },
+ isTrust: { name: 'Trust Wallet', icon: TRUST_WALLET_ICON },
+ isLedgerConnect: { name: 'Ledger', icon: LEDGER_ICON },
+}
+
+/**
+ * Checks the window object for the presence of a known injectors and returns the most relevant injector name and icon.
+ * Returns a default metamask installation object if no wallet is detected.
+ *
+ * @param isDarkMode - optional parameter to determine which color mode of the
+ */
+export function getInjection(isDarkMode?: boolean): { name: string; icon: string } {
+ for (const [key, wallet] of Object.entries(InjectedWalletTable)) {
+ if (window.ethereum?.[key as keyof Window['ethereum']]) return wallet
+ }
+
+ // Phantom sets its flag in a different part of the window object
+ if (window.phantom?.ethereum?.isPhantom) return { name: 'Phantom', icon: PHANTOM_ICON }
+
+ // Check for MetaMask last, as other injectors will also set this flag, i.e. Brave browser and Phantom wallet
+ if (window.ethereum?.isMetaMask) return { name: 'MetaMask', icon: METAMASK_ICON }
+
+ // Prompt metamask installation when there is no injection present or the only injection detected is coinbase (CB has separate entry point in UI)
+ if (!window.ethereum || window.ethereum.isCoinbaseWallet) return { name: 'Install MetaMask', icon: METAMASK_ICON }
+
+ // Use a generic icon when injection is present but no known non-coinbase wallet is detected
+ return { name: 'Browser Wallet', icon: isDarkMode ? INJECTED_DARK_ICON : INJECTED_LIGHT_ICON }
+}
+
+/**
+ * Returns true if `isMetaMask` is set to true and another non-metamask injector cannot be detected.
+ *
+ * Some non-metamask wallets set `isMetaMask` to true for dapp-compatability reasons. If one of these
+ * injectors are detected, this function will return false.
+ * https://wallet-docs.brave.com/ethereum/wallet-detection#compatability-with-metamask
+ */
+export const getIsMetaMaskWallet = () => getInjection().name === 'MetaMask'
export const getIsCoinbaseWallet = () => Boolean(window.ethereum?.isCoinbaseWallet)
diff --git a/src/react-app-env.d.ts b/src/react-app-env.d.ts
index a20944ddce..5689976978 100644
--- a/src/react-app-env.d.ts
+++ b/src/react-app-env.d.ts
@@ -19,11 +19,17 @@ interface Window {
// set by the Rabby browser extension
isRabby?: true
// set by the Trust Wallet browser extension
- isTrustWallet?: true
+ isTrust?: true
// set by the Ledger Extension Web 3 browser extension
isLedgerConnect?: true
autoRefreshOnNetworkChange?: boolean
}
+ // set by the Phantom Wallet browser extension
+ phantom?: {
+ ethereum?: {
+ isPhantom?: true
+ }
+ }
web3?: Record
}