UNPKG

@dynamic-labs/sdk-react-core

Version:

A React SDK for implementing wallet web3 authentication and authorization to your website.

276 lines (271 loc) 14.8 kB
'use client' 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var _tslib = require('../../../../../_virtual/_tslib.cjs'); var React = require('react'); var utils = require('@dynamic-labs/utils'); var walletConnectorCore = require('@dynamic-labs/wallet-connector-core'); var sdkApiCore = require('@dynamic-labs/sdk-api-core'); var UserWalletsContext = require('../../../context/UserWalletsContext/UserWalletsContext.cjs'); require('../../../config/ApiEndpoint.cjs'); require('../../../store/state/projectSettings/projectSettings.cjs'); require('../../constants/values.cjs'); require('@dynamic-labs/multi-wallet'); require('../../../shared/logger.cjs'); require('../../constants/colors.cjs'); require('react-international-phone'); require('@dynamic-labs/iconic'); require('react/jsx-runtime'); require('../../../context/ViewContext/ViewContext.cjs'); require('@dynamic-labs/wallet-book'); require('../../../shared/consts/index.cjs'); require('../../../store/state/nonce/nonce.cjs'); var shouldManuallyReconnectOnRefresh = require('../../functions/shouldManuallyReconnectOnRefresh/shouldManuallyReconnectOnRefresh.cjs'); var updatePrimaryWalletId = require('../../functions/updatePrimaryWalletId/updatePrimaryWalletId.cjs'); var getWalletUniqueId = require('../../functions/getWalletUniqueId/getWalletUniqueId.cjs'); var connectedWalletsInfo = require('../../../store/state/connectedWalletsInfo/connectedWalletsInfo.cjs'); require('../../../store/state/dynamicContextProps/dynamicContextProps.cjs'); var primaryWalletId = require('../../../store/state/primaryWalletId/primaryWalletId.cjs'); require('../../../store/state/user/user.cjs'); var session = require('../../../data/api/session/session.cjs'); require('../../../locale/locale.cjs'); var isConnectOnly = require('../authenticationHooks/helpers/isConnectOnly.cjs'); var getWalletConnectorForWallet = require('../../functions/getWalletConnectorForWallet/getWalletConnectorForWallet.cjs'); var useDebounce = require('../useDebounce/useDebounce.cjs'); var authMode = require('../../../store/state/authMode/authMode.cjs'); var updateUserWalletsFromConnectedWallets = require('./updateUserWalletsFromConnectedWallets/updateUserWalletsFromConnectedWallets.cjs'); const useConnectWallet = ({ enableVisitTrackingOnConnectOnly, environmentId, primaryWalletId: primaryWalletId$1, walletConnectorOptions, handleConnectedWallet, setShowAuthFlow, isBridgeFlow, }) => { const connectedWalletsInfo$1 = connectedWalletsInfo.useConnectedWalletsInfo(); const [connectedWallets, _setConnectedWallets] = React.useState([]); const { setUserWallets, addedWalletsIds, removedWalletsIds } = UserWalletsContext.useInternalUserWallets(); /** This wrapper is to ensure userWallets is always properly updated alongside connectedWallets */ const setConnectedWallets = React.useCallback((newWallets) => { // Prevent unnecessary re-renders when state is empty _setConnectedWallets((prevWallets) => { if (prevWallets.length === 0 && newWallets.length === 0) { return prevWallets; } return newWallets; }); setUserWallets((userWallets) => updateUserWalletsFromConnectedWallets.updateUserWalletsFromConnectedWallets(userWallets, newWallets)); }, [setUserWallets]); const disconnectWallet = React.useCallback((walletId) => _tslib.__awaiter(void 0, void 0, void 0, function* () { const walletToDisconnect = connectedWallets.find((wallet) => wallet.id === walletId); yield (walletToDisconnect === null || walletToDisconnect === void 0 ? void 0 : walletToDisconnect.connector.endSession()); const updatedConnectedWalletsInfo = connectedWalletsInfo$1.filter((wallet) => wallet.id !== walletId); connectedWalletsInfo.setConnectedWalletsInfo(updatedConnectedWalletsInfo); removedWalletsIds.current.push(walletId); if (walletId !== primaryWalletId$1) { return; } const hasConnectedWallet = updatedConnectedWalletsInfo.length > 0; if (isBridgeFlow || !hasConnectedWallet) { primaryWalletId.resetPrimaryWalletId(); } else { updatePrimaryWalletId.updatePrimaryWalletId(updatedConnectedWalletsInfo[0].id); } }), [ connectedWallets, connectedWalletsInfo$1, isBridgeFlow, primaryWalletId$1, removedWalletsIds, ]); // The function to update and define the connectedWallets list. // It should be called on the first render, when connectedWalletsInfo updates and when walletConnectorOptions updates. // To avoid unnecessary updates that are causing issues with connectors added asynchronously, // we're debouncing this function const updateConnectedWalletsList = useDebounce.useDebounce(() => _tslib.__awaiter(void 0, void 0, void 0, function* () { const walletConnectors = walletConnectorOptions.map((wallet) => wallet.walletConnector); if (!walletConnectors.length) { return; } const updatedConnectedWallets = (yield Promise.all(connectedWalletsInfo$1.map((storedConnectedWalletInfo) => _tslib.__awaiter(void 0, void 0, void 0, function* () { const walletConnector = walletConnectorCore.getWalletConnectorByKey(walletConnectors, storedConnectedWalletInfo.walletConnectorKey); if (!walletConnector) { walletConnectorCore.logger.error('Could not find walletConnector: ' + storedConnectedWalletInfo.walletConnectorKey); yield disconnectWallet(storedConnectedWalletInfo.id); return null; } if (walletConnectorCore.isHardwareWalletConnector(walletConnector) && storedConnectedWalletInfo.hardwareWallet === sdkApiCore.HardwareWalletEnum.Ledger) { walletConnector.isHardwareWalletEnabled = true; } const [walletAddress] = yield walletConnector.getConnectedAccounts(); if (!walletAddress) { yield disconnectWallet(storedConnectedWalletInfo.id); return null; } const additionalAddresses = yield walletConnector.getAdditionalAddresses(walletAddress); const walletChain = walletConnector.connectedChain; const walletObject = walletConnector.createWallet({ additionalAddresses, address: walletAddress, chain: walletChain, connector: walletConnector, id: storedConnectedWalletInfo.id, isAuthenticated: false, key: walletConnector.key, }); return walletObject; })))).filter((wallet) => Boolean(wallet)); setConnectedWallets(updatedConnectedWallets); }), 300); // Generate the connectedWallets list when connectedWalletsInfo (localStorage) or memoized wallet connector updates React.useEffect(() => { updateConnectedWalletsList(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [connectedWalletsInfo$1, walletConnectorOptions]); const updateConnectedWalletById = React.useCallback((walletId, walletObject) => { var _a; const clonedConnectedWalletsList = [...connectedWallets]; const connectedWalletIndex = clonedConnectedWalletsList.findIndex((connectedWallet) => connectedWallet.id === walletId); if (connectedWalletIndex < 0) { return; } clonedConnectedWalletsList[connectedWalletIndex] = clonedConnectedWalletsList[connectedWalletIndex].connector.createWallet(Object.assign(Object.assign({}, clonedConnectedWalletsList[connectedWalletIndex]), { address: (_a = walletObject.address) !== null && _a !== void 0 ? _a : clonedConnectedWalletsList[connectedWalletIndex].address, connector: getWalletConnectorForWallet.getWalletConnectorForWallet(clonedConnectedWalletsList[connectedWalletIndex]) })); setConnectedWallets(clonedConnectedWalletsList); }, [connectedWallets, setConnectedWallets]); // Keeps connected wallet data inside localStorage const applyConnectedWalletToStore = React.useCallback(({ walletId, walletConnectorKey, walletChain, provider, }) => { const updatedConnectedWalletsInfo = [...connectedWalletsInfo$1]; const walletConnectors = walletConnectorOptions.map((wallet) => wallet.walletConnector); const walletConnector = walletConnectorCore.getWalletConnectorByKey(walletConnectors, walletConnectorKey); const hardwareWallet = walletConnector && walletConnectorCore.isHardwareWalletConnector(walletConnector) && walletConnector.isHardwareWalletEnabled ? sdkApiCore.HardwareWalletEnum.Ledger : undefined; updatedConnectedWalletsInfo.push({ hardwareWallet, id: walletId, provider, walletChain, walletConnectorKey, }); connectedWalletsInfo.setConnectedWalletsInfo(updatedConnectedWalletsInfo); }, [connectedWalletsInfo$1, walletConnectorOptions]); // Updates connected wallet (network and address) and verifies connected wallet connection const refreshConnectedWallet = (walletId, walletConnector) => _tslib.__awaiter(void 0, void 0, void 0, function* () { if (shouldManuallyReconnectOnRefresh.shouldManuallyReconnectOnRefresh(walletConnector)) { yield walletConnector.connect(); } const currentWalletConnectorAddress = yield walletConnector.getAddress(); if (currentWalletConnectorAddress && handleConnectedWallet) { const shouldProceedWithConnection = yield handleConnectedWallet({ address: currentWalletConnectorAddress, chain: walletConnector.connectedChain, connector: walletConnector, }); if (!shouldProceedWithConnection) { walletConnectorCore.logger.info('Connection was not established because handleConnectedWallet returned false'); disconnectWallet(walletId); setShowAuthFlow(false, { emitCancelAuth: true }); return; } } updateConnectedWalletById(walletId, { address: currentWalletConnectorAddress, }); }); const connectWallet = React.useCallback((walletConnector, getAddressOpts, options) => _tslib.__awaiter(void 0, void 0, void 0, function* () { const { applyHandleConnectedWallet = true } = options !== null && options !== void 0 ? options : {}; let walletAddress; try { walletAddress = yield walletConnector.getAddress(getAddressOpts); } catch (error) { if (error instanceof utils.CustomError) { throw error; } } // Throw a generic error for any errors we're not processing above if (!walletAddress) { throw new utils.MissingPublicAddressError(); } if (handleConnectedWallet && applyHandleConnectedWallet) { const shouldProceedWithConnection = yield handleConnectedWallet({ address: walletAddress, chain: walletConnector.connectedChain, connector: walletConnector, }); if (!shouldProceedWithConnection) { walletConnectorCore.logger.info('Connection was not established because handleConnectedWallet returned false'); setShowAuthFlow(false); return; } } const isWalletStored = connectedWalletsInfo$1.some(({ walletConnectorKey: storedWalletConnectorKey }) => storedWalletConnectorKey === walletConnector.key); const walletChain = walletConnector.connectedChain; const authMode$1 = authMode.getAuthMode(); const shouldCreateVisit = !isWalletStored && (authMode$1 !== 'connect-only' || enableVisitTrackingOnConnectOnly); if (shouldCreateVisit) { // send information to backend to kick off background jobs // so verify/sign on the next step could go by more quickly // this is async work, but DO NOT AWAIT session.createVisit({ authMode: authMode$1, chain: walletChain || '', environmentId, publicWalletAddress: walletAddress, walletName: walletConnector.key, walletProvider: walletConnectorCore.getWalletProvider(walletConnector), }); } // On connect and sign, we don't want to add this wallet to userWallets // until it has been signed. Therefore, we don't add it to // the connectedWallets array because userWallets draws from it. // In this scenario we only need the wallet address, since the id will come from somewhere else. // In fact, there is a refactor planned to never use the connect-wallet-X ids anymore: // https://linear.app/dynamic-labs/issue/QNTM-784/rework-the-way-we-compute-wallet-ids if (!isConnectOnly.isConnectOnly()) return { address: walletAddress, id: '' }; const walletId = getWalletUniqueId.getWalletUniqueId({ address: walletAddress, chain: walletConnector.connectedChain, connectorKey: walletConnector.key, }); if (!primaryWalletId$1) { updatePrimaryWalletId.updatePrimaryWalletId(walletId); } addedWalletsIds.current.push(walletId); if (isWalletStored) { yield updateConnectedWalletsList(); } else { applyConnectedWalletToStore({ provider: walletConnectorCore.getWalletProvider(walletConnector), walletAddress: walletAddress, walletChain, walletConnectorKey: walletConnector.key, walletId, }); } return { address: walletAddress, id: walletId }; }), [ addedWalletsIds, applyConnectedWalletToStore, connectedWalletsInfo$1, enableVisitTrackingOnConnectOnly, environmentId, handleConnectedWallet, primaryWalletId$1, setShowAuthFlow, updateConnectedWalletsList, ]); const getConnectedWalletById = React.useCallback((walletId) => connectedWallets.find((wallet) => wallet.id === walletId), [connectedWallets]); return { connectWallet, connectedWallets, connectedWalletsInfo: connectedWalletsInfo$1, disconnectWallet, getConnectedWalletById, refreshConnectedWallet, }; }; exports.useConnectWallet = useConnectWallet;