diff --git a/packages/core/exports/index.ts b/packages/core/exports/index.ts
index 98b14a9e0b..547b5fd49a 100644
--- a/packages/core/exports/index.ts
+++ b/packages/core/exports/index.ts
@@ -24,7 +24,10 @@ export type {
} from '../src/controllers/ConnectionController.js'
export { ConnectorController } from '../src/controllers/ConnectorController.js'
-export type { ConnectorControllerState } from '../src/controllers/ConnectorController.js'
+export type {
+ ConnectorControllerState,
+ ConnectorWithProviders
+} from '../src/controllers/ConnectorController.js'
export { SnackController } from '../src/controllers/SnackController.js'
export type { SnackControllerState } from '../src/controllers/SnackController.js'
diff --git a/packages/core/src/controllers/ConnectorController.ts b/packages/core/src/controllers/ConnectorController.ts
index f83deb0f54..fef906384d 100644
--- a/packages/core/src/controllers/ConnectorController.ts
+++ b/packages/core/src/controllers/ConnectorController.ts
@@ -7,7 +7,7 @@ import { ThemeController } from './ThemeController.js'
import { ChainController } from './ChainController.js'
// -- Types --------------------------------------------- //
-interface ConnectorWithProviders extends Connector {
+export interface ConnectorWithProviders extends Connector {
connectors?: Connector[]
}
export interface ConnectorControllerState {
diff --git a/packages/core/src/utils/ConstantsUtil.ts b/packages/core/src/utils/ConstantsUtil.ts
index e5d094eafe..2a65154ae4 100644
--- a/packages/core/src/utils/ConstantsUtil.ts
+++ b/packages/core/src/utils/ConstantsUtil.ts
@@ -236,7 +236,7 @@ export const ConstantsUtil = {
legalCheckbox: false,
smartSessions: false,
collapseWallets: false,
- connectMethodsOrder: ['email', 'social', 'wallet'],
- walletFeaturesOrder: ['onramp', 'swaps', 'receive', 'send']
+ walletFeaturesOrder: ['onramp', 'swaps', 'receive', 'send'],
+ connectMethodsOrder: undefined
} satisfies Features
}
diff --git a/packages/scaffold-ui/src/partials/w3m-connector-list/index.ts b/packages/scaffold-ui/src/partials/w3m-connector-list/index.ts
index a3fc959e50..68c7214404 100644
--- a/packages/scaffold-ui/src/partials/w3m-connector-list/index.ts
+++ b/packages/scaffold-ui/src/partials/w3m-connector-list/index.ts
@@ -2,15 +2,10 @@ import { customElement } from '@reown/appkit-ui'
import { LitElement, html } from 'lit'
import styles from './styles.js'
-import {
- ApiController,
- ConnectorController,
- OptionsController,
- StorageUtil
-} from '@reown/appkit-core'
+import { ConnectorController, OptionsController } from '@reown/appkit-core'
import { property, state } from 'lit/decorators.js'
-import { WalletUtil } from '../../utils/WalletUtil.js'
import { ifDefined } from 'lit/directives/if-defined.js'
+import { ConnectorUtil } from '../../utils/ConnectorUtil.js'
@customElement('w3m-connector-list')
export class W3mConnectorList extends LitElement {
public static override styles = styles
@@ -37,7 +32,7 @@ export class W3mConnectorList extends LitElement {
// -- Render -------------------------------------------- //
public override render() {
const { custom, recent, announced, injected, multiChain, recommended, featured, external } =
- this.getConnectorsByType()
+ ConnectorUtil.getConnectorsByType(this.connectors)
const enableWalletConnect = OptionsController.state.enableWalletConnect
@@ -91,31 +86,6 @@ export class W3mConnectorList extends LitElement {
`
}
-
- private getConnectorsByType() {
- const { featured, recommended } = ApiController.state
- const { customWallets: custom } = OptionsController.state
- const recent = StorageUtil.getRecentWallets()
-
- const filteredRecommended = WalletUtil.filterOutDuplicateWallets(recommended)
- const filteredFeatured = WalletUtil.filterOutDuplicateWallets(featured)
-
- const multiChain = this.connectors.filter(connector => connector.type === 'MULTI_CHAIN')
- const announced = this.connectors.filter(connector => connector.type === 'ANNOUNCED')
- const injected = this.connectors.filter(connector => connector.type === 'INJECTED')
- const external = this.connectors.filter(connector => connector.type === 'EXTERNAL')
-
- return {
- custom,
- recent,
- external,
- multiChain,
- announced,
- injected,
- recommended: filteredRecommended,
- featured: filteredFeatured
- }
- }
}
declare global {
diff --git a/packages/scaffold-ui/src/utils/ConnectorUtil.ts b/packages/scaffold-ui/src/utils/ConnectorUtil.ts
new file mode 100644
index 0000000000..16909b498b
--- /dev/null
+++ b/packages/scaffold-ui/src/utils/ConnectorUtil.ts
@@ -0,0 +1,66 @@
+import {
+ ApiController,
+ OptionsController,
+ StorageUtil,
+ type ConnectorWithProviders,
+ CoreHelperUtil,
+ ConnectionController
+} from '@reown/appkit-core'
+import { WalletUtil } from './WalletUtil.js'
+
+export const ConnectorUtil = {
+ getConnectorsByType(connectors: ConnectorWithProviders[]) {
+ const { featured, recommended } = ApiController.state
+ const { customWallets: custom } = OptionsController.state
+ const recent = StorageUtil.getRecentWallets()
+
+ const filteredRecommended = WalletUtil.filterOutDuplicateWallets(recommended)
+ const filteredFeatured = WalletUtil.filterOutDuplicateWallets(featured)
+
+ const multiChain = connectors.filter(connector => connector.type === 'MULTI_CHAIN')
+ const announced = connectors.filter(connector => connector.type === 'ANNOUNCED')
+ const injected = connectors.filter(connector => connector.type === 'INJECTED')
+
+ const external = connectors.filter(connector => connector.type === 'EXTERNAL')
+
+ return {
+ custom,
+ recent,
+ external,
+ multiChain,
+ announced,
+ injected,
+ recommended: filteredRecommended,
+ featured: filteredFeatured
+ }
+ },
+ showConnector(connector: ConnectorWithProviders) {
+ if (connector.type === 'INJECTED') {
+ if (!CoreHelperUtil.isMobile() && connector.name === 'Browser Wallet') {
+ return false
+ }
+
+ const walletRDNS = connector.info?.rdns
+
+ if (!walletRDNS && !ConnectionController.checkInstalled()) {
+ return false
+ }
+
+ if (walletRDNS && ApiController.state.excludedRDNS) {
+ if (ApiController.state.excludedRDNS.includes(walletRDNS)) {
+ return false
+ }
+ }
+ }
+
+ if (connector.type === 'ANNOUNCED') {
+ const rdns = connector.info?.rdns
+
+ if (rdns && ApiController.state.excludedRDNS.includes(rdns)) {
+ return false
+ }
+ }
+
+ return true
+ }
+}
diff --git a/packages/scaffold-ui/src/utils/ConstantsUtil.ts b/packages/scaffold-ui/src/utils/ConstantsUtil.ts
index 7e6ba337ba..4f6d4d27e9 100644
--- a/packages/scaffold-ui/src/utils/ConstantsUtil.ts
+++ b/packages/scaffold-ui/src/utils/ConstantsUtil.ts
@@ -1,3 +1,5 @@
+import type { ConnectMethod } from '@reown/appkit-core'
+
export const ConstantsUtil = {
ACCOUNT_TABS: [{ label: 'Tokens' }, { label: 'NFTs' }, { label: 'Activity' }],
SECURE_SITE_ORIGIN:
@@ -6,6 +8,7 @@ export const ConstantsUtil = {
Next: 'next',
Prev: 'prev'
},
+ DEFAULT_CONNECT_METHOD_ORDER: ['email', 'social', 'wallet'] as ConnectMethod[],
ANIMATION_DURATIONS: {
HeaderText: 120,
ModalHeight: 150,
diff --git a/packages/scaffold-ui/src/views/w3m-connect-view/index.ts b/packages/scaffold-ui/src/views/w3m-connect-view/index.ts
index 88c075c8e5..5868f41b91 100644
--- a/packages/scaffold-ui/src/views/w3m-connect-view/index.ts
+++ b/packages/scaffold-ui/src/views/w3m-connect-view/index.ts
@@ -7,15 +7,15 @@ import {
CoreHelperUtil,
OptionsController,
RouterController,
+ type ConnectMethod,
type WalletGuideType
} from '@reown/appkit-core'
import { state } from 'lit/decorators/state.js'
import { property } from 'lit/decorators.js'
import { classMap } from 'lit/directives/class-map.js'
import { ifDefined } from 'lit/directives/if-defined.js'
-import { ConstantsUtil } from '@reown/appkit-core'
-
-const defaultConnectMethodsOrder = ConstantsUtil.DEFAULT_FEATURES.connectMethodsOrder
+import { ConnectorUtil } from '../../utils/ConnectorUtil.js'
+import { ConstantsUtil } from '../../utils/ConstantsUtil.js'
@customElement('w3m-connect-view')
export class W3mConnectView extends LitElement {
@@ -119,11 +119,7 @@ export class W3mConnectView extends LitElement {
// -- Private ------------------------------------------- //
private renderConnectMethod(tabIndex?: number) {
- const connectMethodsOrder = this.features?.connectMethodsOrder || defaultConnectMethodsOrder
-
- if (!connectMethodsOrder) {
- return null
- }
+ const connectMethodsOrder = this.getConnectOrderMethod()
return html`${connectMethodsOrder.map((method, index) => {
switch (method) {
@@ -155,7 +151,7 @@ export class W3mConnectView extends LitElement {
}
private checkIsThereNextMethod(currentIndex: number): string | undefined {
- const connectMethodsOrder = this.features?.connectMethodsOrder || defaultConnectMethodsOrder
+ const connectMethodsOrder = this.getConnectOrderMethod()
const nextMethod = connectMethodsOrder[currentIndex + 1] as
| 'wallet'
@@ -349,6 +345,25 @@ export class W3mConnectView extends LitElement {
)
}
+ private getConnectOrderMethod() {
+ const connectMethodOrder = this.features?.connectMethodsOrder
+
+ if (connectMethodOrder) {
+ return connectMethodOrder
+ }
+
+ const { injected, announced } = ConnectorUtil.getConnectorsByType(this.connectors)
+
+ const shownInjected = injected.filter(ConnectorUtil.showConnector)
+ const shownAnnounced = announced.filter(ConnectorUtil.showConnector)
+
+ if (shownInjected.length || shownAnnounced.length) {
+ return ['wallet', 'email', 'social'] as ConnectMethod[]
+ }
+
+ return ConstantsUtil.DEFAULT_CONNECT_METHOD_ORDER
+ }
+
// -- Private Methods ----------------------------------- //
private onContinueWalletClick() {
RouterController.push('ConnectWallets')
diff --git a/packages/scaffold-ui/test/views/w3m-connect-view.test.ts b/packages/scaffold-ui/test/views/w3m-connect-view.test.ts
index 1cb4c15dd9..00923c1d65 100644
--- a/packages/scaffold-ui/test/views/w3m-connect-view.test.ts
+++ b/packages/scaffold-ui/test/views/w3m-connect-view.test.ts
@@ -3,7 +3,12 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'
import { fixture } from '@open-wc/testing'
import { html } from 'lit'
import { HelpersUtil } from '../utils/HelpersUtil'
-import { OptionsController } from '@reown/appkit-core'
+import {
+ OptionsController,
+ type ConnectorWithProviders,
+ ConnectorController,
+ CoreHelperUtil
+} from '@reown/appkit-core'
// --- Constants ---------------------------------------------------- //
const EMAIL_LOGIN_WIDGET = 'w3m-email-login-widget'
@@ -13,21 +18,34 @@ const COLLAPSE_WALLETS_BUTTON = 'w3m-collapse-wallets-button'
const SEPARATOR = 'wui-separator'
const EMAIL_SEPARATOR = 'w3m-email-login-or-separator'
+const INSTALLED_WALLET = {
+ id: 'metamask',
+ name: 'MetaMask',
+ type: 'ANNOUNCED'
+} as ConnectorWithProviders
+
describe('W3mConnectView - Connection Methods', () => {
beforeEach(() => {
+ vi.spyOn(CoreHelperUtil, 'isMobile').mockReturnValue(false)
+
vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({
...OptionsController.state,
enableWallets: true,
features: {
email: true,
socials: ['google', 'facebook'],
- connectMethodsOrder: ['wallet', 'email', 'social'],
+ connectMethodsOrder: ['email', 'wallet', 'social'],
collapseWallets: false
}
})
})
- it('should render connection methods in specified order', async () => {
+ it('should render connection methods in specified order based on connectMethodsOrder option', async () => {
+ vi.spyOn(ConnectorController, 'state', 'get').mockReturnValue({
+ ...ConnectorController.state,
+ connectors: [INSTALLED_WALLET]
+ })
+
const element: W3mConnectView = await fixture(html``)
const children = Array.from(
@@ -39,6 +57,37 @@ describe('W3mConnectView - Connection Methods', () => {
expect(widgets).toContain(EMAIL_LOGIN_WIDGET)
expect(widgets).toContain(SOCIAL_LOGIN_WIDGET)
+ // Check order
+ expect(widgets.indexOf(EMAIL_LOGIN_WIDGET)).toBeLessThan(widgets.indexOf(WALLET_LOGIN_LIST))
+ expect(widgets.indexOf(WALLET_LOGIN_LIST)).toBeLessThan(widgets.indexOf(SOCIAL_LOGIN_WIDGET))
+ })
+
+ it('should render connection methods in the correct order based on if there are installed wallets', async () => {
+ vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({
+ ...OptionsController.state,
+ features: {
+ email: true,
+ socials: ['google', 'facebook']
+ }
+ })
+
+ vi.spyOn(ConnectorController, 'state', 'get').mockReturnValue({
+ ...ConnectorController.state,
+ connectors: [INSTALLED_WALLET]
+ })
+
+ const element: W3mConnectView = await fixture(html``)
+
+ const children = Array.from(
+ element.shadowRoot?.querySelector('.connect-methods')?.children ?? []
+ )
+ const widgets = children.map(child => child.tagName.toLowerCase())
+
+ // Assertions
+ expect(widgets).toContain(EMAIL_LOGIN_WIDGET)
+ expect(widgets).toContain(WALLET_LOGIN_LIST)
+ expect(widgets).toContain(SOCIAL_LOGIN_WIDGET)
+
// Check order
expect(widgets.indexOf(WALLET_LOGIN_LIST)).toBeLessThan(widgets.indexOf(EMAIL_LOGIN_WIDGET))
expect(widgets.indexOf(EMAIL_LOGIN_WIDGET)).toBeLessThan(widgets.indexOf(SOCIAL_LOGIN_WIDGET))
@@ -64,6 +113,16 @@ describe('W3mConnectView - Connection Methods', () => {
})
it('should render one separator between wallet and email/social group', async () => {
+ vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({
+ ...OptionsController.state,
+ enableWallets: true,
+ features: {
+ email: true,
+ socials: ['google'],
+ connectMethodsOrder: ['wallet', 'email', 'social']
+ }
+ })
+
const element: W3mConnectView = await fixture(html``)
const separators = Array.from(element.shadowRoot?.querySelectorAll(SEPARATOR) ?? [])