diff --git a/.github/workflows/nextjs_bundle_analysis.yml b/.github/workflows/nextjs_bundle_analysis.yml
index 1840f8d380..2e9672b0df 100644
--- a/.github/workflows/nextjs_bundle_analysis.yml
+++ b/.github/workflows/nextjs_bundle_analysis.yml
@@ -28,6 +28,8 @@ jobs:
with:
secrets: ${{ toJSON(secrets) }}
+ # Here's the first place where next-bundle-analysis' own script is used
+ # This step pulls the raw bundle stats for the current bundle
- name: Analyze bundle
run: npx -p nextjs-bundle-analysis report
@@ -45,6 +47,19 @@ jobs:
branch: ${{ github.event.pull_request.base.ref }}
path: .next/analyze/base
+ # And here's the second place - this runs after we have both the current and
+ # base branch bundle stats, and will compare them to determine what changed.
+ # There are two configurable arguments that come from package.json:
+ #
+ # - budget: optional, set a budget (bytes) against which size changes are measured
+ # it's set to 350kb here by default, as informed by the following piece:
+ # https://infrequently.org/2021/03/the-performance-inequality-gap/
+ #
+ # - red-status-percentage: sets the percent size increase where you get a red
+ # status indicator, defaults to 20%
+ #
+ # Either of these arguments can be changed or removed by editing the `nextBundleAnalysis`
+ # entry in your package.json file.
- name: Compare with base branch bundle
if: success() && github.event.number
run: ls -laR .next/analyze/base && npx -p nextjs-bundle-analysis compare
@@ -58,8 +73,26 @@ jobs:
echo "$(cat .next/analyze/__bundle_analysis_comment.txt)" >> $GITHUB_OUTPUT
echo EOF >> $GITHUB_OUTPUT
- - name: Comment
- uses: marocchino/sticky-pull-request-comment@v2
+ - name: Find Comment
+ uses: peter-evans/find-comment@v2
+ if: success() && github.event.number
+ id: fc
+ with:
+ issue-number: ${{ github.event.number }}
+ body-includes: ''
+
+ - name: Create Comment
+ uses: peter-evans/create-or-update-comment@v2
+ if: success() && github.event.number && steps.fc.outputs.comment-id == 0
+ with:
+ issue-number: ${{ github.event.number }}
+ body: ${{ steps.get-comment-body.outputs.body }}
+
+ - name: Update Comment
+ uses: peter-evans/create-or-update-comment@v2
+ if: success() && github.event.number && steps.fc.outputs.comment-id != 0
with:
- header: next-bundle-analysis
- message: ${{ steps.get-comment-body.outputs.body }}
+ issue-number: ${{ github.event.number }}
+ body: ${{ steps.get-comment-body.outputs.body }}
+ comment-id: ${{ steps.fc.outputs.comment-id }}
+ edit-mode: replace
diff --git a/.gitignore b/.gitignore
index 505387fd77..97916164f6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -52,5 +52,4 @@ yalc.lock
/public/worker-*.js
/public/workbox-*.js
/public/workbox-*.js.map
-/public/fallback*
-/public/*.js.LICENSE.txt
\ No newline at end of file
+/public/fallback*
\ No newline at end of file
diff --git a/src/components/common/ConnectWallet/WalletDetails.tsx b/src/components/common/ConnectWallet/WalletDetails.tsx
index 6a2ad4caf7..5f0442f50a 100644
--- a/src/components/common/ConnectWallet/WalletDetails.tsx
+++ b/src/components/common/ConnectWallet/WalletDetails.tsx
@@ -1,13 +1,8 @@
-import { Box, Divider, Skeleton, SvgIcon, Typography } from '@mui/material'
-import dynamic from 'next/dynamic'
+import { Box, Divider, SvgIcon, Typography } from '@mui/material'
import type { ReactElement } from 'react'
import LockIcon from '@/public/images/common/lock.svg'
-
-const SocialSigner = dynamic(() => import('@/components/common/SocialSigner'), {
- loading: () => ,
-})
-
+import SocialSigner from '@/components/common/SocialSigner'
import WalletLogin from '@/components/welcome/WelcomeLogin/WalletLogin'
const WalletDetails = ({ onConnect }: { onConnect: () => void }): ReactElement => {
diff --git a/src/components/common/SocialSigner/index.tsx b/src/components/common/SocialSigner/index.tsx
index 0282008027..dbc62649bb 100644
--- a/src/components/common/SocialSigner/index.tsx
+++ b/src/components/common/SocialSigner/index.tsx
@@ -1,7 +1,4 @@
-import useSocialWallet from '@/hooks/wallets/mpc/useSocialWallet'
-import { type ISocialWalletService } from '@/services/mpc/interfaces'
import { Box, Button, LinearProgress, SvgIcon, Tooltip, Typography } from '@mui/material'
-import { COREKIT_STATUS } from '@web3auth/mpc-core-kit'
import { useCallback, useContext, useMemo, useState } from 'react'
import { PasswordRecovery } from '@/components/common/SocialSigner/PasswordRecovery'
import GoogleLogo from '@/public/images/welcome/logo-google.svg'
@@ -18,6 +15,8 @@ import { isSocialLoginWallet } from '@/services/mpc/SocialLoginModule'
import { CGW_NAMES } from '@/hooks/wallets/consts'
import { type ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
import { TxModalContext } from '@/components/tx-flow'
+import { COREKIT_STATUS } from '@web3auth/mpc-core-kit'
+import useSocialWallet from '@/hooks/wallets/mpc/useSocialWallet'
import madProps from '@/utils/mad-props'
import { asError } from '@/services/exceptions/utils'
import ErrorMessage from '@/components/tx/ErrorMessage'
@@ -42,7 +41,7 @@ const useIsSocialWalletEnabled = () => {
}
type SocialSignerLoginProps = {
- socialWalletService: ISocialWalletService | undefined
+ socialWalletService: ReturnType
wallet: ReturnType
supportedChains: ReturnType
isMPCLoginEnabled: ReturnType
diff --git a/src/components/welcome/WelcomeLogin/index.tsx b/src/components/welcome/WelcomeLogin/index.tsx
index 9fcc869f44..ad768bf84a 100644
--- a/src/components/welcome/WelcomeLogin/index.tsx
+++ b/src/components/welcome/WelcomeLogin/index.tsx
@@ -1,9 +1,9 @@
+import SocialSigner from '@/components/common/SocialSigner'
import { AppRoutes } from '@/config/routes'
import { useHasFeature } from '@/hooks/useChains'
import { FEATURES } from '@/utils/chains'
-import { Paper, SvgIcon, Typography, Divider, Link, Box, Skeleton } from '@mui/material'
+import { Paper, SvgIcon, Typography, Divider, Link, Box } from '@mui/material'
import SafeLogo from '@/public/images/logo-text.svg'
-import dynamic from 'next/dynamic'
import css from './styles.module.css'
import { useRouter } from 'next/router'
import WalletLogin from './WalletLogin'
@@ -11,10 +11,6 @@ import { LOAD_SAFE_EVENTS, CREATE_SAFE_EVENTS } from '@/services/analytics/event
import Track from '@/components/common/Track'
import { trackEvent } from '@/services/analytics'
-const SocialSigner = dynamic(() => import('@/components/common/SocialSigner'), {
- loading: () => ,
-})
-
const WelcomeLogin = () => {
const router = useRouter()
const isSocialLoginEnabled = useHasFeature(FEATURES.SOCIAL_LOGIN)
diff --git a/src/hooks/wallets/mpc/__tests__/useMPC.test.ts b/src/hooks/wallets/mpc/__tests__/useMPC.test.ts
index 7c839a0cb8..2cdfd3f689 100644
--- a/src/hooks/wallets/mpc/__tests__/useMPC.test.ts
+++ b/src/hooks/wallets/mpc/__tests__/useMPC.test.ts
@@ -1,7 +1,8 @@
import * as useOnboard from '@/hooks/wallets/useOnboard'
import * as socialWalletOptions from '@/services/mpc/config'
-import { waitFor } from '@/tests/test-utils'
-import { _getMPCCoreKitInstance, initMPC, setMPCCoreKitInstance } from '../useMPC'
+import { renderHook, waitFor } from '@/tests/test-utils'
+import { _getMPCCoreKitInstance, setMPCCoreKitInstance, useInitMPC } from '../useMPC'
+import * as useChains from '@/hooks/useChains'
import { type ChainInfo, RPC_AUTHENTICATION } from '@safe-global/safe-gateway-typescript-sdk'
import { hexZeroPad } from 'ethers/lib/utils'
import { ONBOARD_MPC_MODULE_LABEL } from '@/services/mpc/SocialLoginModule'
@@ -62,55 +63,53 @@ class EventEmittingMockProvider {
}
}
-describe('initMPC', () => {
- const mockOnboard = {
- state: {
- get: () => ({
- wallets: [],
- walletModules: [],
- }),
- },
- } as unknown as OnboardAPI
-
- const mockChain = {
- chainId: '5',
- chainName: 'Goerli',
- blockExplorerUriTemplate: {
- address: 'https://goerli.someprovider.io/{address}',
- txHash: 'https://goerli.someprovider.io/{txHash}',
- api: 'https://goerli.someprovider.io/',
- },
- nativeCurrency: {
- decimals: 18,
- logoUri: 'https://logo.goerli.com',
- name: 'Goerli ETH',
- symbol: 'ETH',
- },
- rpcUri: {
- authentication: RPC_AUTHENTICATION.NO_AUTHENTICATION,
- value: 'https://goerli.somerpc.io',
- },
- } as unknown as ChainInfo
-
+describe('useInitMPC', () => {
beforeEach(() => {
jest.resetAllMocks()
jest.spyOn(socialWalletOptions, 'isSocialWalletOptions').mockReturnValue(true)
})
-
it('should set the coreKit if user is not logged in yet', async () => {
- jest.spyOn(useOnboard, 'connectWallet').mockImplementation(() => Promise.resolve(undefined))
+ const connectWalletSpy = jest.fn().mockImplementation(() => Promise.resolve())
+ jest.spyOn(useOnboard, 'connectWallet').mockImplementation(connectWalletSpy)
jest.spyOn(useOnboard, 'getConnectedWallet').mockReturnValue(null)
+ jest.spyOn(useOnboard, 'default').mockReturnValue({
+ state: {
+ get: () => ({
+ wallets: [],
+ walletModules: [],
+ }),
+ },
+ } as unknown as OnboardAPI)
+ jest.spyOn(useChains, 'useCurrentChain').mockReturnValue({
+ chainId: '5',
+ chainName: 'Goerli',
+ blockExplorerUriTemplate: {
+ address: 'https://goerli.someprovider.io/{address}',
+ txHash: 'https://goerli.someprovider.io/{txHash}',
+ api: 'https://goerli.someprovider.io/',
+ },
+ nativeCurrency: {
+ decimals: 18,
+ logoUri: 'https://logo.goerli.com',
+ name: 'Goerli ETH',
+ symbol: 'ETH',
+ },
+ rpcUri: {
+ authentication: RPC_AUTHENTICATION.NO_AUTHENTICATION,
+ value: 'https://goerli.somerpc.io',
+ },
+ } as unknown as ChainInfo)
const mockWeb3AuthMpcCoreKit = jest.spyOn(require('@web3auth/mpc-core-kit'), 'Web3AuthMPCCoreKit')
mockWeb3AuthMpcCoreKit.mockImplementation(() => {
return new MockMPCCoreKit(COREKIT_STATUS.INITIALIZED, null)
})
- await initMPC(mockChain, mockOnboard)
+ renderHook(() => useInitMPC())
await waitFor(() => {
expect(_getMPCCoreKitInstance()).toBeDefined()
- expect(useOnboard.connectWallet).not.toBeCalled()
+ expect(connectWalletSpy).not.toBeCalled()
})
})
@@ -118,6 +117,33 @@ describe('initMPC', () => {
const connectWalletSpy = jest.fn().mockImplementation(() => Promise.resolve())
jest.spyOn(useOnboard, 'connectWallet').mockImplementation(connectWalletSpy)
jest.spyOn(useOnboard, 'getConnectedWallet').mockReturnValue(null)
+ jest.spyOn(useOnboard, 'default').mockReturnValue({
+ state: {
+ get: () => ({
+ wallets: [],
+ walletModules: [],
+ }),
+ },
+ } as unknown as OnboardAPI)
+ jest.spyOn(useChains, 'useCurrentChain').mockReturnValue({
+ chainId: '5',
+ chainName: 'Goerli',
+ blockExplorerUriTemplate: {
+ address: 'https://goerli.someprovider.io/{address}',
+ txHash: 'https://goerli.someprovider.io/{txHash}',
+ api: 'https://goerli.someprovider.io/',
+ },
+ nativeCurrency: {
+ decimals: 18,
+ logoUri: 'https://logo.goerli.com',
+ name: 'Goerli ETH',
+ symbol: 'ETH',
+ },
+ rpcUri: {
+ authentication: RPC_AUTHENTICATION.NO_AUTHENTICATION,
+ value: 'https://goerli.somerpc.io',
+ },
+ } as unknown as ChainInfo)
const mockWeb3AuthMpcCoreKit = jest.spyOn(require('@web3auth/mpc-core-kit'), 'Web3AuthMPCCoreKit')
const mockProvider = jest.fn()
@@ -125,7 +151,7 @@ describe('initMPC', () => {
return new MockMPCCoreKit(COREKIT_STATUS.LOGGED_IN, mockProvider as unknown as MPCProvider)
})
- await initMPC(mockChain, mockOnboard)
+ renderHook(() => useInitMPC())
await waitFor(() => {
expect(connectWalletSpy).toBeCalled()
@@ -134,13 +160,41 @@ describe('initMPC', () => {
})
it('should copy event handlers and emit chainChanged if the current chain is updated', async () => {
- jest.spyOn(useOnboard, 'connectWallet').mockImplementation(() => Promise.resolve(undefined))
+ const connectWalletSpy = jest.fn().mockImplementation(() => Promise.resolve())
+ jest.spyOn(useOnboard, 'connectWallet').mockImplementation(connectWalletSpy)
jest.spyOn(useOnboard, 'getConnectedWallet').mockReturnValue({
address: hexZeroPad('0x1', 20),
label: ONBOARD_MPC_MODULE_LABEL,
chainId: '1',
provider: {} as unknown as EIP1193Provider,
})
+ jest.spyOn(useOnboard, 'default').mockReturnValue({
+ state: {
+ get: () => ({
+ wallets: [],
+ walletModules: [],
+ }),
+ },
+ } as unknown as OnboardAPI)
+ jest.spyOn(useChains, 'useCurrentChain').mockReturnValue({
+ chainId: '5',
+ chainName: 'Goerli',
+ blockExplorerUriTemplate: {
+ address: 'https://goerli.someprovider.io/{address}',
+ txHash: 'https://goerli.someprovider.io/{txHash}',
+ api: 'https://goerli.someprovider.io/',
+ },
+ nativeCurrency: {
+ decimals: 18,
+ logoUri: 'https://logo.goerli.com',
+ name: 'Goerli ETH',
+ symbol: 'ETH',
+ },
+ rpcUri: {
+ authentication: RPC_AUTHENTICATION.NO_AUTHENTICATION,
+ value: 'https://goerli.somerpc.io',
+ },
+ } as unknown as ChainInfo)
const mockWeb3AuthMpcCoreKit = jest.spyOn(require('@web3auth/mpc-core-kit'), 'Web3AuthMPCCoreKit')
const mockChainChangedListener = jest.fn()
@@ -161,12 +215,12 @@ describe('initMPC', () => {
return new MockMPCCoreKit(COREKIT_STATUS.LOGGED_IN, mockProvider as unknown as MPCProvider)
})
- await initMPC(mockChain, mockOnboard)
+ renderHook(() => useInitMPC())
await waitFor(() => {
expect(mockChainChangedListener).toHaveBeenCalledWith('0x5')
expect(_getMPCCoreKitInstance()).toBeDefined()
- expect(useOnboard.connectWallet).not.toBeCalled()
+ expect(connectWalletSpy).not.toBeCalled()
})
})
})
diff --git a/src/hooks/wallets/mpc/useMPC.ts b/src/hooks/wallets/mpc/useMPC.ts
index c73a8e2fee..b0b9d8544a 100644
--- a/src/hooks/wallets/mpc/useMPC.ts
+++ b/src/hooks/wallets/mpc/useMPC.ts
@@ -1,83 +1,88 @@
-import { IS_PRODUCTION } from '@/config/constants'
-import { connectWallet, getConnectedWallet } from '@/hooks/wallets/useOnboard'
+import { useEffect } from 'react'
import ExternalStore from '@/services/ExternalStore'
-import { SOCIAL_WALLET_OPTIONS } from '@/services/mpc/config'
-import { ONBOARD_MPC_MODULE_LABEL } from '@/services/mpc/SocialLoginModule'
-import { type ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
-import { type OnboardAPI } from '@web3-onboard/core'
+import { COREKIT_STATUS, Web3AuthMPCCoreKit, WEB3AUTH_NETWORK } from '@web3auth/mpc-core-kit'
import { CHAIN_NAMESPACES } from '@web3auth/base'
-import type { Web3AuthMPCCoreKit } from '@web3auth/mpc-core-kit'
-import { COREKIT_STATUS } from '@web3auth/mpc-core-kit'
+
+import { useCurrentChain } from '@/hooks/useChains'
import { getRpcServiceUrl } from '../web3'
+import useOnboard, { connectWallet, getConnectedWallet } from '@/hooks/wallets/useOnboard'
+import { useInitSocialWallet } from './useSocialWallet'
+import { ONBOARD_MPC_MODULE_LABEL } from '@/services/mpc/SocialLoginModule'
+import { isSocialWalletOptions, SOCIAL_WALLET_OPTIONS } from '@/services/mpc/config'
+import { IS_PRODUCTION } from '@/config/constants'
const { getStore, setStore, useStore } = new ExternalStore()
-export const initMPC = async (chain: ChainInfo, onboard: OnboardAPI) => {
- const chainConfig = {
- chainId: `0x${Number(chain.chainId).toString(16)}`,
- chainNamespace: CHAIN_NAMESPACES.EIP155,
- rpcTarget: getRpcServiceUrl(chain.rpcUri),
- displayName: chain.chainName,
- blockExplorer: new URL(chain.blockExplorerUriTemplate.address).origin,
- ticker: chain.nativeCurrency.symbol,
- tickerName: chain.nativeCurrency.name,
- }
+export const useInitMPC = () => {
+ const chain = useCurrentChain()
+ const onboard = useOnboard()
+ useInitSocialWallet()
- const currentInstance = getStore()
- let previousChainChangedListeners: Function[] = []
- if (currentInstance?.provider) {
- // We are already connected. We copy onboards event listener for the chainChanged event to propagate a potentially new chainId
- const oldProvider = currentInstance.provider
- previousChainChangedListeners = oldProvider.listeners('chainChanged')
- }
+ useEffect(() => {
+ if (!chain || !onboard || !isSocialWalletOptions(SOCIAL_WALLET_OPTIONS)) {
+ return
+ }
- const { Web3AuthMPCCoreKit, WEB3AUTH_NETWORK } = await import('@web3auth/mpc-core-kit')
+ const chainConfig = {
+ chainId: `0x${Number(chain.chainId).toString(16)}`,
+ chainNamespace: CHAIN_NAMESPACES.EIP155,
+ rpcTarget: getRpcServiceUrl(chain.rpcUri),
+ displayName: chain.chainName,
+ blockExplorer: new URL(chain.blockExplorerUriTemplate.address).origin,
+ ticker: chain.nativeCurrency.symbol,
+ tickerName: chain.nativeCurrency.name,
+ }
- const web3AuthCoreKit = new Web3AuthMPCCoreKit({
- web3AuthClientId: SOCIAL_WALLET_OPTIONS.web3AuthClientId,
- // Available networks are "sapphire_devnet", "sapphire_mainnet"
- web3AuthNetwork: WEB3AUTH_NETWORK.MAINNET,
- baseUrl: `${window.location.origin}/`,
- uxMode: 'popup',
- enableLogging: !IS_PRODUCTION,
- //@ts-ignore
- chainConfig,
- manualSync: true,
- hashedFactorNonce: 'safe-global-sfa-nonce',
- })
+ const currentInstance = getStore()
+ let previousChainChangedListeners: Function[] = []
+ if (currentInstance?.provider) {
+ // We are already connected. We copy onboards event listener for the chainChanged event to propagate a potentially new chainId
+ const oldProvider = currentInstance.provider
+ previousChainChangedListeners = oldProvider.listeners('chainChanged')
+ }
- return web3AuthCoreKit
- .init()
- .then(() => {
- setStore(web3AuthCoreKit)
- // If rehydration was successful, connect to onboard
- if (web3AuthCoreKit.status !== COREKIT_STATUS.LOGGED_IN || !web3AuthCoreKit.provider) {
- return web3AuthCoreKit
- }
-
- const connectedWallet = getConnectedWallet(onboard.state.get().wallets)
- if (!connectedWallet) {
- connectWallet(onboard, {
- autoSelect: {
- label: ONBOARD_MPC_MODULE_LABEL,
- disableModals: true,
- },
- }).catch((reason) => console.error('Error connecting to MPC module:', reason))
- } else {
- const newProvider = web3AuthCoreKit.provider
+ const web3AuthCoreKit = new Web3AuthMPCCoreKit({
+ web3AuthClientId: SOCIAL_WALLET_OPTIONS.web3AuthClientId,
+ // Available networks are "sapphire_devnet", "sapphire_mainnet"
+ web3AuthNetwork: WEB3AUTH_NETWORK.MAINNET,
+ baseUrl: `${window.location.origin}/`,
+ uxMode: 'popup',
+ enableLogging: !IS_PRODUCTION,
+ chainConfig,
+ manualSync: true,
+ hashedFactorNonce: 'safe-global-sfa-nonce',
+ })
- // To propagate the changedChain we disconnect and connect
- if (previousChainChangedListeners.length > 0 && newProvider) {
- previousChainChangedListeners.forEach((previousListener) =>
- newProvider.addListener('chainChanged', (...args: []) => previousListener(...args)),
- )
- newProvider.emit('chainChanged', `0x${Number(chainConfig.chainId).toString(16)}`)
+ web3AuthCoreKit
+ .init()
+ .then(() => {
+ setStore(web3AuthCoreKit)
+ // If rehydration was successful, connect to onboard
+ if (web3AuthCoreKit.status !== COREKIT_STATUS.LOGGED_IN || !web3AuthCoreKit.provider) {
+ return
}
- }
+ const connectedWallet = getConnectedWallet(onboard.state.get().wallets)
+ if (!connectedWallet) {
+ connectWallet(onboard, {
+ autoSelect: {
+ label: ONBOARD_MPC_MODULE_LABEL,
+ disableModals: true,
+ },
+ }).catch((reason) => console.error('Error connecting to MPC module:', reason))
+ } else {
+ const newProvider = web3AuthCoreKit.provider
- return web3AuthCoreKit
- })
- .catch((error) => console.error(error))
+ // To propagate the changedChain we disconnect and connect
+ if (previousChainChangedListeners.length > 0 && newProvider) {
+ previousChainChangedListeners.forEach((previousListener) =>
+ newProvider.addListener('chainChanged', (...args: []) => previousListener(...args)),
+ )
+ newProvider.emit('chainChanged', `0x${Number(chainConfig.chainId).toString(16)}`)
+ }
+ }
+ })
+ .catch((error) => console.error(error))
+ }, [chain, onboard])
}
export const _getMPCCoreKitInstance = getStore
diff --git a/src/hooks/wallets/mpc/useRehydrateSocialWallet.ts b/src/hooks/wallets/mpc/useRehydrateSocialWallet.ts
deleted file mode 100644
index 799d7f2036..0000000000
--- a/src/hooks/wallets/mpc/useRehydrateSocialWallet.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import useAddressBook from '@/hooks/useAddressBook'
-import useChainId from '@/hooks/useChainId'
-import { useCurrentChain } from '@/hooks/useChains'
-import useOnboard, { connectWallet } from '@/hooks/wallets/useOnboard'
-import { ONBOARD_MPC_MODULE_LABEL } from '@/services/mpc/SocialLoginModule'
-import { useAppDispatch } from '@/store'
-import { upsertAddressBookEntry } from '@/store/addressBookSlice'
-import { type WalletState } from '@web3-onboard/core'
-import { type UserInfo } from '@web3auth/mpc-core-kit'
-import { useCallback, useEffect } from 'react'
-import { checksumAddress } from '@/utils/addresses'
-
-const useRehydrateSocialWallet = () => {
- const chain = useCurrentChain()
- const onboard = useOnboard()
- const currentChainId = useChainId()
- const addressBook = useAddressBook()
- const dispatch = useAppDispatch()
-
- const updateAddressBook = useCallback(
- (userInfo: UserInfo | undefined, wallets: WalletState[] | undefined | void) => {
- if (!userInfo || !wallets || !currentChainId || wallets.length === 0) return
-
- const address = wallets[0].accounts[0]?.address
- if (address) {
- const signerAddress = checksumAddress(address)
- if (addressBook[signerAddress] === undefined) {
- const email = userInfo.email
- dispatch(upsertAddressBookEntry({ address: signerAddress, chainId: currentChainId, name: email }))
- }
- }
- },
- [addressBook, currentChainId, dispatch],
- )
-
- useEffect(() => {
- if (!chain || !onboard) return
-
- const rehydrate = async () => {
- const { initMPC } = await import('./useMPC')
- const { initSocialWallet } = await import('./useSocialWallet')
- const mpcCoreKit = await initMPC(chain, onboard)
-
- if (!mpcCoreKit) return
-
- const socialWalletService = await initSocialWallet(mpcCoreKit)
-
- const onConnect = async () => {
- const wallets = await connectWallet(onboard, {
- autoSelect: {
- label: ONBOARD_MPC_MODULE_LABEL,
- disableModals: true,
- },
- }).catch((reason) => console.error('Error connecting to MPC module:', reason))
-
- // If the signer is not in the address book => add the user's email as name
- const userInfo = socialWalletService?.getUserInfo()
- updateAddressBook(userInfo, wallets)
- }
-
- socialWalletService.setOnConnect(onConnect)
- }
-
- void rehydrate()
- }, [chain, onboard, updateAddressBook])
-}
-
-export default useRehydrateSocialWallet
diff --git a/src/hooks/wallets/mpc/useSocialWallet.ts b/src/hooks/wallets/mpc/useSocialWallet.ts
index 8db21735d6..d98998ffdd 100644
--- a/src/hooks/wallets/mpc/useSocialWallet.ts
+++ b/src/hooks/wallets/mpc/useSocialWallet.ts
@@ -1,15 +1,59 @@
+import useAddressBook from '@/hooks/useAddressBook'
+import useChainId from '@/hooks/useChainId'
import ExternalStore from '@/services/ExternalStore'
import type { ISocialWalletService } from '@/services/mpc/interfaces'
-import { type Web3AuthMPCCoreKit } from '@web3auth/mpc-core-kit'
+import { ONBOARD_MPC_MODULE_LABEL } from '@/services/mpc/SocialLoginModule'
+import SocialWalletService from '@/services/mpc/SocialWalletService'
+import { useAppDispatch } from '@/store'
+import { upsertAddressBookEntry } from '@/store/addressBookSlice'
+import { checksumAddress } from '@/utils/addresses'
+import { useCallback, useEffect } from 'react'
+import useOnboard, { connectWallet } from '../useOnboard'
+import useMpc from './useMPC'
const { getStore, setStore, useStore } = new ExternalStore()
-export const initSocialWallet = async (mpcCoreKit: Web3AuthMPCCoreKit) => {
- const SocialWalletService = (await import('@/services/mpc/SocialWalletService')).default
- const socialWalletService = new SocialWalletService(mpcCoreKit)
- setStore(socialWalletService)
+export const useInitSocialWallet = () => {
+ const mpcCoreKit = useMpc()
+ const onboard = useOnboard()
+ const addressBook = useAddressBook()
+ const currentChainId = useChainId()
+ const dispatch = useAppDispatch()
+ const socialWalletService = useStore()
- return socialWalletService
+ const onConnect = useCallback(async () => {
+ if (!onboard || !socialWalletService) return
+
+ const wallets = await connectWallet(onboard, {
+ autoSelect: {
+ label: ONBOARD_MPC_MODULE_LABEL,
+ disableModals: true,
+ },
+ }).catch((reason) => console.error('Error connecting to MPC module:', reason))
+
+ // If the signer is not in the address book => add the user's email as name
+ const userInfo = socialWalletService.getUserInfo()
+ if (userInfo && wallets && currentChainId && wallets.length > 0) {
+ const address = wallets[0].accounts[0]?.address
+ if (address) {
+ const signerAddress = checksumAddress(address)
+ if (addressBook[signerAddress] === undefined) {
+ const email = userInfo.email
+ dispatch(upsertAddressBookEntry({ address: signerAddress, chainId: currentChainId, name: email }))
+ }
+ }
+ }
+ }, [addressBook, currentChainId, dispatch, onboard, socialWalletService])
+
+ useEffect(() => {
+ socialWalletService?.setOnConnect(onConnect)
+ }, [onConnect, socialWalletService])
+
+ useEffect(() => {
+ if (mpcCoreKit) {
+ setStore(new SocialWalletService(mpcCoreKit))
+ }
+ }, [mpcCoreKit])
}
export const getSocialWalletService = getStore
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 04fb7abb8f..b4dc4d94c5 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -1,4 +1,3 @@
-import useRehydrateSocialWallet from '@/hooks/wallets/mpc/useRehydrateSocialWallet'
import PasswordRecoveryModal from '@/services/mpc/PasswordRecoveryModal'
import Sentry from '@/services/sentry' // needs to be imported first
import type { ReactNode } from 'react'
@@ -39,6 +38,7 @@ import useSafeMessageNotifications from '@/hooks/messages/useSafeMessageNotifica
import useSafeMessagePendingStatuses from '@/hooks/messages/useSafeMessagePendingStatuses'
import useChangedValue from '@/hooks/useChangedValue'
import { TxModalProvider } from '@/components/tx-flow'
+import { useInitMPC } from '@/hooks/wallets/mpc/useMPC'
import { WalletConnectProvider } from '@/services/walletconnect/WalletConnectContext'
import useABTesting from '@/services/tracking/useAbTesting'
import { AbTest } from '@/services/tracking/abTesting'
@@ -64,7 +64,7 @@ const InitApp = (): null => {
useTxTracking()
useSafeMsgTracking()
useBeamer()
- useRehydrateSocialWallet()
+ useInitMPC()
useABTesting(AbTest.HUMAN_DESCRIPTION)
return null
diff --git a/src/services/mpc/SocialLoginModule.ts b/src/services/mpc/SocialLoginModule.ts
index 84052dfbed..6e34ce89d8 100644
--- a/src/services/mpc/SocialLoginModule.ts
+++ b/src/services/mpc/SocialLoginModule.ts
@@ -1,9 +1,14 @@
+import { _getMPCCoreKitInstance } from '@/hooks/wallets/mpc/useMPC'
+import { getSocialWalletService } from '@/hooks/wallets/mpc/useSocialWallet'
import { getWeb3ReadOnly } from '@/hooks/wallets/web3'
+import * as PasswordRecoveryModal from '@/services/mpc/PasswordRecoveryModal'
import { FEATURES, hasFeature } from '@/utils/chains'
import type { ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
import { type WalletInit, ProviderRpcError } from '@web3-onboard/common'
import { type EIP1193Provider } from '@web3-onboard/core'
-import { type Web3AuthMPCCoreKit } from '@web3auth/mpc-core-kit'
+import { COREKIT_STATUS } from '@web3auth/mpc-core-kit'
+
+const getMPCProvider = () => _getMPCCoreKitInstance()?.provider
const assertDefined = (mpcProvider: T | undefined) => {
if (!mpcProvider) {
@@ -18,9 +23,9 @@ export const isSocialLoginWallet = (walletLabel: string | undefined) => {
return walletLabel === ONBOARD_MPC_MODULE_LABEL
}
-const getConnectedAccounts = async (provider: typeof Web3AuthMPCCoreKit.prototype.provider | undefined) => {
+const getConnectedAccounts = async () => {
try {
- const web3 = assertDefined(provider)
+ const web3 = assertDefined(getMPCProvider())
return web3.request({ method: 'eth_accounts' })
} catch (e) {
throw new ProviderRpcError({
@@ -45,13 +50,6 @@ function MpcModule(chain: ChainInfo): WalletInit {
label: ONBOARD_MPC_MODULE_LABEL,
getIcon: async () => (await import('./icon')).default,
getInterface: async () => {
- const { _getMPCCoreKitInstance } = await import('@/hooks/wallets/mpc/useMPC')
- const { getSocialWalletService } = await import('@/hooks/wallets/mpc/useSocialWallet')
- const { COREKIT_STATUS } = await import('@web3auth/mpc-core-kit')
- const { open } = await import('./PasswordRecoveryModal')
-
- const getMPCProvider = () => _getMPCCoreKitInstance()?.provider
-
const provider: EIP1193Provider = {
on: (event, listener) => {
const web3 = assertDefined(getMPCProvider())
@@ -87,11 +85,11 @@ function MpcModule(chain: ChainInfo): WalletInit {
const status = await socialWalletService.loginAndCreate()
if (status === COREKIT_STATUS.REQUIRED_SHARE) {
- open(() => {
- getConnectedAccounts(getMPCProvider()).then(resolve).catch(reject)
+ PasswordRecoveryModal.open(() => {
+ getConnectedAccounts().then(resolve).catch(reject)
})
} else {
- getConnectedAccounts(getMPCProvider()).then(resolve).catch(reject)
+ getConnectedAccounts().then(resolve).catch(reject)
}
}
return