UNPKG

@web3auth/no-modal

Version:
247 lines (243 loc) 9.1 kB
import _objectSpread from '@babel/runtime/helpers/objectSpread2'; import _defineProperty from '@babel/runtime/helpers/defineProperty'; import { getAccountsFromNamespaces, parseAccountId } from '@walletconnect/utils'; import { providerErrors, JRPCEngine, providerFromEngine } from '@web3auth/auth'; import { formatChainId } from './utils.js'; import { switchChain, addChain, getAccounts, getEthProviderHandlers, getSolProviderHandlers } from './walletConnectV2Utils.js'; import { createEthMiddleware, createEthChainSwitchMiddleware } from '../../providers/ethereum-provider/rpc/ethRpcMiddlewares.js'; import { createEthJsonRpcClient } from '../../providers/ethereum-provider/rpc/jrpcClient.js'; import { createSolanaMiddleware } from '../../providers/solana-provider/rpc/solanaRpcMiddlewares.js'; import { createSolanaJsonRpcClient } from '../../providers/solana-provider/rpc/JrpcClient.js'; import { BaseProvider } from '../../providers/base-provider/baseProvider.js'; import { WalletLoginError } from '../../base/errors/index.js'; import { CHAIN_NAMESPACES } from '@toruslabs/base-controllers'; import { log } from '../../base/loglevel.js'; var _WalletConnectV2Provider; class WalletConnectV2Provider extends BaseProvider { constructor({ config, state, connector }) { super({ config: { chain: config.chain, chains: config.chains, skipLookupNetwork: !!config.skipLookupNetwork }, state: _objectSpread(_objectSpread({}, state || {}), {}, { chainId: "loading", accounts: [] }) }); _defineProperty(this, "connector", null); this.connector = connector || null; } async enable() { if (!this.connector) throw providerErrors.custom({ message: "Connector is not initialized, pass wallet connect connector in constructor", code: 4902 }); await this.setupProvider(this.connector); return this._providerEngineProxy.request({ method: "eth_accounts" }); } async setupProvider(connector) { this.onConnectorStateUpdate(connector); await this.setupEngine(connector, this.config.chain.chainId); } async switchChain({ chainId }) { if (!this.connector) throw providerErrors.custom({ message: "Connector is not initialized, pass wallet connect connector in constructor", code: 4902 }); const newChainConfig = this.getChain(chainId); if (!newChainConfig) throw WalletLoginError.connectionError("Chain config is not available"); const currentNumChainId = parseInt(this.getCurrentChainId(), 16); await switchChain({ connector: this.connector, chainId: currentNumChainId, newChainId: chainId }); await this.setupEngine(this.connector, chainId); this.lookupNetwork(this.connector, chainId); this.update({ chainId }); } async addChain(chainConfig) { if (!this.connector) throw providerErrors.custom({ message: "Connector is not initialized, pass wallet connect connector in constructor", code: 4902 }); const currentNumChainId = parseInt(this.getCurrentChainId(), 16); await addChain({ connector: this.connector, chainId: currentNumChainId, chainConfig }); } // no need to implement this method in wallet connect v2. async lookupNetwork(_, chainId) { return chainId; } async setupEngine(connector, chainId) { const chain = this.getChain(chainId); if (chain.chainNamespace === CHAIN_NAMESPACES.EIP155) { await this.setupEthEngine(connector, chainId); } else if (chain.chainNamespace === CHAIN_NAMESPACES.SOLANA) { await this.setupSolEngine(connector, chainId); } else { throw new Error(`Unsupported chainNamespace: ${chain.chainNamespace}`); } this.emit("chainChanged", chainId); this.emit("connect", { chainId }); this.update({ chainId }); } async setupEthEngine(connector, chainId) { const chain = this.getChain(chainId); const numChainId = parseInt(chainId, 16); const providerHandlers = getEthProviderHandlers({ connector, chainId: numChainId }); const jrpcRes = await getAccounts(connector); this.update({ accounts: jrpcRes || [] }); const ethMiddleware = createEthMiddleware(providerHandlers); const chainSwitchMiddleware = this.getEthChainSwitchMiddleware(); const engine = new JRPCEngine(); const { networkMiddleware } = createEthJsonRpcClient(chain); engine.push(ethMiddleware); engine.push(chainSwitchMiddleware); engine.push(networkMiddleware); const provider = providerFromEngine(engine); this.updateProviderEngineProxy(provider); } async setupSolEngine(connector, chainId) { const chain = this.getChain(chainId); const providerHandlers = getSolProviderHandlers({ connector, chainId }); const jrpcRes = await getAccounts(connector); this.update({ accounts: jrpcRes || [] }); const solMiddleware = createSolanaMiddleware(providerHandlers); const engine = new JRPCEngine(); const { networkMiddleware } = createSolanaJsonRpcClient(chain); engine.push(solMiddleware); engine.push(networkMiddleware); const provider = providerFromEngine(engine); this.updateProviderEngineProxy(provider); } getEthChainSwitchMiddleware() { const chainSwitchHandlers = { switchChain: async params => { const { chainId } = params; await this.switchChain({ chainId }); }, addChain: async params => { await this.addChain(params); } }; const chainSwitchMiddleware = createEthChainSwitchMiddleware(chainSwitchHandlers); return chainSwitchMiddleware; } connectedTopic() { var _this$connector; if (!this.connector) throw WalletLoginError.notConnectedError("Wallet connect connector is not connected"); if ((_this$connector = this.connector) !== null && _this$connector !== void 0 && (_this$connector = _this$connector.session) !== null && _this$connector !== void 0 && _this$connector.length) { var _this$connector$sessi; // currently we are supporting only 1 active session const lastKeyIndex = this.connector.session.keys.length - 1; return (_this$connector$sessi = this.connector.session.get(this.connector.session.keys[lastKeyIndex])) === null || _this$connector$sessi === void 0 ? void 0 : _this$connector$sessi.topic; } return undefined; } checkIfAccountAllowed(address) { if (!this.connector || !this.connectedTopic()) return false; const sessionData = this.connector.session.get(this.connectedTopic()); const allAccounts = getAccountsFromNamespaces(sessionData.namespaces); let accountAllowed = false; for (const account of allAccounts) { var _parsedAccount$addres; const parsedAccount = parseAccountId(account); if (((_parsedAccount$addres = parsedAccount.address) === null || _parsedAccount$addres === void 0 ? void 0 : _parsedAccount$addres.toLowerCase()) === (address === null || address === void 0 ? void 0 : address.toLowerCase())) { accountAllowed = true; break; } } return accountAllowed; } async onConnectorStateUpdate(connector) { connector.events.on("session_event", async payload => { log.debug("session_event data", payload); if (!this.provider) throw WalletLoginError.notConnectedError("Wallet connect connector is not connected"); const { event } = payload.params; const { name, data } = event || {}; // Check if accounts changed and trigger event if (name === "accountsChanged" && data !== null && data !== void 0 && data.length && this.state.accounts[0] !== data[0] && this.checkIfAccountAllowed(data[0])) { this.update({ accounts: data }); this.emit("accountsChanged", data); } if (event.name === "chainChanged") { if (!data) return; const connectedChainId = data; const formattedChainId = formatChainId(connectedChainId); // Check if chainId changed and trigger event const { currentChain } = this; if (formattedChainId && currentChain.chainId !== formattedChainId) { // Handle rpcUrl update await this.setupEngine(connector, formattedChainId); } } }); } getCurrentChainId() { const currentChain = this.state.chainId; if (!currentChain || currentChain === "loading") { return this.config.chains[0].chainId; } return currentChain; } } _WalletConnectV2Provider = WalletConnectV2Provider; _defineProperty(WalletConnectV2Provider, "getProviderInstance", async params => { const providerFactory = new _WalletConnectV2Provider({ config: { chain: params.chain, chains: params.chains, skipLookupNetwork: params.skipLookupNetwork } }); await providerFactory.setupProvider(params.connector); return providerFactory; }); export { WalletConnectV2Provider };