From 798e998b4c08cfd00c6a1af9fffd8290e9f99f5c Mon Sep 17 00:00:00 2001 From: Manuel Gellfart Date: Thu, 9 Nov 2023 16:06:54 +0100 Subject: [PATCH] Epic Seedless-onboarding (#2534) - Adds option to create a social signer via google - Adds Settings page for setting up MFA via password recovery for Social signer - Redesigns Welcome Page --------- Co-authored-by: Usame Algan Co-authored-by: Usame Algan <5880855+usame-algan@users.noreply.github.com> Co-authored-by: Michael <30682308+mike10ca@users.noreply.github.com> Co-authored-by: katspaugh <381895+katspaugh@users.noreply.github.com> --- .env.example | 7 +- .github/workflows/build/action.yml | 2 + cypress/e2e/pages/create_wallet.pages.js | 25 +- cypress/e2e/pages/import_export.pages.js | 6 +- cypress/e2e/pages/load_safe.pages.js | 4 +- cypress/e2e/pages/owners.pages.js | 7 +- cypress/e2e/smoke/create_safe_simple.cy.js | 42 +- cypress/e2e/smoke/import_export_data.cy.js | 6 +- cypress/support/constants.js | 1 + jest.config.cjs | 4 +- next.config.mjs | 2 +- package.json | 5 +- public/images/common/bar-chart.svg | 5 + public/images/common/check-filled.svg | 3 + public/images/common/lock-small.svg | 4 + public/images/common/lock-warning.svg | 6 + public/images/common/lock.svg | 3 + public/images/common/shield-off.svg | 12 + public/images/common/shield.svg | 3 + public/images/logo-text.svg | 9 + public/images/welcome/logo-google.svg | 6 + .../common/ConnectWallet/AccountCenter.tsx | 89 +- .../common/ConnectWallet/ConnectionCenter.tsx | 79 ++ .../common/ConnectWallet/WalletDetails.tsx | 30 + .../__tests__/AccountCenter.test.tsx | 35 + .../__tests__/ConnectionCenter.test.tsx | 18 + src/components/common/ConnectWallet/index.tsx | 5 +- .../common/ConnectWallet/styles.module.css | 52 +- .../common/ConnectWallet/useConnectWallet.ts | 14 +- src/components/common/ErrorBoundary/index.tsx | 2 +- .../EthHashInfo/SrcEthHashInfo/index.tsx | 2 +- src/components/common/Footer/index.tsx | 2 +- src/components/common/Header/index.tsx | 2 +- .../common/NetworkSelector/index.tsx | 28 +- .../common/NetworkSelector/styles.module.css | 4 + .../common/PageHeader/styles.module.css | 2 +- src/components/common/PageLayout/index.tsx | 1 - .../common/SafeLoadingError/index.tsx | 2 +- .../common/SocialLoginInfo/index.tsx | 55 ++ .../common/SocialLoginInfo/styles.module.css | 35 + .../common/SocialSigner/PasswordRecovery.tsx | 114 +++ .../__tests__/PasswordRecovery.test.tsx | 48 + .../__tests__/SocialSignerLogin.test.tsx | 201 +++++ src/components/common/SocialSigner/index.tsx | 185 ++++ .../common/SocialSigner/styles.module.css | 24 + .../common/WalletInfo/index.test.tsx | 182 ++++ src/components/common/WalletInfo/index.tsx | 137 ++- .../common/WalletInfo/styles.module.css | 44 +- .../common/WalletOverview/index.tsx | 56 ++ .../common/WalletOverview/styles.module.css | 38 + .../common/icons/KeyholeIcon/index.tsx | 31 +- .../new-safe/create/OverviewWidget/index.tsx | 4 +- .../__tests__/useSyncSafeCreationStep.test.ts | 23 +- src/components/new-safe/create/index.tsx | 23 +- .../create/steps/ConnectWalletStep/index.tsx | 40 - .../create/steps/ReviewStep/index.test.tsx | 42 + .../create/steps/ReviewStep/index.tsx | 142 ++- .../create/steps/SetNameStep/index.tsx | 12 +- .../create/steps/StatusStep/index.tsx | 2 +- .../create/useSyncSafeCreationStep.ts | 14 +- src/components/new-safe/load/index.tsx | 2 +- .../PushNotificationsBanner/index.tsx | 11 +- .../ExportMPCAccountModal.tsx | 147 ++++ .../SocialSignerExport/index.tsx | 47 + .../SocialSignerExport/styles.module.css | 10 + .../SocialSignerMFA/PasswordInput.tsx | 44 + .../SocialSignerMFA/index.test.tsx | 45 + .../SecurityLogin/SocialSignerMFA/index.tsx | 298 +++++++ .../SocialSignerMFA/styles.module.css | 76 ++ .../settings/SecurityLogin/index.tsx | 51 ++ .../settings/SettingsHeader/index.test.tsx | 78 ++ .../settings/SettingsHeader/index.tsx | 28 +- src/components/sidebar/SafeList/index.tsx | 10 +- src/components/sidebar/Sidebar/index.tsx | 2 +- .../sidebar/SidebarNavigation/config.tsx | 8 + src/components/tx-flow/index.tsx | 1 + src/components/welcome/NewSafe.tsx | 193 +---- src/components/welcome/NewSafeSocial.tsx | 86 ++ .../{ => SafeListDrawer}/DataWidget.tsx | 0 .../welcome/SafeListDrawer/index.tsx | 55 ++ .../welcome/SafeListDrawer/styles.module.css | 33 + .../welcome/WelcomeLogin/WalletLogin.tsx | 63 ++ .../__tests__/WalletLogin.test.tsx | 96 ++ src/components/welcome/WelcomeLogin/index.tsx | 60 ++ .../welcome/WelcomeLogin/styles.module.css | 19 + src/components/welcome/styles.module.css | 147 ++-- src/config/routes.ts | 6 +- src/hooks/__tests__/useTxTracking.test.ts | 39 +- src/hooks/useMnemonicName/dict.ts | 11 +- src/hooks/useMnemonicName/index.ts | 12 +- .../useMnemonicName/useMnemonicName.test.ts | 16 +- .../wallets/__tests__/useOnboard.test.ts | 254 ++++++ src/hooks/wallets/consts.ts | 3 + .../wallets/mpc/__tests__/useMPC.test.ts | 226 +++++ src/hooks/wallets/mpc/useMPC.ts | 92 ++ src/hooks/wallets/mpc/useSocialWallet.ts | 63 ++ src/hooks/wallets/useOnboard.test.ts | 69 -- src/hooks/wallets/useOnboard.ts | 16 +- src/hooks/wallets/wallets.ts | 8 + src/pages/_app.tsx | 5 + src/pages/index.tsx | 4 +- src/pages/settings/security-login.tsx | 23 + src/pages/wc.tsx | 2 +- src/pages/{welcome.tsx => welcome/index.tsx} | 0 src/pages/welcome/social-login.tsx | 17 + src/service-workers/index.ts | 3 + src/service-workers/mpc-core-kit-sw.ts | 325 +++++++ .../analytics/events/createLoadSafe.ts | 11 +- src/services/analytics/events/mpcWallet.ts | 56 ++ src/services/exceptions/ErrorCodes.ts | 3 + src/services/mpc/PasswordRecoveryModal.tsx | 42 + src/services/mpc/SocialLoginModule.ts | 136 +++ src/services/mpc/SocialWalletService.ts | 163 ++++ .../mpc/__mocks__/SocialWalletService.ts | 74 ++ .../mpc/__tests__/SocialWalletService.test.ts | 271 ++++++ src/services/mpc/__tests__/module.test.ts | 125 +++ src/services/mpc/config.ts | 40 + src/services/mpc/icon.ts | 12 + src/services/mpc/interfaces.ts | 52 ++ .../mpc/recovery/DeviceShareRecovery.ts | 59 ++ .../mpc/recovery/SecurityQuestionRecovery.ts | 48 + src/store/__tests__/addressBookSlice.test.ts | 12 + src/store/addressBookSlice.ts | 3 + src/styles/globals.css | 4 + src/tests/builders/eip1193Provider.ts | 10 + src/tests/builders/wallet.ts | 16 + src/utils/addresses.ts | 6 +- src/utils/chains.ts | 1 + yarn.lock | 820 +++++++++++++++++- 129 files changed, 6109 insertions(+), 640 deletions(-) create mode 100644 public/images/common/bar-chart.svg create mode 100644 public/images/common/check-filled.svg create mode 100644 public/images/common/lock-small.svg create mode 100644 public/images/common/lock-warning.svg create mode 100644 public/images/common/lock.svg create mode 100644 public/images/common/shield-off.svg create mode 100644 public/images/common/shield.svg create mode 100644 public/images/logo-text.svg create mode 100644 public/images/welcome/logo-google.svg create mode 100644 src/components/common/ConnectWallet/ConnectionCenter.tsx create mode 100644 src/components/common/ConnectWallet/WalletDetails.tsx create mode 100644 src/components/common/ConnectWallet/__tests__/AccountCenter.test.tsx create mode 100644 src/components/common/ConnectWallet/__tests__/ConnectionCenter.test.tsx create mode 100644 src/components/common/SocialLoginInfo/index.tsx create mode 100644 src/components/common/SocialLoginInfo/styles.module.css create mode 100644 src/components/common/SocialSigner/PasswordRecovery.tsx create mode 100644 src/components/common/SocialSigner/__tests__/PasswordRecovery.test.tsx create mode 100644 src/components/common/SocialSigner/__tests__/SocialSignerLogin.test.tsx create mode 100644 src/components/common/SocialSigner/index.tsx create mode 100644 src/components/common/SocialSigner/styles.module.css create mode 100644 src/components/common/WalletInfo/index.test.tsx create mode 100644 src/components/common/WalletOverview/index.tsx create mode 100644 src/components/common/WalletOverview/styles.module.css delete mode 100644 src/components/new-safe/create/steps/ConnectWalletStep/index.tsx create mode 100644 src/components/new-safe/create/steps/ReviewStep/index.test.tsx create mode 100644 src/components/settings/SecurityLogin/SocialSignerExport/ExportMPCAccountModal.tsx create mode 100644 src/components/settings/SecurityLogin/SocialSignerExport/index.tsx create mode 100644 src/components/settings/SecurityLogin/SocialSignerExport/styles.module.css create mode 100644 src/components/settings/SecurityLogin/SocialSignerMFA/PasswordInput.tsx create mode 100644 src/components/settings/SecurityLogin/SocialSignerMFA/index.test.tsx create mode 100644 src/components/settings/SecurityLogin/SocialSignerMFA/index.tsx create mode 100644 src/components/settings/SecurityLogin/SocialSignerMFA/styles.module.css create mode 100644 src/components/settings/SecurityLogin/index.tsx create mode 100644 src/components/settings/SettingsHeader/index.test.tsx create mode 100644 src/components/welcome/NewSafeSocial.tsx rename src/components/welcome/{ => SafeListDrawer}/DataWidget.tsx (100%) create mode 100644 src/components/welcome/SafeListDrawer/index.tsx create mode 100644 src/components/welcome/SafeListDrawer/styles.module.css create mode 100644 src/components/welcome/WelcomeLogin/WalletLogin.tsx create mode 100644 src/components/welcome/WelcomeLogin/__tests__/WalletLogin.test.tsx create mode 100644 src/components/welcome/WelcomeLogin/index.tsx create mode 100644 src/components/welcome/WelcomeLogin/styles.module.css create mode 100644 src/hooks/wallets/__tests__/useOnboard.test.ts create mode 100644 src/hooks/wallets/mpc/__tests__/useMPC.test.ts create mode 100644 src/hooks/wallets/mpc/useMPC.ts create mode 100644 src/hooks/wallets/mpc/useSocialWallet.ts delete mode 100644 src/hooks/wallets/useOnboard.test.ts create mode 100644 src/pages/settings/security-login.tsx rename src/pages/{welcome.tsx => welcome/index.tsx} (100%) create mode 100644 src/pages/welcome/social-login.tsx create mode 100644 src/service-workers/mpc-core-kit-sw.ts create mode 100644 src/services/analytics/events/mpcWallet.ts create mode 100644 src/services/mpc/PasswordRecoveryModal.tsx create mode 100644 src/services/mpc/SocialLoginModule.ts create mode 100644 src/services/mpc/SocialWalletService.ts create mode 100644 src/services/mpc/__mocks__/SocialWalletService.ts create mode 100644 src/services/mpc/__tests__/SocialWalletService.test.ts create mode 100644 src/services/mpc/__tests__/module.test.ts create mode 100644 src/services/mpc/config.ts create mode 100644 src/services/mpc/icon.ts create mode 100644 src/services/mpc/interfaces.ts create mode 100644 src/services/mpc/recovery/DeviceShareRecovery.ts create mode 100644 src/services/mpc/recovery/SecurityQuestionRecovery.ts create mode 100644 src/tests/builders/eip1193Provider.ts create mode 100644 src/tests/builders/wallet.ts diff --git a/.env.example b/.env.example index 6642c2c52c..4ee43536d7 100644 --- a/.env.example +++ b/.env.example @@ -40,4 +40,9 @@ NEXT_PUBLIC_FIREBASE_OPTIONS_STAGING= NEXT_PUBLIC_FIREBASE_VAPID_KEY_STAGING= # Redefine -NEXT_PUBLIC_REDEFINE_API= \ No newline at end of file +NEXT_PUBLIC_REDEFINE_API= + +# Social Login +NEXT_PUBLIC_SOCIAL_WALLET_OPTIONS_STAGING= +NEXT_PUBLIC_SOCIAL_WALLET_OPTIONS_PRODUCTION= + diff --git a/.github/workflows/build/action.yml b/.github/workflows/build/action.yml index fd57aada4f..8a8c32e0c1 100644 --- a/.github/workflows/build/action.yml +++ b/.github/workflows/build/action.yml @@ -43,6 +43,8 @@ runs: NEXT_PUBLIC_SAFE_RELAY_SERVICE_URL_STAGING: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_SAFE_GELATO_RELAY_SERVICE_URL_STAGING }} NEXT_PUBLIC_IS_OFFICIAL_HOST: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_IS_OFFICIAL_HOST }} NEXT_PUBLIC_REDEFINE_API: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_REDEFINE_API }} + NEXT_PUBLIC_SOCIAL_WALLET_OPTIONS_STAGING: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_SOCIAL_WALLET_OPTIONS_STAGING }} + NEXT_PUBLIC_SOCIAL_WALLET_OPTIONS_PRODUCTION: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_SOCIAL_WALLET_OPTIONS_PRODUCTION }} NEXT_PUBLIC_FIREBASE_OPTIONS_PRODUCTION: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_FIREBASE_OPTIONS_PRODUCTION }} NEXT_PUBLIC_FIREBASE_OPTIONS_STAGING: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_FIREBASE_OPTIONS_STAGING }} NEXT_PUBLIC_FIREBASE_VAPID_KEY_PRODUCTION: ${{ fromJSON(inputs.secrets).NEXT_PUBLIC_FIREBASE_VAPID_KEY_PRODUCTION }} diff --git a/cypress/e2e/pages/create_wallet.pages.js b/cypress/e2e/pages/create_wallet.pages.js index 706f7e4da1..ba4f9f8599 100644 --- a/cypress/e2e/pages/create_wallet.pages.js +++ b/cypress/e2e/pages/create_wallet.pages.js @@ -1,5 +1,7 @@ import * as constants from '../../support/constants' +const welcomeLoginScreen = '[data-testid="welcome-login"]' +const expandMoreIcon = 'svg[data-testid="ExpandMoreIcon"]' const nameInput = 'input[name="name"]' const selectNetworkBtn = '[data-cy="create-safe-select-network"]' const ownerInput = 'input[name^="owners"][name$="name"]' @@ -7,16 +9,17 @@ const ownerAddress = 'input[name^="owners"][name$="address"]' const thresholdInput = 'input[name="threshold"]' export const removeOwnerBtn = 'button[aria-label="Remove owner"]' const connectingContainer = 'div[class*="connecting-container"]' -const createNewSafeBtn = 'span[data-track="create-safe: Open stepper"]' +const createNewSafeBtn = 'span[data-track="create-safe: Continue to creation"]' +const connectWalletBtn = 'Connect wallet' const changeNetworkWarningStr = 'Change your wallet network' const safeAccountSetupStr = 'Safe Account setup' -const policy1_1 = '1/1 policy' +const policy1_2 = '1/1 policy' export const walletName = 'test1-sepolia-safe' -export const defaltSepoliaPlaceholder = 'sepolia-safe' +export const defaltSepoliaPlaceholder = 'Sepolia Safe' export function verifyPolicy1_1() { - cy.contains(policy1_1).should('exist') + cy.contains(policy1_2).should('exist') // TOD: Need data-cy for containers } @@ -49,13 +52,23 @@ export function clickOnCreateNewSafeBtn() { cy.get(createNewSafeBtn).click().wait(1000) } +export function clickOnConnectWalletBtn() { + cy.get(welcomeLoginScreen).within(() => { + cy.get('button').contains(connectWalletBtn).should('be.visible').should('be.enabled').click().wait(1000) + }) +} + export function typeWalletName(name) { cy.get(nameInput).type(name).should('have.value', name) } +export function clearWalletName() { + cy.get(nameInput).clear() +} + export function selectNetwork(network, regex = false) { cy.wait(1000) - cy.get(selectNetworkBtn).should('be.visible').click() + cy.get(expandMoreIcon).eq(1).parents('div').eq(1).click() cy.wait(1000) cy.get('li').contains(network).click() cy.get('body').click() @@ -91,7 +104,7 @@ export function typeOwnerAddress(address, index, clearOnly = false) { } export function clickOnAddNewOwnerBtn() { - cy.contains('button', 'Add new owner').click() + cy.contains('button', 'Add new owner').click().wait(700) } export function addNewOwner(name, address, index) { diff --git a/cypress/e2e/pages/import_export.pages.js b/cypress/e2e/pages/import_export.pages.js index e5b49348ba..d2bf9b050b 100644 --- a/cypress/e2e/pages/import_export.pages.js +++ b/cypress/e2e/pages/import_export.pages.js @@ -25,7 +25,7 @@ export function clickOnImportBtn() { } export function clickOnImportBtnDataImportModal() { - cy.contains(dataImportModalStr).parent().contains('button', 'Import').click() + cy.contains('button', 'Import').click() } export function uploadFile(filePath) { @@ -44,6 +44,10 @@ export function clickOnImportedSafe(safe) { cy.contains(safe).click() } +export function clickOnOpenSafeListSidebar() { + cy.contains('My Safe Accounts').click() +} + export function clickOnClosePushNotificationsBanner() { cy.waitForSelector(() => { return cy.get('h6').contains(enablePushNotificationsStr).siblings('.MuiButtonBase-root').click({ force: true }) diff --git a/cypress/e2e/pages/load_safe.pages.js b/cypress/e2e/pages/load_safe.pages.js index bc0fa83daa..488b343bc6 100644 --- a/cypress/e2e/pages/load_safe.pages.js +++ b/cypress/e2e/pages/load_safe.pages.js @@ -1,6 +1,6 @@ import * as constants from '../../support/constants' -const addExistingAccountBtnStr = 'Add existing Account' +const addExistingAccountBtnStr = 'Add existing one' const contactStr = 'Name, address & network' const invalidAddressFormatErrorMsg = 'Invalid address format' @@ -16,7 +16,7 @@ const ownersConfirmationsStr = 'Owners and confirmations' const transactionStr = 'Transactions' export function openLoadSafeForm() { - cy.contains('button', addExistingAccountBtnStr).click() + cy.contains('a', addExistingAccountBtnStr).click() cy.contains(contactStr) } diff --git a/cypress/e2e/pages/owners.pages.js b/cypress/e2e/pages/owners.pages.js index 51d0c658f6..6e2e30aef3 100644 --- a/cypress/e2e/pages/owners.pages.js +++ b/cypress/e2e/pages/owners.pages.js @@ -19,6 +19,7 @@ const thresholdDropdown = 'div[aria-haspopup="listbox"]' const thresholdOption = 'li[role="option"]' const existingOwnerAddressInput = (index) => `input[name="owners.${index}.address"]` const existingOwnerNameInput = (index) => `input[name="owners.${index}.name"]` +const singleOwnerNameInput = 'input[name="name"]' const disconnectBtnStr = 'Disconnect' const notConnectedStatus = 'Connect' @@ -57,9 +58,9 @@ export function verifyExistingOwnerName(index, name) { cy.get(existingOwnerNameInput(index)).should('have.value', name) } -export function typeExistingOwnerName(index, name) { - cy.get(existingOwnerNameInput(index)).clear().type(name) - main.verifyInputValue(existingOwnerNameInput(index), name) +export function typeExistingOwnerName(name) { + cy.get(singleOwnerNameInput).clear().type(name) + main.verifyInputValue(singleOwnerNameInput, name) } export function verifyOwnerDeletionWindowDisplayed() { diff --git a/cypress/e2e/smoke/create_safe_simple.cy.js b/cypress/e2e/smoke/create_safe_simple.cy.js index 9dc90f4723..7f5a8690c3 100644 --- a/cypress/e2e/smoke/create_safe_simple.cy.js +++ b/cypress/e2e/smoke/create_safe_simple.cy.js @@ -1,29 +1,27 @@ import * as constants from '../../support/constants' import * as main from '../../e2e/pages/main.page' import * as createwallet from '../pages/create_wallet.pages' - import * as owner from '../pages/owners.pages' describe('Safe creation tests', () => { beforeEach(() => { - cy.visit(constants.createNewSafeSepoliaUrl) + cy.visit(constants.welcomeUrl + '?chain=sep') cy.clearLocalStorage() main.acceptCookies() }) it('Verify a Wallet can be connected [C56101]', () => { - owner.waitForConnectionStatus() - cy.visit(constants.welcomeUrl) + createwallet.clickOnCreateNewSafeBtn() owner.clickOnWalletExpandMoreIcon() owner.clickOnDisconnectBtn() - createwallet.clickOnCreateNewSafeBtn() - owner.clickOnConnectBtn() + createwallet.clickOnConnectWalletBtn() createwallet.connectWallet() }) it('Verify Next button is disabled until switching to network is done [C56102]', () => { owner.waitForConnectionStatus() createwallet.selectNetwork(constants.networks.ethereum) + createwallet.clickOnCreateNewSafeBtn() createwallet.checkNetworkChangeWarningMsg() createwallet.verifyNextBtnIsDisabled() createwallet.selectNetwork(constants.networks.sepolia) @@ -32,43 +30,49 @@ describe('Safe creation tests', () => { it('Verify that a new Wallet has default name related to the selected network [C56099]', () => { owner.waitForConnectionStatus() + createwallet.clickOnCreateNewSafeBtn() createwallet.verifyDefaultWalletName(createwallet.defaltSepoliaPlaceholder) }) it('Verify error message is displayed if wallet name input exceeds 50 characters [C56098]', () => { owner.waitForConnectionStatus() + createwallet.clickOnCreateNewSafeBtn() createwallet.typeWalletName(main.generateRandomString(51)) owner.verifyErrorMsgInvalidAddress(constants.addressBookErrrMsg.exceedChars) + createwallet.clearWalletName() }) it('Verify there is no error message is displayed if wallet name input contains less than 50 characters [C56100]', () => { owner.waitForConnectionStatus() + createwallet.clickOnCreateNewSafeBtn() createwallet.typeWalletName(main.generateRandomString(50)) owner.verifyValidWalletName(constants.addressBookErrrMsg.exceedChars) }) it('Verify current connected account is shown as default owner [C56091]', () => { owner.waitForConnectionStatus() + createwallet.clickOnCreateNewSafeBtn() owner.clickOnNextBtn() owner.verifyExistingOwnerAddress(0, constants.DEFAULT_OWNER_ADDRESS) }) it('Verify error message is displayed if owner name input exceeds 50 characters [C56092]', () => { owner.waitForConnectionStatus() - owner.clickOnNextBtn() - owner.typeExistingOwnerName(0, main.generateRandomString(51)) + createwallet.clickOnCreateNewSafeBtn() + owner.typeExistingOwnerName(main.generateRandomString(51)) owner.verifyErrorMsgInvalidAddress(constants.addressBookErrrMsg.exceedChars) }) it('Verify there is no error message is displayed if owner name input contains less than 50 characters [C56093]', () => { owner.waitForConnectionStatus() - owner.clickOnNextBtn() - owner.typeExistingOwnerName(0, main.generateRandomString(50)) + createwallet.clickOnCreateNewSafeBtn() + owner.typeExistingOwnerName(main.generateRandomString(50)) owner.verifyValidWalletName(constants.addressBookErrrMsg.exceedChars) }) it('Verify Add and Remove Owner Row works as expected [C56094]', () => { owner.waitForConnectionStatus() + createwallet.clickOnCreateNewSafeBtn() owner.clickOnNextBtn() createwallet.clickOnAddNewOwnerBtn() owner.verifyNumberOfOwners(2) @@ -82,26 +86,34 @@ describe('Safe creation tests', () => { it('Verify Threshold Setup [C56096]', () => { owner.waitForConnectionStatus() + createwallet.clickOnCreateNewSafeBtn() owner.clickOnNextBtn() createwallet.clickOnAddNewOwnerBtn() - owner.verifyNumberOfOwners(2) createwallet.clickOnAddNewOwnerBtn() owner.verifyNumberOfOwners(3) - owner.verifyThresholdLimit(1, 3) + createwallet.clickOnAddNewOwnerBtn() + owner.verifyNumberOfOwners(4) + owner.verifyThresholdLimit(1, 4) createwallet.updateThreshold(3) createwallet.removeOwner(1) + owner.verifyThresholdLimit(1, 3) + createwallet.removeOwner(1) owner.verifyThresholdLimit(1, 2) + createwallet.updateThreshold(1) }) it('Verify data persistence [C56103]', () => { const ownerName = 'David' owner.waitForConnectionStatus() - createwallet.typeWalletName(createwallet.walletName) + createwallet.clickOnCreateNewSafeBtn() owner.clickOnNextBtn() createwallet.clickOnAddNewOwnerBtn() createwallet.typeOwnerName(ownerName, 1) createwallet.typeOwnerAddress(constants.SEPOLIA_OWNER_2, 1) - owner.verifyThresholdLimit(1, 2) + owner.clickOnBackBtn() + createwallet.clearWalletName() + createwallet.typeWalletName(createwallet.walletName) + owner.clickOnNextBtn() owner.clickOnNextBtn() createwallet.verifySafeNameInSummaryStep(createwallet.walletName) createwallet.verifyOwnerNameInSummaryStep(ownerName) @@ -125,12 +137,14 @@ describe('Safe creation tests', () => { it('Verify tip is displayed on right side for threshold 1/1 [C56097]', () => { owner.waitForConnectionStatus() + createwallet.clickOnCreateNewSafeBtn() owner.clickOnNextBtn() createwallet.verifyPolicy1_1() }) it('Verify address input validation rules [C56095]', () => { owner.waitForConnectionStatus() + createwallet.clickOnCreateNewSafeBtn() owner.clickOnNextBtn() createwallet.clickOnAddNewOwnerBtn() createwallet.typeOwnerAddress(main.generateRandomString(10), 1) diff --git a/cypress/e2e/smoke/import_export_data.cy.js b/cypress/e2e/smoke/import_export_data.cy.js index 140b5d9dc1..2bcc125943 100644 --- a/cypress/e2e/smoke/import_export_data.cy.js +++ b/cypress/e2e/smoke/import_export_data.cy.js @@ -6,19 +6,19 @@ import * as constants from '../../support/constants' describe('Import Export Data tests', () => { before(() => { cy.clearLocalStorage() - cy.visit(constants.welcomeUrl) + cy.visit(constants.dataSettingsUrl) main.acceptCookies() - file.verifyImportBtnIsVisible() }) it('Verify Safe can be accessed after test file upload [C56111]', () => { const filePath = '../fixtures/data_import.json' const safe = constants.SEPOLIA_CSV_ENTRY.name - file.clickOnImportBtn() file.uploadFile(filePath) file.verifyImportModalData() file.clickOnImportBtnDataImportModal() + cy.visit(constants.welcomeUrl) + file.clickOnOpenSafeListSidebar() file.clickOnImportedSafe(safe) file.clickOnClosePushNotificationsBanner() }) diff --git a/cypress/support/constants.js b/cypress/support/constants.js index 6daeacfc92..e9dce33964 100644 --- a/cypress/support/constants.js +++ b/cypress/support/constants.js @@ -54,6 +54,7 @@ export const requestPermissionsUrl = '/request-permissions' export const getPermissionsUrl = '/get-permissions' export const appSettingsUrl = '/settings/safe-apps' export const setupUrl = '/settings/setup?safe=' +export const dataSettingsUrl = '/settings/data' export const invalidAppUrl = 'https://my-invalid-custom-app.com/manifest.json' export const validAppUrlJson = 'https://my-valid-custom-app.com/manifest.json' export const validAppUrl = 'https://my-valid-custom-app.com' diff --git a/jest.config.cjs b/jest.config.cjs index 2ba19a6f88..1b06adda63 100644 --- a/jest.config.cjs +++ b/jest.config.cjs @@ -8,13 +8,13 @@ const createJestConfig = nextJest({ // Add any custom config to be passed to Jest const customJestConfig = { setupFilesAfterEnv: ['/jest.setup.js'], + moduleNameMapper: { // Handle module aliases (this will be automatically configured for you soon) '^@/(.*)$': '/src/$1', '^.+\\.(svg)$': '/mocks/svg.js', isows: '/node_modules/isows/_cjs/index.js', }, - transformIgnorePatterns: ['node_modules/(?!isows/)'], testEnvironment: 'jest-environment-jsdom', testEnvironmentOptions: { url: 'http://localhost/balances?safe=rin:0xb3b83bf204C458B461de9B0CD2739DB152b4fa5A' }, globals: { @@ -25,5 +25,5 @@ const customJestConfig = { // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async module.exports = async () => ({ ...(await createJestConfig(customJestConfig)()), - transformIgnorePatterns: ['node_modules/(?!(uint8arrays|multiformats)/)'], + transformIgnorePatterns: ['node_modules/(?!(uint8arrays|multiformats|@web3-onboard/common)/)'], }) diff --git a/next.config.mjs b/next.config.mjs index 1470c8d524..07d1f2a35d 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -32,7 +32,7 @@ const nextConfig = { dirs: ['src'], }, experimental: { - optimizePackageImports: ['@mui/material', '@mui/icons-material', 'lodash', 'date-fns'] + optimizePackageImports: ['@mui/material', '@mui/icons-material', 'lodash', 'date-fns'], }, webpack(config) { config.module.rules.push({ diff --git a/package.json b/package.json index 9882a430e1..26ac24be3c 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "homepage": "https://github.com/safe-global/safe-wallet-web", "license": "GPL-3.0", "type": "module", - "version": "1.21.0", + "version": "1.22.0", "scripts": { "dev": "next dev", "start": "next dev", @@ -56,6 +56,7 @@ "@safe-global/safe-react-components": "^2.0.6", "@sentry/react": "^7.74.0", "@sentry/tracing": "^7.74.0", + "@tkey-mpc/common-types": "^8.2.2", "@truffle/hdwallet-provider": "^2.1.4", "@walletconnect/utils": "^2.10.2", "@walletconnect/web3wallet": "^1.9.2", @@ -66,7 +67,9 @@ "@web3-onboard/ledger": "2.3.2", "@web3-onboard/trezor": "^2.4.2", "@web3-onboard/walletconnect": "^2.4.7", + "@web3auth/mpc-core-kit": "^1.1.3", "blo": "^1.1.1", + "bn.js": "^5.2.1", "classnames": "^2.3.1", "date-fns": "^2.29.2", "ethers": "5.7.2", diff --git a/public/images/common/bar-chart.svg b/public/images/common/bar-chart.svg new file mode 100644 index 0000000000..f6beb44899 --- /dev/null +++ b/public/images/common/bar-chart.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/images/common/check-filled.svg b/public/images/common/check-filled.svg new file mode 100644 index 0000000000..284624fc19 --- /dev/null +++ b/public/images/common/check-filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/common/lock-small.svg b/public/images/common/lock-small.svg new file mode 100644 index 0000000000..2620c043c8 --- /dev/null +++ b/public/images/common/lock-small.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/images/common/lock-warning.svg b/public/images/common/lock-warning.svg new file mode 100644 index 0000000000..6972e1bb15 --- /dev/null +++ b/public/images/common/lock-warning.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/public/images/common/lock.svg b/public/images/common/lock.svg new file mode 100644 index 0000000000..9535a642e0 --- /dev/null +++ b/public/images/common/lock.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/common/shield-off.svg b/public/images/common/shield-off.svg new file mode 100644 index 0000000000..f36482d5ca --- /dev/null +++ b/public/images/common/shield-off.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/images/common/shield.svg b/public/images/common/shield.svg new file mode 100644 index 0000000000..f7d12a900f --- /dev/null +++ b/public/images/common/shield.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/logo-text.svg b/public/images/logo-text.svg new file mode 100644 index 0000000000..b71ae734a4 --- /dev/null +++ b/public/images/logo-text.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/public/images/welcome/logo-google.svg b/public/images/welcome/logo-google.svg new file mode 100644 index 0000000000..65781d4881 --- /dev/null +++ b/public/images/welcome/logo-google.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/common/ConnectWallet/AccountCenter.tsx b/src/components/common/ConnectWallet/AccountCenter.tsx index 161e9e1bb2..c28d607e09 100644 --- a/src/components/common/ConnectWallet/AccountCenter.tsx +++ b/src/components/common/ConnectWallet/AccountCenter.tsx @@ -1,48 +1,21 @@ import type { MouseEvent } from 'react' import { useState } from 'react' -import { Box, Button, ButtonBase, Paper, Popover, Typography } from '@mui/material' +import { Box, ButtonBase, Paper, Popover } from '@mui/material' import css from '@/components/common/ConnectWallet/styles.module.css' -import EthHashInfo from '@/components/common/EthHashInfo' import ExpandLessIcon from '@mui/icons-material/ExpandLess' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' -import useOnboard, { switchWallet } from '@/hooks/wallets/useOnboard' -import { useAppSelector } from '@/store' -import { selectChainById } from '@/store/chainsSlice' -import Identicon from '@/components/common/Identicon' -import ChainSwitcher from '../ChainSwitcher' -import useAddressBook from '@/hooks/useAddressBook' import { type ConnectedWallet } from '@/hooks/wallets/useOnboard' -import WalletInfo, { UNKNOWN_CHAIN_NAME } from '../WalletInfo' +import WalletOverview from '../WalletOverview' +import WalletInfo from '@/components/common/WalletInfo' -const AccountCenter = ({ wallet }: { wallet: ConnectedWallet }) => { +export const AccountCenter = ({ wallet }: { wallet: ConnectedWallet }) => { const [anchorEl, setAnchorEl] = useState(null) - const onboard = useOnboard() - const chainInfo = useAppSelector((state) => selectChainById(state, wallet.chainId)) - const addressBook = useAddressBook() - const prefix = chainInfo?.shortName - const handleSwitchWallet = () => { - if (onboard) { - handleClose() - switchWallet(onboard) - } - } - - const handleDisconnect = () => { - if (!wallet) return - - onboard?.disconnectWallet({ - label: wallet.label, - }) - - handleClose() - } - - const handleClick = (event: MouseEvent) => { + const openWalletInfo = (event: MouseEvent) => { setAnchorEl(event.currentTarget) } - const handleClose = () => { + const closeWalletInfo = () => { setAnchorEl(null) } @@ -51,9 +24,15 @@ const AccountCenter = ({ wallet }: { wallet: ConnectedWallet }) => { return ( <> - + - + {open ? : } @@ -65,7 +44,7 @@ const AccountCenter = ({ wallet }: { wallet: ConnectedWallet }) => { id={id} open={open} anchorEl={anchorEl} - onClose={handleClose} + onClose={closeWalletInfo} anchorOrigin={{ vertical: 'bottom', horizontal: 'center', @@ -81,43 +60,7 @@ const AccountCenter = ({ wallet }: { wallet: ConnectedWallet }) => { }} > - - - - {addressBook[wallet.address] || wallet.ens} - - - - - - - - - Wallet - {wallet.label} - - - Connected network - {chainInfo?.chainName || UNKNOWN_CHAIN_NAME} - - - - - - - - + diff --git a/src/components/common/ConnectWallet/ConnectionCenter.tsx b/src/components/common/ConnectWallet/ConnectionCenter.tsx new file mode 100644 index 0000000000..1e04b377d2 --- /dev/null +++ b/src/components/common/ConnectWallet/ConnectionCenter.tsx @@ -0,0 +1,79 @@ +import ConnectWalletButton from '@/components/common/ConnectWallet/ConnectWalletButton' +import { useHasFeature } from '@/hooks/useChains' +import { FEATURES } from '@/utils/chains' +import madProps from '@/utils/mad-props' +import { Popover, ButtonBase, Typography, Paper, Box } from '@mui/material' +import ExpandMoreIcon from '@mui/icons-material/ExpandMore' +import ExpandLessIcon from '@mui/icons-material/ExpandLess' +import classnames from 'classnames' +import { useState, type MouseEvent, type ReactElement } from 'react' + +import KeyholeIcon from '@/components/common/icons/KeyholeIcon' +import WalletDetails from '@/components/common/ConnectWallet/WalletDetails' + +import css from '@/components/common/ConnectWallet/styles.module.css' + +export const ConnectionCenter = ({ isSocialLoginEnabled }: { isSocialLoginEnabled: boolean }): ReactElement => { + const [anchorEl, setAnchorEl] = useState(null) + const open = !!anchorEl + + const handleClick = (event: MouseEvent) => { + setAnchorEl(event.currentTarget) + } + + const handleClose = () => { + setAnchorEl(null) + } + + const ExpandIcon = open ? ExpandLessIcon : ExpandMoreIcon + + if (!isSocialLoginEnabled) { + return ( + + + + ) + } + + return ( + <> + + + + + Not connected + palette.error.main }}> + Connect wallet + + + + + + + + + + + + + ) +} + +const useIsSocialLoginEnabled = () => useHasFeature(FEATURES.SOCIAL_LOGIN) + +export default madProps(ConnectionCenter, { + isSocialLoginEnabled: useIsSocialLoginEnabled, +}) diff --git a/src/components/common/ConnectWallet/WalletDetails.tsx b/src/components/common/ConnectWallet/WalletDetails.tsx new file mode 100644 index 0000000000..5f0442f50a --- /dev/null +++ b/src/components/common/ConnectWallet/WalletDetails.tsx @@ -0,0 +1,30 @@ +import { Box, Divider, SvgIcon, Typography } from '@mui/material' +import type { ReactElement } from 'react' + +import LockIcon from '@/public/images/common/lock.svg' +import SocialSigner from '@/components/common/SocialSigner' +import WalletLogin from '@/components/welcome/WelcomeLogin/WalletLogin' + +const WalletDetails = ({ onConnect }: { onConnect: () => void }): ReactElement => { + return ( + <> + + + + + + + + + + + or + + + + + + ) +} + +export default WalletDetails diff --git a/src/components/common/ConnectWallet/__tests__/AccountCenter.test.tsx b/src/components/common/ConnectWallet/__tests__/AccountCenter.test.tsx new file mode 100644 index 0000000000..382b7acb1d --- /dev/null +++ b/src/components/common/ConnectWallet/__tests__/AccountCenter.test.tsx @@ -0,0 +1,35 @@ +import { render } from '@/tests/test-utils' +import { AccountCenter } from '@/components/common/ConnectWallet/AccountCenter' +import { type EIP1193Provider } from '@web3-onboard/core' +import { act, waitFor } from '@testing-library/react' + +const mockWallet = { + address: '0x1234567890123456789012345678901234567890', + chainId: '5', + label: '', + provider: null as unknown as EIP1193Provider, +} + +describe('AccountCenter', () => { + it('should open and close the account center on click', async () => { + const { getByText, getByTestId } = render() + + const openButton = getByTestId('open-account-center') + + act(() => { + openButton.click() + }) + + const disconnectButton = getByText('Disconnect') + + expect(disconnectButton).toBeInTheDocument() + + act(() => { + disconnectButton.click() + }) + + await waitFor(() => { + expect(disconnectButton).not.toBeInTheDocument() + }) + }) +}) diff --git a/src/components/common/ConnectWallet/__tests__/ConnectionCenter.test.tsx b/src/components/common/ConnectWallet/__tests__/ConnectionCenter.test.tsx new file mode 100644 index 0000000000..5ca16f4512 --- /dev/null +++ b/src/components/common/ConnectWallet/__tests__/ConnectionCenter.test.tsx @@ -0,0 +1,18 @@ +import { ConnectionCenter } from '@/components/common/ConnectWallet/ConnectionCenter' +import { render } from '@/tests/test-utils' + +describe('ConnectionCenter', () => { + it('displays a Connect wallet button if the social login feature is enabled', () => { + const { getByText, queryByText } = render() + + expect(getByText('Connect wallet')).toBeInTheDocument() + expect(queryByText('Connect')).not.toBeInTheDocument() + }) + + it('displays the ConnectWalletButton if the social login feature is disabled', () => { + const { getByText, queryByText } = render() + + expect(queryByText('Connect wallet')).not.toBeInTheDocument() + expect(getByText('Connect')).toBeInTheDocument() + }) +}) diff --git a/src/components/common/ConnectWallet/index.tsx b/src/components/common/ConnectWallet/index.tsx index aaf6812b1a..45a9f33a9f 100644 --- a/src/components/common/ConnectWallet/index.tsx +++ b/src/components/common/ConnectWallet/index.tsx @@ -1,13 +1,12 @@ import type { ReactElement } from 'react' import useWallet from '@/hooks/wallets/useWallet' import AccountCenter from '@/components/common/ConnectWallet/AccountCenter' -import ConnectWalletButton from './ConnectWalletButton' -import css from './styles.module.css' +import ConnectionCenter from './ConnectionCenter' const ConnectWallet = (): ReactElement => { const wallet = useWallet() - return
{wallet ? : }
+ return wallet ? : } export default ConnectWallet diff --git a/src/components/common/ConnectWallet/styles.module.css b/src/components/common/ConnectWallet/styles.module.css index 24057834f2..b41bbc8399 100644 --- a/src/components/common/ConnectWallet/styles.module.css +++ b/src/components/common/ConnectWallet/styles.module.css @@ -1,5 +1,6 @@ -.container { - padding: 0 var(--space-2); +.connectedContainer { + display: flex; + align-items: center; } .buttonContainer { @@ -7,18 +8,23 @@ align-items: center; text-align: left; gap: var(--space-1); + padding: 0 var(--space-2); } .popoverContainer { padding: var(--space-2); - width: 250px; + width: 300px; display: flex; flex-direction: column; align-items: center; - gap: var(--space-2); + gap: var(--space-1); border: 1px solid var(--color-border-light); } +.largeGap { + gap: var(--space-2); +} + .addressName { text-align: center; overflow: hidden; @@ -27,6 +33,18 @@ width: 100%; } +.profileImg { + border-radius: var(--space-2); + width: 32px; + height: 32px; +} + +.profileData { + display: flex; + flex-direction: column; + align-items: flex-start; +} + .rowContainer { align-self: stretch; margin-left: calc(var(--space-2) * -1); @@ -45,3 +63,29 @@ .row:last-of-type { border-bottom: 1px solid var(--color-border-light); } + +.pairingDetails { + display: flex; + flex-direction: column; + align-items: center; + gap: var(--space-2); +} + +.loginButton { + min-height: 42px; +} + +.loginError { + width: 100%; + margin: 0; +} + +@media (max-width: 599.95px) { + .socialLoginInfo > div > div { + display: none; + } + + .notConnected { + display: none; + } +} diff --git a/src/components/common/ConnectWallet/useConnectWallet.ts b/src/components/common/ConnectWallet/useConnectWallet.ts index 9dc10e7930..b3f832229e 100644 --- a/src/components/common/ConnectWallet/useConnectWallet.ts +++ b/src/components/common/ConnectWallet/useConnectWallet.ts @@ -1,19 +1,17 @@ -import { useMemo } from 'react' +import { useCallback } from 'react' import useOnboard, { connectWallet } from '@/hooks/wallets/useOnboard' import { OVERVIEW_EVENTS, trackEvent } from '@/services/analytics' -const useConnectWallet = (): (() => void) => { +const useConnectWallet = () => { const onboard = useOnboard() - return useMemo(() => { + return useCallback(() => { if (!onboard) { - return () => {} + return Promise.resolve(undefined) } - return () => { - trackEvent(OVERVIEW_EVENTS.OPEN_ONBOARD) - connectWallet(onboard) - } + trackEvent(OVERVIEW_EVENTS.OPEN_ONBOARD) + return connectWallet(onboard) }, [onboard]) } diff --git a/src/components/common/ErrorBoundary/index.tsx b/src/components/common/ErrorBoundary/index.tsx index e277db308a..f25c1bbcfa 100644 --- a/src/components/common/ErrorBoundary/index.tsx +++ b/src/components/common/ErrorBoundary/index.tsx @@ -33,7 +33,7 @@ const ErrorBoundary: FallbackRender = ({ error, componentStack }) => { {componentStack} )} - + Go home diff --git a/src/components/common/EthHashInfo/SrcEthHashInfo/index.tsx b/src/components/common/EthHashInfo/SrcEthHashInfo/index.tsx index 1fbbd76d89..34041dbdfb 100644 --- a/src/components/common/EthHashInfo/SrcEthHashInfo/index.tsx +++ b/src/components/common/EthHashInfo/SrcEthHashInfo/index.tsx @@ -71,7 +71,7 @@ const SrcEthHashInfo = ({ {name && ( - + {name} )} diff --git a/src/components/common/Footer/index.tsx b/src/components/common/Footer/index.tsx index afd19922e0..545b1f43aa 100644 --- a/src/components/common/Footer/index.tsx +++ b/src/components/common/Footer/index.tsx @@ -11,7 +11,7 @@ import MUILink from '@mui/material/Link' import { IS_DEV, IS_OFFICIAL_HOST } from '@/config/constants' const footerPages = [ - AppRoutes.welcome, + AppRoutes.welcome.index, AppRoutes.settings.index, AppRoutes.imprint, AppRoutes.privacy, diff --git a/src/components/common/Header/index.tsx b/src/components/common/Header/index.tsx index c18ebcd039..6919ca1526 100644 --- a/src/components/common/Header/index.tsx +++ b/src/components/common/Header/index.tsx @@ -34,7 +34,7 @@ const Header = ({ onMenuToggle, onBatchToggle }: HeaderProps): ReactElement => { const enableWc = !!chain && hasFeature(chain, FEATURES.NATIVE_WALLETCONNECT) // Logo link: if on Dashboard, link to Welcome, otherwise to the root (which redirects to either Dashboard or Welcome) - const logoHref = router.pathname === AppRoutes.home ? AppRoutes.welcome : AppRoutes.index + const logoHref = router.pathname === AppRoutes.home ? AppRoutes.welcome.index : AppRoutes.index const handleMenuToggle = () => { if (onMenuToggle) { diff --git a/src/components/common/NetworkSelector/index.tsx b/src/components/common/NetworkSelector/index.tsx index efe261b122..5e3ac1e676 100644 --- a/src/components/common/NetworkSelector/index.tsx +++ b/src/components/common/NetworkSelector/index.tsx @@ -1,20 +1,34 @@ import Link from 'next/link' import type { SelectChangeEvent } from '@mui/material' -import { MenuItem, Select, Skeleton } from '@mui/material' +import { MenuItem, Select, Skeleton, Tooltip } from '@mui/material' import ExpandMoreIcon from '@mui/icons-material/ExpandMore' import useChains from '@/hooks/useChains' import { useRouter } from 'next/router' import ChainIndicator from '../ChainIndicator' import css from './styles.module.css' import { useChainId } from '@/hooks/useChainId' -import type { ReactElement } from 'react' +import { type ReactElement, forwardRef } from 'react' import { useCallback } from 'react' import { AppRoutes } from '@/config/routes' import { trackEvent, OVERVIEW_EVENTS } from '@/services/analytics' +import useWallet from '@/hooks/wallets/useWallet' +import { isSocialWalletEnabled } from '@/hooks/wallets/wallets' +import { isSocialLoginWallet } from '@/services/mpc/SocialLoginModule' -const keepPathRoutes = [AppRoutes.welcome, AppRoutes.newSafe.create, AppRoutes.newSafe.load] +const keepPathRoutes = [AppRoutes.welcome.index, AppRoutes.newSafe.create, AppRoutes.newSafe.load] + +const MenuWithTooltip = forwardRef(function MenuWithTooltip(props: any, ref) { + return ( + +
    + {props.children} +
+
+ ) +}) const NetworkSelector = (props: { onChainSelect?: () => void }): ReactElement => { + const wallet = useWallet() const { configs } = useChains() const chainId = useChainId() const router = useRouter() @@ -53,6 +67,8 @@ const NetworkSelector = (props: { onChainSelect?: () => void }): ReactElement => } } + const isSocialLogin = isSocialLoginWallet(wallet?.label) + return configs.length ? (