Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions packages/app/src/Providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { APIProvider } from 'contexts/Api'
import { BalancesProvider } from 'contexts/Balances'
import { ExternalAccountsProvider } from 'contexts/Connect/ExternalAccounts'
import { ImportedAccountsProvider } from 'contexts/Connect/ImportedAccounts'
import { OtherAccountsProvider } from 'contexts/Connect/OtherAccounts'
import { CurrencyProvider } from 'contexts/Currency'
import { EraStakersProvider } from 'contexts/EraStakers'
import { FiltersProvider } from 'contexts/Filters'
Expand Down Expand Up @@ -68,7 +67,6 @@ export const Providers = () => {
],
HardwareAccountsProvider,
ExternalAccountsProvider,
OtherAccountsProvider,
ImportedAccountsProvider,
WalletConnectProvider,
ProxiesProvider,
Expand Down
28 changes: 26 additions & 2 deletions packages/app/src/contexts/Connect/ExternalAccounts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import { useNetwork } from 'contexts/Network'
import {
addExternalAccount as addExternalAccountBus,
externalAccountExists,
externalAccounts$,
removeExternalAccounts,
} from 'global-bus'
import type { ReactNode } from 'react'
import { type ReactNode, useEffect, useState } from 'react'
import type { AccountAddedBy, ExternalAccount } from 'types'
import type {
AddExternalAccountResult,
Expand All @@ -31,6 +32,11 @@ export const ExternalAccountsProvider = ({
const { activeAddress, setActiveAccount } = useActiveAccounts()
const { ss58 } = getStakingChainData(network)

// Store external accounts in state
const [externalAccounts, setExternalAccounts] = useState<ExternalAccount[]>(
[],
)

// Adds an external account to imported accounts
const addExternalAccount = (
address: string,
Expand Down Expand Up @@ -94,9 +100,27 @@ export const ExternalAccountsProvider = ({
}
}

// Gets all accounts for a network
const getExternalAccounts = (network: string) =>
externalAccounts.filter((a) => a.network === network)

// Subscribe to global bus
useEffect(() => {
const sub = externalAccounts$.subscribe((result) => {
setExternalAccounts(result)
})
return () => {
sub.unsubscribe()
}
}, [])

return (
<ExternalAccountsContext.Provider
value={{ addExternalAccount, forgetExternalAccounts }}
value={{
getExternalAccounts,
addExternalAccount,
forgetExternalAccounts,
}}
>
{children}
</ExternalAccountsContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import type { AccountAddedBy, ExternalAccount } from 'types'

export interface ExternalAccountsContextInterface {
getExternalAccounts: (network: string) => ExternalAccount[]
addExternalAccount: (
address: string,
addedBy: AccountAddedBy,
Expand Down
64 changes: 55 additions & 9 deletions packages/app/src/contexts/Connect/ImportedAccounts/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,24 @@
// SPDX-License-Identifier: GPL-3.0-only

import { createSafeContext, useEffectIgnoreInitial } from '@w3ux/hooks'
import { useExtensionAccounts } from '@w3ux/react-connect-kit'
import {
useExtensionAccounts,
useHardwareAccounts,
} from '@w3ux/react-connect-kit'
import type { ExtensionAccount, HardwareAccount } from '@w3ux/types'
import { ManualSigners } from 'consts'
import { getStakingChainData } from 'consts/util'
import { useActiveAccounts } from 'contexts/ActiveAccounts'
import { useNetwork } from 'contexts/Network'
import type { ReactNode } from 'react'
import { useCallback } from 'react'
import { useCallback, useState } from 'react'
import type {
ActiveAccount,
ExternalAccount,
ImportedAccount,
MaybeAddress,
} from 'types'
import { useOtherAccounts } from '../OtherAccounts'
import { useExternalAccounts } from '../ExternalAccounts'
import { getActiveAccountLocal } from '../Utils'
import type { ImportedAccountsContextInterface } from './types'

Expand All @@ -28,14 +32,33 @@ export const ImportedAccountsProvider = ({
children: ReactNode
}) => {
const { network } = useNetwork()
const { otherAccounts } = useOtherAccounts()
const { setActiveAccount } = useActiveAccounts()
const { getExtensionAccounts } = useExtensionAccounts()

const { getExternalAccounts } = useExternalAccounts()
const { getHardwareAccounts } = useHardwareAccounts()
const { setActiveAccount, activeAccount } = useActiveAccounts()
const { getExtensionAccounts, extensionsSynced } = useExtensionAccounts()
const { ss58 } = getStakingChainData(network)

// Whether active account import checks have been completed
const [accountsInitialised, setAccountsInitialised] = useState<boolean>(false)

// Get the imported extension accounts formatted with the current network's ss58 prefix
const extensionAccounts = getExtensionAccounts(ss58)
const allAccounts = extensionAccounts.concat(otherAccounts)
const extensionAccounts: ExtensionAccount[] = getExtensionAccounts(ss58)

// Get the imported hardware accounts for the current network
const hardwareAccounts: HardwareAccount[] = getHardwareAccounts(
'ledger',
network,
)
.concat(getHardwareAccounts('vault', network))
.concat(getHardwareAccounts('wallet_connect', network))

// Get the imported external accounts for the current network
const externalAccounts: ExternalAccount[] = getExternalAccounts(network)

// Combine all imported accounts
const allAccounts: ImportedAccount[] = extensionAccounts
.concat(hardwareAccounts)
.concat(externalAccounts)

// Stringify account addresses and account names to determine if they have changed. Ignore other properties including `signer` and `source`
const shallowAccountStringify = (accounts: ImportedAccount[]) => {
Expand Down Expand Up @@ -141,6 +164,28 @@ export const ImportedAccountsProvider = ({
}
}, [network, stringifiedAccountsKey])

// Once extensions are fully initialised, fetch accounts from other sources and re-sync active
// account. Only runs once per app load
useEffectIgnoreInitial(() => {
if (extensionsSynced === 'synced' && !accountsInitialised) {
setAccountsInitialised(true)

// If active account is not yet set, check if it has been imported in other accounts
if (!activeAccount) {
const activeAccountFound = allAccounts.find(
({ address }) =>
address === getActiveAccountLocal(network, ss58)?.address,
)
if (activeAccountFound) {
setActiveAccount({
address: activeAccountFound.address,
source: activeAccountFound.source,
})
}
}
}
}, [extensionsSynced])

return (
<ImportedAccountsContext.Provider
value={{
Expand All @@ -150,6 +195,7 @@ export const ImportedAccountsProvider = ({
accountHasSigner,
requiresManualSign,
stringifiedAccountsKey,
accountsInitialised,
}}
>
{children}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export interface ImportedAccountsContextInterface {
accountHasSigner: (activeAccount: ActiveAccount) => boolean
requiresManualSign: (activeAccount: ActiveAccount) => boolean
stringifiedAccountsKey: string
accountsInitialised: boolean
}
Loading