UNPKG

@wagmi/connectors

Version:

Collection of connectors for Wagmi

386 lines 16.5 kB
import { ChainNotConfiguredError, createConnector, } from '@wagmi/core'; import { SwitchChainError, UserRejectedRequestError, getAddress, numberToHex, } from 'viem'; coinbaseWallet.type = 'coinbaseWallet'; export function coinbaseWallet(parameters = {}) { if (parameters.version === '3' || parameters.headlessMode) return version3(parameters); return version4(parameters); } function version4(parameters) { let walletProvider; let accountsChanged; let chainChanged; let disconnect; return createConnector((config) => ({ id: 'coinbaseWalletSDK', name: 'Coinbase Wallet', rdns: 'com.coinbase.wallet', type: coinbaseWallet.type, async connect({ chainId, ...rest } = {}) { try { const provider = await this.getProvider(); const accounts = (await provider.request({ method: 'eth_requestAccounts', params: 'instantOnboarding' in rest && rest.instantOnboarding ? [{ onboarding: 'instant' }] : [], })).map((x) => getAddress(x)); if (!accountsChanged) { accountsChanged = this.onAccountsChanged.bind(this); provider.on('accountsChanged', accountsChanged); } if (!chainChanged) { chainChanged = this.onChainChanged.bind(this); provider.on('chainChanged', chainChanged); } if (!disconnect) { disconnect = this.onDisconnect.bind(this); provider.on('disconnect', disconnect); } // Switch to chain if provided let currentChainId = await this.getChainId(); if (chainId && currentChainId !== chainId) { const chain = await this.switchChain({ chainId }).catch((error) => { if (error.code === UserRejectedRequestError.code) throw error; return { id: currentChainId }; }); currentChainId = chain?.id ?? currentChainId; } return { accounts, chainId: currentChainId }; } catch (error) { if (/(user closed modal|accounts received is empty|user denied account|request rejected)/i.test(error.message)) throw new UserRejectedRequestError(error); throw error; } }, async disconnect() { const provider = await this.getProvider(); if (accountsChanged) { provider.removeListener('accountsChanged', accountsChanged); accountsChanged = undefined; } if (chainChanged) { provider.removeListener('chainChanged', chainChanged); chainChanged = undefined; } if (disconnect) { provider.removeListener('disconnect', disconnect); disconnect = undefined; } provider.disconnect(); provider.close?.(); }, async getAccounts() { const provider = await this.getProvider(); return (await provider.request({ method: 'eth_accounts', })).map((x) => getAddress(x)); }, async getChainId() { const provider = await this.getProvider(); const chainId = (await provider.request({ method: 'eth_chainId', })); return Number(chainId); }, async getProvider() { if (!walletProvider) { const preference = (() => { if (typeof parameters.preference === 'string') return { options: parameters.preference }; return { ...parameters.preference, options: parameters.preference?.options ?? 'all', }; })(); const { createCoinbaseWalletSDK } = await import('@coinbase/wallet-sdk'); const sdk = createCoinbaseWalletSDK({ ...parameters, appChainIds: config.chains.map((x) => x.id), preference, }); walletProvider = sdk.getProvider(); } return walletProvider; }, async isAuthorized() { try { const accounts = await this.getAccounts(); return !!accounts.length; } catch { return false; } }, async switchChain({ addEthereumChainParameter, chainId }) { const chain = config.chains.find((chain) => chain.id === chainId); if (!chain) throw new SwitchChainError(new ChainNotConfiguredError()); const provider = await this.getProvider(); try { await provider.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: numberToHex(chain.id) }], }); return chain; } catch (error) { // Indicates chain is not added to provider if (error.code === 4902) { try { let blockExplorerUrls; if (addEthereumChainParameter?.blockExplorerUrls) blockExplorerUrls = addEthereumChainParameter.blockExplorerUrls; else blockExplorerUrls = chain.blockExplorers?.default.url ? [chain.blockExplorers?.default.url] : []; let rpcUrls; if (addEthereumChainParameter?.rpcUrls?.length) rpcUrls = addEthereumChainParameter.rpcUrls; else rpcUrls = [chain.rpcUrls.default?.http[0] ?? '']; const addEthereumChain = { blockExplorerUrls, chainId: numberToHex(chainId), chainName: addEthereumChainParameter?.chainName ?? chain.name, iconUrls: addEthereumChainParameter?.iconUrls, nativeCurrency: addEthereumChainParameter?.nativeCurrency ?? chain.nativeCurrency, rpcUrls, }; await provider.request({ method: 'wallet_addEthereumChain', params: [addEthereumChain], }); return chain; } catch (error) { throw new UserRejectedRequestError(error); } } throw new SwitchChainError(error); } }, onAccountsChanged(accounts) { if (accounts.length === 0) this.onDisconnect(); else config.emitter.emit('change', { accounts: accounts.map((x) => getAddress(x)), }); }, onChainChanged(chain) { const chainId = Number(chain); config.emitter.emit('change', { chainId }); }, async onDisconnect(_error) { config.emitter.emit('disconnect'); const provider = await this.getProvider(); if (accountsChanged) { provider.removeListener('accountsChanged', accountsChanged); accountsChanged = undefined; } if (chainChanged) { provider.removeListener('chainChanged', chainChanged); chainChanged = undefined; } if (disconnect) { provider.removeListener('disconnect', disconnect); disconnect = undefined; } }, })); } function version3(parameters) { const reloadOnDisconnect = false; let sdk; let walletProvider; let accountsChanged; let chainChanged; let disconnect; return createConnector((config) => ({ id: 'coinbaseWalletSDK', name: 'Coinbase Wallet', rdns: 'com.coinbase.wallet', type: coinbaseWallet.type, async connect({ chainId } = {}) { try { const provider = await this.getProvider(); const accounts = (await provider.request({ method: 'eth_requestAccounts', })).map((x) => getAddress(x)); if (!accountsChanged) { accountsChanged = this.onAccountsChanged.bind(this); provider.on('accountsChanged', accountsChanged); } if (!chainChanged) { chainChanged = this.onChainChanged.bind(this); provider.on('chainChanged', chainChanged); } if (!disconnect) { disconnect = this.onDisconnect.bind(this); provider.on('disconnect', disconnect); } // Switch to chain if provided let currentChainId = await this.getChainId(); if (chainId && currentChainId !== chainId) { const chain = await this.switchChain({ chainId }).catch((error) => { if (error.code === UserRejectedRequestError.code) throw error; return { id: currentChainId }; }); currentChainId = chain?.id ?? currentChainId; } return { accounts, chainId: currentChainId }; } catch (error) { if (/(user closed modal|accounts received is empty|user denied account)/i.test(error.message)) throw new UserRejectedRequestError(error); throw error; } }, async disconnect() { const provider = await this.getProvider(); if (accountsChanged) { provider.removeListener('accountsChanged', accountsChanged); accountsChanged = undefined; } if (chainChanged) { provider.removeListener('chainChanged', chainChanged); chainChanged = undefined; } if (disconnect) { provider.removeListener('disconnect', disconnect); disconnect = undefined; } provider.disconnect(); provider.close(); }, async getAccounts() { const provider = await this.getProvider(); return (await provider.request({ method: 'eth_accounts', })).map((x) => getAddress(x)); }, async getChainId() { const provider = await this.getProvider(); const chainId = await provider.request({ method: 'eth_chainId', }); return Number(chainId); }, async getProvider() { if (!walletProvider) { // Unwrapping import for Vite compatibility. // See: https://github.com/vitejs/vite/issues/9703 const CoinbaseWalletSDK = await (async () => { const { default: SDK } = await import('cbw-sdk'); if (typeof SDK !== 'function' && typeof SDK.default === 'function') return SDK.default; return SDK; })(); sdk = new CoinbaseWalletSDK({ ...parameters, reloadOnDisconnect }); // Force types to retrieve private `walletExtension` method from the Coinbase Wallet SDK. const walletExtensionChainId = sdk.walletExtension?.getChainId(); const chain = config.chains.find((chain) => parameters.chainId ? chain.id === parameters.chainId : chain.id === walletExtensionChainId) || config.chains[0]; const chainId = parameters.chainId || chain?.id; const jsonRpcUrl = parameters.jsonRpcUrl || chain?.rpcUrls.default.http[0]; walletProvider = sdk.makeWeb3Provider(jsonRpcUrl, chainId); } return walletProvider; }, async isAuthorized() { try { const accounts = await this.getAccounts(); return !!accounts.length; } catch { return false; } }, async switchChain({ addEthereumChainParameter, chainId }) { const chain = config.chains.find((chain) => chain.id === chainId); if (!chain) throw new SwitchChainError(new ChainNotConfiguredError()); const provider = await this.getProvider(); try { await provider.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: numberToHex(chain.id) }], }); return chain; } catch (error) { // Indicates chain is not added to provider if (error.code === 4902) { try { let blockExplorerUrls; if (addEthereumChainParameter?.blockExplorerUrls) blockExplorerUrls = addEthereumChainParameter.blockExplorerUrls; else blockExplorerUrls = chain.blockExplorers?.default.url ? [chain.blockExplorers?.default.url] : []; let rpcUrls; if (addEthereumChainParameter?.rpcUrls?.length) rpcUrls = addEthereumChainParameter.rpcUrls; else rpcUrls = [chain.rpcUrls.default?.http[0] ?? '']; const addEthereumChain = { blockExplorerUrls, chainId: numberToHex(chainId), chainName: addEthereumChainParameter?.chainName ?? chain.name, iconUrls: addEthereumChainParameter?.iconUrls, nativeCurrency: addEthereumChainParameter?.nativeCurrency ?? chain.nativeCurrency, rpcUrls, }; await provider.request({ method: 'wallet_addEthereumChain', params: [addEthereumChain], }); return chain; } catch (error) { throw new UserRejectedRequestError(error); } } throw new SwitchChainError(error); } }, onAccountsChanged(accounts) { if (accounts.length === 0) this.onDisconnect(); else config.emitter.emit('change', { accounts: accounts.map((x) => getAddress(x)), }); }, onChainChanged(chain) { const chainId = Number(chain); config.emitter.emit('change', { chainId }); }, async onDisconnect(_error) { config.emitter.emit('disconnect'); const provider = await this.getProvider(); if (accountsChanged) { provider.removeListener('accountsChanged', accountsChanged); accountsChanged = undefined; } if (chainChanged) { provider.removeListener('chainChanged', chainChanged); chainChanged = undefined; } if (disconnect) { provider.removeListener('disconnect', disconnect); disconnect = undefined; } }, })); } //# sourceMappingURL=coinbaseWallet.js.map