Skip to content

Commit

Permalink
Prevent "no multisig" from being displayed before we checked (#390)
Browse files Browse the repository at this point in the history
Co-authored-by: Anton Lykhoyda <[email protected]>
  • Loading branch information
Tbaut and Lykhoyda authored Oct 11, 2023
1 parent db2697b commit f3040eb
Show file tree
Hide file tree
Showing 18 changed files with 195 additions and 108 deletions.
3 changes: 2 additions & 1 deletion packages/ui/cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { AuthRequests, Extension, TxRequests } from './Extension'
import { MultisigInfo, rejectCurrentMultisigTxs } from '../utils/rejectCurrentMultisigTxs'
import { InjectedAccountWitMnemonic } from '../fixtures/injectedAccounts'
import 'cypress-wait-until'

// ***********************************************
// This example commands.ts shows you how to
Expand Down Expand Up @@ -67,7 +68,7 @@ Cypress.Commands.add('rejectAuth', (id: number, reason: string) => {
})

Cypress.Commands.add('getTxRequests', () => {
return cy.wait(500).then(() => cy.wrap(extension.getTxRequests()))
return cy.wrap(extension.getTxRequests())
})

Cypress.Commands.add('approveTx', (id: number) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/cypress/support/page-objects/landingPage.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const landingPage = {
watchAccountButton: () => cy.get('[data-cy=button-watch-address]'),
accountsOrRpcLoader: () => cy.get('[data-cy="loader-accounts-rpc-connection"]'),
accountsLoader: () => cy.get('[data-cy="loader-accounts-connection"]'),
noAccountFoundError: () => cy.get('[data-cy="text-no-account-found"]')
}
5 changes: 4 additions & 1 deletion packages/ui/cypress/tests/login.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ import { injectedAccounts } from '../fixtures/injectedAccounts'
import { landingPageUrl } from '../fixtures/landingData'
import { landingPage } from '../support/page-objects/landingPage'
import { topMenuItems } from '../support/page-objects/topMenuItems'
import { waitForAuthRequest } from '../utils/waitForAuthRequests'

describe('Connect Account', () => {
beforeEach(() => {
cy.visit(landingPageUrl)
cy.initExtension(injectedAccounts)
topMenuItems.connectButton().click()
landingPage.accountsOrRpcLoader().should('contain', 'Loading accounts')
landingPage.accountsLoader().should('contain', 'Loading accounts')
})

it('Reject connection', () => {
waitForAuthRequest()
cy.getAuthRequests().then((authRequests) => {
const requests = Object.values(authRequests)
// we should have 1 connection request to the extension
Expand All @@ -26,6 +28,7 @@ describe('Connect Account', () => {
})

it('Connects with Alice', () => {
waitForAuthRequest()
const AliceAddress = Object.values(injectedAccounts)[0].address
cy.getAuthRequests().then((authRequests) => {
const requests = Object.values(authRequests)
Expand Down
8 changes: 6 additions & 2 deletions packages/ui/cypress/tests/transactions.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { multisigPage } from '../support/page-objects/multisigPage'
import { notifications } from '../support/page-objects/notifications'
import { sendTxModal } from '../support/page-objects/sendTxModal'
import { topMenuItems } from '../support/page-objects/topMenuItems'
import { waitForAuthRequest } from '../utils/waitForAuthRequests'
import { waitForTxRequest } from '../utils/waitForTxRequests'

const AliceAddress = Object.values(injectedAccounts)[0].address

Expand All @@ -20,7 +22,8 @@ describe('Perform transactions', () => {
cy.visit(landingPageUrl)
cy.initExtension(injectedAccounts)
topMenuItems.connectButton().click()
landingPage.accountsOrRpcLoader().should('contain', 'Loading accounts')
landingPage.accountsLoader().should('contain', 'Loading accounts')
waitForAuthRequest()
cy.getAuthRequests().then((authRequests) => {
const requests = Object.values(authRequests)
// we should have 1 connection request to the extension
Expand All @@ -38,9 +41,9 @@ describe('Perform transactions', () => {
multisigPage.newTransactionButton().click()
sendTxModal.sendTxTitle().should('be.visible')
fillAndSubmitTransactionForm()
waitForTxRequest()
cy.getTxRequests().then((req) => {
const txRequests = Object.values(req)
console.log('txRequests', JSON.stringify(txRequests))
cy.wrap(txRequests.length).should('eq', 1)
cy.wrap(txRequests[0].payload.address).should('eq', AliceAddress)
sendTxModal.buttonSend().should('be.disabled')
Expand All @@ -67,6 +70,7 @@ describe('Perform transactions', () => {
multisigPage.newTransactionButton().click()
sendTxModal.sendTxTitle().should('be.visible')
fillAndSubmitTransactionForm()
waitForTxRequest()
cy.getTxRequests().then((req) => {
const txRequests = Object.values(req)
cy.wrap(txRequests.length).should('eq', 1)
Expand Down
2 changes: 2 additions & 0 deletions packages/ui/cypress/utils/waitForAuthRequests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const waitForAuthRequest = () =>
cy.waitUntil(() => cy.getAuthRequests().then((req) => Object.entries(req).length > 0))
2 changes: 2 additions & 0 deletions packages/ui/cypress/utils/waitForTxRequests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const waitForTxRequest = () =>
cy.waitUntil(() => cy.getTxRequests().then((req) => Object.entries(req).length > 0))
1 change: 1 addition & 0 deletions packages/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@typescript-eslint/parser": "^6.7.2",
"@vitejs/plugin-react": "^4.0.4",
"cypress": "^13.2.0",
"cypress-wait-until": "^2.0.1",
"eslint": "^8.49.0",
"eslint-config-prettier": "^9.0.0",
"eslint-config-react-app": "^7.0.1",
Expand Down
1 change: 0 additions & 1 deletion packages/ui/src/components/modals/ChangeMultisig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import { Button } from '../library'
import { ModalCloseButton } from '../library/ModalCloseButton'
import { useGetSortAddress } from '../../hooks/useGetSortAddress'
import { useGetMultisigAddress } from '../../contexts/useGetMultisigAddress'
import BN from 'bn.js'

interface Props {
onClose: () => void
Expand Down
13 changes: 8 additions & 5 deletions packages/ui/src/contexts/AccountsContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export interface IAccountContext {
selectedSigner?: Signer
allowConnectionToExtension: () => void
isAllowedToConnectToExtension: boolean
isLocalStorageSetupDone: boolean
}

const AccountContext = createContext<IAccountContext | undefined>(undefined)
Expand All @@ -38,6 +39,7 @@ const AccountContextProvider = ({ children }: AccountContextProps) => {
const ownAddressList = useMemo(() => ownAccountList.map((a) => a.address), [ownAccountList])
const [accountGotRequested, setAccountGotRequested] = useState(false)
const { chainInfo } = useApi()
const [isLocalStorageSetupDone, setIsLocalStorageSetupDone] = useState(false)
// update the current account list with the right network prefix
// this will run for every network change
useEffect(() => {
Expand Down Expand Up @@ -67,8 +69,6 @@ const AccountContextProvider = ({ children }: AccountContextProps) => {

const getaccountList = useCallback(
async (isEthereum: boolean): Promise<void> => {
setIsAccountLoading(true)

web3Enable(DAPP_NAME)
.then(
(ext) => {
Expand Down Expand Up @@ -131,6 +131,7 @@ const AccountContextProvider = ({ children }: AccountContextProps) => {

if (!accountGotRequested && isAllowedToConnectToExtension) {
setAccountGotRequested(true)
setIsAccountLoading(true)
// delay the request by 500ms
// race condition see https://github.com/polkadot-js/extension/issues/938
setTimeout(() => {
Expand All @@ -142,9 +143,9 @@ const AccountContextProvider = ({ children }: AccountContextProps) => {
getaccountList,
isAccountLoading,
isAllowedToConnectToExtension,
accountGotRequested,
chainInfo,
isExtensionError
isExtensionError,
accountGotRequested
])

useEffect(() => {
Expand All @@ -153,6 +154,7 @@ const AccountContextProvider = ({ children }: AccountContextProps) => {
if (previouslyAllowed === 'true') {
setIsAllowedToConnectToExtension(true)
}
setIsLocalStorageSetupDone(true)
}
}, [isAllowedToConnectToExtension])

Expand Down Expand Up @@ -181,7 +183,8 @@ const AccountContextProvider = ({ children }: AccountContextProps) => {
getAccountByAddress,
selectedSigner,
allowConnectionToExtension,
isAllowedToConnectToExtension
isAllowedToConnectToExtension,
isLocalStorageSetupDone
}}
>
{children}
Expand Down
8 changes: 7 additions & 1 deletion packages/ui/src/contexts/MultiProxyContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,11 @@ const MultiProxyContextProvider = ({ children }: MultisigContextProps) => {
),
[selectedMultiProxy, ownAddressList]
)
const [isRefreshingMultiProxyList, setIsRefreshingMultiProxyList] = useState(false)

const refreshPureToQueryAndMultisigList = useCallback(
(data: MultisigsBySignatoriesOrWatchedSubscription | null) => {
setIsRefreshingMultiProxyList(true)
// we do have an answer, but there is no multisig
if (!!data?.accountMultisigs && data.accountMultisigs.length === 0) {
setPureToQuery([])
Expand Down Expand Up @@ -123,11 +125,14 @@ const MultiProxyContextProvider = ({ children }: MultisigContextProps) => {
// add the selection to the pure to query
setPureToQuery(Array.from(pureToQuerySet))
}

setIsRefreshingMultiProxyList(false)
},
[]
)

const refreshWatchedPureList = useCallback((data: PureByIdsSubscription | null) => {
setIsRefreshingMultiProxyList(true)
const pureProxyMap = new Map<string, Omit<MultiProxy, 'proxy'>>()
// we do have an answer, but there is nothing
if (!!data?.accounts && data.accounts.length === 0) {
Expand Down Expand Up @@ -174,6 +179,7 @@ const MultiProxyContextProvider = ({ children }: MultisigContextProps) => {
)

setPureProxyList(pureProxyArray)
setIsRefreshingMultiProxyList(false)
}, [])

const ownAddressIds = useAccountId(ownAddressList)
Expand Down Expand Up @@ -277,7 +283,7 @@ const MultiProxyContextProvider = ({ children }: MultisigContextProps) => {
selectedMultiProxy,
multiProxyList,
selectMultiProxy,
isLoading: isMultisigsubLoading || isPureSubLoading,
isLoading: isMultisigsubLoading || isPureSubLoading || isRefreshingMultiProxyList,
selectedHasProxy,
error: isMultisigSubError || isPureSubError,
getMultisigByAddress,
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/src/contexts/WalletConnectContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const WalletConnectContextProvider = ({ children }: WalletConnectContextProps) =
const core = useMemo(
() =>
new Core({
logger: 'info',
logger: undefined, // use 'debug' to get more insight
projectId: import.meta.env.VITE_WALLETCONNECT_PROJECT_ID
// relayUrl: relayerRegionURL ?? import.meta.env.VITE_WALLETCONNECT_PUBLIC_RELAY_URL
}),
Expand Down
4 changes: 3 additions & 1 deletion packages/ui/src/contexts/WatchedAddressesContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export interface IWatchedAddressesContext {
addWatchedAccount: (address: string) => void
removeWatchedAccount: (address: string) => void
watchedAddresses: string[]
isInitialized: boolean
}

const WatchedAddressesContext = createContext<IWatchedAddressesContext | undefined>(undefined)
Expand Down Expand Up @@ -84,7 +85,8 @@ const WatchedAddressesContextProvider = ({ children }: WatchedAddressesProps) =>
value={{
addWatchedAccount,
removeWatchedAccount,
watchedAddresses
watchedAddresses,
isInitialized
}}
>
{children}
Expand Down
70 changes: 70 additions & 0 deletions packages/ui/src/hooks/useDisplayError.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import {
HiOutlineArrowTopRightOnSquare as LaunchIcon,
HiOutlineExclamationCircle as ErrorOutlineIcon
} from 'react-icons/hi2'

import { styled } from '@mui/material/styles'
import { useAccounts } from '../contexts/AccountsContext'
import { Link } from '../components/library'
import { Center } from '../components/layout/Center'
import { useWatchedAddresses } from '../contexts/WatchedAddressesContext'
import { useMultiProxy } from '../contexts/MultiProxyContext'

export const useDisplayError = () => {
const { isExtensionError, isAccountLoading } = useAccounts()
const { watchedAddresses } = useWatchedAddresses()
const { error: multisigQueryError } = useMultiProxy()

if (isExtensionError && watchedAddresses.length === 0 && !isAccountLoading) {
return (
<CenterStyled>
<h3 data-cy="text-no-account-found">
No account found. Please connect at least one in a wallet extension. More info at{' '}
<Linkstyled
href="https://wiki.polkadot.network/docs/wallets-and-extensions"
target="_blank"
rel="noreferrer"
>
wiki.polkadot.network
<LaunchIcon
className="launchIcon"
size={20}
/>
</Linkstyled>
</h3>
</CenterStyled>
)
}

if (multisigQueryError) {
return (
<CenterStyled>
<ErrorMessageStyled>
<ErrorOutlineIcon size={64} />
<div>An error occurred.</div>
</ErrorMessageStyled>
</CenterStyled>
)
}

return null
}

const Linkstyled = styled(Link)`
display: inline-flex;
padding-left: 0.2rem;
align-items: center;
.launchIcon {
margin-left: 0.5rem;
}
`

const CenterStyled = styled(Center)`
text-align: center;
`

const ErrorMessageStyled = styled('div')`
text-align: center;
margin-top: 1rem;
`
62 changes: 62 additions & 0 deletions packages/ui/src/hooks/useDisplayLoader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { styled } from '@mui/material/styles'
import { useMultiProxy } from '../contexts/MultiProxyContext'
import { useApi } from '../contexts/ApiContext'
import { Box, CircularProgress } from '@mui/material'
import { useNetwork } from '../contexts/NetworkContext'
import { useAccounts } from '../contexts/AccountsContext'
import { useWatchedAddresses } from '../contexts/WatchedAddressesContext'

export const useDisplayLoader = () => {
const { isLoading: isLoadingMultisigs } = useMultiProxy()
const { api } = useApi()
const { selectedNetworkInfo } = useNetwork()
const { isAccountLoading, isLocalStorageSetupDone } = useAccounts()
const { isInitialized: isWatchAddressInitialized } = useWatchedAddresses()

if (!isWatchAddressInitialized || !isLocalStorageSetupDone) {
return (
<LoaderBoxStyled data-cy="loader-initialization">
<CircularProgress />
Initialization...
</LoaderBoxStyled>
)
}

if (!api) {
return (
<LoaderBoxStyled data-cy="loader-rpc-connection">
<CircularProgress />
{`Connecting to the node at ${selectedNetworkInfo?.rpcUrl}`}
</LoaderBoxStyled>
)
}

if (isAccountLoading) {
return (
<LoaderBoxStyled data-cy="loader-accounts-connection">
<CircularProgress />
Loading accounts...
</LoaderBoxStyled>
)
}

if (isLoadingMultisigs) {
return (
<LoaderBoxStyled data-cy="loader-accounts-connection">
<CircularProgress />
<div>Loading your multisigs...</div>
</LoaderBoxStyled>
)
}

return null
}

const LoaderBoxStyled = styled(Box)`
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
width: 100%;
padding: 1rem;
`
2 changes: 1 addition & 1 deletion packages/ui/src/hooks/usePendingTx.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const usePendingTx = (multiProxy?: MultiProxy) => {
setIsLoading(false)
})
.catch(console.error)
}, [api, multisigs])
}, [api, chainInfo, multisigs])

useEffect(() => {
refresh()
Expand Down
Loading

0 comments on commit f3040eb

Please sign in to comment.