UNPKG

@web3auth/no-modal

Version:
277 lines (273 loc) 12.4 kB
'use strict'; var _objectWithoutProperties = require('@babel/runtime/helpers/objectWithoutProperties'); var _objectSpread = require('@babel/runtime/helpers/objectSpread2'); var react = require('react'); var viem = require('viem'); var wagmi = require('wagmi'); require('@babel/runtime/helpers/defineProperty'); require('@segment/analytics-next'); var loglevel = require('../../base/loglevel.js'); var baseControllers = require('@toruslabs/base-controllers'); require('@toruslabs/session-manager'); require('@web3auth/auth'); var index = require('../../base/errors/index.js'); require('@toruslabs/constants'); require('@toruslabs/http-helpers'); require('../../base/constants.js'); require('../../base/wallet/index.js'); require('../../base/connector/connectorStatus.js'); var constants$1 = require('../../base/connector/constants.js'); require('jwt-decode'); require('../../base/plugin/errors.js'); require('../../base/plugin/IPlugin.js'); require('../context/Web3AuthInnerContext.js'); require('../context/WalletServicesInnerContext.js'); var useWeb3Auth = require('../hooks/useWeb3Auth.js'); var useWeb3AuthDisconnect = require('../hooks/useWeb3AuthDisconnect.js'); var constants = require('./constants.js'); const _excluded = ["children"]; function getWeb3authConnector(config) { return config.connectors.find(c => c.id === constants$1.WEB3AUTH_CONNECTOR_ID); } // Helper to create a Web3Auth connector to connect with wagmi // eslint-disable-next-line @typescript-eslint/no-explicit-any function createWeb3AuthConnectorForWagmi(provider) { const baseConnector = wagmi.injected({ target: { provider: provider, id: constants$1.WEB3AUTH_CONNECTOR_ID, name: "Web3Auth" } }); return config => { const connector = baseConnector(config); const baseOnAccountsChanged = connector.onAccountsChanged.bind(connector); // we need to handle the `accountsChanged` event emitted on the cross-namespace chain switch. // on evm -> solana, the accountsChanged event is emitted with the solana address, which is not valid for evm. // that causes the `invalid account address` error in wagmi. So, here, we're filtering out the solana addresses. connector.onAccountsChanged = accounts => { if (accounts.length > 0 && !accounts.every(account => typeof account === "string" && viem.isAddress(account))) { loglevel.log.warn("onAccountsChanged::accountsChanged event received on non-EVM address"); return; } baseOnAccountsChanged(accounts); }; return connector; }; } // Helper to initialize connectors for the given wallets // eslint-disable-next-line @typescript-eslint/no-explicit-any function setupConnector(provider, config) { let connector = getWeb3authConnector(config); if (connector) return connector; // Create new connector if not already existing connector = createWeb3AuthConnectorForWagmi(provider); const result = config._internal.connectors.setup(connector); config._internal.connectors.setState(current => [...current, result]); return result; } async function connectWeb3AuthWithWagmi(connector, config) { var _config$storage, _config$storage2; await Promise.all([(_config$storage = config.storage) === null || _config$storage === void 0 ? void 0 : _config$storage.removeItem(`${connector.id}.disconnected`), (_config$storage2 = config.storage) === null || _config$storage2 === void 0 ? void 0 : _config$storage2.setItem("recentConnectorId", connector.id)]); let chainId = await connector.getChainId(); if (!config.chains.find(c => c.id === chainId)) { chainId = config.chains[0].id; } const accounts = await connector.getAccounts(); const connections = new Map([[connector.uid, { accounts: [accounts[0]], chainId, connector }]]); config.setState(state => _objectSpread(_objectSpread({}, state), {}, { chainId, connections, current: connector.uid, status: "connected" })); } function resetConnectorState(config) { config._internal.connectors.setState(prev => prev.filter(c => c.id !== constants$1.WEB3AUTH_CONNECTOR_ID)); config.connectors.filter(c => c.id !== constants$1.WEB3AUTH_CONNECTOR_ID); } async function disconnectWeb3AuthFromWagmi(config) { var _config$storage3, _config$storage4; const connector = getWeb3authConnector(config); await Promise.all([(_config$storage3 = config.storage) === null || _config$storage3 === void 0 ? void 0 : _config$storage3.setItem(`${connector === null || connector === void 0 ? void 0 : connector.id}.disconnected`, true), (_config$storage4 = config.storage) === null || _config$storage4 === void 0 ? void 0 : _config$storage4.removeItem("injected.connected")]); resetConnectorState(config); config.setState(state => _objectSpread(_objectSpread({}, state), {}, { chainId: state.chainId, connections: new Map(), current: undefined, status: "disconnected" })); } function Web3AuthWagmiProvider({ children }) { var _connection$ethereumP, _connection$connector; const { isConnected, connection, chainNamespace } = useWeb3Auth.useWeb3Auth(); const { disconnect } = useWeb3AuthDisconnect.useWeb3AuthDisconnect(); const wagmiConfig = wagmi.useConfig(); const { mutate: reconnect } = wagmi.useReconnect(); const suppressWagmiDisconnect = react.useRef(false); const lastSyncedProvider = react.useRef((_connection$ethereumP = connection === null || connection === void 0 ? void 0 : connection.ethereumProvider) !== null && _connection$ethereumP !== void 0 ? _connection$ethereumP : null); const lastSyncedConnectorName = react.useRef((_connection$connector = connection === null || connection === void 0 ? void 0 : connection.connectorName) !== null && _connection$connector !== void 0 ? _connection$connector : null); wagmi.useConnectionEffect({ onDisconnect: async () => { loglevel.log.info("Disconnected from wagmi"); const isSuppressed = suppressWagmiDisconnect.current; suppressWagmiDisconnect.current = false; if (!isSuppressed && isConnected) await disconnect(); // reset wagmi connector state if the provider handles disconnection because of the accountsChanged event // from the connected provider if (getWeb3authConnector(wagmiConfig)) { resetConnectorState(wagmiConfig); } } }); react.useEffect(() => { (async _connection$ethereumP2 => { const newConnection = connection !== null && connection !== void 0 ? connection : null; const newEth = (_connection$ethereumP2 = connection === null || connection === void 0 ? void 0 : connection.ethereumProvider) !== null && _connection$ethereumP2 !== void 0 ? _connection$ethereumP2 : null; const w3aWagmiConnector = getWeb3authConnector(wagmiConfig); const shouldBindToWagmi = isConnected && chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155 && Boolean(newConnection && newEth); if (shouldBindToWagmi) { const hasSameBinding = lastSyncedProvider.current === newEth && lastSyncedConnectorName.current === newConnection.connectorName && wagmiConfig.state.status === "connected"; if (hasSameBinding) { // rehydration: already connected to the same provider, so no need to reconnect return; } // `ethereumProvider` is a stable proxy (`commonJRPCProvider`) across account switches, // so key wagmi resyncs off the Web3Auth connection object instead of provider identity. if (w3aWagmiConnector) { resetConnectorState(wagmiConfig); } lastSyncedProvider.current = newEth; lastSyncedConnectorName.current = newConnection.connectorName; const connector = setupConnector(newEth, wagmiConfig); if (!connector) { loglevel.log.error("Failed to setup react wagmi connector"); throw new Error("Failed to setup connector"); } await connectWeb3AuthWithWagmi(connector, wagmiConfig); reconnect(); } else { lastSyncedProvider.current = null; lastSyncedConnectorName.current = null; if (wagmiConfig.state.status === "connected") { suppressWagmiDisconnect.current = true; await disconnectWeb3AuthFromWagmi(wagmiConfig); } else if (w3aWagmiConnector) { resetConnectorState(wagmiConfig); } } })(); }, [chainNamespace, connection, isConnected, reconnect, wagmiConfig]); return react.createElement(react.Fragment, null, children); } function WagmiProvider(_ref) { let { children } = _ref, props = _objectWithoutProperties(_ref, _excluded); const { config } = props; const { web3Auth, isInitialized } = useWeb3Auth.useWeb3Auth(); const getTransport = chain => { const { wsTarget, rpcTarget, fallbackWsTargets = [], fallbackRpcTargets = [] } = chain; const transports = []; if (wsTarget) transports.push(wagmi.webSocket(wsTarget)); if (fallbackWsTargets.length > 0) transports.push(...fallbackWsTargets.map(target => wagmi.webSocket(target))); if (rpcTarget) transports.push(wagmi.http(rpcTarget)); if (fallbackRpcTargets.length > 0) transports.push(...fallbackRpcTargets.map(target => wagmi.http(target))); return wagmi.fallback(transports); }; const finalConfig = react.useMemo(() => { var _web3Auth$coreOptions; web3Auth === null || web3Auth === void 0 || web3Auth.setAnalyticsProperties({ wagmi_enabled: true }); if (!isInitialized) return constants.defaultWagmiConfig; const finalConfig = _objectSpread(_objectSpread({ ssr: true }, config), {}, { chains: undefined, connectors: [], transports: {}, multiInjectedProviderDiscovery: false, client: undefined }); const wagmiChains = []; if (isInitialized && web3Auth !== null && web3Auth !== void 0 && (_web3Auth$coreOptions = web3Auth.coreOptions) !== null && _web3Auth$coreOptions !== void 0 && _web3Auth$coreOptions.chains) { var _web3Auth$currentChai; const defaultChainId = (_web3Auth$currentChai = web3Auth.currentChain) === null || _web3Auth$currentChai === void 0 ? void 0 : _web3Auth$currentChai.chainId; const chains = web3Auth.coreOptions.chains.filter(chain => chain.chainNamespace === baseControllers.CHAIN_NAMESPACES.EIP155); if (chains.length === 0) throw index.WalletInitializationError.invalidParams("No valid chains found in web3auth config for wagmi."); chains.forEach(chain => { const wagmiChain = viem.defineChain({ id: Number.parseInt(chain.chainId, 16), // id in number form name: chain.displayName, rpcUrls: { default: { http: [chain.rpcTarget], webSocket: [chain.wsTarget] } }, blockExplorers: chain.blockExplorerUrl ? { default: { name: "explorer", // TODO: correct name if chain config has it url: chain.blockExplorerUrl } } : undefined, nativeCurrency: { name: chain.tickerName, symbol: chain.ticker, decimals: chain.decimals || 18 } }); if (defaultChainId === chain.chainId) { wagmiChains.unshift(wagmiChain); } else { wagmiChains.push(wagmiChain); } finalConfig.transports[wagmiChain.id] = getTransport(chain); }); finalConfig.chains = [wagmiChains[0], ...wagmiChains.slice(1)]; } return wagmi.createConfig(finalConfig); }, [config, web3Auth, isInitialized]); return react.createElement(wagmi.WagmiProvider, // typecast to WagmiProviderPropsBase to avoid type error // as we are omitting the config prop from WagmiProviderProps // and creating a new config object with the finalConfig _objectSpread(_objectSpread({}, props), {}, { config: finalConfig, reconnectOnMount: false }), react.createElement(Web3AuthWagmiProvider, null, children)); } exports.WagmiProvider = WagmiProvider; exports.connectWeb3AuthWithWagmi = connectWeb3AuthWithWagmi; exports.createWeb3AuthConnectorForWagmi = createWeb3AuthConnectorForWagmi; exports.disconnectWeb3AuthFromWagmi = disconnectWeb3AuthFromWagmi; exports.getWeb3authConnector = getWeb3authConnector; exports.resetConnectorState = resetConnectorState; exports.setupConnector = setupConnector;