UNPKG

@pushchain/ui-kit

Version:

Push Chain is a true universal L1 that is 100% EVM compatible. It allows developers to deploy once and make their apps instantly compatible with users from all other L1s (Ethereum, Solana, etc) with zero on-chain code change.

647 lines 27.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.WalletContextProvider = exports.WalletContext = void 0; const tslib_1 = require("tslib"); const jsx_runtime_1 = require("react/jsx-runtime"); const react_1 = tslib_1.__importStar(require("react")); const core_1 = require("@pushchain/core"); const progress_hook_types_1 = require("@pushchain/core/src/lib/progress-hook/progress-hook.types"); const types_1 = require("../types"); const constants_1 = require("../constants"); const WalletProviderRegistry_1 = require("../providers/walletProviders/WalletProviderRegistry"); const PushWalletToast_1 = require("../components/PushWalletToast"); const LoginModal_1 = require("../components/LoginModal"); const WalletContextMap_1 = require("./WalletContextMap"); const useWaapAuth_1 = require("../providers/waap/useWaapAuth"); const waapProvider_1 = require("../providers/waap/waapProvider"); const phantomMobile_1 = require("../providers/walletProviders/solana/phantomMobile"); const walletAuthorization_1 = require("./walletAuthorization"); exports.WalletContext = (0, react_1.createContext)(null); const WalletContextProvider = ({ children, config, app, themeMode = constants_1.PushUI.CONSTANTS.THEME.DARK, themeOverrides, }) => { const [universalAccount, setUniversalAccount] = (0, react_1.useState)(null); const iframeRef = (0, react_1.useRef)(null); const [isWalletVisible, setWalletVisibility] = (0, react_1.useState)(false); // to display the iframe as connect button is clicked const [isWalletMinimised, setMinimiseWallet] = (0, react_1.useState)(false); // to display/hide minimized wallet modal const [isIframeLoading, setIframeLoading] = (0, react_1.useState)(true); const isIframeLoadingRef = (0, react_1.useRef)(isIframeLoading); const [isReadOnly, setIsReadOnly] = (0, react_1.useState)(false); const [connectionStatus, setConnectionStatus] = (0, react_1.useState)(types_1.ConnectionStatus.NOT_CONNECTED); const [externalWallet, setExternalWallet] = (0, react_1.useState)(null); // to connect with external wallet const [progress, setProgress] = (0, react_1.useState)(null); const upgradeResolverRef = (0, react_1.useRef)(null); const pendingExternalWalletStatusRef = (0, react_1.useRef)(null); const pushChainClientRef = (0, react_1.useRef)(null); const setPushChainClient = (client) => { pushChainClientRef.current = client; }; const [modalAppData, setModalAppData] = (0, react_1.useState)(app ? { title: app?.title, logoURL: app?.logoUrl, description: app?.description, } : undefined); const [walletAppData, setWalletAppData] = (0, react_1.useState)(app ? { title: app?.title, logoURL: app?.logoUrl, description: app?.description, } : undefined); const [activeTriggerId, setActiveTriggerId] = (0, react_1.useState)(); const { loginWithWaapSocial } = (0, useWaapAuth_1.useWaapAuth)(); const toggleButtonRefs = react_1.default.useRef({}); const updateModalAppData = (newData) => { setModalAppData((prevData) => ({ ...prevData, ...newData, })); }; const updateWalletAppData = (newData) => { setWalletAppData((prevData) => ({ ...prevData, ...newData, })); }; const handleConnectToPushWallet = () => { setWalletVisibility(true); setConnectionStatus(types_1.ConnectionStatus.CONNECTING); }; // sending wallet config to the Push wallet const sendWalletConfig = () => { const walletConfig = { loginDefaults: config.login, themeMode, appMetadata: walletAppData, themeOverrides: themeOverrides || {}, }; sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.WALLET_CONFIG, data: { ...walletConfig, }, }); }; const handleUserLogOutEvent = () => { if (externalWallet) { const providerReceived = WalletProviderRegistry_1.walletRegistry.getProvider(externalWallet.providerName); providerReceived?.disconnect(); } setConnectionStatus(types_1.ConnectionStatus.NOT_CONNECTED); setUniversalAccount(null); setMinimiseWallet(false); setWalletVisibility(false); setIframeLoading(true); setExternalWallet(null); pendingExternalWalletStatusRef.current = null; setIsReadOnly(false); localStorage.removeItem(`walletInfo_${config?.uid || 'default'}`); document.body.style.overflow = ''; }; // sending events to wallet from dapp const sendMessageToPushWallet = (message) => { if (iframeRef?.current?.contentWindow) { try { iframeRef.current.contentWindow.postMessage(message, constants_1.WALLET_CONFIG_URL[config.network]); } catch (error) { console.error('Error sending message to push wallet tab:', error); } } }; const sendExternalWalletConnectionStatus = (connectedWallet) => { if (isIframeLoadingRef.current || !iframeRef?.current?.contentWindow) { pendingExternalWalletStatusRef.current = connectedWallet; return; } sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.CONNECTION_STATUS, data: { status: 'successful', ...connectedWallet, }, }); }; // response when the wallet sends logged in action const handleIsLoggedInAction = () => { handleNewConnectionRequest(); // setExternalWallet(null); }; // sending a new connection request as soon as wallet gets connected const handleNewConnectionRequest = () => { setConnectionStatus(types_1.ConnectionStatus.AUTHENTICATING); sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.NEW_CONNECTION_REQUEST, }); }; const handleAppConnectionSuccess = (response) => { setConnectionStatus(types_1.ConnectionStatus.CONNECTED); setMinimiseWallet(true); // setIsReadOnly(false); if (response.account) { setUniversalAccount(response.account); } localStorage.setItem(`walletInfo_${config?.uid || 'default'}`, JSON.stringify({ account: response.account, uid: config?.uid || 'default', })); }; const handleAppConnectionRejection = () => { setConnectionStatus(types_1.ConnectionStatus.RETRY); setUniversalAccount(null); }; // Connect external wallet const handleExternalWalletConnection = async (data) => { try { const providerReceived = WalletProviderRegistry_1.walletRegistry.getProvider(data.provider); if (!providerReceived) { return; } const walletInfo = await providerReceived.connect(data.chain); setConnectionStatus(types_1.ConnectionStatus.CONNECTED); setMinimiseWallet(true); const result = core_1.PushChain.utils.account.fromChainAgnostic(walletInfo.caipAddress); setUniversalAccount(result); const connectedWallet = { address: walletInfo.caipAddress, providerName: data.provider, chainType: data.chain, }; localStorage.setItem(`walletInfo_${config?.uid || 'default'}`, JSON.stringify({ wallet: connectedWallet, uid: config?.uid || 'default', })); setExternalWallet(connectedWallet); sendExternalWalletConnectionStatus(connectedWallet); } catch (error) { console.log('Failed to connect to provider', error); sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.CONNECTION_STATUS, data: { status: 'rejected', }, }); throw new Error('Failed to connect to provider'); } }; // handles external wallet signature request const handleExternalWalletSignRequest = async (data) => { if (!externalWallet) { throw new Error('No External wallet connected'); } try { const providerReceived = WalletProviderRegistry_1.walletRegistry.getProvider(externalWallet.providerName); if (!providerReceived) { throw new Error('Provider not found'); } const signature = await providerReceived.signMessage(data); return signature; } catch (error) { console.log('Error in generating signature', error); throw new Error('Signature request failed'); } }; const handleExternalWalletSignTransactionRequest = async (data) => { if (!externalWallet) { throw new Error('No External wallet connected'); } try { const providerReceived = WalletProviderRegistry_1.walletRegistry.getProvider(externalWallet.providerName); if (!providerReceived) { throw new Error('Provider not found'); } const signature = await providerReceived.signAndSendTransaction(data); return signature; } catch (error) { console.log('Error in generating signature', error); throw new Error('Signature request failed'); } }; const handleExternalWalletSignTypedDataRequest = async (data) => { if (!externalWallet) { throw new Error('No External wallet connected'); } try { const providerReceived = WalletProviderRegistry_1.walletRegistry.getProvider(externalWallet.providerName); if (!providerReceived) { throw new Error('Provider not found'); } const signature = await providerReceived.signTypedData(data); return signature; } catch (error) { console.log('Error in generating signature', error); throw new Error('Signature request failed'); } }; const handleSocialConnection = async () => { const result = await loginWithWaapSocial(); if (!result) return; console.log(result); const w = await core_1.PushChain.utils.account.convertExecutorToOriginAccount(result.address); if (!w.account) return; // setUniversalAccount(w.account); // localStorage.setItem( // `walletInfo_${config?.uid || 'default'}`, // JSON.stringify({ // account: w.account, // uid: config?.uid || 'default' // }) // ); sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.SOCIAL_CONNECTION_STATUS, data: { account: w.account, }, }); }; const handleSocialSignAndSendMessage = async (message) => { try { const signature = await (0, waapProvider_1.waapSignMessage)(message); sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.SIGN_MESSAGE, data: { signature }, }); } catch (error) { sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.ERROR, data: { error: error, }, }); } }; const handleSocialSignAndSendTransaction = async (txn) => { try { const signature = await (0, waapProvider_1.waapSignAndSendTransaction)(txn); sendMessageToPushWallet({ type: constants_1.WALLET_TO_APP_ACTION.SIGN_TRANSACTION, data: { signature }, }); } catch (error) { sendMessageToPushWallet({ type: constants_1.WALLET_TO_APP_ACTION.ERROR, data: { error: error, }, }); } }; const handleSocialSignTypedData = async (typedData) => { try { const signature = await (0, waapProvider_1.waapSignTypedData)(typedData); sendMessageToPushWallet({ type: constants_1.WALLET_TO_APP_ACTION.SIGN_TYPED_DATA, data: { signature }, }); } catch (error) { sendMessageToPushWallet({ type: constants_1.WALLET_TO_APP_ACTION.ERROR, data: { error: error, }, }); } }; const handleSignMessage = async (data) => { let signature; if (externalWallet) { signature = await handleExternalWalletSignRequest(data); } else { signature = await (0, waapProvider_1.waapSignMessage)(data); } return signature; }; const handleSignAndSendTransaction = async (data) => { let signature; if (externalWallet) { signature = await handleExternalWalletSignTransactionRequest(data); } else { signature = await (0, waapProvider_1.waapSignAndSendTransaction)(data); } return signature; }; const handleSignTypedData = async (data) => { let signature; if (externalWallet) { signature = await handleExternalWalletSignTypedDataRequest(data); } else { signature = await (0, waapProvider_1.waapSignTypedData)(data); } return signature; }; const handleSignAuthorization = async (params) => { return (0, walletAuthorization_1.signAuthorizationForWalletConnection)(externalWallet, params, WalletProviderRegistry_1.walletRegistry, waapProvider_1.waapSignAuthorization); }; const getAuthWindowConfig = () => { // Calculate the screen width and height const screenWidth = window.screen.width; const screenHeight = window.screen.height; const width = 500; const height = 600; // Calculate the position to center the window const left = (screenWidth - width) / 2; const top = (screenHeight - height) / 2; // Open a new window with the calculated position const windowFeatures = `width=${width},height=${height},left=${left},top=${top},resizable,scrollbars`; return windowFeatures; }; const requestPushWalletConnection = () => { setMinimiseWallet(false); sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.RECONNECT_WALLET, }); // Wait for a response from the Push Wallet iframe return new Promise((resolve, reject) => { const handleMessage = (event) => { if (event.data.type === constants_1.WALLET_TO_APP_ACTION.APP_CONNECTION_SUCCESS) { window.removeEventListener('message', handleMessage); if (event.data.error) { reject(new Error(event.data.error)); } else { resolve(event.data); } } if (event.data.type === constants_1.WALLET_TO_APP_ACTION.APP_CONNECTION_CANCELLED) { window.removeEventListener('message', handleMessage); reject(new Error('Push Wallet connection failed')); setMinimiseWallet(true); } }; window.addEventListener('message', handleMessage); setTimeout(() => { window.removeEventListener('message', handleMessage); reject(new Error('Push Wallet connection timed out')); setMinimiseWallet(true); }, 100000); }); }; const checkAndShowUpgradeIfNeeded = async (pushChainClient) => { setPushChainClient(pushChainClient); if (!pushChainClient) { return false; } try { await pushChainClient.accountStatusReady; if (!pushChainClient.isReadMode && pushChainClient.accountStatus.uea.loaded && pushChainClient.accountStatus.uea.requiresUpgrade) { setMinimiseWallet(false); sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.SHOW_UPGRADE_DRAWER, data: { currentVersion: pushChainClient.accountStatus.uea.version, newVersion: pushChainClient.accountStatus.uea.minRequiredVersion, }, }); // Wait for upgrade button click from iframe return new Promise((resolve, reject) => { upgradeResolverRef.current = { success: () => { upgradeResolverRef.current = null; resolve(true); }, error: (error) => { upgradeResolverRef.current = null; resolve(false); }, }; }); } return true; } catch (error) { console.error('Error checking upgrade status:', error); return false; } }; const handleUpgradeAccountSuccess = () => { setMinimiseWallet(true); // Resolve any pending upgrade promise if (upgradeResolverRef.current?.success) { upgradeResolverRef.current.success(); upgradeResolverRef.current = null; } }; const handleUpgradeAccountError = (error) => { setMinimiseWallet(true); // Reject any pending upgrade promise if (upgradeResolverRef.current?.error) { upgradeResolverRef.current.error(error instanceof Error ? error : new Error('Upgrade failed')); upgradeResolverRef.current = null; } }; const handleUpgradeAccount = async () => { const pushChainClient = pushChainClientRef.current; if (!pushChainClient) { throw new Error('PushChain client not initialized'); } try { await pushChainClient.upgradeAccount({ progressHook: (progress) => { setProgress(progress); if (progress.id === progress_hook_types_1.PROGRESS_HOOK.UEA_MIG_9901) { setTimeout(() => setProgress(null), 10000); } }, }); // Send success response to iframe sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.UPGRADE_ACCOUNT_RESPONSE, data: { success: true }, }); handleUpgradeAccountSuccess(); } catch (error) { console.error('Error upgrading account:', error); // Send error response to iframe sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.UPGRADE_ACCOUNT_RESPONSE, data: { success: false, error: error instanceof Error ? error.message : 'Upgrade failed', }, }); // Reject the upgrade promise if (upgradeResolverRef.current?.error) { upgradeResolverRef.current.error(error instanceof Error ? error : new Error('Upgrade failed')); } } }; (0, react_1.useEffect)(() => { isIframeLoadingRef.current = isIframeLoading; }, [isIframeLoading]); (0, react_1.useEffect)(() => { if ((0, phantomMobile_1.hasPhantomMobileConnectRequest)()) return; const walletInfo = localStorage.getItem(`walletInfo_${config?.uid || 'default'}`); const walletData = walletInfo ? JSON.parse(walletInfo) : null; if (!walletData) return; if (walletData.uid !== config?.uid) return; if (walletData?.wallet && walletData.wallet?.providerName) { setUniversalAccount(core_1.PushChain.utils.account.fromChainAgnostic(walletData.wallet.address)); setExternalWallet(walletData.wallet); } else { setUniversalAccount(walletData.account); } setIsReadOnly(true); setMinimiseWallet(true); setWalletVisibility(true); setConnectionStatus(types_1.ConnectionStatus.CONNECTED); }, []); (0, react_1.useEffect)(() => { const requestedChain = (0, phantomMobile_1.consumePhantomMobileConnectRequest)(); if (!requestedChain) return; setWalletVisibility(true); setConnectionStatus(types_1.ConnectionStatus.CONNECTING); setIsReadOnly(false); handleExternalWalletConnection({ chain: requestedChain, provider: phantomMobile_1.PHANTOM_PROVIDER_NAME, }).catch((error) => { console.log('Failed to resume Phantom mobile connection', error); setConnectionStatus(types_1.ConnectionStatus.RETRY); }); }, []); (0, react_1.useEffect)(() => { if (isIframeLoading || !pendingExternalWalletStatusRef.current) return; const connectedWallet = pendingExternalWalletStatusRef.current; pendingExternalWalletStatusRef.current = null; sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.CONNECTION_STATUS, data: { status: 'successful', ...connectedWallet, }, }); }, [isIframeLoading]); (0, react_1.useEffect)(() => { if (isIframeLoading) return; if (!isReadOnly) return; if (externalWallet) { sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.READ_ONLY_CONNECTION_STATUS, data: { status: 'successful', ...externalWallet, }, }); } else if (universalAccount) { sendMessageToPushWallet({ type: constants_1.APP_TO_WALLET_ACTION.READ_ONLY_CONNECTION_STATUS, data: { status: 'successful', ...universalAccount, }, }); } }, [isIframeLoading, externalWallet]); (0, react_1.useEffect)(() => { const messageHandler = (event) => { if (iframeRef.current?.contentWindow !== event.source) return; switch (event.data.type) { case constants_1.WALLET_TO_APP_ACTION.CONNECT_EXTERNAL_WALLET: handleExternalWalletConnection(event.data.data); break; case constants_1.WALLET_TO_APP_ACTION.CONNECT_SOCIAL: handleSocialConnection(); break; case constants_1.WALLET_TO_APP_ACTION.IS_LOGGED_IN: handleIsLoggedInAction(); break; case constants_1.WALLET_TO_APP_ACTION.APP_CONNECTION_SUCCESS: handleAppConnectionSuccess(event.data.data); break; case constants_1.WALLET_TO_APP_ACTION.APP_CONNECTION_REJECTED: handleAppConnectionRejection(); break; case constants_1.APP_TO_WALLET_ACTION.SIGN_MESSAGE: handleSocialSignAndSendMessage(event.data.data); break; case constants_1.APP_TO_WALLET_ACTION.SIGN_TRANSACTION: handleSocialSignAndSendTransaction(event.data.data); break; case constants_1.APP_TO_WALLET_ACTION.SIGN_TYPED_DATA: handleSocialSignTypedData(event.data.data); break; case constants_1.WALLET_TO_APP_ACTION.IS_LOGGED_OUT: handleUserLogOutEvent(); break; case constants_1.WALLET_TO_APP_ACTION.CLOSE_IFRAME: if (universalAccount) setMinimiseWallet(true); else handleUserLogOutEvent(); break; case constants_1.WALLET_TO_APP_ACTION.UPGRADE_ACCOUNT_REQUEST: handleUpgradeAccount(); break; case constants_1.WALLET_TO_APP_ACTION.UPGRADE_ACCOUNT_SUCCESS: handleUpgradeAccountSuccess(); break; case constants_1.WALLET_TO_APP_ACTION.UPGRADE_ACCOUNT_ERROR: handleUpgradeAccountError(); break; default: console.warn('Unknown message type:', event.data.type); } }; window.addEventListener('message', messageHandler); return () => window.removeEventListener('message', messageHandler); }, [universalAccount]); const WalletContext = (0, WalletContextMap_1.getWalletContext)(config?.uid || 'default'); return ((0, jsx_runtime_1.jsxs)(WalletContext.Provider, { value: { app, config, connectionStatus, universalAccount, isWalletMinimised, modalAppData, themeMode, themeOverrides: {}, updateModalAppData, walletAppData, updateWalletAppData, setMinimiseWallet, handleConnectToPushWallet, handleUserLogOutEvent, handleSignMessage, handleSignAndSendTransaction, handleSignTypedData, handleSignAuthorization, progress, setProgress, isReadOnly, setIsReadOnly, handleExternalWalletConnection, requestPushWalletConnection, checkAndShowUpgradeIfNeeded, activeTriggerId, setActiveTriggerId, toggleButtonRefs, connectionType: externalWallet ? 'external' : 'social', }, children: [(0, jsx_runtime_1.jsx)(LoginModal_1.LoginModal, { iframeRef: iframeRef, themeMode: themeMode, modalAppData: modalAppData, isWalletVisible: isWalletVisible, isIframeLoading: isIframeLoading, setIframeLoading: setIframeLoading, sendWalletConfig: sendWalletConfig, config: config, universalAccount: universalAccount, isWalletMinimised: isWalletMinimised, setMinimiseWallet: setMinimiseWallet, handleUserLogOutEvent: handleUserLogOutEvent, sendMessageToPushWallet: sendMessageToPushWallet, isReadOnly: isReadOnly, toggleButtonRefs: toggleButtonRefs, activeTriggerId: activeTriggerId }), progress && ((0, jsx_runtime_1.jsx)(PushWalletToast_1.PushWalletToast, { progress: progress, setProgress: setProgress, initialChain: universalAccount?.chain, toastPosition: config?.toast?.position, hidden: config?.toast?.hidden })), children] })); }; exports.WalletContextProvider = WalletContextProvider; //# sourceMappingURL=WalletContext.js.map