diff --git a/lib/components/ens-cache-provider.react.js b/lib/components/ens-cache-provider.react.js --- a/lib/components/ens-cache-provider.react.js +++ b/lib/components/ens-cache-provider.react.js @@ -3,14 +3,21 @@ import * as React from 'react'; import { ENSCache, type EthersProvider } from '../utils/ens-cache'; +import { + getENSNames as baseGetENSNames, + type GetENSNames, +} from '../utils/ens-helpers'; type ENSCacheContextType = { +ensCache: ?ENSCache, + +getENSNames: ?GetENSNames, +}; +const defaultContext = { + ensCache: undefined, + getENSNames: undefined, }; const ENSCacheContext: React.Context = React.createContext( - { - ensCache: undefined, - }, + defaultContext, ); type Props = { @@ -19,12 +26,14 @@ }; function ENSCacheProvider(props: Props): React.Node { const { provider, children } = props; - const context = React.useMemo( - () => ({ - ensCache: provider ? new ENSCache(provider) : null, - }), - [provider], - ); + const context = React.useMemo(() => { + if (!provider) { + return defaultContext; + } + const ensCache = new ENSCache(provider); + const getENSNames: GetENSNames = baseGetENSNames.bind(null, ensCache); + return { ensCache, getENSNames }; + }, [provider]); return ( {children} diff --git a/lib/utils/ens-helpers.js b/lib/utils/ens-helpers.js new file mode 100644 --- /dev/null +++ b/lib/utils/ens-helpers.js @@ -0,0 +1,75 @@ +// @flow + +import { userIdentifiedByETHAddress } from '../shared/account-utils'; +import { ENSCache } from './ens-cache'; + +type BaseUserInfo = { +username?: ?string, ... }; +export type GetENSNames = ( + users: $ReadOnlyArray, +) => Promise; + +async function getENSNames( + ensCache: ENSCache, + users: $ReadOnlyArray, +): Promise { + const info = users.map(user => { + if (!user) { + return user; + } + const { username } = user; + const ethAddress = + username && userIdentifiedByETHAddress(user) ? username : null; + const cachedResult = ethAddress + ? ensCache.getCachedNameForAddress(ethAddress) + : null; + return { + input: user, + ethAddress, + cachedResult, + }; + }); + + const needFetch = info + .map(user => { + if (!user) { + return null; + } + const { ethAddress, cachedResult } = user; + if (cachedResult || !ethAddress) { + return null; + } + return ethAddress; + }) + .filter(Boolean); + + const ensNames = new Map(); + if (needFetch.length > 0) { + await Promise.all( + needFetch.map(async (ethAddress: string) => { + const ensName = await ensCache.getNameForAddress(ethAddress); + if (ensName) { + ensNames.set(ethAddress, ensName); + } + }), + ); + } + + return info.map(user => { + if (!user) { + return user; + } + const { input, ethAddress, cachedResult } = user; + if (cachedResult) { + return { ...input, username: cachedResult }; + } else if (!ethAddress) { + return input; + } + const ensName = ensNames.get(ethAddress); + if (ensName) { + return { ...input, username: ensName }; + } + return input; + }); +} + +export { getENSNames };