diff --git a/cypress/e2e/add_owner.cy.js b/cypress/e2e/add_owner.cy.js
index 3bc9275b1f..d63a568e5f 100644
--- a/cypress/e2e/add_owner.cy.js
+++ b/cypress/e2e/add_owner.cy.js
@@ -4,8 +4,6 @@ const offset = 7
describe('Adding an owner', () => {
before(() => {
- cy.connectE2EWallet()
-
cy.visit(`/${TEST_SAFE}/settings/setup`)
cy.contains('button', 'Accept selection').click()
diff --git a/cypress/e2e/create_safe.cy.js b/cypress/e2e/create_safe.cy.js
index 04ea76eefc..3906b002d2 100644
--- a/cypress/e2e/create_safe.cy.js
+++ b/cypress/e2e/create_safe.cy.js
@@ -1,7 +1,5 @@
describe('Create Safe', () => {
it('should create a new Safe', () => {
- cy.connectE2EWallet()
-
cy.visit('/welcome')
// Close cookie banner
diff --git a/cypress/e2e/non_owner_spending_limit.cy.js b/cypress/e2e/non_owner_spending_limit.cy.js
index da18f7f3c9..581a9f426b 100644
--- a/cypress/e2e/non_owner_spending_limit.cy.js
+++ b/cypress/e2e/non_owner_spending_limit.cy.js
@@ -3,8 +3,6 @@ const SPENDING_LIMIT_SAFE = 'gor:0xBE3C5aFF7f66c23fe71c3047911f9Aa0026b281B'
describe('Check non-owner spending limit beneficiary modal', () => {
before(() => {
- cy.connectE2EWallet()
-
cy.visit(`/${SPENDING_LIMIT_SAFE}/home`, { failOnStatusCode: false })
cy.contains('Accept selection').click()
diff --git a/cypress/e2e/smoke/create_safe_simple.cy.js b/cypress/e2e/smoke/create_safe_simple.cy.js
index 30b2540be7..1cd65e41f8 100644
--- a/cypress/e2e/smoke/create_safe_simple.cy.js
+++ b/cypress/e2e/smoke/create_safe_simple.cy.js
@@ -3,8 +3,6 @@ const OWNER_ADDRESS = '0xE297437d6b53890cbf004e401F3acc67c8b39665'
describe('Create Safe form', () => {
it('should navigate to the form', () => {
- cy.connectE2EWallet()
-
cy.visit('/welcome')
// Close cookie banner
diff --git a/cypress/e2e/smoke/create_tx.cy.js b/cypress/e2e/smoke/create_tx.cy.js
index 74b13e352d..0d09229447 100644
--- a/cypress/e2e/smoke/create_tx.cy.js
+++ b/cypress/e2e/smoke/create_tx.cy.js
@@ -6,7 +6,6 @@ const currentNonce = 3
describe('Queue a transaction on 1/N', () => {
before(() => {
- cy.connectE2EWallet()
cy.useProdCGW()
cy.visit(`/home?safe=${SAFE}`)
diff --git a/cypress/e2e/smoke/nfts.cy.js b/cypress/e2e/smoke/nfts.cy.js
index 3a5d8e9d46..a1613d9376 100644
--- a/cypress/e2e/smoke/nfts.cy.js
+++ b/cypress/e2e/smoke/nfts.cy.js
@@ -2,8 +2,6 @@ const TEST_SAFE = 'gor:0x97d314157727D517A706B5D08507A1f9B44AaaE9'
describe('Assets > NFTs', () => {
before(() => {
- cy.connectE2EWallet()
-
cy.visit(`/balances/nfts?safe=${TEST_SAFE}`)
cy.contains('button', 'Accept selection').click()
cy.contains(/E2E Wallet @ G(รถ|oe)rli/)
diff --git a/cypress/e2e/smoke/pending_actions.cy.js b/cypress/e2e/smoke/pending_actions.cy.js
index e381212f6d..080996a301 100644
--- a/cypress/e2e/smoke/pending_actions.cy.js
+++ b/cypress/e2e/smoke/pending_actions.cy.js
@@ -2,9 +2,7 @@ const SAFE = 'gor:0xCD4FddB8FfA90012DFE11eD4bf258861204FeEAE'
describe('Pending actions', () => {
before(() => {
- cy.connectE2EWallet()
cy.useProdCGW()
-
cy.visit(`/welcome`)
cy.contains('button', 'Accept selection').click()
})
diff --git a/cypress/e2e/spending_limit.cy.js b/cypress/e2e/spending_limit.cy.js
index 9def385933..403d1b93ce 100644
--- a/cypress/e2e/spending_limit.cy.js
+++ b/cypress/e2e/spending_limit.cy.js
@@ -3,8 +3,6 @@ const SPENDING_LIMIT_SAFE = 'gor:0x28F95E682D1dd632b54Dc61740575f49DB39Eb7F'
describe('Check spending limit modal', () => {
before(() => {
- cy.connectE2EWallet()
-
cy.visit(`/${SPENDING_LIMIT_SAFE}/home`, { failOnStatusCode: false })
cy.contains('Accept selection').click()
diff --git a/cypress/e2e/tx_modal.cy.js b/cypress/e2e/tx_modal.cy.js
index 1d50ca9f6a..89b92256d4 100644
--- a/cypress/e2e/tx_modal.cy.js
+++ b/cypress/e2e/tx_modal.cy.js
@@ -5,8 +5,6 @@ const SAFE_NONCE = '6'
describe('Tx Modal', () => {
before(() => {
- cy.connectE2EWallet()
-
// Open the Safe used for testing
cy.visit(`/${TEST_SAFE}`)
cy.contains('a', 'Accept selection').click()
diff --git a/cypress/e2e/tx_simulation.cy.js b/cypress/e2e/tx_simulation.cy.js
index aeaed28cb7..885fc17b33 100644
--- a/cypress/e2e/tx_simulation.cy.js
+++ b/cypress/e2e/tx_simulation.cy.js
@@ -3,8 +3,6 @@ const RECIPIENT_ADDRESS = '0x6a5602335a878ADDCa4BF63a050E34946B56B5bC'
describe('Tx Simulation', () => {
before(() => {
- cy.connectE2EWallet()
-
// Open the Safe used for testing
cy.visit(`/${TEST_SAFE}/home`, { failOnStatusCode: false })
cy.contains('button', 'Accept selection').click()
diff --git a/cypress/support/commands.js b/cypress/support/commands.js
index 75eae8fba5..2f9a1336ed 100644
--- a/cypress/support/commands.js
+++ b/cypress/support/commands.js
@@ -1,10 +1,3 @@
-Cypress.Commands.add('connectE2EWallet', () => {
- cy.on('window:before:load', (window) => {
- // Does not work unless `JSON.stringify` is used
- window.localStorage.setItem('SAFE_v2__lastWallet', JSON.stringify('E2E Wallet'))
- })
-})
-
Cypress.Commands.add('useProdCGW', () => {
cy.on('window:before:load', (window) => {
window.localStorage.setItem('SAFE_v2__debugProdCgw', JSON.stringify(true))
diff --git a/src/components/batch/BatchSidebar/index.tsx b/src/components/batch/BatchSidebar/index.tsx
index 19aaf48363..350a4c4dbb 100644
--- a/src/components/batch/BatchSidebar/index.tsx
+++ b/src/components/batch/BatchSidebar/index.tsx
@@ -75,7 +75,12 @@ const BatchSidebar = ({ isOpen, onToggle }: { isOpen: boolean; onToggle: (open:
diff --git a/src/components/batch/BatchSidebar/styles.module.css b/src/components/batch/BatchSidebar/styles.module.css
index 1f8ba735f9..a762c5aa37 100644
--- a/src/components/batch/BatchSidebar/styles.module.css
+++ b/src/components/batch/BatchSidebar/styles.module.css
@@ -26,7 +26,7 @@
}
.txs ul {
- padding: 0 var(--space-3) var(--space-3);
+ padding: 0 var(--space-3) var(--space-2);
display: flex;
flex-direction: column;
gap: var(--space-1);
@@ -43,6 +43,10 @@
height: calc(100% + 31px);
}
+.confirmButton {
+ margin-top: var(--space-1);
+}
+
.txs svg {
color: var(--color-border-main);
transition: color 0.1s ease-in;
diff --git a/src/components/common/ConnectWallet/AccountCenter.tsx b/src/components/common/ConnectWallet/AccountCenter.tsx
index 5909748a2e..0994631fee 100644
--- a/src/components/common/ConnectWallet/AccountCenter.tsx
+++ b/src/components/common/ConnectWallet/AccountCenter.tsx
@@ -5,7 +5,7 @@ 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, { forgetLastWallet, switchWallet } from '@/hooks/wallets/useOnboard'
+import useOnboard, { switchWallet } from '@/hooks/wallets/useOnboard'
import { useAppSelector } from '@/store'
import { selectChainById } from '@/store/chainsSlice'
import Identicon from '@/components/common/Identicon'
@@ -36,7 +36,6 @@ const AccountCenter = ({ wallet }: { wallet: ConnectedWallet }) => {
label: wallet.label,
})
- forgetLastWallet()
handleClose()
}
diff --git a/src/components/common/NavTabs/index.tsx b/src/components/common/NavTabs/index.tsx
index 1d0adc8a63..4637d02e72 100644
--- a/src/components/common/NavTabs/index.tsx
+++ b/src/components/common/NavTabs/index.tsx
@@ -32,7 +32,7 @@ const NextLinkComposed = forwardRef(function NextCompo
const NavTabs = ({ tabs }: { tabs: NavItem[] }) => {
const router = useRouter()
- const activeTab = tabs.map((tab) => tab.href).indexOf(router.pathname)
+ const activeTab = Math.max(0, tabs.map((tab) => tab.href).indexOf(router.pathname))
const query = router.query.safe ? { safe: router.query.safe } : undefined
return (
diff --git a/src/components/tx-flow/flows/SuccessScreen/StatusMessage.tsx b/src/components/tx-flow/flows/SuccessScreen/StatusMessage.tsx
index 572e5ee48a..db0102266d 100644
--- a/src/components/tx-flow/flows/SuccessScreen/StatusMessage.tsx
+++ b/src/components/tx-flow/flows/SuccessScreen/StatusMessage.tsx
@@ -9,17 +9,17 @@ const getStep = (status: PendingStatus, error?: Error) => {
case PendingStatus.PROCESSING:
case PendingStatus.RELAYING:
return {
- description: 'Transaction is now processing.',
+ description: 'Transaction is now processing',
instruction: 'The transaction was confirmed and is now being processed.',
}
case PendingStatus.INDEXING:
return {
- description: 'Transaction was processed.',
+ description: 'Transaction was processed',
instruction: 'It is now being indexed.',
}
default:
return {
- description: error ? 'Transaction failed' : 'Transaction was successful.',
+ description: error ? 'Transaction failed' : 'Transaction was successful',
instruction: error ? error.message : '',
}
}
diff --git a/src/hooks/wallets/useOnboard.ts b/src/hooks/wallets/useOnboard.ts
index d440c01c8c..5e38bb1ab1 100644
--- a/src/hooks/wallets/useOnboard.ts
+++ b/src/hooks/wallets/useOnboard.ts
@@ -4,14 +4,14 @@ import { type ChainInfo } from '@safe-global/safe-gateway-typescript-sdk'
import { getAddress } from 'ethers/lib/utils'
import useChains, { useCurrentChain } from '@/hooks/useChains'
import ExternalStore from '@/services/ExternalStore'
-import { localItem } from '@/services/local-storage/local'
import { logError, Errors } from '@/services/exceptions'
import { trackEvent, WALLET_EVENTS } from '@/services/analytics'
import { useInitPairing } from '@/services/pairing/hooks'
-import { isWalletUnlocked, WalletNames } from '@/utils/wallets'
import { useAppSelector } from '@/store'
import { type EnvState, selectRpc } from '@/store/settingsSlice'
-import { WALLET_KEYS } from './consts'
+import { E2E_WALLET_NAME } from '@/tests/e2e-wallet'
+
+const WALLETCONNECT = 'WalletConnect'
export type ConnectedWallet = {
label: string
@@ -22,12 +22,6 @@ export type ConnectedWallet = {
icon?: string
}
-const lastWalletStorage = localItem('lastWallet')
-
-export const forgetLastWallet = () => {
- lastWalletStorage.remove()
-}
-
const { getStore, setStore, useStore } = new ExternalStore()
export const initOnboard = async (
@@ -67,16 +61,15 @@ export const getConnectedWallet = (wallets: WalletState[]): ConnectedWallet | nu
}
}
-const getWalletConnectLabel = async ({ label, provider }: ConnectedWallet): Promise => {
- if (label.toUpperCase() !== WALLET_KEYS.WALLETCONNECT.toUpperCase()) return
-
+const getWalletConnectLabel = async (wallet: ConnectedWallet): Promise => {
const UNKNOWN_PEER = 'Unknown'
- const { default: WalletConnect } = await import('@walletconnect/client')
-
- const peerWallet =
- ((provider as unknown as any).connector as InstanceType).peerMeta?.name || UNKNOWN_PEER
-
- return peerWallet ?? UNKNOWN_PEER
+ const { label } = wallet
+ const isWalletConnect = label.startsWith(WALLETCONNECT)
+ if (!isWalletConnect) return
+ const { connector } = wallet.provider as unknown as any
+ const peerWalletV2 = connector.session?.peer?.metadata?.name
+ const peerWalletV1 = connector.peerMeta?.name
+ return peerWalletV2 || peerWalletV1 || UNKNOWN_PEER
}
const trackWalletType = (wallet: ConnectedWallet) => {
@@ -118,7 +111,7 @@ export const connectWallet = async (
// On mobile, automatically choose WalletConnect if there is no injected wallet
if (!options && isMobile() && !hasInjectedWallet()) {
options = {
- autoSelect: WalletNames.WALLET_CONNECT_V2,
+ autoSelect: WALLETCONNECT,
}
}
@@ -133,17 +126,6 @@ export const connectWallet = async (
return
}
- // Save the last used wallet and track the wallet type
- const newWallet = getConnectedWallet(wallets)
-
- if (newWallet) {
- // Save
- lastWalletStorage.set(newWallet.label)
-
- // Track
- trackWalletType(newWallet)
- }
-
isConnecting = false
return wallets
@@ -153,7 +135,7 @@ export const switchWallet = (onboard: OnboardAPI) => {
connectWallet(onboard)
}
-// Disable/enable wallets according to chain and cache the last used wallet
+// Disable/enable wallets according to chain
export const useInitOnboard = () => {
const { configs } = useChains()
const chain = useCurrentChain()
@@ -178,21 +160,37 @@ export const useInitOnboard = () => {
onboard.state.actions.setWalletModules(supportedWallets)
}
- // Connect to the last connected wallet
enableWallets().then(() => {
- if (onboard.state.get().wallets.length > 0) return
-
- const label = lastWalletStorage.get()
- if (!label) return
-
- isWalletUnlocked(label).then((isUnlocked) => {
- isUnlocked &&
- connectWallet(onboard, {
- autoSelect: { label, disableModals: false },
- })
- })
+ // e2e wallet
+ if (typeof window !== 'undefined' && window.Cypress) {
+ connectWallet(onboard, {
+ autoSelect: { label: E2E_WALLET_NAME, disableModals: true },
+ })
+ }
})
}, [chain, onboard])
+
+ // Track connected wallet
+ useEffect(() => {
+ let lastConnectedWallet = ''
+ if (!onboard) return
+
+ const walletSubscription = onboard.state.select('wallets').subscribe((wallets) => {
+ const newWallet = getConnectedWallet(wallets)
+ if (newWallet) {
+ if (newWallet.label !== lastConnectedWallet) {
+ lastConnectedWallet = newWallet.label
+ trackWalletType(newWallet)
+ }
+ } else {
+ lastConnectedWallet = ''
+ }
+ })
+
+ return () => {
+ walletSubscription.unsubscribe()
+ }
+ }, [onboard])
}
export default useStore
diff --git a/src/services/onboard.ts b/src/services/onboard.ts
index d50faf53ca..f34f28b10c 100644
--- a/src/services/onboard.ts
+++ b/src/services/onboard.ts
@@ -58,9 +58,8 @@ export const createOnboard = (
connect: {
removeWhereIsMyWalletWarning: true,
+ autoConnectLastWallet: true,
},
-
- // TODO: Investigate using `autoConnectLastWallet` instead of our `lastWalletStorage`
})
return onboard
diff --git a/src/utils/wallets.ts b/src/utils/wallets.ts
index 969732049f..cb3dd8b2e9 100644
--- a/src/utils/wallets.ts
+++ b/src/utils/wallets.ts
@@ -1,13 +1,8 @@
-import { ProviderLabel } from '@web3-onboard/injected-wallets'
-import { hasValidPairingSession } from '@/services/pairing/utils'
-import { PAIRING_MODULE_LABEL } from '@/services/pairing/module'
-import { E2E_WALLET_NAME } from '@/tests/e2e-wallet'
import type { EthersError } from '@/utils/ethers-utils'
import { ErrorCode } from '@ethersproject/logger'
import { type ConnectedWallet } from '@/hooks/wallets/useOnboard'
import { getWeb3ReadOnly, isSmartContract } from '@/hooks/wallets/web3'
import { WALLET_KEYS } from '@/hooks/wallets/consts'
-import { WALLET_CONNECT_V1_MODULE_NAME } from '@/hooks/wallets/wallets'
const isWCRejection = (err: Error): boolean => {
return /rejected/.test(err?.message)
@@ -21,43 +16,6 @@ export const isWalletRejection = (err: EthersError | Error): boolean => {
return isEthersRejection(err as EthersError) || isWCRejection(err)
}
-export const WalletNames = {
- METAMASK: ProviderLabel.MetaMask,
- WALLET_CONNECT: WALLET_CONNECT_V1_MODULE_NAME,
- WALLET_CONNECT_V2: 'WalletConnect',
- SAFE_MOBILE_PAIRING: PAIRING_MODULE_LABEL,
-}
-
-/* Check if the wallet is unlocked. */
-export const isWalletUnlocked = async (walletName: string): Promise => {
- if (typeof window === 'undefined') return false
-
- if (window.ethereum?.isConnected?.()) {
- return true
- }
-
- // Only MetaMask exposes a method to check if the wallet is unlocked
- if (walletName === WalletNames.METAMASK) {
- return window.ethereum?._metamask?.isUnlocked?.() || false
- }
-
- // Wallet connect creates a localStorage entry when connected and removes it when disconnected
- if (walletName === WalletNames.WALLET_CONNECT) {
- return window.localStorage.getItem('walletconnect') !== null
- }
-
- // Our own Safe mobile pairing module
- if (walletName === WalletNames.SAFE_MOBILE_PAIRING && hasValidPairingSession()) {
- return hasValidPairingSession()
- }
-
- if (walletName === E2E_WALLET_NAME) {
- return Boolean(window.Cypress)
- }
-
- return false
-}
-
export const isHardwareWallet = (wallet: ConnectedWallet): boolean => {
return [WALLET_KEYS.LEDGER, WALLET_KEYS.TREZOR, WALLET_KEYS.KEYSTONE].includes(
wallet.label.toUpperCase() as WALLET_KEYS,