Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

:fix allowUnsupportedChain param to work correctly #3447

Merged
merged 21 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
61df3ef
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Nov 25, 2024
2cb1a1b
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Nov 26, 2024
d2bf2bc
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Nov 27, 2024
0bd4276
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Nov 28, 2024
a4c24da
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Nov 28, 2024
5eecce4
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Nov 29, 2024
b3d2efe
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Nov 29, 2024
0a0aeca
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Dec 2, 2024
cf37108
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Dec 5, 2024
34ee496
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Dec 6, 2024
7df0378
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Dec 10, 2024
9f1174d
wip
svenvoskamp Dec 10, 2024
c95f623
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Dec 10, 2024
26c8ad4
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Dec 11, 2024
ab675ab
Merge branch 'main' of github.com:reown-com/appkit
svenvoskamp Dec 12, 2024
6584fd5
fix unsupportedChain param
svenvoskamp Dec 12, 2024
c2ebc4d
add changeset
svenvoskamp Dec 12, 2024
c6a8d57
Merge branch 'main' into fix/allow-unsupported-chain
svenvoskamp Dec 12, 2024
bd01d2c
add ui tests
svenvoskamp Dec 12, 2024
1dcdb1a
Merge branch 'fix/allow-unsupported-chain' of github.com:reown-com/ap…
svenvoskamp Dec 12, 2024
b9c44e8
add consstant
svenvoskamp Dec 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .changeset/hip-students-move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
'@reown/appkit-scaffold-ui': patch
'@reown/appkit': patch
'@reown/appkit-core': patch
'@reown/appkit-adapter-ethers': patch
'@reown/appkit-adapter-ethers5': patch
'@reown/appkit-adapter-solana': patch
'@reown/appkit-adapter-wagmi': patch
'@reown/appkit-utils': patch
'@reown/appkit-cdn': patch
'@reown/appkit-cli': patch
'@reown/appkit-common': patch
'@reown/appkit-experimental': patch
'@reown/appkit-polyfills': patch
'@reown/appkit-siwe': patch
'@reown/appkit-siwx': patch
'@reown/appkit-ui': patch
'@reown/appkit-wallet': patch
'@reown/appkit-wallet-button': patch
---

Fix allowUnsupportedChain param to work correctly
4 changes: 4 additions & 0 deletions packages/appkit/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,10 @@ export class AppKit {
OptionsController.setSdkVersion(options.sdkVersion)
OptionsController.setEnableEmbedded(options.enableEmbedded)

if (options.allowUnsupportedChain) {
OptionsController.setAllowUnsupportedChain(options.allowUnsupportedChain)
}

if (!options.projectId) {
AlertController.open(ErrorUtil.ALERT_ERRORS.PROJECT_ID_NOT_CONFIGURED, 'error')

Expand Down
47 changes: 47 additions & 0 deletions packages/appkit/src/tests/appkit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,53 @@ describe('Base', () => {
expect(isClientSpy).toHaveBeenCalled()
})

it('should not show unsupported chain UI when allowUnsupportedChain is true', async () => {
vi.mocked(ChainController).state = {
chains: new Map([['eip155', { namespace: 'eip155' }]]),
activeChain: 'eip155'
} as any
;(appKit as any).caipNetworks = [{ id: 'eip155:1', chainNamespace: 'eip155' }]

vi.mocked(OptionsController).state = {
allowUnsupportedChain: true
} as any

const mockAdapter = {
getAccounts: vi.fn().mockResolvedValue([]),
syncConnection: vi.fn().mockResolvedValue({
chainId: 'eip155:999', // Unsupported chain
address: '0x123'
}),
getBalance: vi.fn().mockResolvedValue({ balance: '0', symbol: 'ETH' }),
getProfile: vi.fn().mockResolvedValue({}),
on: vi.fn(),
off: vi.fn(),
emit: vi.fn()
}

vi.spyOn(appKit as any, 'getAdapter').mockReturnValue(mockAdapter)

vi.spyOn(StorageUtil, 'setConnectedConnector').mockImplementation(vi.fn())

vi.spyOn(appKit as any, 'setUnsupportedNetwork').mockImplementation(vi.fn())

vi.spyOn(SafeLocalStorage, 'getItem').mockImplementation((key: string) => {
if (key === SafeLocalStorageKeys.CONNECTED_CONNECTOR) {
return 'test-wallet'
}
if (key === SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK_ID) {
return 'eip155:1'
}
return undefined
})

vi.mocked(ChainController.showUnsupportedChainUI).mockImplementation(vi.fn())

await (appKit as any).syncExistingConnection()

expect(ChainController.showUnsupportedChainUI).not.toHaveBeenCalled()
})

it('should subscribe to providers', () => {
const callback = vi.fn()
const providers = {
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/controllers/ChainController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ModalController } from './ModalController.js'
import { EventsController } from './EventsController.js'
import { RouterController } from './RouterController.js'
import { StorageUtil } from '../utils/StorageUtil.js'
import { OptionsController } from './OptionsController.js'

// -- Constants ----------------------------------------- //
const accountState: AccountControllerState = {
Expand Down Expand Up @@ -233,7 +234,7 @@ export const ChainController = {

const isSupported = this.checkIfSupportedNetwork(caipNetwork.chainNamespace)

if (!isSupported) {
if (!isSupported && !OptionsController.state.allowUnsupportedChain) {
this.showUnsupportedChainUI()
}
},
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/controllers/OptionsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ export interface OptionsControllerStatePublic {
* @default false
*/
enableEmbedded?: boolean
/**
* Allow users to switch to an unsupported chain.
* @default false
*/
allowUnsupportedChain?: boolean
}

export interface OptionsControllerStateInternal {
Expand Down Expand Up @@ -292,5 +297,9 @@ export const OptionsController = {

setEnableEmbedded(enableEmbedded: OptionsControllerState['enableEmbedded']) {
state.enableEmbedded = enableEmbedded
},

setAllowUnsupportedChain(allowUnsupportedChain: OptionsControllerState['allowUnsupportedChain']) {
state.allowUnsupportedChain = allowUnsupportedChain
}
}
5 changes: 5 additions & 0 deletions packages/core/tests/controllers/OptionsController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,9 @@ describe('OptionsController', () => {
OptionsController.setSdkVersion('react-wagmi-3.0.0')
expect(OptionsController.state.sdkVersion).toEqual('react-wagmi-3.0.0')
})

it('should update state correctly on setAllowUnsupportedChain()', () => {
OptionsController.setAllowUnsupportedChain(true)
expect(OptionsController.state.allowUnsupportedChain).toEqual(true)
})
})
16 changes: 12 additions & 4 deletions packages/scaffold-ui/src/modal/w3m-account-button/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
AssetUtil,
ChainController,
CoreHelperUtil,
ModalController
ModalController,
OptionsController
} from '@reown/appkit-core'
import type { WuiAccountButton } from '@reown/appkit-ui'
import { LitElement, html } from 'lit'
Expand Down Expand Up @@ -39,7 +40,12 @@ class W3mAccountButtonBase extends LitElement {

@state() private networkImage = AssetUtil.getNetworkImage(this.network)

@state() private isSupported = true
// eslint-disable-next-line no-nested-ternary
@state() private isSupported = OptionsController.state.allowUnsupportedChain
? true
: ChainController.state.activeChain
? ChainController.checkIfSupportedNetwork(ChainController.state.activeChain)
: true

// -- Lifecycle ----------------------------------------- //
public constructor() {
Expand Down Expand Up @@ -82,7 +88,9 @@ class W3mAccountButtonBase extends LitElement {
return html`
<wui-account-button
.disabled=${Boolean(this.disabled)}
.isUnsupportedChain=${!this.isSupported}
.isUnsupportedChain=${OptionsController.state.allowUnsupportedChain
? false
: !this.isSupported}
address=${ifDefined(CoreHelperUtil.getPlainAddress(this.caipAddress))}
profileName=${ifDefined(this.profileName)}
networkSrc=${ifDefined(this.networkImage)}
Expand All @@ -101,7 +109,7 @@ class W3mAccountButtonBase extends LitElement {

// -- Private ------------------------------------------- //
private onClick() {
if (this.isSupported) {
if (this.isSupported || OptionsController.state.allowUnsupportedChain) {
ModalController.open()
} else {
ModalController.open({ view: 'UnsupportedChain' })
Expand Down
14 changes: 10 additions & 4 deletions packages/scaffold-ui/src/modal/w3m-network-button/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import {
AssetUtil,
ChainController,
EventsController,
ModalController
ModalController,
OptionsController
} from '@reown/appkit-core'
import type { WuiNetworkButton } from '@reown/appkit-ui'
import { LitElement, html } from 'lit'
Expand All @@ -31,7 +32,12 @@ class W3mNetworkButtonBase extends LitElement {

@state() private loading = ModalController.state.loading

@state() private isSupported = true
// eslint-disable-next-line no-nested-ternary
@state() private isSupported = OptionsController.state.allowUnsupportedChain
? true
: ChainController.state.activeChain
? ChainController.checkIfSupportedNetwork(ChainController.state.activeChain)
: true

// -- Lifecycle ----------------------------------------- //
public constructor() {
Expand Down Expand Up @@ -69,7 +75,7 @@ class W3mNetworkButtonBase extends LitElement {
return html`
<wui-network-button
.disabled=${Boolean(this.disabled || this.loading)}
.isUnsupportedChain=${!isSupported}
.isUnsupportedChain=${OptionsController.state.allowUnsupportedChain ? false : !isSupported}
imageSrc=${ifDefined(this.networkImage)}
@click=${this.onClick.bind(this)}
>
Expand All @@ -82,7 +88,7 @@ class W3mNetworkButtonBase extends LitElement {
// -- Private ------------------------------------------- //
private getLabel() {
if (this.network) {
if (!this.isSupported) {
if (!this.isSupported && !OptionsController.state.allowUnsupportedChain) {
return 'Switch Network'
}

Expand Down
124 changes: 124 additions & 0 deletions packages/scaffold-ui/test/modal/w3m-account-button.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import { expect, html, fixture } from '@open-wc/testing'

import {
AccountController,
ChainController,
OptionsController,
ModalController,
RouterController
} from '@reown/appkit-core'
import { W3mAccountButton } from '../../src/modal/w3m-account-button'
import { describe, it, afterEach, vi } from 'vitest'
import type { CaipNetwork } from '@reown/appkit-common'

const mockCaipNetwork: CaipNetwork = {
chainNamespace: 'eip155',
caipNetworkId: 'eip155:1',
id: 1,
name: '',
nativeCurrency: { name: '', symbol: '', decimals: 0 },
rpcUrls: { default: { http: [], webSocket: undefined } }
}

const mockCaipAddress = 'eip155:1:0x0000000000000000000000000000000000000000'
describe('W3mAccountButton', () => {
afterEach(() => {
vi.clearAllMocks()
})

it('should set isUnsupportedChain to false when allowUnsupportedChain is true', async () => {
vi.spyOn(ChainController.state, 'activeChain', 'get').mockReturnValue('eip155')
vi.spyOn(ChainController, 'checkIfSupportedNetwork').mockReturnValue(true)
vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({
...OptionsController.state,
allowUnsupportedChain: true
})

vi.spyOn(AccountController, 'state', 'get').mockReturnValue({
...AccountController.state,
profileName: 'test'
})

const button = (await fixture(
html`<w3m-account-button></w3m-account-button>`
)) as W3mAccountButton

const accountButton = button.shadowRoot?.querySelector('wui-account-button')
expect(accountButton).to.exist

expect(accountButton?.isUnsupportedChain).to.equal(false)
})

it('should set isUnsupportedChain to true when allowUnsupportedChain is false and chain is unsupported', async () => {
vi.spyOn(ChainController.state, 'activeChain', 'get').mockReturnValue('eip155')
vi.spyOn(ChainController.state, 'activeCaipNetwork', 'get').mockReturnValue(mockCaipNetwork)
vi.spyOn(ChainController, 'checkIfSupportedNetwork').mockReturnValue(false)
vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({
...OptionsController.state,
allowUnsupportedChain: false
})

const button = (await fixture(
html`<w3m-account-button></w3m-account-button>`
)) as W3mAccountButton

const accountButton = button.shadowRoot?.querySelector('wui-account-button')
expect(accountButton).to.exist
expect(accountButton?.isUnsupportedChain).to.equal(true)
})

describe('onClick behavior', () => {
it('should open modal normally when chain is supported', async () => {
vi.spyOn(ChainController.state, 'activeChain', 'get').mockReturnValue('eip155')
vi.spyOn(ChainController, 'checkIfSupportedNetwork').mockReturnValue(true)
vi.spyOn(ChainController.state, 'activeCaipAddress', 'get').mockReturnValue(mockCaipAddress)

vi.spyOn(ModalController, 'open')

const button = await fixture(html`<w3m-account-button></w3m-account-button>`)
const accountButton = button.shadowRoot?.querySelector('wui-account-button')

await accountButton?.click()

expect(RouterController.state.view).to.equal('Account')
})

it('should open modal normally when chain is not supported and allowUnsupportedChain is true', async () => {
vi.spyOn(ChainController.state, 'activeChain', 'get').mockReturnValue('eip155')
vi.spyOn(ChainController, 'checkIfSupportedNetwork').mockReturnValue(false)
vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({
...OptionsController.state,
allowUnsupportedChain: true
})
vi.spyOn(ChainController.state, 'activeCaipAddress', 'get').mockReturnValue(mockCaipAddress)

vi.spyOn(ModalController, 'open')

const button = await fixture(html`<w3m-account-button></w3m-account-button>`)
const accountButton = button.shadowRoot?.querySelector('wui-account-button')

await accountButton?.click()

expect(RouterController.state.view).to.equal('Account')
})

it('should open modal in UnsupportedChain view when chain is not supported and allowUnsupportedChain is false', async () => {
vi.spyOn(ChainController.state, 'activeChain', 'get').mockReturnValue('eip155')
vi.spyOn(ChainController, 'checkIfSupportedNetwork').mockReturnValue(false)
vi.spyOn(OptionsController, 'state', 'get').mockReturnValue({
...OptionsController.state,
allowUnsupportedChain: false
})
vi.spyOn(ChainController.state, 'activeCaipAddress', 'get').mockReturnValue(mockCaipAddress)

vi.spyOn(ModalController, 'open')

const button = await fixture(html`<w3m-account-button></w3m-account-button>`)
const accountButton = button.shadowRoot?.querySelector('wui-account-button')

await accountButton?.click()

expect(RouterController.state.view).to.equal('UnsupportedChain')
})
})
})
Loading
Loading