UNPKG

@dynamic-labs/sdk-react-core

Version:

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

104 lines (99 loc) 5.14 kB
'use client' 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var jsxRuntime = require('react/jsx-runtime'); var React = require('react'); var dynamicEvents = require('../../events/dynamicEvents.cjs'); var loadingAndLifecycle = require('../../store/state/loadingAndLifecycle/loadingAndLifecycle.cjs'); /** Context for accessing the current user/session's wallets */ const UserWalletsContext = React.createContext(undefined); const UserWalletsProvider = ({ children }) => { const [userWallets, _setUserWallets] = React.useState([]); const prevUserWallets = React.useRef([]); const addedWalletsIds = React.useRef([]); const removedWalletsIds = React.useRef([]); const setUserWallets = React.useCallback((returnUpdatedWallets) => { _setUserWallets((prevWallets) => { const updatedWallets = returnUpdatedWallets(prevWallets); // Use old state value if nothing changed to prevent unnecessary re-renders if (updatedWallets.length === 0 && prevWallets.length === 0) return prevWallets; if (prevWallets.length === 0 && updatedWallets.length > 0) { dynamicEvents.dynamicEvents.emit('userWalletsPopulated', updatedWallets); } prevUserWallets.current = prevWallets; return updatedWallets; }); }, []); // it's an useEffect because it needs to be called after the userWallets state is updated React.useEffect(() => { addedWalletsIds.current.forEach((walletId) => { const wallet = userWallets.find(({ id }) => id === walletId); if (!wallet) return; dynamicEvents.dynamicEvents.emit('walletAdded', wallet, userWallets); }); removedWalletsIds.current.forEach((walletId) => { const wallet = prevUserWallets.current.find(({ id }) => id === walletId); if (!wallet) return; dynamicEvents.dynamicEvents.emit('walletRemoved', wallet, userWallets); }); addedWalletsIds.current = []; removedWalletsIds.current = []; }, [userWallets]); const memoizedRegisterUserWallet = React.useCallback((newWallet) => setUserWallets((userWallets) => [...userWallets, newWallet]), [setUserWallets]); const memoizedRemoveUserWallet = React.useCallback((walletId) => setUserWallets((userWallets) => userWallets.filter(({ id }) => walletId !== id)), [setUserWallets]); return (jsxRuntime.jsx(UserWalletsContext.Provider, { value: { addedWalletsIds, registerUserWallet: memoizedRegisterUserWallet, removeUserWallet: memoizedRemoveUserWallet, removedWalletsIds, setUserWallets, userWallets, }, children: children })); }; /** Provides access to state and setters of the current user/session wallets array */ const useInternalUserWallets = () => { const context = React.useContext(UserWalletsContext); if (!context) throw new Error('Can only call useInternalUserWallets inside UserWalletsProvider'); return context; }; /** Provides access to the current user/session wallets */ const useUserWallets = () => { var _a; const context = React.useContext(UserWalletsContext); // EXPLANATION: // // The problem: // When we call useConnectAndSign, the wallet that is then added remains in an incomplete state until // all tasks initiated by useConnectAndSign have completely finished running. // If, say, a customer calls switchNetwork() on it in this meantime, the SDK will enter a broken state. // Can be checked by attempting signMessage with wagmi after entering this broken state. // // The Solution: // In order to prevent customers from accessing these wallets while they are incomplete, // we return the old value of userWallets until useConnectAndSign has completely finished running. // // This is done by setting this "initialWalletVerificationInProgress" flag to true while it runs, // and storing the previous value of userWallets in verifiedUserWallets. // We then return this ref instead of the current userWallets. // // This ref is only updated when initialWalletVerificationInProgress is false, i.e. when // there is no wallet being added at the moment. // // FYI this same logic is used in useDynamicContext for primaryWallet const verifiedUserWallets = React.useRef([]); const { initialWalletVerificationInProgress } = loadingAndLifecycle.useLoadingAndLifecycle(); if (!context) throw new Error('Can only call useUserWallets inside UserWalletsProvider'); if (!initialWalletVerificationInProgress) { verifiedUserWallets.current = (_a = context === null || context === void 0 ? void 0 : context.userWallets) !== null && _a !== void 0 ? _a : []; } return verifiedUserWallets.current; }; exports.UserWalletsContext = UserWalletsContext; exports.UserWalletsProvider = UserWalletsProvider; exports.useInternalUserWallets = useInternalUserWallets; exports.useUserWallets = useUserWallets;