From cf1e0b18c21dba75240f6f261697598e3e6704c9 Mon Sep 17 00:00:00 2001 From: MK Date: Fri, 13 Dec 2024 16:05:25 +0000 Subject: [PATCH 01/26] chore: adapter improvement --- packages/adapters/wagmi/src/client.ts | 73 +++--- .../wagmi/src/connectors/AuthConnector.ts | 1 - packages/appkit/exports/constants.ts | 2 +- .../src/adapters/ChainAdapterBlueprint.ts | 59 ++--- packages/appkit/src/adapters/index.ts | 1 + packages/appkit/src/client.ts | 208 +++++++----------- packages/core/exports/index.ts | 5 +- .../src/controllers/ConnectorController.ts | 3 +- 8 files changed, 137 insertions(+), 215 deletions(-) diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index 94e840c4ba..39cb1d274e 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -1,6 +1,6 @@ import type UniversalProvider from '@walletconnect/universal-provider' -import type { AppKitNetwork, BaseNetwork, CaipNetwork } from '@reown/appkit-common' -import { AdapterBlueprint } from '@reown/appkit/adapters' +import type { AppKitNetwork, BaseNetwork, CaipNetwork, ChainNamespace } from '@reown/appkit-common' +import { AdapterBlueprint, type ChainAdapterConnector } from '@reown/appkit/adapters' import { CoreHelperUtil } from '@reown/appkit-core' import { connect, @@ -27,7 +27,8 @@ import { getAccount, prepareTransactionRequest, reconnect, - watchPendingTransactions + watchPendingTransactions, + watchConnectors } from '@wagmi/core' import { type Chain } from '@wagmi/core/chains' @@ -186,7 +187,6 @@ export class WagmiAdapter extends AdapterBlueprint { } } }) - watchConnections(this.wagmiConfig, { onChange: connections => { if (connections.length === 0) { @@ -232,9 +232,7 @@ export class WagmiAdapter extends AdapterBlueprint { customConnectors.push( authConnector({ chains: this.wagmiChains, - options: { projectId: options.projectId }, - provider: this.availableConnectors.find(c => c.id === ConstantsUtil.AUTH_CONNECTOR_ID) - ?.provider as W3mFrameProvider + options: { projectId: options.projectId } }) ) } @@ -359,40 +357,41 @@ export class WagmiAdapter extends AdapterBlueprint { } public syncConnectors(options: AppKitOptions, appKit: AppKit) { - this.addWagmiConnectors(options, appKit) - - const connectors = this.wagmiConfig.connectors.map(connector => ({ - ...connector, - chain: this.namespace - })) + watchConnectors(this.wagmiConfig, { + onChange: async connectors => { + const prepareConnectors = connectors.map(async connector => { + let provider: Provider | W3mFrameProvider | UniversalProvider | undefined = undefined + + if (connector.id === ConstantsUtil.AUTH_CONNECTOR_ID) { + provider = (await connector.getProvider().catch(() => undefined)) as W3mFrameProvider + } + + const preparedConnector: ChainAdapterConnector = { + id: connector.id, + explorerId: PresetsUtil.ConnectorExplorerIds[connector.id], + imageUrl: options?.connectorImages?.[connector.id] ?? connector.icon, + name: PresetsUtil.ConnectorNamesMap[connector.id] ?? connector.name, + imageId: PresetsUtil.ConnectorImageIds[connector.id], + type: PresetsUtil.ConnectorTypesMap[connector.type] ?? 'EXTERNAL', + info: + connector.id === ConstantsUtil.INJECTED_CONNECTOR_ID + ? undefined + : { rdns: connector.id }, + provider, + chain: this.namespace as ChainNamespace, + chains: [] + } + + return preparedConnector + }) - const uniqueIds = new Set() - const filteredConnectors = connectors.filter(item => { - const isDuplicate = uniqueIds.has(item.id) - uniqueIds.add(item.id) + const preparedConnectors = await Promise.all(prepareConnectors) - return !isDuplicate - }) - - filteredConnectors.forEach(connector => { - const shouldSkip = ConstantsUtil.AUTH_CONNECTOR_ID === connector.id - - const injectedConnector = connector.id === ConstantsUtil.INJECTED_CONNECTOR_ID - - if (!shouldSkip && this.namespace) { - this.addConnector({ - id: connector.id, - explorerId: PresetsUtil.ConnectorExplorerIds[connector.id], - imageUrl: options?.connectorImages?.[connector.id] ?? connector.icon, - name: PresetsUtil.ConnectorNamesMap[connector.id] ?? connector.name, - imageId: PresetsUtil.ConnectorImageIds[connector.id], - type: PresetsUtil.ConnectorTypesMap[connector.type] ?? 'EXTERNAL', - info: injectedConnector ? undefined : { rdns: connector.id }, - chain: this.namespace, - chains: [] - }) + this.addConnector(preparedConnectors) } }) + + this.addWagmiConnectors(options, appKit) } public async syncConnection( diff --git a/packages/adapters/wagmi/src/connectors/AuthConnector.ts b/packages/adapters/wagmi/src/connectors/AuthConnector.ts index a82190a9a6..29f28453c0 100644 --- a/packages/adapters/wagmi/src/connectors/AuthConnector.ts +++ b/packages/adapters/wagmi/src/connectors/AuthConnector.ts @@ -16,7 +16,6 @@ interface W3mFrameProviderOptions { export type AuthParameters = { chains?: CreateConfigParameters['chains'] options: W3mFrameProviderOptions - provider: W3mFrameProvider } // -- Connector ------------------------------------------------------------------------------------ diff --git a/packages/appkit/exports/constants.ts b/packages/appkit/exports/constants.ts index d8315b844b..ff90ead2f6 100644 --- a/packages/appkit/exports/constants.ts +++ b/packages/appkit/exports/constants.ts @@ -1 +1 @@ -export const PACKAGE_VERSION = '1.5.3' +export const PACKAGE_VERSION = '1.6.0' diff --git a/packages/appkit/src/adapters/ChainAdapterBlueprint.ts b/packages/appkit/src/adapters/ChainAdapterBlueprint.ts index 3a7c0f09e9..ed5c799d9d 100644 --- a/packages/appkit/src/adapters/ChainAdapterBlueprint.ts +++ b/packages/appkit/src/adapters/ChainAdapterBlueprint.ts @@ -14,22 +14,28 @@ import { type Connector as AppKitConnector, type AuthConnector, type Metadata, - type Tokens + type Tokens, + type ConnectorWithProviders } from '@reown/appkit-core' -import type UniversalProvider from '@walletconnect/universal-provider' -import type { W3mFrameProvider } from '@reown/appkit-wallet' -import { ConstantsUtil, PresetsUtil } from '@reown/appkit-utils' import type { AppKitOptions } from '../utils/index.js' import type { AppKit } from '../client.js' import { snapshot } from 'valtio/vanilla' -type EventName = 'disconnect' | 'accountChanged' | 'switchNetwork' | 'pendingTransactions' +type EventName = + | 'disconnect' + | 'accountChanged' + | 'switchNetwork' + | 'pendingTransactions' + | 'addConnectors' + type EventData = { disconnect: () => void accountChanged: { address: string; chainId?: number | string } switchNetwork: { address?: string; chainId: number | string } pendingTransactions: () => void + addConnectors: ConnectorWithProviders[] } + type EventCallback = (data: EventData[T]) => void /** @@ -43,7 +49,7 @@ export abstract class AdapterBlueprint< public caipNetworks?: CaipNetwork[] public projectId?: string - protected availableConnectors: Connector[] = [] + protected allConnectors: Connector[] = [] protected connector?: Connector protected provider?: Connector['provider'] @@ -74,7 +80,7 @@ export abstract class AdapterBlueprint< * @returns {Connector[]} An array of available connectors */ public get connectors(): Connector[] { - return this.availableConnectors + return this.allConnectors } /** @@ -85,43 +91,11 @@ export abstract class AdapterBlueprint< return this.caipNetworks || [] } - /** - * Sets the universal provider for WalletConnect. - * @param {UniversalProvider} universalProvider - The universal provider instance - */ - public setUniversalProvider(universalProvider: UniversalProvider) { - this.addConnector({ - id: ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID, - type: 'WALLET_CONNECT', - name: PresetsUtil.ConnectorNamesMap[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID], - provider: universalProvider, - imageId: PresetsUtil.ConnectorImageIds[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID], - chain: this.namespace, - chains: [] - } as unknown as Connector) - } - - /** - * Sets the auth provider. - * @param {W3mFrameProvider} authProvider - The auth provider instance - */ - public setAuthProvider(authProvider: W3mFrameProvider): void { - this.addConnector({ - id: ConstantsUtil.AUTH_CONNECTOR_ID, - type: 'AUTH', - name: 'Auth', - provider: authProvider, - imageId: PresetsUtil.ConnectorImageIds[ConstantsUtil.AUTH_CONNECTOR_ID], - chain: this.namespace, - chains: [] - } as unknown as Connector) - } - /** * Adds one or more connectors to the available connectors list. * @param {...Connector} connectors - The connectors to add */ - protected addConnector(...connectors: Connector[]) { + protected addConnector(connectors: Connector[]) { if (connectors.some(connector => connector.id === 'ID_AUTH')) { const authConnector = connectors.find( connector => connector.id === 'ID_AUTH' @@ -145,7 +119,8 @@ export abstract class AdapterBlueprint< } const connectorsAdded = new Set() - this.availableConnectors = [...connectors, ...this.availableConnectors].filter(connector => { + + this.allConnectors = [...this.allConnectors, ...connectors].filter(connector => { if (connectorsAdded.has(connector.id)) { return false } @@ -154,6 +129,8 @@ export abstract class AdapterBlueprint< return true }) + + this.emit('addConnectors', this.allConnectors) } protected setStatus(status: AccountControllerState['status'], chainNamespace?: ChainNamespace) { diff --git a/packages/appkit/src/adapters/index.ts b/packages/appkit/src/adapters/index.ts index 9babae1e07..f09b2ba1f4 100644 --- a/packages/appkit/src/adapters/index.ts +++ b/packages/appkit/src/adapters/index.ts @@ -1 +1,2 @@ export { AdapterBlueprint } from './ChainAdapterBlueprint.js' +export type { ChainAdapterConnector } from './ChainAdapterConnector.js' diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index a6d9ef784f..d84c81db59 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -12,7 +12,6 @@ import { type UseAppKitNetworkReturn, type NetworkControllerClient, type ConnectionControllerClient, - ConstantsUtil as CoreConstantsUtil, type ConnectorType, type WriteContractArgs, type Provider, @@ -50,7 +49,6 @@ import { } from '@reown/appkit-core' import { setColorTheme, setThemeVariables } from '@reown/appkit-ui' import { - ConstantsUtil, type CaipNetwork, type ChainNamespace, type CaipAddress, @@ -80,7 +78,6 @@ import type { AdapterBlueprint } from './adapters/ChainAdapterBlueprint.js' import UniversalProvider from '@walletconnect/universal-provider' import type { SessionTypes } from '@walletconnect/types' import type { UniversalProviderOpts } from '@walletconnect/universal-provider' -import { W3mFrameProviderSingleton } from './auth-provider/W3MFrameProviderSingleton.js' declare global { interface Window { @@ -182,6 +179,8 @@ export class AppKit { private defaultCaipNetwork?: CaipNetwork + private isListeningToAuthProvider = false + public constructor( options: AppKitOptions & { adapters?: ChainAdapter[] @@ -204,15 +203,11 @@ export class AppKit { ) { this.caipNetworks = this.extendCaipNetworks(options) this.defaultCaipNetwork = this.extendDefaultCaipNetwork(options) - await this.initControllers(options) - this.createAuthProvider() - await this.createUniversalProvider() + this.initControllers(options) this.createClients() ChainController.initialize(options.adapters ?? [], this.caipNetworks) - this.chainAdapters = await this.createAdapters( - options.adapters as unknown as AdapterBlueprint[] - ) - await this.initChainAdapters() + this.chainAdapters = this.createAdapters(options.adapters as unknown as AdapterBlueprint[]) + this.initChainAdapters(options.adapters as unknown as AdapterBlueprint[]) this.syncRequestedNetworks() await this.initOrContinue() await this.syncExistingConnection() @@ -641,7 +636,7 @@ export class AppKit { } // -- Private ------------------------------------------------------------------ - private async initControllers( + private initControllers( options: AppKitOptions & { adapters?: ChainAdapter[] } & { @@ -710,25 +705,27 @@ export class AppKit { OptionsController.setSIWX(options.siwx) } - const evmAdapter = options.adapters?.find( - adapter => adapter.namespace === ConstantsUtil.CHAIN.EVM - ) - - // Set the SIWE client for EVM chains - if (evmAdapter) { - if (options.siweConfig) { - if (options.siwx) { - throw new Error('Cannot set both `siweConfig` and `siwx` options') - } - - const siwe = await import('@reown/appkit-siwe') - if (typeof siwe.mapToSIWX !== 'function') { - throw new Error('Please update the `@reown/appkit-siwe` package to the latest version') - } - - OptionsController.setSIWX(siwe.mapToSIWX(options.siweConfig)) - } - } + /* + * Const evmAdapter = options.adapters?.find( + * adapter => adapter.namespace === ConstantsUtil.CHAIN.EVM + * ) + * + * // Set the SIWE client for EVM chains + * if (evmAdapter) { + * if (options.siweConfig) { + * if (options.siwx) { + * throw new Error('Cannot set both `siweConfig` and `siwx` options') + * } + * + * const siwe = await import('@reown/appkit-siwe') + * if (typeof siwe.mapToSIWX !== 'function') { + * throw new Error('Please update the `@reown/appkit-siwe` package to the latest version') + * } + * + * OptionsController.setSIWX(siwe.mapToSIWX(options.siweConfig)) + * } + * } + */ } private getDefaultMetaData() { @@ -794,9 +791,7 @@ export class AppKit { connectWalletConnect: async (onUri: (uri: string) => void) => { const adapter = this.getAdapter(ChainController.state.activeChain as ChainNamespace) - this.universalProvider?.on('display_uri', (uri: string) => { - onUri(uri) - }) + this.universalProvider?.on('display_uri', onUri) this.setClientId( (await this.universalProvider?.client?.core?.crypto?.getClientId()) || null @@ -840,37 +835,16 @@ export class AppKit { throw new Error('Adapter not found') } - let res: AdapterBlueprint.ConnectResult | undefined = undefined - try { - res = await adapter.connect({ - id, - info, - type, - provider, - chainId: caipNetwork?.id || this.getCaipNetwork()?.id, - rpcUrl: - caipNetwork?.rpcUrls?.default?.http?.[0] || - this.getCaipNetwork()?.rpcUrls?.default?.http?.[0] - }) - /** - * In some cases with wagmi connectors, the connector is already connected - * which throws an `Is already connected`error. In such cases, we need to reconnect - * to restore the session. - * We check if the reconnect method exists (which it does for wagmi connectors) and if so - * we attempt to reconnect and restore the session state. - */ - } catch (error) { - if (!adapter?.reconnect) { - throw new Error('Adapter is not able to connect') - } - await adapter.reconnect({ - id, - info, - type, - provider, - chainId: this.getCaipNetwork()?.id - }) - } + const res = await adapter.connect({ + id, + info, + type, + provider, + chainId: caipNetwork?.id || this.getCaipNetwork()?.id, + rpcUrl: + caipNetwork?.rpcUrls?.default?.http?.[0] || + this.getCaipNetwork()?.rpcUrls?.default?.http?.[0] + }) if (res) { this.syncProvider({ @@ -1134,6 +1108,12 @@ export class AppKit { } private async listenAuthConnector(provider: W3mFrameProvider) { + if (this.isListeningToAuthProvider) { + return + } + + this.isListeningToAuthProvider = true + this.setLoading(true) const isLoginEmailUsed = provider.getLoginEmailUsed() this.setLoading(isLoginEmailUsed) @@ -1433,27 +1413,6 @@ export class AppKit { address = AccountController.state.address as string } - if ((adapter as ChainAdapter)?.adapterType === 'wagmi') { - try { - await adapter?.connect({ - id: 'walletConnect', - type: 'WALLET_CONNECT', - chainId: ChainController.state.activeCaipNetwork?.id as string | number - }) - } catch (error) { - /** - * Handle edge case where wagmi detects existing connection but lacks to complete UniversalProvider instance. - * Connection attempt fails due to already connected state - reconnect to restore provider state. - */ - if (adapter?.reconnect) { - adapter?.reconnect({ - id: 'walletConnect', - type: 'WALLET_CONNECT' - }) - } - } - } - this.syncWalletConnectAccounts(chainNamespace) await this.syncAccount({ @@ -1797,30 +1756,7 @@ export class AppKit { return this.universalProvider } - private createAuthProvider() { - const emailEnabled = - this.options?.features?.email === undefined - ? CoreConstantsUtil.DEFAULT_FEATURES.email - : this.options?.features?.email - const socialsEnabled = this.options?.features?.socials - ? this.options?.features?.socials?.length > 0 - : CoreConstantsUtil.DEFAULT_FEATURES.socials - if (this.options?.projectId && (emailEnabled || socialsEnabled)) { - this.authProvider = W3mFrameProviderSingleton.getInstance({ - projectId: this.options.projectId, - onTimeout: () => { - AlertController.open(ErrorUtil.ALERT_ERRORS.SOCIALS_TIMEOUT, 'error') - } - }) - this.listenAuthConnector(this.authProvider) - } - } - - private async createAdapters(blueprints?: AdapterBlueprint[]): Promise { - if (!this.universalProvider) { - this.universalProvider = await this.getUniversalProvider() - } - + private createAdapters(blueprints?: AdapterBlueprint[]) { this.syncRequestedNetworks() return this.chainNamespaces.reduce((adapters, namespace) => { @@ -1834,25 +1770,11 @@ export class AppKit { projectId: this.options?.projectId, networks: this.caipNetworks }) - if (this.universalProvider) { - adapters[namespace].setUniversalProvider(this.universalProvider) - } - if (this.authProvider) { - adapters[namespace].setAuthProvider(this.authProvider) - } - - adapters[namespace].syncConnectors(this.options, this) } else { adapters[namespace] = new UniversalAdapter({ namespace, networks: this.caipNetworks }) - if (this.universalProvider) { - adapters[namespace].setUniversalProvider(this.universalProvider) - } - if (this.authProvider) { - adapters[namespace].setAuthProvider(this.authProvider) - } } ChainController.state.chains.set(namespace, { @@ -1869,17 +1791,37 @@ export class AppKit { }, {} as Adapters) } - private async initChainAdapters() { - await Promise.all( - // eslint-disable-next-line @typescript-eslint/require-await - this.chainNamespaces.map(async namespace => { - if (this.options) { - this.listenAdapter(namespace) + private listenConnectors(chainNamespace: ChainNamespace) { + const adapter = this.getAdapter(chainNamespace) + + if (!adapter) { + return + } + + adapter.on('addConnectors', connectors => { + const authConnector = connectors.find(c => c.id === UtilConstantsUtil.AUTH_CONNECTOR_ID) + + if (authConnector) { + this.listenAuthConnector(authConnector.provider as W3mFrameProvider) + } + + this.setConnectors(connectors) + }) + } + + private initChainAdapters(blueprints: AdapterBlueprint[]) { + this.chainNamespaces.forEach(namespace => { + const blueprint = blueprints?.find(b => b.namespace === namespace) + + this.listenConnectors(namespace) + + if (blueprint) { + this.chainAdapters?.[namespace].syncConnectors(this.options, this) + } + + this.listenAdapter(namespace) + }) - this.setConnectors(this.chainAdapters?.[namespace]?.connectors || []) - } - }) - ) this.listenWalletConnect() } 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..68497686b2 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 { @@ -158,6 +158,7 @@ export const ConnectorController = { getAuthConnector(): AuthConnector | undefined { const activeNamespace = ChainController.state.activeChain const authConnector = state.connectors.find(c => c.id === 'ID_AUTH') + if (!authConnector) { return undefined } From 995ee1ef1d066a60c15a7d3268ac9db50a7ad179 Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 12:36:29 +0000 Subject: [PATCH 02/26] chore: create universal provider and auth provider after adapter creation --- packages/adapters/ethers/src/client.ts | 72 ++++++++------ packages/adapters/ethers5/src/client.ts | 72 ++++++++------ packages/adapters/solana/src/client.ts | 72 +++++++------- packages/adapters/wagmi/src/client.ts | 24 ++++- .../src/connectors/AuthConnectorExport.ts | 13 +-- .../src/adapters/ChainAdapterBlueprint.ts | 39 ++++++++ packages/appkit/src/client.ts | 98 ++++++++++++------- 7 files changed, 244 insertions(+), 146 deletions(-) diff --git a/packages/adapters/ethers/src/client.ts b/packages/adapters/ethers/src/client.ts index 1ecde2036f..b3210af423 100644 --- a/packages/adapters/ethers/src/client.ts +++ b/packages/adapters/ethers/src/client.ts @@ -1,4 +1,4 @@ -import { AdapterBlueprint } from '@reown/appkit/adapters' +import { AdapterBlueprint, type ChainAdapterConnector } from '@reown/appkit/adapters' import type { CaipNetwork } from '@reown/appkit-common' import { ConstantsUtil as CommonConstantsUtil } from '@reown/appkit-common' import { @@ -256,30 +256,36 @@ export class EthersAdapter extends AdapterBlueprint { this.listenInjectedConnector(true) } - const connectors = Object.keys(this.ethersConfig || {}).filter( + const validConnectors = Object.keys(this.ethersConfig || {}).filter( key => key !== 'metadata' && key !== 'EIP6963' ) - connectors.forEach(connector => { - const key = connector === 'coinbase' ? 'coinbaseWalletSDK' : connector - - const injectedConnector = connector === ConstantsUtil.INJECTED_CONNECTOR_ID - - if (this.namespace) { - this.addConnector({ - id: key, - explorerId: PresetsUtil.ConnectorExplorerIds[key], - imageUrl: options?.connectorImages?.[key], - name: PresetsUtil.ConnectorNamesMap[key], - imageId: PresetsUtil.ConnectorImageIds[key], - type: PresetsUtil.ConnectorTypesMap[key] ?? 'EXTERNAL', - info: injectedConnector ? undefined : { rdns: key }, - chain: this.namespace, - chains: [], - provider: this.ethersConfig?.[connector as keyof ProviderType] as Provider - }) - } - }) + const connectors = validConnectors + .map(connector => { + const id = connector === 'coinbase' ? 'coinbaseWalletSDK' : connector + + const isInjected = connector === ConstantsUtil.INJECTED_CONNECTOR_ID + + if (this.namespace) { + return { + id, + explorerId: PresetsUtil.ConnectorExplorerIds[id], + imageUrl: options?.connectorImages?.[id], + name: PresetsUtil.ConnectorNamesMap[id], + imageId: PresetsUtil.ConnectorImageIds[id], + type: PresetsUtil.ConnectorTypesMap[id] ?? 'EXTERNAL', + info: isInjected ? undefined : { rdns: id }, + chain: this.namespace, + chains: [], + provider: this.ethersConfig?.[connector as keyof ProviderType] as Provider + } as ChainAdapterConnector + } + + return undefined + }) + .filter(Boolean) + + this.addConnector(connectors as ChainAdapterConnector[]) } public async connectWalletConnect(onUri: (uri: string) => void) { @@ -311,16 +317,18 @@ export class EthersAdapter extends AdapterBlueprint { const type = PresetsUtil.ConnectorTypesMap[ConstantsUtil.EIP6963_CONNECTOR_ID] if (type && this.namespace) { - this.addConnector({ - id: info?.rdns || '', - type, - imageUrl: info?.icon, - name: info?.name, - provider, - info, - chain: this.namespace, - chains: [] - }) + this.addConnector([ + { + id: info?.rdns || '', + type, + imageUrl: info?.icon, + name: info?.name, + provider, + info, + chain: this.namespace, + chains: [] + } + ]) } } } diff --git a/packages/adapters/ethers5/src/client.ts b/packages/adapters/ethers5/src/client.ts index 240e48074c..9579590aad 100644 --- a/packages/adapters/ethers5/src/client.ts +++ b/packages/adapters/ethers5/src/client.ts @@ -1,4 +1,4 @@ -import { AdapterBlueprint } from '@reown/appkit/adapters' +import { AdapterBlueprint, type ChainAdapterConnector } from '@reown/appkit/adapters' import type { CaipNetwork } from '@reown/appkit-common' import { ConstantsUtil as CommonConstantsUtil } from '@reown/appkit-common' import { @@ -257,30 +257,36 @@ export class Ethers5Adapter extends AdapterBlueprint { this.listenInjectedConnector(true) } - const connectors = Object.keys(this.ethersConfig || {}).filter( + const validConnectors = Object.keys(this.ethersConfig || {}).filter( key => key !== 'metadata' && key !== 'EIP6963' ) - connectors.forEach(connector => { - const key = connector === 'coinbase' ? 'coinbaseWalletSDK' : connector - - const injectedConnector = connector === ConstantsUtil.INJECTED_CONNECTOR_ID - - if (this.namespace) { - this.addConnector({ - id: key, - explorerId: PresetsUtil.ConnectorExplorerIds[key], - imageUrl: options?.connectorImages?.[key], - name: PresetsUtil.ConnectorNamesMap[key], - imageId: PresetsUtil.ConnectorImageIds[key], - type: PresetsUtil.ConnectorTypesMap[key] ?? 'EXTERNAL', - info: injectedConnector ? undefined : { rdns: key }, - chain: this.namespace, - chains: [], - provider: this.ethersConfig?.[connector as keyof ProviderType] as Provider - }) - } - }) + const connectors = validConnectors + .map(connector => { + const key = connector === 'coinbase' ? 'coinbaseWalletSDK' : connector + + const isInjected = connector === ConstantsUtil.INJECTED_CONNECTOR_ID + + if (this.namespace) { + return { + id: key, + explorerId: PresetsUtil.ConnectorExplorerIds[key], + imageUrl: options?.connectorImages?.[key], + name: PresetsUtil.ConnectorNamesMap[key], + imageId: PresetsUtil.ConnectorImageIds[key], + type: PresetsUtil.ConnectorTypesMap[key] ?? 'EXTERNAL', + info: isInjected ? undefined : { rdns: key }, + chain: this.namespace, + chains: [], + provider: this.ethersConfig?.[connector as keyof ProviderType] as Provider + } as ChainAdapterConnector + } + + return undefined + }) + .filter(Boolean) + + this.addConnector(connectors as ChainAdapterConnector[]) } public async connectWalletConnect(onUri: (uri: string) => void) { @@ -312,16 +318,18 @@ export class Ethers5Adapter extends AdapterBlueprint { const type = PresetsUtil.ConnectorTypesMap[ConstantsUtil.EIP6963_CONNECTOR_ID] if (type && this.namespace) { - this.addConnector({ - id: info?.rdns || '', - type, - imageUrl: info?.icon, - name: info?.name, - provider, - info, - chain: this.namespace, - chains: [] - }) + this.addConnector([ + { + id: info?.rdns || '', + type, + imageUrl: info?.icon, + name: info?.name, + provider, + info, + chain: this.namespace, + chains: [] + } + ]) } } } diff --git a/packages/adapters/solana/src/client.ts b/packages/adapters/solana/src/client.ts index 51a4f8a141..e0143ce680 100644 --- a/packages/adapters/solana/src/client.ts +++ b/packages/adapters/solana/src/client.ts @@ -1,4 +1,4 @@ -import { WcHelpersUtil, type AppKit, type AppKitOptions } from '@reown/appkit' +import { WcHelpersUtil, AppKit, type AppKitOptions } from '@reown/appkit' import { ConstantsUtil as CommonConstantsUtil, type CaipNetwork, @@ -100,32 +100,36 @@ export class SolanaAdapter extends AdapterBlueprint { chains: this.caipNetworks as CaipNetwork[] }) - this.addConnector({ - id: ConstantsUtil.AUTH_CONNECTOR_ID, - type: 'AUTH', - provider: this.authProvider as unknown as W3mFrameProvider, - name: 'Auth', - chain: this.namespace as ChainNamespace, - chains: [] - }) + this.addConnector([ + { + id: ConstantsUtil.AUTH_CONNECTOR_ID, + type: 'AUTH', + provider: this.authProvider as unknown as W3mFrameProvider, + name: 'Auth', + chain: this.namespace as ChainNamespace, + chains: [] + } + ]) } // Add Coinbase Wallet if available if (typeof window !== 'undefined' && 'coinbaseSolana' in window) { - this.addConnector({ - id: 'coinbaseWallet', - type: 'EXTERNAL', - // @ts-expect-error window.coinbaseSolana exists - provider: new CoinbaseWalletProvider({ - provider: window.coinbaseSolana as SolanaCoinbaseWallet, - chains: this.caipNetworks as CaipNetwork[], - getActiveChain: () => appKit.getCaipNetwork(this.namespace) as CaipNetwork - }), - name: 'Coinbase Wallet', - chain: this.namespace as ChainNamespace, - explorerId: PresetsUtil.ConnectorExplorerIds[ConstantsUtil.COINBASE_SDK_CONNECTOR_ID], - chains: [] - }) + this.addConnector([ + { + id: 'coinbaseWallet', + type: 'EXTERNAL', + // @ts-expect-error window.coinbaseSolana exists + provider: new CoinbaseWalletProvider({ + provider: window.coinbaseSolana as SolanaCoinbaseWallet, + chains: this.caipNetworks as CaipNetwork[], + getActiveChain: () => appKit.getCaipNetwork(this.namespace) as CaipNetwork + }), + name: 'Coinbase Wallet', + chain: this.namespace as ChainNamespace, + explorerId: PresetsUtil.ConnectorExplorerIds[ConstantsUtil.COINBASE_SDK_CONNECTOR_ID], + chains: [] + } + ]) } // Watch for standard wallet adapters @@ -134,16 +138,18 @@ export class SolanaAdapter extends AdapterBlueprint { () => appKit.getCaipNetwork(this.namespace), (...providers: WalletStandardProvider[]) => { providers.forEach(provider => { - this.addConnector({ - id: PresetsUtil.ConnectorExplorerIds[provider.name] || provider.name, - type: 'ANNOUNCED', - provider: provider as unknown as Provider, - imageUrl: provider.icon, - name: provider.name, - chain: CommonConstantsUtil.CHAIN.SOLANA, - explorerId: PresetsUtil.ConnectorExplorerIds[provider.name], - chains: [] - }) + this.addConnector([ + { + id: PresetsUtil.ConnectorExplorerIds[provider.name] || provider.name, + type: 'ANNOUNCED', + provider: provider as unknown as Provider, + imageUrl: provider.icon, + name: provider.name, + chain: CommonConstantsUtil.CHAIN.SOLANA, + explorerId: PresetsUtil.ConnectorExplorerIds[provider.name], + chains: [] + } + ]) }) } ) diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index 39cb1d274e..dd46cc05f6 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -97,6 +97,16 @@ export class WagmiAdapter extends AdapterBlueprint { this.setupWatchers() } + // Ignoring adding auth provider since we already add it in wagmi + override addAuthProvider() { + return undefined + } + + // Ignoring adding universal provider since we already add it in wagmi + override addUniversalProvider() { + return undefined + } + override async getAccounts( params: AdapterBlueprint.GetAccountsParams ): Promise { @@ -360,10 +370,16 @@ export class WagmiAdapter extends AdapterBlueprint { watchConnectors(this.wagmiConfig, { onChange: async connectors => { const prepareConnectors = connectors.map(async connector => { - let provider: Provider | W3mFrameProvider | UniversalProvider | undefined = undefined - - if (connector.id === ConstantsUtil.AUTH_CONNECTOR_ID) { - provider = (await connector.getProvider().catch(() => undefined)) as W3mFrameProvider + let provider: W3mFrameProvider | UniversalProvider | undefined = undefined + + if ( + connector.id === ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID || + connector.id === ConstantsUtil.AUTH_CONNECTOR_ID + ) { + provider = (await connector.getProvider().catch(() => undefined)) as + | W3mFrameProvider + | UniversalProvider + | undefined } const preparedConnector: ChainAdapterConnector = { diff --git a/packages/adapters/wagmi/src/connectors/AuthConnectorExport.ts b/packages/adapters/wagmi/src/connectors/AuthConnectorExport.ts index 279e382bc7..e724c12deb 100644 --- a/packages/adapters/wagmi/src/connectors/AuthConnectorExport.ts +++ b/packages/adapters/wagmi/src/connectors/AuthConnectorExport.ts @@ -1,8 +1,5 @@ import type { CreateConfigParameters } from '@wagmi/core' import { authConnector as authConnectorWagmi } from './AuthConnector.js' -import { ErrorUtil } from '@reown/appkit-utils' -import { AlertController } from '@reown/appkit-core' -import { W3mFrameProviderSingleton } from '@reown/appkit/auth-provider' interface W3mFrameProviderOptions { projectId: string @@ -14,13 +11,5 @@ export type AuthParameters = { } export function authConnector(parameters: AuthParameters) { - return authConnectorWagmi({ - ...parameters, - provider: W3mFrameProviderSingleton.getInstance({ - projectId: parameters.options.projectId, - onTimeout: () => { - AlertController.open(ErrorUtil.ALERT_ERRORS.SOCIALS_TIMEOUT, 'error') - } - }) - }) + return authConnectorWagmi(parameters) } diff --git a/packages/appkit/src/adapters/ChainAdapterBlueprint.ts b/packages/appkit/src/adapters/ChainAdapterBlueprint.ts index ed5c799d9d..94c8417906 100644 --- a/packages/appkit/src/adapters/ChainAdapterBlueprint.ts +++ b/packages/appkit/src/adapters/ChainAdapterBlueprint.ts @@ -20,6 +20,9 @@ import { import type { AppKitOptions } from '../utils/index.js' import type { AppKit } from '../client.js' import { snapshot } from 'valtio/vanilla' +import type UniversalProvider from '@walletconnect/universal-provider' +import { ConstantsUtil, PresetsUtil } from '@reown/appkit-utils' +import type { W3mFrameProvider } from '@reown/appkit-wallet' type EventName = | 'disconnect' @@ -91,6 +94,42 @@ export abstract class AdapterBlueprint< return this.caipNetworks || [] } + /** + * Sets the universal provider for WalletConnect. + * @param {UniversalProvider} addUniversalProvider - The universal provider instance + */ + public addUniversalProvider(universalProvider: UniversalProvider) { + this.addConnector([ + { + id: ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID, + type: 'WALLET_CONNECT', + name: PresetsUtil.ConnectorNamesMap[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID], + provider: universalProvider, + imageId: PresetsUtil.ConnectorImageIds[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID], + chain: this.namespace, + chains: [] + } as unknown as Connector + ]) + } + + /** + * Sets the auth provider. + * @param {W3mFrameProvider} addAuthConnector - The auth provider instance + */ + public addAuthProvider(authProvider: W3mFrameProvider): void { + this.addConnector([ + { + id: ConstantsUtil.AUTH_CONNECTOR_ID, + type: 'AUTH', + name: 'Auth', + provider: authProvider, + imageId: PresetsUtil.ConnectorImageIds[ConstantsUtil.AUTH_CONNECTOR_ID], + chain: this.namespace, + chains: [] + } as unknown as Connector + ]) + } + /** * Adds one or more connectors to the available connectors list. * @param {...Connector} connectors - The connectors to add diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index d84c81db59..7b181a5094 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -19,6 +19,7 @@ import { type EstimateGasTransactionArgs, type AccountControllerState, type AdapterNetworkState, + ConstantsUtil as CoreConstantsUtil, type Features, SIWXUtil, type ConnectionStatus, @@ -78,6 +79,7 @@ import type { AdapterBlueprint } from './adapters/ChainAdapterBlueprint.js' import UniversalProvider from '@walletconnect/universal-provider' import type { SessionTypes } from '@walletconnect/types' import type { UniversalProviderOpts } from '@walletconnect/universal-provider' +import { W3mFrameProviderSingleton } from './auth-provider/W3MFrameProviderSingleton.js' declare global { interface Window { @@ -179,8 +181,6 @@ export class AppKit { private defaultCaipNetwork?: CaipNetwork - private isListeningToAuthProvider = false - public constructor( options: AppKitOptions & { adapters?: ChainAdapter[] @@ -207,7 +207,7 @@ export class AppKit { this.createClients() ChainController.initialize(options.adapters ?? [], this.caipNetworks) this.chainAdapters = this.createAdapters(options.adapters as unknown as AdapterBlueprint[]) - this.initChainAdapters(options.adapters as unknown as AdapterBlueprint[]) + this.initChainAdapters() this.syncRequestedNetworks() await this.initOrContinue() await this.syncExistingConnection() @@ -658,8 +658,6 @@ export class AppKit { return } - this.adapters = options.adapters - const defaultMetaData = this.getDefaultMetaData() if (!options.metadata && defaultMetaData) { @@ -1108,12 +1106,6 @@ export class AppKit { } private async listenAuthConnector(provider: W3mFrameProvider) { - if (this.isListeningToAuthProvider) { - return - } - - this.isListeningToAuthProvider = true - this.setLoading(true) const isLoginEmailUsed = provider.getLoginEmailUsed() this.setLoading(isLoginEmailUsed) @@ -1741,7 +1733,9 @@ export class AppKit { logger } - this.universalProvider = await UniversalProvider.init(universalProviderOptions) + const universalProvider = await UniversalProvider.init(universalProviderOptions) + this.universalProvider = universalProvider + this.listenWalletConnect() } public async getUniversalProvider() { @@ -1756,6 +1750,38 @@ export class AppKit { return this.universalProvider } + private createAuthProvider() { + const isEmailEnabled = + this.options?.features?.email === undefined + ? CoreConstantsUtil.DEFAULT_FEATURES.email + : this.options?.features?.email + const isSocialsEnabled = this.options?.features?.socials + ? this.options?.features?.socials?.length > 0 + : CoreConstantsUtil.DEFAULT_FEATURES.socials + if (this.options?.projectId && (isEmailEnabled || isSocialsEnabled)) { + this.authProvider = W3mFrameProviderSingleton.getInstance({ + projectId: this.options.projectId, + onTimeout: () => { + AlertController.open(ErrorUtil.ALERT_ERRORS.SOCIALS_TIMEOUT, 'error') + } + }) + this.listenAuthConnector(this.authProvider) + } + } + + private async createUniversalProviderForAdapter(chainNamespace: ChainNamespace) { + await this.getUniversalProvider() + + if (this.universalProvider) { + this.chainAdapters?.[chainNamespace].addUniversalProvider(this.universalProvider) + } + } + + private createAuthProviderForAdapter(chainNamespace: ChainNamespace) { + this.createAuthProvider() + this.chainAdapters?.[chainNamespace].addAuthProvider(this.authProvider as W3mFrameProvider) + } + private createAdapters(blueprints?: AdapterBlueprint[]) { this.syncRequestedNetworks() @@ -1770,6 +1796,12 @@ export class AppKit { projectId: this.options?.projectId, networks: this.caipNetworks }) + if (this.universalProvider) { + adapters[namespace].addUniversalProvider(this.universalProvider) + } + if (this.authProvider) { + adapters[namespace].addAuthProvider(this.authProvider) + } } else { adapters[namespace] = new UniversalAdapter({ namespace, @@ -1791,38 +1823,38 @@ export class AppKit { }, {} as Adapters) } - private listenConnectors(chainNamespace: ChainNamespace) { + private createConnectorsForAdapter(namespace: ChainNamespace) { + this.createUniversalProviderForAdapter(namespace) + this.createAuthProviderForAdapter(namespace) + } + + private onConnectors(chainNamespace: ChainNamespace) { const adapter = this.getAdapter(chainNamespace) - if (!adapter) { - return - } + adapter?.on('addConnectors', connectors => { + this.setConnectors(connectors) - adapter.on('addConnectors', connectors => { - const authConnector = connectors.find(c => c.id === UtilConstantsUtil.AUTH_CONNECTOR_ID) + const walletConnect = connectors.find( + ({ id }) => id === UtilConstantsUtil.WALLET_CONNECT_CONNECTOR_ID + ) - if (authConnector) { - this.listenAuthConnector(authConnector.provider as W3mFrameProvider) + /* + * Sometimes w3m-modal doesn't have all connectors at once, and we need to check if + * walletConnect connector image exists and fetch the image if it doesn't. + */ + if (walletConnect && !AssetUtil.getWalletImageById(walletConnect.imageId)) { + ApiController._fetchConnectorImage(walletConnect.imageId as string) } - - this.setConnectors(connectors) }) } - private initChainAdapters(blueprints: AdapterBlueprint[]) { + private initChainAdapters() { this.chainNamespaces.forEach(namespace => { - const blueprint = blueprints?.find(b => b.namespace === namespace) - - this.listenConnectors(namespace) - - if (blueprint) { - this.chainAdapters?.[namespace].syncConnectors(this.options, this) - } - + this.onConnectors(namespace) + this.chainAdapters?.[namespace].syncConnectors(this.options, this) + this.createConnectorsForAdapter(namespace) this.listenAdapter(namespace) }) - - this.listenWalletConnect() } private setDefaultNetwork() { From 90aa105bd603d68ef428dc7ff5f42cd8812ebf9d Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 15:09:02 +0000 Subject: [PATCH 03/26] chore: remove provider creation on adapter level --- packages/appkit/src/client.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 7b181a5094..3cf4f6788c 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -1796,12 +1796,6 @@ export class AppKit { projectId: this.options?.projectId, networks: this.caipNetworks }) - if (this.universalProvider) { - adapters[namespace].addUniversalProvider(this.universalProvider) - } - if (this.authProvider) { - adapters[namespace].addAuthProvider(this.authProvider) - } } else { adapters[namespace] = new UniversalAdapter({ namespace, From 1c748ee4111da448b9ff4eda9686b406be800ccd Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 15:18:17 +0000 Subject: [PATCH 04/26] chore: remove code from bitcoin adapter to prevent build issues for now --- packages/adapters/bitcoin/src/adapter.ts | 48 ++---------------------- 1 file changed, 3 insertions(+), 45 deletions(-) diff --git a/packages/adapters/bitcoin/src/adapter.ts b/packages/adapters/bitcoin/src/adapter.ts index 044c775e42..694aa48c79 100644 --- a/packages/adapters/bitcoin/src/adapter.ts +++ b/packages/adapters/bitcoin/src/adapter.ts @@ -1,18 +1,8 @@ -import { - CoreHelperUtil, - WcHelpersUtil, - type AppKit, - type AppKitOptions, - type Provider -} from '@reown/appkit' +import { CoreHelperUtil, WcHelpersUtil, type AppKitOptions, type Provider } from '@reown/appkit' import { AdapterBlueprint } from '@reown/appkit/adapters' import type { BitcoinConnector } from './utils/BitcoinConnector.js' import type UniversalProvider from '@walletconnect/universal-provider' -import { SatsConnectConnector } from './connectors/SatsConnectConnector.js' -import { WalletStandardConnector } from './connectors/WalletStandardConnector.js' import { WalletConnectProvider } from './utils/WalletConnectProvider.js' -import { LeatherConnector } from './connectors/LeatherConnector.js' -import { OKXConnector } from './connectors/OKXConnector.js' import { UnitsUtil } from './utils/UnitsUtil.js' import { BitcoinApi } from './utils/BitcoinApi.js' import { bitcoin } from '@reown/appkit/networks' @@ -93,40 +83,8 @@ export class BitcoinAdapter extends AdapterBlueprint { accounts: accounts || [] } } - override syncConnectors(_options?: AppKitOptions, appKit?: AppKit): void { - function getActiveNetwork() { - return appKit?.getCaipNetwork() - } - - WalletStandardConnector.watchWallets({ - callback: this.addConnector.bind(this), - requestedChains: this.networks - }) - - this.addConnector( - ...SatsConnectConnector.getWallets({ - requestedChains: this.networks, - getActiveNetwork - }).map(connector => { - switch (connector.wallet.id) { - case LeatherConnector.ProviderId: - return new LeatherConnector({ - connector - }) - - default: - return connector - } - }) - ) - - const okxConnector = OKXConnector.getWallet({ - requestedChains: this.networks, - getActiveNetwork - }) - if (okxConnector) { - this.addConnector(okxConnector) - } + override syncConnectors(_options?: AppKitOptions): void { + return undefined } override syncConnection( From 5b941a9e45d1f36c45907178394008cc7f2878e7 Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 15:38:45 +0000 Subject: [PATCH 05/26] chore: await controllers --- packages/appkit/src/client.ts | 47 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 35f9b9a90c..40e84c1ebe 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -54,7 +54,8 @@ import { type ChainNamespace, type CaipAddress, type CaipNetworkId, - NetworkUtil + NetworkUtil, + ConstantsUtil } from '@reown/appkit-common' import type { AppKitOptions } from './utils/TypesUtil.js' import { @@ -203,7 +204,7 @@ export class AppKit { ) { this.caipNetworks = this.extendCaipNetworks(options) this.defaultCaipNetwork = this.extendDefaultCaipNetwork(options) - this.initControllers(options) + await this.initControllers(options) this.createClients() ChainController.initialize(options.adapters ?? [], this.caipNetworks) this.chainAdapters = this.createAdapters(options.adapters as unknown as AdapterBlueprint[]) @@ -636,7 +637,7 @@ export class AppKit { } // -- Private ------------------------------------------------------------------ - private initControllers( + private async initControllers( options: AppKitOptions & { adapters?: ChainAdapter[] } & { @@ -703,27 +704,25 @@ export class AppKit { OptionsController.setSIWX(options.siwx) } - /* - * Const evmAdapter = options.adapters?.find( - * adapter => adapter.namespace === ConstantsUtil.CHAIN.EVM - * ) - * - * // Set the SIWE client for EVM chains - * if (evmAdapter) { - * if (options.siweConfig) { - * if (options.siwx) { - * throw new Error('Cannot set both `siweConfig` and `siwx` options') - * } - * - * const siwe = await import('@reown/appkit-siwe') - * if (typeof siwe.mapToSIWX !== 'function') { - * throw new Error('Please update the `@reown/appkit-siwe` package to the latest version') - * } - * - * OptionsController.setSIWX(siwe.mapToSIWX(options.siweConfig)) - * } - * } - */ + const evmAdapter = options.adapters?.find( + adapter => adapter.namespace === ConstantsUtil.CHAIN.EVM + ) + + // Set the SIWE client for EVM chains + if (evmAdapter) { + if (options.siweConfig) { + if (options.siwx) { + throw new Error('Cannot set both `siweConfig` and `siwx` options') + } + + const siwe = await import('@reown/appkit-siwe') + if (typeof siwe.mapToSIWX !== 'function') { + throw new Error('Please update the `@reown/appkit-siwe` package to the latest version') + } + + OptionsController.setSIWX(siwe.mapToSIWX(options.siweConfig)) + } + } } private getDefaultMetaData() { From 59c14802986a2e7a5c8794791dae6acd6a74e012 Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 16:09:49 +0000 Subject: [PATCH 06/26] revert: edit bitcoin adapter --- packages/adapters/bitcoin/src/adapter.ts | 48 ++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/packages/adapters/bitcoin/src/adapter.ts b/packages/adapters/bitcoin/src/adapter.ts index 694aa48c79..fb0a8092f1 100644 --- a/packages/adapters/bitcoin/src/adapter.ts +++ b/packages/adapters/bitcoin/src/adapter.ts @@ -1,8 +1,18 @@ -import { CoreHelperUtil, WcHelpersUtil, type AppKitOptions, type Provider } from '@reown/appkit' +import { + CoreHelperUtil, + WcHelpersUtil, + type AppKit, + type AppKitOptions, + type Provider +} from '@reown/appkit' import { AdapterBlueprint } from '@reown/appkit/adapters' import type { BitcoinConnector } from './utils/BitcoinConnector.js' import type UniversalProvider from '@walletconnect/universal-provider' +import { SatsConnectConnector } from './connectors/SatsConnectConnector.js' +import { WalletStandardConnector } from './connectors/WalletStandardConnector.js' import { WalletConnectProvider } from './utils/WalletConnectProvider.js' +import { LeatherConnector } from './connectors/LeatherConnector.js' +import { OKXConnector } from './connectors/OKXConnector.js' import { UnitsUtil } from './utils/UnitsUtil.js' import { BitcoinApi } from './utils/BitcoinApi.js' import { bitcoin } from '@reown/appkit/networks' @@ -83,8 +93,40 @@ export class BitcoinAdapter extends AdapterBlueprint { accounts: accounts || [] } } - override syncConnectors(_options?: AppKitOptions): void { - return undefined + override syncConnectors(_options?: AppKitOptions, appKit?: AppKit): void { + function getActiveNetwork() { + return appKit?.getCaipNetwork() + } + + WalletStandardConnector.watchWallets({ + callback: wallets => this.addConnector([wallets]), + requestedChains: this.networks + }) + + this.addConnector([ + ...SatsConnectConnector.getWallets({ + requestedChains: this.networks, + getActiveNetwork + }).map(connector => { + switch (connector.wallet.id) { + case LeatherConnector.ProviderId: + return new LeatherConnector({ + connector + }) + + default: + return connector + } + }) + ]) + + const okxConnector = OKXConnector.getWallet({ + requestedChains: this.networks, + getActiveNetwork + }) + if (okxConnector) { + this.addConnector([okxConnector]) + } } override syncConnection( From 9f00cd5a43ff80c275ccd2c28e83c673dd6da9b1 Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 16:26:57 +0000 Subject: [PATCH 07/26] chore: migrate logic on chain blueprint level instead of adapter level --- packages/adapters/bitcoin/src/adapter.ts | 8 +- packages/adapters/ethers/src/client.ts | 72 ++++++++---------- packages/adapters/ethers5/src/client.ts | 72 ++++++++---------- packages/adapters/solana/src/client.ts | 72 +++++++++--------- packages/adapters/wagmi/src/client.ts | 26 +++---- .../src/adapters/ChainAdapterBlueprint.ts | 74 +++++++++---------- packages/appkit/src/client.ts | 6 +- packages/core/exports/index.ts | 5 +- .../src/controllers/ConnectorController.ts | 3 +- 9 files changed, 150 insertions(+), 188 deletions(-) diff --git a/packages/adapters/bitcoin/src/adapter.ts b/packages/adapters/bitcoin/src/adapter.ts index fb0a8092f1..044c775e42 100644 --- a/packages/adapters/bitcoin/src/adapter.ts +++ b/packages/adapters/bitcoin/src/adapter.ts @@ -99,11 +99,11 @@ export class BitcoinAdapter extends AdapterBlueprint { } WalletStandardConnector.watchWallets({ - callback: wallets => this.addConnector([wallets]), + callback: this.addConnector.bind(this), requestedChains: this.networks }) - this.addConnector([ + this.addConnector( ...SatsConnectConnector.getWallets({ requestedChains: this.networks, getActiveNetwork @@ -118,14 +118,14 @@ export class BitcoinAdapter extends AdapterBlueprint { return connector } }) - ]) + ) const okxConnector = OKXConnector.getWallet({ requestedChains: this.networks, getActiveNetwork }) if (okxConnector) { - this.addConnector([okxConnector]) + this.addConnector(okxConnector) } } diff --git a/packages/adapters/ethers/src/client.ts b/packages/adapters/ethers/src/client.ts index b3210af423..1ecde2036f 100644 --- a/packages/adapters/ethers/src/client.ts +++ b/packages/adapters/ethers/src/client.ts @@ -1,4 +1,4 @@ -import { AdapterBlueprint, type ChainAdapterConnector } from '@reown/appkit/adapters' +import { AdapterBlueprint } from '@reown/appkit/adapters' import type { CaipNetwork } from '@reown/appkit-common' import { ConstantsUtil as CommonConstantsUtil } from '@reown/appkit-common' import { @@ -256,36 +256,30 @@ export class EthersAdapter extends AdapterBlueprint { this.listenInjectedConnector(true) } - const validConnectors = Object.keys(this.ethersConfig || {}).filter( + const connectors = Object.keys(this.ethersConfig || {}).filter( key => key !== 'metadata' && key !== 'EIP6963' ) - const connectors = validConnectors - .map(connector => { - const id = connector === 'coinbase' ? 'coinbaseWalletSDK' : connector - - const isInjected = connector === ConstantsUtil.INJECTED_CONNECTOR_ID - - if (this.namespace) { - return { - id, - explorerId: PresetsUtil.ConnectorExplorerIds[id], - imageUrl: options?.connectorImages?.[id], - name: PresetsUtil.ConnectorNamesMap[id], - imageId: PresetsUtil.ConnectorImageIds[id], - type: PresetsUtil.ConnectorTypesMap[id] ?? 'EXTERNAL', - info: isInjected ? undefined : { rdns: id }, - chain: this.namespace, - chains: [], - provider: this.ethersConfig?.[connector as keyof ProviderType] as Provider - } as ChainAdapterConnector - } - - return undefined - }) - .filter(Boolean) - - this.addConnector(connectors as ChainAdapterConnector[]) + connectors.forEach(connector => { + const key = connector === 'coinbase' ? 'coinbaseWalletSDK' : connector + + const injectedConnector = connector === ConstantsUtil.INJECTED_CONNECTOR_ID + + if (this.namespace) { + this.addConnector({ + id: key, + explorerId: PresetsUtil.ConnectorExplorerIds[key], + imageUrl: options?.connectorImages?.[key], + name: PresetsUtil.ConnectorNamesMap[key], + imageId: PresetsUtil.ConnectorImageIds[key], + type: PresetsUtil.ConnectorTypesMap[key] ?? 'EXTERNAL', + info: injectedConnector ? undefined : { rdns: key }, + chain: this.namespace, + chains: [], + provider: this.ethersConfig?.[connector as keyof ProviderType] as Provider + }) + } + }) } public async connectWalletConnect(onUri: (uri: string) => void) { @@ -317,18 +311,16 @@ export class EthersAdapter extends AdapterBlueprint { const type = PresetsUtil.ConnectorTypesMap[ConstantsUtil.EIP6963_CONNECTOR_ID] if (type && this.namespace) { - this.addConnector([ - { - id: info?.rdns || '', - type, - imageUrl: info?.icon, - name: info?.name, - provider, - info, - chain: this.namespace, - chains: [] - } - ]) + this.addConnector({ + id: info?.rdns || '', + type, + imageUrl: info?.icon, + name: info?.name, + provider, + info, + chain: this.namespace, + chains: [] + }) } } } diff --git a/packages/adapters/ethers5/src/client.ts b/packages/adapters/ethers5/src/client.ts index 9579590aad..240e48074c 100644 --- a/packages/adapters/ethers5/src/client.ts +++ b/packages/adapters/ethers5/src/client.ts @@ -1,4 +1,4 @@ -import { AdapterBlueprint, type ChainAdapterConnector } from '@reown/appkit/adapters' +import { AdapterBlueprint } from '@reown/appkit/adapters' import type { CaipNetwork } from '@reown/appkit-common' import { ConstantsUtil as CommonConstantsUtil } from '@reown/appkit-common' import { @@ -257,36 +257,30 @@ export class Ethers5Adapter extends AdapterBlueprint { this.listenInjectedConnector(true) } - const validConnectors = Object.keys(this.ethersConfig || {}).filter( + const connectors = Object.keys(this.ethersConfig || {}).filter( key => key !== 'metadata' && key !== 'EIP6963' ) - const connectors = validConnectors - .map(connector => { - const key = connector === 'coinbase' ? 'coinbaseWalletSDK' : connector - - const isInjected = connector === ConstantsUtil.INJECTED_CONNECTOR_ID - - if (this.namespace) { - return { - id: key, - explorerId: PresetsUtil.ConnectorExplorerIds[key], - imageUrl: options?.connectorImages?.[key], - name: PresetsUtil.ConnectorNamesMap[key], - imageId: PresetsUtil.ConnectorImageIds[key], - type: PresetsUtil.ConnectorTypesMap[key] ?? 'EXTERNAL', - info: isInjected ? undefined : { rdns: key }, - chain: this.namespace, - chains: [], - provider: this.ethersConfig?.[connector as keyof ProviderType] as Provider - } as ChainAdapterConnector - } - - return undefined - }) - .filter(Boolean) - - this.addConnector(connectors as ChainAdapterConnector[]) + connectors.forEach(connector => { + const key = connector === 'coinbase' ? 'coinbaseWalletSDK' : connector + + const injectedConnector = connector === ConstantsUtil.INJECTED_CONNECTOR_ID + + if (this.namespace) { + this.addConnector({ + id: key, + explorerId: PresetsUtil.ConnectorExplorerIds[key], + imageUrl: options?.connectorImages?.[key], + name: PresetsUtil.ConnectorNamesMap[key], + imageId: PresetsUtil.ConnectorImageIds[key], + type: PresetsUtil.ConnectorTypesMap[key] ?? 'EXTERNAL', + info: injectedConnector ? undefined : { rdns: key }, + chain: this.namespace, + chains: [], + provider: this.ethersConfig?.[connector as keyof ProviderType] as Provider + }) + } + }) } public async connectWalletConnect(onUri: (uri: string) => void) { @@ -318,18 +312,16 @@ export class Ethers5Adapter extends AdapterBlueprint { const type = PresetsUtil.ConnectorTypesMap[ConstantsUtil.EIP6963_CONNECTOR_ID] if (type && this.namespace) { - this.addConnector([ - { - id: info?.rdns || '', - type, - imageUrl: info?.icon, - name: info?.name, - provider, - info, - chain: this.namespace, - chains: [] - } - ]) + this.addConnector({ + id: info?.rdns || '', + type, + imageUrl: info?.icon, + name: info?.name, + provider, + info, + chain: this.namespace, + chains: [] + }) } } } diff --git a/packages/adapters/solana/src/client.ts b/packages/adapters/solana/src/client.ts index e0143ce680..51a4f8a141 100644 --- a/packages/adapters/solana/src/client.ts +++ b/packages/adapters/solana/src/client.ts @@ -1,4 +1,4 @@ -import { WcHelpersUtil, AppKit, type AppKitOptions } from '@reown/appkit' +import { WcHelpersUtil, type AppKit, type AppKitOptions } from '@reown/appkit' import { ConstantsUtil as CommonConstantsUtil, type CaipNetwork, @@ -100,36 +100,32 @@ export class SolanaAdapter extends AdapterBlueprint { chains: this.caipNetworks as CaipNetwork[] }) - this.addConnector([ - { - id: ConstantsUtil.AUTH_CONNECTOR_ID, - type: 'AUTH', - provider: this.authProvider as unknown as W3mFrameProvider, - name: 'Auth', - chain: this.namespace as ChainNamespace, - chains: [] - } - ]) + this.addConnector({ + id: ConstantsUtil.AUTH_CONNECTOR_ID, + type: 'AUTH', + provider: this.authProvider as unknown as W3mFrameProvider, + name: 'Auth', + chain: this.namespace as ChainNamespace, + chains: [] + }) } // Add Coinbase Wallet if available if (typeof window !== 'undefined' && 'coinbaseSolana' in window) { - this.addConnector([ - { - id: 'coinbaseWallet', - type: 'EXTERNAL', - // @ts-expect-error window.coinbaseSolana exists - provider: new CoinbaseWalletProvider({ - provider: window.coinbaseSolana as SolanaCoinbaseWallet, - chains: this.caipNetworks as CaipNetwork[], - getActiveChain: () => appKit.getCaipNetwork(this.namespace) as CaipNetwork - }), - name: 'Coinbase Wallet', - chain: this.namespace as ChainNamespace, - explorerId: PresetsUtil.ConnectorExplorerIds[ConstantsUtil.COINBASE_SDK_CONNECTOR_ID], - chains: [] - } - ]) + this.addConnector({ + id: 'coinbaseWallet', + type: 'EXTERNAL', + // @ts-expect-error window.coinbaseSolana exists + provider: new CoinbaseWalletProvider({ + provider: window.coinbaseSolana as SolanaCoinbaseWallet, + chains: this.caipNetworks as CaipNetwork[], + getActiveChain: () => appKit.getCaipNetwork(this.namespace) as CaipNetwork + }), + name: 'Coinbase Wallet', + chain: this.namespace as ChainNamespace, + explorerId: PresetsUtil.ConnectorExplorerIds[ConstantsUtil.COINBASE_SDK_CONNECTOR_ID], + chains: [] + }) } // Watch for standard wallet adapters @@ -138,18 +134,16 @@ export class SolanaAdapter extends AdapterBlueprint { () => appKit.getCaipNetwork(this.namespace), (...providers: WalletStandardProvider[]) => { providers.forEach(provider => { - this.addConnector([ - { - id: PresetsUtil.ConnectorExplorerIds[provider.name] || provider.name, - type: 'ANNOUNCED', - provider: provider as unknown as Provider, - imageUrl: provider.icon, - name: provider.name, - chain: CommonConstantsUtil.CHAIN.SOLANA, - explorerId: PresetsUtil.ConnectorExplorerIds[provider.name], - chains: [] - } - ]) + this.addConnector({ + id: PresetsUtil.ConnectorExplorerIds[provider.name] || provider.name, + type: 'ANNOUNCED', + provider: provider as unknown as Provider, + imageUrl: provider.icon, + name: provider.name, + chain: CommonConstantsUtil.CHAIN.SOLANA, + explorerId: PresetsUtil.ConnectorExplorerIds[provider.name], + chains: [] + }) }) } ) diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index dd46cc05f6..ceb946e916 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -1,6 +1,6 @@ import type UniversalProvider from '@walletconnect/universal-provider' import type { AppKitNetwork, BaseNetwork, CaipNetwork, ChainNamespace } from '@reown/appkit-common' -import { AdapterBlueprint, type ChainAdapterConnector } from '@reown/appkit/adapters' +import { AdapterBlueprint } from '@reown/appkit/adapters' import { CoreHelperUtil } from '@reown/appkit-core' import { connect, @@ -97,13 +97,15 @@ export class WagmiAdapter extends AdapterBlueprint { this.setupWatchers() } - // Ignoring adding auth provider since we already add it in wagmi - override addAuthProvider() { + /* + * We don't want to set auth provider or universal provider + * since it's already done wagmi + */ + override setAuthProvider() { return undefined } - // Ignoring adding universal provider since we already add it in wagmi - override addUniversalProvider() { + override setUniversalProvider() { return undefined } @@ -368,8 +370,8 @@ export class WagmiAdapter extends AdapterBlueprint { public syncConnectors(options: AppKitOptions, appKit: AppKit) { watchConnectors(this.wagmiConfig, { - onChange: async connectors => { - const prepareConnectors = connectors.map(async connector => { + onChange: connectors => { + connectors.forEach(async connector => { let provider: W3mFrameProvider | UniversalProvider | undefined = undefined if ( @@ -382,7 +384,7 @@ export class WagmiAdapter extends AdapterBlueprint { | undefined } - const preparedConnector: ChainAdapterConnector = { + this.addConnector({ id: connector.id, explorerId: PresetsUtil.ConnectorExplorerIds[connector.id], imageUrl: options?.connectorImages?.[connector.id] ?? connector.icon, @@ -396,14 +398,8 @@ export class WagmiAdapter extends AdapterBlueprint { provider, chain: this.namespace as ChainNamespace, chains: [] - } - - return preparedConnector + }) }) - - const preparedConnectors = await Promise.all(prepareConnectors) - - this.addConnector(preparedConnectors) } }) diff --git a/packages/appkit/src/adapters/ChainAdapterBlueprint.ts b/packages/appkit/src/adapters/ChainAdapterBlueprint.ts index 94c8417906..8435146325 100644 --- a/packages/appkit/src/adapters/ChainAdapterBlueprint.ts +++ b/packages/appkit/src/adapters/ChainAdapterBlueprint.ts @@ -14,31 +14,28 @@ import { type Connector as AppKitConnector, type AuthConnector, type Metadata, - type Tokens, - type ConnectorWithProviders + type Tokens } from '@reown/appkit-core' +import type UniversalProvider from '@walletconnect/universal-provider' +import type { W3mFrameProvider } from '@reown/appkit-wallet' +import { ConstantsUtil, PresetsUtil } from '@reown/appkit-utils' import type { AppKitOptions } from '../utils/index.js' import type { AppKit } from '../client.js' import { snapshot } from 'valtio/vanilla' -import type UniversalProvider from '@walletconnect/universal-provider' -import { ConstantsUtil, PresetsUtil } from '@reown/appkit-utils' -import type { W3mFrameProvider } from '@reown/appkit-wallet' type EventName = | 'disconnect' | 'accountChanged' | 'switchNetwork' + | 'connectors' | 'pendingTransactions' - | 'addConnectors' - type EventData = { disconnect: () => void accountChanged: { address: string; chainId?: number | string } switchNetwork: { address?: string; chainId: number | string } + connectors: ChainAdapterConnector[] pendingTransactions: () => void - addConnectors: ConnectorWithProviders[] } - type EventCallback = (data: EventData[T]) => void /** @@ -52,7 +49,7 @@ export abstract class AdapterBlueprint< public caipNetworks?: CaipNetwork[] public projectId?: string - protected allConnectors: Connector[] = [] + protected availableConnectors: Connector[] = [] protected connector?: Connector protected provider?: Connector['provider'] @@ -83,7 +80,7 @@ export abstract class AdapterBlueprint< * @returns {Connector[]} An array of available connectors */ public get connectors(): Connector[] { - return this.allConnectors + return this.availableConnectors } /** @@ -96,45 +93,41 @@ export abstract class AdapterBlueprint< /** * Sets the universal provider for WalletConnect. - * @param {UniversalProvider} addUniversalProvider - The universal provider instance + * @param {UniversalProvider} universalProvider - The universal provider instance */ - public addUniversalProvider(universalProvider: UniversalProvider) { - this.addConnector([ - { - id: ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID, - type: 'WALLET_CONNECT', - name: PresetsUtil.ConnectorNamesMap[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID], - provider: universalProvider, - imageId: PresetsUtil.ConnectorImageIds[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID], - chain: this.namespace, - chains: [] - } as unknown as Connector - ]) + public setUniversalProvider(universalProvider: UniversalProvider) { + this.addConnector({ + id: ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID, + type: 'WALLET_CONNECT', + name: PresetsUtil.ConnectorNamesMap[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID], + provider: universalProvider, + imageId: PresetsUtil.ConnectorImageIds[ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID], + chain: this.namespace, + chains: [] + } as unknown as Connector) } /** * Sets the auth provider. - * @param {W3mFrameProvider} addAuthConnector - The auth provider instance + * @param {W3mFrameProvider} authProvider - The auth provider instance */ - public addAuthProvider(authProvider: W3mFrameProvider): void { - this.addConnector([ - { - id: ConstantsUtil.AUTH_CONNECTOR_ID, - type: 'AUTH', - name: 'Auth', - provider: authProvider, - imageId: PresetsUtil.ConnectorImageIds[ConstantsUtil.AUTH_CONNECTOR_ID], - chain: this.namespace, - chains: [] - } as unknown as Connector - ]) + public setAuthProvider(authProvider: W3mFrameProvider): void { + this.addConnector({ + id: ConstantsUtil.AUTH_CONNECTOR_ID, + type: 'AUTH', + name: 'Auth', + provider: authProvider, + imageId: PresetsUtil.ConnectorImageIds[ConstantsUtil.AUTH_CONNECTOR_ID], + chain: this.namespace, + chains: [] + } as unknown as Connector) } /** * Adds one or more connectors to the available connectors list. * @param {...Connector} connectors - The connectors to add */ - protected addConnector(connectors: Connector[]) { + protected addConnector(...connectors: Connector[]) { if (connectors.some(connector => connector.id === 'ID_AUTH')) { const authConnector = connectors.find( connector => connector.id === 'ID_AUTH' @@ -158,8 +151,7 @@ export abstract class AdapterBlueprint< } const connectorsAdded = new Set() - - this.allConnectors = [...this.allConnectors, ...connectors].filter(connector => { + this.availableConnectors = [...connectors, ...this.availableConnectors].filter(connector => { if (connectorsAdded.has(connector.id)) { return false } @@ -169,7 +161,7 @@ export abstract class AdapterBlueprint< return true }) - this.emit('addConnectors', this.allConnectors) + this.emit('connectors', this.availableConnectors) } protected setStatus(status: AccountControllerState['status'], chainNamespace?: ChainNamespace) { diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 40e84c1ebe..af127d1fa9 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -1764,13 +1764,13 @@ export class AppKit { await this.getUniversalProvider() if (this.universalProvider) { - this.chainAdapters?.[chainNamespace].addUniversalProvider(this.universalProvider) + this.chainAdapters?.[chainNamespace].setUniversalProvider(this.universalProvider) } } private createAuthProviderForAdapter(chainNamespace: ChainNamespace) { this.createAuthProvider() - this.chainAdapters?.[chainNamespace].addAuthProvider(this.authProvider as W3mFrameProvider) + this.chainAdapters?.[chainNamespace].setAuthProvider(this.authProvider as W3mFrameProvider) } private createAdapters(blueprints?: AdapterBlueprint[]) { @@ -1816,7 +1816,7 @@ export class AppKit { private onConnectors(chainNamespace: ChainNamespace) { const adapter = this.getAdapter(chainNamespace) - adapter?.on('addConnectors', connectors => { + adapter?.on('connectors', connectors => { this.setConnectors(connectors) const walletConnect = connectors.find( diff --git a/packages/core/exports/index.ts b/packages/core/exports/index.ts index 547b5fd49a..98b14a9e0b 100644 --- a/packages/core/exports/index.ts +++ b/packages/core/exports/index.ts @@ -24,10 +24,7 @@ export type { } from '../src/controllers/ConnectionController.js' export { ConnectorController } from '../src/controllers/ConnectorController.js' -export type { - ConnectorControllerState, - ConnectorWithProviders -} from '../src/controllers/ConnectorController.js' +export type { ConnectorControllerState } 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 68497686b2..f83deb0f54 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 --------------------------------------------- // -export interface ConnectorWithProviders extends Connector { +interface ConnectorWithProviders extends Connector { connectors?: Connector[] } export interface ConnectorControllerState { @@ -158,7 +158,6 @@ export const ConnectorController = { getAuthConnector(): AuthConnector | undefined { const activeNamespace = ChainController.state.activeChain const authConnector = state.connectors.find(c => c.id === 'ID_AUTH') - if (!authConnector) { return undefined } From 8779eeeafd08bd9ab148ce896b1169ddeab5cff3 Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 16:42:44 +0000 Subject: [PATCH 08/26] chore: tweak wagmi code --- packages/adapters/wagmi/src/client.ts | 68 ++++++++++++++------------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index ceb946e916..7fac380801 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -368,42 +368,44 @@ export class WagmiAdapter extends AdapterBlueprint { return formatUnits(params.value, params.decimals) } - public syncConnectors(options: AppKitOptions, appKit: AppKit) { - watchConnectors(this.wagmiConfig, { - onChange: connectors => { - connectors.forEach(async connector => { - let provider: W3mFrameProvider | UniversalProvider | undefined = undefined - - if ( - connector.id === ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID || - connector.id === ConstantsUtil.AUTH_CONNECTOR_ID - ) { - provider = (await connector.getProvider().catch(() => undefined)) as - | W3mFrameProvider - | UniversalProvider - | undefined - } - - this.addConnector({ - id: connector.id, - explorerId: PresetsUtil.ConnectorExplorerIds[connector.id], - imageUrl: options?.connectorImages?.[connector.id] ?? connector.icon, - name: PresetsUtil.ConnectorNamesMap[connector.id] ?? connector.name, - imageId: PresetsUtil.ConnectorImageIds[connector.id], - type: PresetsUtil.ConnectorTypesMap[connector.type] ?? 'EXTERNAL', - info: - connector.id === ConstantsUtil.INJECTED_CONNECTOR_ID - ? undefined - : { rdns: connector.id }, - provider, - chain: this.namespace as ChainNamespace, - chains: [] - }) - }) - } + private async addWagmiConnector(connector: Connector, options: AppKitOptions) { + let provider: W3mFrameProvider | UniversalProvider | undefined = undefined + + const shouldFetchProvider = + connector.id === ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID || + connector.id === ConstantsUtil.AUTH_CONNECTOR_ID + + if (shouldFetchProvider) { + provider = (await connector.getProvider().catch(() => undefined)) as + | W3mFrameProvider + | UniversalProvider + | undefined + } + + this.addConnector({ + id: connector.id, + explorerId: PresetsUtil.ConnectorExplorerIds[connector.id], + imageUrl: options?.connectorImages?.[connector.id] ?? connector.icon, + name: PresetsUtil.ConnectorNamesMap[connector.id] ?? connector.name, + imageId: PresetsUtil.ConnectorImageIds[connector.id], + type: PresetsUtil.ConnectorTypesMap[connector.type] ?? 'EXTERNAL', + info: + connector.id === ConstantsUtil.INJECTED_CONNECTOR_ID ? undefined : { rdns: connector.id }, + provider, + chain: this.namespace as ChainNamespace, + chains: [] }) + } + public syncConnectors(options: AppKitOptions, appKit: AppKit) { this.addWagmiConnectors(options, appKit) + + this.wagmiConfig.connectors.forEach(connector => this.addWagmiConnector(connector, options)) + + watchConnectors(this.wagmiConfig, { + onChange: connectors => + connectors.forEach(connector => this.addWagmiConnector(connector, options)) + }) } public async syncConnection( From 2f89a131a395952bd7b4e3204af6e862e7cef484 Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 16:50:36 +0000 Subject: [PATCH 09/26] chore: add comment for visibility --- packages/adapters/wagmi/src/client.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index 7fac380801..1e8e11a3c6 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -97,14 +97,12 @@ export class WagmiAdapter extends AdapterBlueprint { this.setupWatchers() } - /* - * We don't want to set auth provider or universal provider - * since it's already done wagmi - */ + // We already set auth provider in wagmi override setAuthProvider() { return undefined } + // We already set universal provider in wagmi override setUniversalProvider() { return undefined } @@ -398,10 +396,16 @@ export class WagmiAdapter extends AdapterBlueprint { } public syncConnectors(options: AppKitOptions, appKit: AppKit) { + // Add wagmi connectors this.addWagmiConnectors(options, appKit) + // Add current wagmi connectors to chain adapter this.wagmiConfig.connectors.forEach(connector => this.addWagmiConnector(connector, options)) + /* + * Watch for new connectors. This is useful if some EIP6963 connectors + * are added after the initial setup + */ watchConnectors(this.wagmiConfig, { onChange: connectors => connectors.forEach(connector => this.addWagmiConnector(connector, options)) From 17ece789c6373e6cfe472b6030df39dae45f54fe Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 16:56:21 +0000 Subject: [PATCH 10/26] chore: tweak comment --- packages/adapters/wagmi/src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index 1e8e11a3c6..4c7d863876 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -404,7 +404,7 @@ export class WagmiAdapter extends AdapterBlueprint { /* * Watch for new connectors. This is useful if some EIP6963 connectors - * are added after the initial setup + * that are added after the initial setup */ watchConnectors(this.wagmiConfig, { onChange: connectors => From 6c1868003f9a857c30c50541d197f8787d30b641 Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 17:03:22 +0000 Subject: [PATCH 11/26] revert: add setAuthProvider and setUniversalProvider undefined --- packages/adapters/wagmi/src/client.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index 4c7d863876..8acb370688 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -97,16 +97,6 @@ export class WagmiAdapter extends AdapterBlueprint { this.setupWatchers() } - // We already set auth provider in wagmi - override setAuthProvider() { - return undefined - } - - // We already set universal provider in wagmi - override setUniversalProvider() { - return undefined - } - override async getAccounts( params: AdapterBlueprint.GetAccountsParams ): Promise { From a7901d47e7c2a975c22c4e845b89d1156320a403 Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 17:27:55 +0000 Subject: [PATCH 12/26] chore: add mapToSIWX to AppKitSIWEClient --- packages/appkit/src/client.ts | 11 +++-------- packages/siwe/src/client.ts | 6 +++++- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index af127d1fa9..7d9fcbe8b5 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -204,7 +204,7 @@ export class AppKit { ) { this.caipNetworks = this.extendCaipNetworks(options) this.defaultCaipNetwork = this.extendDefaultCaipNetwork(options) - await this.initControllers(options) + this.initControllers(options) this.createClients() ChainController.initialize(options.adapters ?? [], this.caipNetworks) this.chainAdapters = this.createAdapters(options.adapters as unknown as AdapterBlueprint[]) @@ -637,7 +637,7 @@ export class AppKit { } // -- Private ------------------------------------------------------------------ - private async initControllers( + private initControllers( options: AppKitOptions & { adapters?: ChainAdapter[] } & { @@ -715,12 +715,7 @@ export class AppKit { throw new Error('Cannot set both `siweConfig` and `siwx` options') } - const siwe = await import('@reown/appkit-siwe') - if (typeof siwe.mapToSIWX !== 'function') { - throw new Error('Please update the `@reown/appkit-siwe` package to the latest version') - } - - OptionsController.setSIWX(siwe.mapToSIWX(options.siweConfig)) + OptionsController.setSIWX(options.siweConfig.mapToSIWX()) } } } diff --git a/packages/siwe/src/client.ts b/packages/siwe/src/client.ts index 04bbbcc4ae..e790541e96 100644 --- a/packages/siwe/src/client.ts +++ b/packages/siwe/src/client.ts @@ -7,7 +7,7 @@ import type { SIWESession, SIWEVerifyMessageArgs } from '../core/utils/TypeUtils.js' - +import { mapToSIWX } from '../src/mapToSIWX.js' import { SIWXUtil } from '@reown/appkit-core' import { ConstantsUtil } from '../core/utils/ConstantsUtil.js' @@ -41,6 +41,10 @@ export class AppKitSIWEClient { this.methods = siweConfigMethods } + public mapToSIWX() { + return mapToSIWX(this) + } + async getNonce(address?: string) { const nonce = await this.methods.getNonce(address) if (!nonce) { From cfed5bacd52e7ea66f533027e961c7522b706267 Mon Sep 17 00:00:00 2001 From: MK Date: Mon, 16 Dec 2024 18:54:54 +0000 Subject: [PATCH 13/26] chore: adding test for wagmi adapter --- .../adapters/wagmi/src/tests/client.test.ts | 40 +++++++++- packages/appkit/src/tests/appkit.test.ts | 78 ++++++++++++------- 2 files changed, 87 insertions(+), 31 deletions(-) diff --git a/packages/adapters/wagmi/src/tests/client.test.ts b/packages/adapters/wagmi/src/tests/client.test.ts index 2f164ec1a9..df2325d11f 100644 --- a/packages/adapters/wagmi/src/tests/client.test.ts +++ b/packages/adapters/wagmi/src/tests/client.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, beforeEach, vi } from 'vitest' import { WagmiAdapter } from '../client' -import type { Config } from '@wagmi/core' +import type { Config, Connector } from '@wagmi/core' import { disconnect as wagmiDisconnect, getConnections, @@ -16,11 +16,15 @@ import { waitForTransactionReceipt, getAccount, watchPendingTransactions, - http + http, + watchConnectors, + mock } from '@wagmi/core' +import * as wagmiCore from '@wagmi/core' import { mainnet } from '@wagmi/core/chains' import { CaipNetworksUtil } from '@reown/appkit-utils' import type UniversalProvider from '@walletconnect/universal-provider' +import { mockAppKit } from './mocks/AppKit' vi.mock('@wagmi/core', async () => { const actual = await vi.importActual('@wagmi/core') @@ -97,6 +101,38 @@ describe('WagmiAdapter', () => { expect(adapter.namespace).toBe('eip155') }) + it('should set wagmi connectors', () => { + const addWagmiConnector = vi.spyOn(adapter, 'addWagmiConnector' as any) + + vi.spyOn(wagmiCore, 'watchConnectors').mockResolvedValue(vi.fn) + ;(adapter as any).syncConnectors({}, mockAppKit) + + expect(addWagmiConnector).toHaveBeenCalledWith( + { + id: 'test-connector' + }, + {} + ) + }) + + it('should listen for wagmi connector changes', () => { + const onConnectors = vi.fn() + + vi.spyOn(wagmiCore, 'watchConnectors').mockImplementation(onConnectors) + ;(adapter as any).syncConnectors({}, mockAppKit) + + adapter.wagmiConfig._internal.connectors.setState(() => [ + ...adapter.wagmiConfig.connectors, + adapter.wagmiConfig._internal.connectors.setup(mock({ accounts: ['0x123'] })) + ]) + + watchConnectors(adapter.wagmiConfig, { + onChange: onConnectors + }) + + expect(onConnectors).toHaveBeenCalled() + }) + it('should not set info property for injected connector', () => { const mockConnectors = [ { diff --git a/packages/appkit/src/tests/appkit.test.ts b/packages/appkit/src/tests/appkit.test.ts index 01814144a4..ff3ed3a558 100644 --- a/packages/appkit/src/tests/appkit.test.ts +++ b/packages/appkit/src/tests/appkit.test.ts @@ -20,23 +20,28 @@ import { type Connector, StorageUtil, CoreHelperUtil, - AlertController + AlertController, + type ConnectorType } from '@reown/appkit-core' -import { - SafeLocalStorage, - SafeLocalStorageKeys, - type CaipNetwork, - type SafeLocalStorageItems -} from '@reown/appkit-common' +import { SafeLocalStorage, SafeLocalStorageKeys, type CaipNetwork } from '@reown/appkit-common' import { mockOptions } from './mocks/Options' import { UniversalAdapter } from '../universal-adapter/client' import type { AdapterBlueprint } from '../adapters/ChainAdapterBlueprint' import { ProviderUtil } from '../store' -import { ErrorUtil } from '@reown/appkit-utils' +import { CaipNetworksUtil, ErrorUtil } from '@reown/appkit-utils' // Mock all controllers and UniversalAdapterClient vi.mock('@reown/appkit-core') vi.mock('../universal-adapter/client') +vi.mock('../client.ts', async () => { + const actual = await vi.importActual('../client.ts') + + return { + ...actual, + initOrContinue: vi.fn(), + syncExistingConnection: vi.fn() + } +}) describe('Base', () => { let appKit: AppKit @@ -50,23 +55,32 @@ describe('Base', () => { } as any vi.mocked(ConnectorController).getConnectors = vi.fn().mockReturnValue([]) + vi.mocked(CaipNetworksUtil).extendCaipNetworks = vi.fn().mockReturnValue([]) + appKit = new AppKit(mockOptions) }) describe('Base Initialization', () => { - it('should initialize controllers with required provided options', () => { - expect(OptionsController.setSdkVersion).toHaveBeenCalledWith(mockOptions.sdkVersion) - expect(OptionsController.setProjectId).toHaveBeenCalledWith(mockOptions.projectId) - expect(OptionsController.setMetadata).toHaveBeenCalledWith(mockOptions.metadata) - + it('should initialize controllers', () => { const copyMockOptions = { ...mockOptions } + delete copyMockOptions.adapters - expect(EventsController.sendEvent).toHaveBeenCalledWith(mockOptions) - }) + expect(EventsController.sendEvent).toHaveBeenCalledOnce() + expect(EventsController.sendEvent).toHaveBeenCalledWith({ + type: 'track', + event: 'INITIALIZE', + properties: { + ...copyMockOptions, + networks: copyMockOptions.networks.map(n => n.id), + siweConfig: { + options: copyMockOptions.siweConfig?.options || {} + } + } + }) - it('should initialize adapters in ChainController', () => { - expect(ChainController.initialize).toHaveBeenCalledWith(mockOptions.adapters) + expect(ChainController.initialize).toHaveBeenCalledOnce() + expect(ChainController.initialize).toHaveBeenCalledWith(mockOptions.adapters, []) }) it('should set EIP6963 enabled by default', () => { @@ -499,9 +513,15 @@ describe('Base', () => { }) it('should switch network when requested', async () => { + vi.mocked(CaipNetworksUtil).extendCaipNetworks = vi + .fn() + .mockReturnValue([{ id: mainnet.id, name: mainnet.name }]) + + const mockAppKit = new AppKit(mockOptions) + vi.mocked(ChainController.switchActiveNetwork).mockResolvedValue(undefined) - await appKit.switchNetwork(mainnet) + await mockAppKit.switchNetwork(mainnet) expect(ChainController.switchActiveNetwork).toHaveBeenCalledWith( expect.objectContaining({ @@ -510,7 +530,7 @@ describe('Base', () => { }) ) - await appKit.switchNetwork(polygon) + await mockAppKit.switchNetwork(polygon) expect(ChainController.switchActiveNetwork).toHaveBeenCalledTimes(1) }) @@ -522,6 +542,11 @@ describe('Base', () => { } as Connector vi.mocked(ConnectorController.getConnectors).mockReturnValue([mockConnector]) + vi.mocked(StorageUtil.getActiveNetworkProps).mockReturnValue({ + namespace: 'eip155', + chainId: '1', + caipNetworkId: '1' + }) const mockAccountData = { address: '0x123', @@ -529,13 +554,8 @@ describe('Base', () => { chainNamespace: 'eip155' as const } - vi.spyOn(SafeLocalStorage, 'getItem').mockImplementation( - (key: keyof SafeLocalStorageItems) => { - if (key === SafeLocalStorageKeys.CONNECTED_CONNECTOR) { - return mockConnector.id - } - return undefined - } + vi.spyOn(StorageUtil, 'getConnectedConnector').mockReturnValue( + mockConnector.id as ConnectorType ) await appKit['syncAccount'](mockAccountData) @@ -705,7 +725,7 @@ describe('Base', () => { expect(callback).toHaveBeenCalledWith(providers) }) }) - describe('syncExistingConnection', () => { + describe.skip('syncExistingConnection', () => { it('should set status to "connecting" and sync the connection when a connector and namespace are present', async () => { vi.mocked(CoreHelperUtil.isClient).mockReturnValueOnce(true) vi.spyOn(SafeLocalStorage, 'getItem').mockImplementation(key => { @@ -770,7 +790,7 @@ describe('Base', () => { expect(AccountController.setStatus).toHaveBeenCalledWith('disconnected', 'eip155') }) }) - describe('Base Initialization', () => { + describe.skip('Base Initialization', () => { let appKit: AppKit let mockAdapter: AdapterBlueprint let mockUniversalAdapter: any @@ -914,7 +934,7 @@ describe('Base', () => { }) }) - describe('Alert Errors', () => { + describe.skip('Alert Errors', () => { it('should handle alert errors based on error messages', () => { const errors = [ { From b709fb0a00825c7cf815478b5c5a1bf4ab3a3204 Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 09:27:21 +0000 Subject: [PATCH 14/26] chore: add async operation for chain adapters --- packages/appkit/src/client.ts | 38 ++++++++++++----------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 7d9fcbe8b5..3c7434f6ab 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -208,7 +208,7 @@ export class AppKit { this.createClients() ChainController.initialize(options.adapters ?? [], this.caipNetworks) this.chainAdapters = this.createAdapters(options.adapters as unknown as AdapterBlueprint[]) - this.initChainAdapters() + await this.initChainAdapters() this.syncRequestedNetworks() await this.initOrContinue() await this.syncExistingConnection() @@ -1803,38 +1803,26 @@ export class AppKit { }, {} as Adapters) } - private createConnectorsForAdapter(namespace: ChainNamespace) { - this.createUniversalProviderForAdapter(namespace) + private async createConnectorsForAdapter(namespace: ChainNamespace) { + await this.createUniversalProviderForAdapter(namespace) this.createAuthProviderForAdapter(namespace) } private onConnectors(chainNamespace: ChainNamespace) { const adapter = this.getAdapter(chainNamespace) - adapter?.on('connectors', connectors => { - this.setConnectors(connectors) - - const walletConnect = connectors.find( - ({ id }) => id === UtilConstantsUtil.WALLET_CONNECT_CONNECTOR_ID - ) - - /* - * Sometimes w3m-modal doesn't have all connectors at once, and we need to check if - * walletConnect connector image exists and fetch the image if it doesn't. - */ - if (walletConnect && !AssetUtil.getWalletImageById(walletConnect.imageId)) { - ApiController._fetchConnectorImage(walletConnect.imageId as string) - } - }) + adapter?.on('connectors', this.setConnectors.bind(this)) } - private initChainAdapters() { - this.chainNamespaces.forEach(namespace => { - this.onConnectors(namespace) - this.chainAdapters?.[namespace].syncConnectors(this.options, this) - this.createConnectorsForAdapter(namespace) - this.listenAdapter(namespace) - }) + private async initChainAdapters() { + await Promise.all( + this.chainNamespaces.map(async namespace => { + this.onConnectors(namespace) + this.listenAdapter(namespace) + this.chainAdapters?.[namespace].syncConnectors(this.options, this) + await this.createConnectorsForAdapter(namespace) + }) + ) } private setDefaultNetwork() { From 38f57680b003aeff1b23dfa2a24d4ad9f2a30753 Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 12:00:50 +0000 Subject: [PATCH 15/26] chore: add tests --- packages/appkit/src/client.ts | 10 +- packages/appkit/src/tests/appkit.test.ts | 155 +++++++++++++++------ packages/appkit/src/tests/mocks/Options.ts | 11 +- packages/appkit/src/tests/siwe.test.ts | 23 ++- 4 files changed, 146 insertions(+), 53 deletions(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 3c7434f6ab..502c5db80a 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -1667,12 +1667,12 @@ export class AppKit { return this.chainAdapters?.[namespace] } + private isSafe() { + return typeof window !== 'undefined' + } + private createUniversalProvider() { - if ( - !this.universalProviderInitPromise && - typeof window !== 'undefined' && - this.options?.projectId - ) { + if (!this.universalProviderInitPromise && this.isSafe() && this.options?.projectId) { this.universalProviderInitPromise = this.initializeUniversalAdapter() } diff --git a/packages/appkit/src/tests/appkit.test.ts b/packages/appkit/src/tests/appkit.test.ts index ff3ed3a558..8d6b52b1c7 100644 --- a/packages/appkit/src/tests/appkit.test.ts +++ b/packages/appkit/src/tests/appkit.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, beforeEach, vi } from 'vitest' import { AppKit } from '../client' -import { mainnet, polygon } from '../networks/index.js' +import { base, mainnet, polygon, solana } from '../networks/index.js' import { AccountController, ModalController, @@ -21,7 +21,8 @@ import { StorageUtil, CoreHelperUtil, AlertController, - type ConnectorType + type ConnectorType, + type ChainAdapter } from '@reown/appkit-core' import { SafeLocalStorage, SafeLocalStorageKeys, type CaipNetwork } from '@reown/appkit-common' import { mockOptions } from './mocks/Options' @@ -29,6 +30,8 @@ import { UniversalAdapter } from '../universal-adapter/client' import type { AdapterBlueprint } from '../adapters/ChainAdapterBlueprint' import { ProviderUtil } from '../store' import { CaipNetworksUtil, ErrorUtil } from '@reown/appkit-utils' +import mockUniversalAdapter from './mocks/Adapter' +import { UniversalProvider } from '@walletconnect/universal-provider' // Mock all controllers and UniversalAdapterClient vi.mock('@reown/appkit-core') @@ -574,6 +577,13 @@ describe('Base', () => { chainId: '1', chainNamespace: 'eip155' as const } + + vi.mocked(StorageUtil.getActiveNetworkProps).mockReturnValue({ + namespace: 'eip155', + chainId: '1', + caipNetworkId: '1' + }) + vi.mocked(BlockchainApiController.fetchIdentity).mockResolvedValue({ name: 'John Doe', avatar: null @@ -591,27 +601,35 @@ describe('Base', () => { }) it('should disconnect correctly', async () => { + vi.mocked(CaipNetworksUtil.extendCaipNetworks).mockReturnValue([ + { id: 'eip155:1', chainNamespace: 'eip155' } as CaipNetwork + ]) + vi.mocked(ChainController).state = { chains: new Map([['eip155', { namespace: 'eip155' }]]), activeChain: 'eip155' } as any const mockRemoveItem = vi.fn() - vi.spyOn(SafeLocalStorage, 'removeItem').mockImplementation(mockRemoveItem) - await appKit.disconnect() + vi.spyOn(SafeLocalStorage, 'removeItem').mockImplementation(mockRemoveItem) - expect(mockRemoveItem).toHaveBeenCalledWith(SafeLocalStorageKeys.CONNECTED_CONNECTOR) - expect(mockRemoveItem).toHaveBeenCalledWith(SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK_ID) + const appKit = new AppKit({ + ...mockOptions, + networks: [base], + projectId: 'YOUR_PROJECT_ID', + adapters: [mockUniversalAdapter] + }) - expect(AccountController.resetAccount).toHaveBeenCalledWith('eip155') + await appKit.disconnect() + expect(mockUniversalAdapter.disconnect).toHaveBeenCalled() expect(AccountController.setStatus).toHaveBeenCalledWith('disconnected', 'eip155') - expect(AccountController.resetAccount).toHaveBeenCalledWith('eip155') }) it('should set unsupported chain when synced chainId is not supported', async () => { - const isClientSpy = vi.spyOn(CoreHelperUtil, 'isClient').mockReturnValue(true) + vi.mocked(StorageUtil.getConnectedConnector).mockReturnValue('EXTERNAL') + vi.mocked(StorageUtil.getActiveNamespace).mockReturnValue('eip155') vi.mocked(ChainController).state = { chains: new Map([['eip155', { namespace: 'eip155' }]]), activeChain: 'eip155' @@ -635,6 +653,8 @@ describe('Base', () => { vi.spyOn(StorageUtil, 'setConnectedConnector').mockImplementation(vi.fn()) + vi.spyOn(appKit as any, 'syncAccount').mockImplementation(vi.fn()) + vi.spyOn(appKit as any, 'setUnsupportedNetwork').mockImplementation(vi.fn()) vi.spyOn(SafeLocalStorage, 'getItem').mockImplementation((key: string) => { @@ -652,7 +672,6 @@ describe('Base', () => { await (appKit as any).syncExistingConnection() expect((appKit as any).setUnsupportedNetwork).toHaveBeenCalled() - expect(isClientSpy).toHaveBeenCalled() }) it('should not show unsupported chain UI when allowUnsupportedChain is true', async () => { @@ -725,17 +744,15 @@ describe('Base', () => { expect(callback).toHaveBeenCalledWith(providers) }) }) - describe.skip('syncExistingConnection', () => { + describe('syncExistingConnection', () => { it('should set status to "connecting" and sync the connection when a connector and namespace are present', async () => { vi.mocked(CoreHelperUtil.isClient).mockReturnValueOnce(true) - vi.spyOn(SafeLocalStorage, 'getItem').mockImplementation(key => { - if (key === SafeLocalStorageKeys.CONNECTED_CONNECTOR) { - return 'test-wallet' - } - if (key === SafeLocalStorageKeys.ACTIVE_CAIP_NETWORK_ID) { - return 'eip155:1' - } - return undefined + vi.spyOn(StorageUtil, 'getActiveNamespace').mockReturnValue('eip155') + vi.spyOn(StorageUtil, 'getConnectedConnector').mockReturnValue('EXTERNAL') + vi.mocked(StorageUtil.getActiveNetworkProps).mockReturnValue({ + namespace: 'eip155', + chainId: '1', + caipNetworkId: '1' }) const mockAdapter = { @@ -790,7 +807,7 @@ describe('Base', () => { expect(AccountController.setStatus).toHaveBeenCalledWith('disconnected', 'eip155') }) }) - describe.skip('Base Initialization', () => { + describe('Base Initialization', () => { let appKit: AppKit let mockAdapter: AdapterBlueprint let mockUniversalAdapter: any @@ -833,22 +850,38 @@ describe('Base', () => { }) it('should call syncConnectors when initializing adapters', async () => { - const createAdapters = (appKit as any).createAdapters.bind(appKit) + vi.mocked(CaipNetworksUtil.extendCaipNetworks).mockReturnValue([ + { id: 'eip155:1', chainNamespace: 'eip155' } as CaipNetwork + ]) - vi.spyOn(appKit as any, 'createUniversalProvider').mockResolvedValue(undefined) + const appKit = new AppKit({ + ...mockOptions, + networks: [base], + projectId: 'YOUR_PROJECT_ID', + adapters: [mockAdapter] + }) - await createAdapters([mockAdapter]) + const initChainAdapters = (appKit as any).initChainAdapters.bind(appKit) - expect(mockAdapter.syncConnectors).toHaveBeenCalledWith( - expect.objectContaining({ - projectId: mockOptions.projectId, - metadata: mockOptions.metadata - }), - expect.any(Object) - ) + vi.spyOn(appKit as any, 'createConnectorsForAdapter').mockResolvedValue(undefined) + + await initChainAdapters([mockAdapter]) + + expect(mockAdapter.syncConnectors).toHaveBeenCalled() }) it('should create UniversalAdapter when no blueprint is provided for namespace', async () => { + vi.mocked(CaipNetworksUtil.extendCaipNetworks).mockReturnValue([ + { id: 'eip155:1', chainNamespace: 'eip155' } as CaipNetwork + ]) + + const appKit = new AppKit({ + ...mockOptions, + networks: [mainnet], + projectId: 'YOUR_PROJECT_ID', + adapters: [mockAdapter] + }) + const createAdapters = (appKit as any).createAdapters.bind(appKit) vi.spyOn(appKit as any, 'createUniversalProvider').mockResolvedValue(undefined) @@ -863,11 +896,18 @@ describe('Base', () => { const adapters = await createAdapters([]) expect(adapters.eip155).toBeDefined() - expect(mockUniversalAdapter.setUniversalProvider).toHaveBeenCalled() + + expect(UniversalAdapter).toHaveBeenCalledWith({ + namespace: 'eip155', + networks: [{ id: 'eip155:1', chainNamespace: 'eip155' } as CaipNetwork] + }) }) it('should initialize multiple adapters for different namespaces', async () => { - const createAdapters = (appKit as any).createAdapters.bind(appKit) + vi.mocked(CaipNetworksUtil.extendCaipNetworks).mockReturnValue([ + { id: '1', chainNamespace: 'eip155' } as CaipNetwork, + { id: 'solana', chainNamespace: 'solana' } as CaipNetwork + ]) const mockSolanaAdapter = { namespace: 'solana', @@ -881,6 +921,15 @@ describe('Base', () => { emit: vi.fn() } as unknown as AdapterBlueprint + const appKit = new AppKit({ + ...mockOptions, + networks: [mainnet, solana], + projectId: 'YOUR_PROJECT_ID', + adapters: [mockSolanaAdapter, mockAdapter] + }) + + const createAdapters = (appKit as any).createAdapters.bind(appKit) + vi.spyOn(appKit as any, 'createUniversalProvider').mockResolvedValue(undefined) const adapters = await createAdapters([mockAdapter, mockSolanaAdapter]) @@ -892,29 +941,47 @@ describe('Base', () => { }) it('should set universal provider and auth provider for each adapter', async () => { - const createAdapters = (appKit as any).createAdapters.bind(appKit) + vi.mocked(CaipNetworksUtil.extendCaipNetworks).mockReturnValue([ + { id: '1', chainNamespace: 'eip155' } as CaipNetwork + ]) + + const appKit = new AppKit({ + ...mockOptions, + networks: [mainnet], + projectId: 'YOUR_PROJECT_ID', + adapters: [mockAdapter] + }) const mockUniversalProvider = { on: vi.fn(), off: vi.fn(), emit: vi.fn() } - vi.spyOn(appKit as any, 'createUniversalProvider').mockResolvedValue(undefined) - vi.spyOn(appKit as any, 'getUniversalProvider').mockResolvedValue(mockUniversalProvider) - await createAdapters([mockAdapter]) + vi.spyOn(appKit as any, 'initialize').mockResolvedValue(undefined) + vi.spyOn(appKit as any, 'isSafe').mockReturnValue(true) + vi.spyOn(UniversalProvider, 'init').mockResolvedValue(mockUniversalProvider as any) - expect(mockAdapter.setUniversalProvider).toHaveBeenCalledWith( - expect.objectContaining({ - on: expect.any(Function), - off: expect.any(Function), - emit: expect.any(Function) - }) - ) + const initChainAdapters = (appKit as any).initChainAdapters.bind(appKit) + + await initChainAdapters([mockAdapter]) + + expect(mockAdapter.setUniversalProvider).toHaveBeenCalled() expect(mockAdapter.setAuthProvider).toHaveBeenCalled() }) it('should update ChainController state with initialized adapters', async () => { + vi.mocked(CaipNetworksUtil.extendCaipNetworks).mockReturnValue([ + { id: '1', chainNamespace: 'eip155' } as CaipNetwork + ]) + + const appKit = new AppKit({ + ...mockOptions, + networks: [mainnet], + projectId: 'YOUR_PROJECT_ID', + adapters: [mockAdapter] + }) + const createAdapters = (appKit as any).createAdapters.bind(appKit) vi.spyOn(appKit as any, 'createUniversalProvider').mockResolvedValue(undefined) @@ -934,7 +1001,7 @@ describe('Base', () => { }) }) - describe.skip('Alert Errors', () => { + describe('Alert Errors', () => { it('should handle alert errors based on error messages', () => { const errors = [ { diff --git a/packages/appkit/src/tests/mocks/Options.ts b/packages/appkit/src/tests/mocks/Options.ts index 6db58d5e31..d2c09e7a75 100644 --- a/packages/appkit/src/tests/mocks/Options.ts +++ b/packages/appkit/src/tests/mocks/Options.ts @@ -2,10 +2,19 @@ import type { ChainAdapter } from '@reown/appkit-core' import type { AppKitOptions } from '../../utils/index.js' import { mainnet, solana } from '../../networks/index.js' import type { SdkVersion } from '@reown/appkit-core' +import { vi } from 'vitest' export const mockOptions = { projectId: 'test-project-id', - adapters: [{ chainNamespace: 'eip155' } as unknown as ChainAdapter], + adapters: [ + { + chainNamespace: 'eip155', + construct: vi.fn(), + on: vi.fn(), + syncConnectors: vi.fn(), + setAuthProvider: vi.fn(), + } as unknown as ChainAdapter + ], networks: [mainnet, solana], metadata: { name: 'Test App', diff --git a/packages/appkit/src/tests/siwe.test.ts b/packages/appkit/src/tests/siwe.test.ts index 9e66fa07e1..0a098d7a77 100644 --- a/packages/appkit/src/tests/siwe.test.ts +++ b/packages/appkit/src/tests/siwe.test.ts @@ -1,6 +1,12 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' -import { ModalController, OptionsController, RouterController, SIWXUtil } from '@reown/appkit-core' -import { AppKit } from '@reown/appkit' +import { + ModalController, + OptionsController, + RouterController, + SIWXUtil, + ChainController +} from '@reown/appkit-core' +import { AppKit, type CaipNetwork } from '@reown/appkit' import * as networks from '@reown/appkit/networks' import { createSIWEConfig, type AppKitSIWEClient } from '@reown/appkit-siwe' import { mockUniversalAdapter } from './mocks/Adapter' @@ -73,7 +79,12 @@ describe('SIWE mapped to SIWX', () => { }) it('should initializeIfEnabled', async () => { - vi.spyOn(siweConfig.methods, 'getSession').mockResolvedValueOnce(null) + vi.spyOn(ChainController, 'checkIfSupportedNetwork').mockReturnValue(true) + + OptionsController.state.siwx = { + getSessions: vi.fn().mockResolvedValueOnce([]) + } as any + await SIWXUtil.initializeIfEnabled() expect(RouterController.state.view).toBe('SIWXSignMessage') @@ -85,6 +96,12 @@ describe('SIWE mapped to SIWX', () => { const createMessageSpy = vi.spyOn(siweConfig.methods, 'createMessage') const verifyMessageSpy = vi.spyOn(siweConfig.methods, 'verifyMessage') + vi.spyOn(ChainController, 'getActiveCaipNetwork').mockReturnValue({ + id: '1', + name: 'Ethereum', + caipNetworkId: 'eip155:1' + } as unknown as CaipNetwork) + await SIWXUtil.requestSignMessage() expect(getNonceSpy).toHaveBeenCalled() From 4fe81434a648f4aa2449d7801d72dfbdbfdbea9e Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 12:10:07 +0000 Subject: [PATCH 16/26] chore: tweak --- packages/adapters/wagmi/src/client.ts | 6 +++--- packages/appkit/src/client.ts | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index 8eecda7978..b0deaa1cd9 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -389,12 +389,12 @@ export class WagmiAdapter extends AdapterBlueprint { // Add wagmi connectors this.addWagmiConnectors(options, appKit) - // Add current wagmi connectors to chain adapter + // Add current wagmi connectors to chain adapter blueprint this.wagmiConfig.connectors.forEach(connector => this.addWagmiConnector(connector, options)) /* - * Watch for new connectors. This is useful if some EIP6963 connectors - * that are added after the initial setup + * Watch for new connectors. This is needed because some EIP6963 connectors + * that are added later in the process the initial setup */ watchConnectors(this.wagmiConfig, { onChange: connectors => diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 2f0af99f65..4bfe180626 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -1747,8 +1747,7 @@ export class AppKit { logger } - const universalProvider = await UniversalProvider.init(universalProviderOptions) - this.universalProvider = universalProvider + this.universalProvider = await UniversalProvider.init(universalProviderOptions) this.listenWalletConnect() } From c108ef3bac0882837f2985bb05c5645f9e1b17b9 Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 12:52:22 +0000 Subject: [PATCH 17/26] chore: fix ci errors --- packages/appkit/src/tests/appkit.test.ts | 3 +-- packages/appkit/src/tests/siwe.test.ts | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/appkit/src/tests/appkit.test.ts b/packages/appkit/src/tests/appkit.test.ts index 8d6b52b1c7..1cfc2f52bf 100644 --- a/packages/appkit/src/tests/appkit.test.ts +++ b/packages/appkit/src/tests/appkit.test.ts @@ -21,8 +21,7 @@ import { StorageUtil, CoreHelperUtil, AlertController, - type ConnectorType, - type ChainAdapter + type ConnectorType } from '@reown/appkit-core' import { SafeLocalStorage, SafeLocalStorageKeys, type CaipNetwork } from '@reown/appkit-common' import { mockOptions } from './mocks/Options' diff --git a/packages/appkit/src/tests/siwe.test.ts b/packages/appkit/src/tests/siwe.test.ts index a771fedb72..e58a7d677f 100644 --- a/packages/appkit/src/tests/siwe.test.ts +++ b/packages/appkit/src/tests/siwe.test.ts @@ -1,12 +1,13 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import { + ChainController, ConnectionController, ModalController, OptionsController, RouterController, SIWXUtil } from '@reown/appkit-core' -import { AppKit } from '@reown/appkit' +import { AppKit, type CaipNetwork } from '@reown/appkit' import * as networks from '@reown/appkit/networks' import { createSIWEConfig, type AppKitSIWEClient } from '@reown/appkit-siwe' import { mockUniversalAdapter } from './mocks/Adapter' From 0a8c9b0489f37758fcb27bbc29c358ff8eaf6b56 Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 13:00:48 +0000 Subject: [PATCH 18/26] chore: remove unused Connector type --- packages/adapters/wagmi/src/tests/client.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapters/wagmi/src/tests/client.test.ts b/packages/adapters/wagmi/src/tests/client.test.ts index e4f0ac616a..119dfe86fd 100644 --- a/packages/adapters/wagmi/src/tests/client.test.ts +++ b/packages/adapters/wagmi/src/tests/client.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, beforeEach, vi } from 'vitest' import { WagmiAdapter } from '../client' -import type { Config, Connector } from '@wagmi/core' +import type { Config } from '@wagmi/core' import { disconnect as wagmiDisconnect, getConnections, From e9524be484ea96315a1b0eb622430bea1afc2377 Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 13:16:55 +0000 Subject: [PATCH 19/26] chore: check if auth provider exists --- packages/appkit/src/client.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 4bfe180626..810455bb35 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -1792,7 +1792,10 @@ export class AppKit { private createAuthProviderForAdapter(chainNamespace: ChainNamespace) { this.createAuthProvider() - this.chainAdapters?.[chainNamespace].setAuthProvider(this.authProvider as W3mFrameProvider) + + if (this.authProvider) { + this.chainAdapters?.[chainNamespace].setAuthProvider(this.authProvider) + } } private createAdapters(blueprints?: AdapterBlueprint[]) { From 3152e621c821f6cf68d78f804fc1ae1fe920d8f2 Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 14:26:18 +0000 Subject: [PATCH 20/26] chore: only fetch provider from auth connector --- packages/adapters/wagmi/src/client.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index b0deaa1cd9..355e33c6e8 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -357,16 +357,11 @@ export class WagmiAdapter extends AdapterBlueprint { } private async addWagmiConnector(connector: Connector, options: AppKitOptions) { - let provider: W3mFrameProvider | UniversalProvider | undefined = undefined + let provider: W3mFrameProvider | undefined = undefined - const shouldFetchProvider = - connector.id === ConstantsUtil.WALLET_CONNECT_CONNECTOR_ID || - connector.id === ConstantsUtil.AUTH_CONNECTOR_ID - - if (shouldFetchProvider) { + if (connector.id === ConstantsUtil.AUTH_CONNECTOR_ID) { provider = (await connector.getProvider().catch(() => undefined)) as | W3mFrameProvider - | UniversalProvider | undefined } From 5dd710720a1ace0d2c5ab73ff35a11ae5f94e35a Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 14:45:46 +0000 Subject: [PATCH 21/26] chore: fixes --- packages/adapters/wagmi/src/client.ts | 13 +++++------ .../adapters/wagmi/src/tests/client.test.ts | 22 +++++++++++-------- packages/appkit/src/client.ts | 10 ++++----- packages/appkit/src/tests/appkit.test.ts | 2 +- .../src/controllers/ConnectorController.ts | 2 +- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/packages/adapters/wagmi/src/client.ts b/packages/adapters/wagmi/src/client.ts index 355e33c6e8..b77b203fc9 100644 --- a/packages/adapters/wagmi/src/client.ts +++ b/packages/adapters/wagmi/src/client.ts @@ -356,13 +356,13 @@ export class WagmiAdapter extends AdapterBlueprint { return formatUnits(params.value, params.decimals) } - private async addWagmiConnector(connector: Connector, options: AppKitOptions) { - let provider: W3mFrameProvider | undefined = undefined - + private addWagmiConnector(connector: Connector, options: AppKitOptions) { + /* + * We don't need to set auth connector from wagmi + * since we already set it in chain adapter blueprint + */ if (connector.id === ConstantsUtil.AUTH_CONNECTOR_ID) { - provider = (await connector.getProvider().catch(() => undefined)) as - | W3mFrameProvider - | undefined + return } this.addConnector({ @@ -374,7 +374,6 @@ export class WagmiAdapter extends AdapterBlueprint { type: PresetsUtil.ConnectorTypesMap[connector.type] ?? 'EXTERNAL', info: connector.id === ConstantsUtil.INJECTED_CONNECTOR_ID ? undefined : { rdns: connector.id }, - provider, chain: this.namespace as ChainNamespace, chains: [] }) diff --git a/packages/adapters/wagmi/src/tests/client.test.ts b/packages/adapters/wagmi/src/tests/client.test.ts index 119dfe86fd..835f64fdb1 100644 --- a/packages/adapters/wagmi/src/tests/client.test.ts +++ b/packages/adapters/wagmi/src/tests/client.test.ts @@ -102,17 +102,21 @@ describe('WagmiAdapter', () => { }) it('should set wagmi connectors', () => { - const addWagmiConnector = vi.spyOn(adapter, 'addWagmiConnector' as any) + adapter.syncConnectors({ networks: [mainnet], projectId: 'YOUR_PROJECT_ID' }, mockAppKit) - vi.spyOn(wagmiCore, 'watchConnectors').mockResolvedValue(vi.fn) - ;(adapter as any).syncConnectors({}, mockAppKit) - - expect(addWagmiConnector).toHaveBeenCalledWith( + expect(adapter.connectors).toStrictEqual([ { - id: 'test-connector' - }, - {} - ) + chain: 'eip155', + chains: [], + explorerId: undefined, + id: 'test-connector', + imageId: undefined, + imageUrl: undefined, + info: { rdns: 'test-connector' }, + name: undefined, + type: 'EXTERNAL' + } + ]) }) it('should listen for wagmi connector changes', () => { diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 810455bb35..0561ae5f4a 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -1695,12 +1695,12 @@ export class AppKit { return this.chainAdapters?.[namespace] } - private isSafe() { - return typeof window !== 'undefined' - } - private createUniversalProvider() { - if (!this.universalProviderInitPromise && this.isSafe() && this.options?.projectId) { + if ( + !this.universalProviderInitPromise && + CoreHelperUtil.isClient() && + this.options?.projectId + ) { this.universalProviderInitPromise = this.initializeUniversalAdapter() } diff --git a/packages/appkit/src/tests/appkit.test.ts b/packages/appkit/src/tests/appkit.test.ts index 1cfc2f52bf..e8f9d3b73d 100644 --- a/packages/appkit/src/tests/appkit.test.ts +++ b/packages/appkit/src/tests/appkit.test.ts @@ -958,7 +958,7 @@ describe('Base', () => { } vi.spyOn(appKit as any, 'initialize').mockResolvedValue(undefined) - vi.spyOn(appKit as any, 'isSafe').mockReturnValue(true) + vi.spyOn(CoreHelperUtil, 'isClient').mockReturnValue(true) vi.spyOn(UniversalProvider, 'init').mockResolvedValue(mockUniversalProvider as any) const initChainAdapters = (appKit as any).initChainAdapters.bind(appKit) diff --git a/packages/core/src/controllers/ConnectorController.ts b/packages/core/src/controllers/ConnectorController.ts index fef906384d..b50868a06d 100644 --- a/packages/core/src/controllers/ConnectorController.ts +++ b/packages/core/src/controllers/ConnectorController.ts @@ -144,7 +144,7 @@ export const ConnectorController = { projectId: optionsState.projectId, sdkType: optionsState.sdkType }) - authConnector.provider.syncTheme({ + authConnector?.provider?.syncTheme({ themeMode, themeVariables, w3mThemeVariables: getW3mThemeVariables(themeVariables, themeMode) From 2068b3c7b43fc0dda0a7b3ef39d6aa1b5d9220fe Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 15:06:16 +0000 Subject: [PATCH 22/26] chore: listen for sync connectors only --- .../adapters/wagmi/src/tests/client.test.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/packages/adapters/wagmi/src/tests/client.test.ts b/packages/adapters/wagmi/src/tests/client.test.ts index 835f64fdb1..f6edb29a72 100644 --- a/packages/adapters/wagmi/src/tests/client.test.ts +++ b/packages/adapters/wagmi/src/tests/client.test.ts @@ -119,24 +119,6 @@ describe('WagmiAdapter', () => { ]) }) - it('should listen for wagmi connector changes', () => { - const onConnectors = vi.fn() - - vi.spyOn(wagmiCore, 'watchConnectors').mockImplementation(onConnectors) - ;(adapter as any).syncConnectors({}, mockAppKit) - - adapter.wagmiConfig._internal.connectors.setState(() => [ - ...adapter.wagmiConfig.connectors, - adapter.wagmiConfig._internal.connectors.setup(mock({ accounts: ['0x123'] })) - ]) - - watchConnectors(adapter.wagmiConfig, { - onChange: onConnectors - }) - - expect(onConnectors).toHaveBeenCalled() - }) - it('should not set info property for injected connector', () => { const mockConnectors = [ { From dd62ee4ee2f1df92ea53424fae9e13c190c7e758 Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 15:48:33 +0000 Subject: [PATCH 23/26] revert: remove reconnect logic for wagmi during siwx login --- packages/appkit/src/client.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/appkit/src/client.ts b/packages/appkit/src/client.ts index 0561ae5f4a..12e4596041 100644 --- a/packages/appkit/src/client.ts +++ b/packages/appkit/src/client.ts @@ -1419,6 +1419,27 @@ export class AppKit { address = AccountController.state.address as string } + if ((adapter as ChainAdapter)?.adapterType === 'wagmi') { + try { + await adapter?.connect({ + id: 'walletConnect', + type: 'WALLET_CONNECT', + chainId: ChainController.state.activeCaipNetwork?.id as string | number + }) + } catch (error) { + /** + * Handle edge case where wagmi detects existing connection but lacks to complete UniversalProvider instance. + * Connection attempt fails due to already connected state - reconnect to restore provider state. + */ + if (adapter?.reconnect) { + adapter?.reconnect({ + id: 'walletConnect', + type: 'WALLET_CONNECT' + }) + } + } + } + this.syncWalletConnectAccounts(chainNamespace) await this.syncAccount({ From 7cfba609dc2d96e4f09d6e813b08cbca71938fbe Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 15:57:06 +0000 Subject: [PATCH 24/26] chore: remove unused code --- packages/adapters/wagmi/src/tests/client.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/adapters/wagmi/src/tests/client.test.ts b/packages/adapters/wagmi/src/tests/client.test.ts index f6edb29a72..8d9469abf7 100644 --- a/packages/adapters/wagmi/src/tests/client.test.ts +++ b/packages/adapters/wagmi/src/tests/client.test.ts @@ -16,11 +16,8 @@ import { waitForTransactionReceipt, getAccount, watchPendingTransactions, - http, - watchConnectors, - mock + http } from '@wagmi/core' -import * as wagmiCore from '@wagmi/core' import { mainnet } from '@wagmi/core/chains' import { CaipNetworksUtil } from '@reown/appkit-utils' import type UniversalProvider from '@walletconnect/universal-provider' From 847cf4f5fab519b5e6571a30e614b11665450d6a Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 18:03:59 +0000 Subject: [PATCH 25/26] chore: mock connectors --- packages/adapters/wagmi/src/tests/client.test.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/adapters/wagmi/src/tests/client.test.ts b/packages/adapters/wagmi/src/tests/client.test.ts index 8d9469abf7..05bb6c93fb 100644 --- a/packages/adapters/wagmi/src/tests/client.test.ts +++ b/packages/adapters/wagmi/src/tests/client.test.ts @@ -18,6 +18,7 @@ import { watchPendingTransactions, http } from '@wagmi/core' +import * as wagmiCore from '@wagmi/core' import { mainnet } from '@wagmi/core/chains' import { CaipNetworksUtil } from '@reown/appkit-utils' import type UniversalProvider from '@walletconnect/universal-provider' @@ -99,6 +100,8 @@ describe('WagmiAdapter', () => { }) it('should set wagmi connectors', () => { + vi.spyOn(wagmiCore, 'watchConnectors').mockImplementation(vi.fn()) + adapter.syncConnectors({ networks: [mainnet], projectId: 'YOUR_PROJECT_ID' }, mockAppKit) expect(adapter.connectors).toStrictEqual([ From 86ae60e20bf289347405ae6c9ef8d7b8e166ffb7 Mon Sep 17 00:00:00 2001 From: MK Date: Tue, 17 Dec 2024 19:18:02 +0000 Subject: [PATCH 26/26] chore: prettier --- packages/adapters/wagmi/src/tests/client.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapters/wagmi/src/tests/client.test.ts b/packages/adapters/wagmi/src/tests/client.test.ts index 05bb6c93fb..00e4b4e4ba 100644 --- a/packages/adapters/wagmi/src/tests/client.test.ts +++ b/packages/adapters/wagmi/src/tests/client.test.ts @@ -101,7 +101,7 @@ describe('WagmiAdapter', () => { it('should set wagmi connectors', () => { vi.spyOn(wagmiCore, 'watchConnectors').mockImplementation(vi.fn()) - + adapter.syncConnectors({ networks: [mainnet], projectId: 'YOUR_PROJECT_ID' }, mockAppKit) expect(adapter.connectors).toStrictEqual([