diff --git a/demo/src/main.ts b/demo/src/main.ts index c13eb1c..c5e62b1 100644 --- a/demo/src/main.ts +++ b/demo/src/main.ts @@ -7,6 +7,7 @@ import { ethers } from 'ethers' const app = createApp(App) app.use(VueDapp, { + connectTimeout: 5000, autoConnect: true, dumb: false, networks: { diff --git a/src/components/Board.vue b/src/components/Board.vue index 69997b7..172bd35 100644 --- a/src/components/Board.vue +++ b/src/components/Board.vue @@ -54,6 +54,8 @@ export default defineComponent({ const isAutoConnecting = ref(false) const isAutoConnect = inject('autoConnect') + const connectTimeout = inject('connectTimeout') as number | undefined + onMounted(async () => { if (isAutoConnect) { try { @@ -70,7 +72,7 @@ export default defineComponent({ const onClickWallet = async (connector: Connector) => { try { close() - await connectWith(connector) + await connectWith(connector, connectTimeout) } catch (err: any) { props.connectErrorHandler && props.connectErrorHandler(err) } diff --git a/src/composables/useWallet.ts b/src/composables/useWallet.ts index 88686ab..f16351d 100644 --- a/src/composables/useWallet.ts +++ b/src/composables/useWallet.ts @@ -67,7 +67,7 @@ export function useWallet(options: useWalletOptions = { useEthers: true }) { } } - async function connectWith(connector: Connector) { + async function connectWith(connector: Connector, timeout?: number) { wallet.error = '' wallet.status = 'connecting' @@ -75,7 +75,7 @@ export function useWallet(options: useWalletOptions = { useEthers: true }) { try { if (!connector) throw new ConnectorNotFoundError() - const { provider } = await connector.connect() + const { provider } = await connector.connect(timeout) wallet.connector = markRaw(connector) wallet.provider = markRaw(provider) diff --git a/src/connectors/connector.ts b/src/connectors/connector.ts index c0b0751..b01f65f 100644 --- a/src/connectors/connector.ts +++ b/src/connectors/connector.ts @@ -19,7 +19,7 @@ export abstract class Connector< this.options = options } - abstract connect(): Promise> + abstract connect(timeout?: number): Promise> abstract getProvider(): Promise abstract disconnect(): Promise abstract onDisconnect(handler: (...args: any[]) => any): void diff --git a/src/connectors/metaMask.ts b/src/connectors/metaMask.ts index 01d3655..e7fa024 100644 --- a/src/connectors/metaMask.ts +++ b/src/connectors/metaMask.ts @@ -81,7 +81,7 @@ export class MetaMaskConnector extends Connector< return false } - async connect() { + async connect(timeout?: number) { let provider = await this.getProvider() /** @@ -96,10 +96,35 @@ export class MetaMaskConnector extends Connector< this.#provider = provider - const accounts = await this.#provider.request({ - method: 'eth_requestAccounts', - params: [{ eth_accounts: {} }], - }) + let accounts + + try { + if (timeout) { + accounts = await Promise.race([ + this.#provider.request({ + method: 'eth_requestAccounts', + params: [{ eth_accounts: {} }], + }), + new Promise((_, reject) => + setTimeout(() => { + reject(new Error('timeout')) + }, timeout), + ), + ]) + } else { + accounts = await this.#provider.request({ + method: 'eth_requestAccounts', + params: [{ eth_accounts: {} }], + }) + } + } catch (error: any) { + throw new Error( + `Failed to request MetaMask${ + error.message ? ': ' + error.message : '' + }`, + ) + } + const account = accounts[0] return { diff --git a/src/plugin.ts b/src/plugin.ts index 3da75ad..7e8ab61 100644 --- a/src/plugin.ts +++ b/src/plugin.ts @@ -13,6 +13,7 @@ export type PluginOptions = { [key: number]: AddEthereumChainParameter } dumb: boolean + connectTimeout?: number } export const VueDapp: Plugin = { @@ -22,6 +23,9 @@ export const VueDapp: Plugin = { availableNetworks.value = { ...NETWORK_DETAILS, ...options.networks } } + options?.connectTimeout && + app.provide('connectTimeout', options?.connectTimeout) + app.provide('autoConnect', options?.autoConnect || false) if (options?.autoConnect && options?.persistDisconnect === false) { const { persistDisconnect } = useWallet()