diff --git a/src/redux-state/thunks/wallet.ts b/src/redux-state/thunks/wallet.ts index 3669a11ea..b82d7f3a8 100644 --- a/src/redux-state/thunks/wallet.ts +++ b/src/redux-state/thunks/wallet.ts @@ -1,4 +1,4 @@ -import { resolveAddressToName } from "shared/utils" +import { resolveAddressToWalletData } from "shared/utils" import { updateBalances, updateConnectedWallet, @@ -24,22 +24,23 @@ export const fetchWalletName = createDappAsyncThunk( claim: { useConnectedWallet }, } = getState() - const resolvedName = await resolveAddressToName(address) + const { name, avatar } = await resolveAddressToWalletData(address) - if (resolvedName) { + if (name) { dispatch( updateConnectedWallet({ address, - name: resolvedName, + name, + avatar, }) ) if (useConnectedWallet) { - dispatch(setClaimingUser({ name: resolvedName, address })) + dispatch(setClaimingUser({ name, address })) } } - return resolvedName + return name } ) diff --git a/src/shared/utils/ens.ts b/src/shared/utils/ens.ts index 691311d95..c26dc0704 100644 --- a/src/shared/utils/ens.ts +++ b/src/shared/utils/ens.ts @@ -10,9 +10,15 @@ export const resolveENS = (name: string) => { } export const resolveAddressToENS = async (address: string) => { - const name = await ethereumProvider.lookupAddress(address) - if (!name) { - throw Error("Invalid ENS domain name") + try { + const name = await ethereumProvider.lookupAddress(address) + const avatar = await ethereumProvider.getAvatar(address) + + if (!name) throw Error("Invalid ENS domain name") + if (!avatar) return { name } + + return { name, avatar } + } catch { + return null } - return name } diff --git a/src/shared/utils/names.ts b/src/shared/utils/names.ts index d19f686ef..ec21305d3 100644 --- a/src/shared/utils/names.ts +++ b/src/shared/utils/names.ts @@ -2,16 +2,21 @@ import { isProbablyEVMAddress, normalizeAddress } from "./address" import { isValidENSDomainName, resolveENS, resolveAddressToENS } from "./ens" import { isValidUNSDomainName, resolveAddressToUNS, resolveUNS } from "./uns" -type NameWithProvider = { - name: string +type WalletData = { + name?: string + avatar?: string +} + +type NameWithProvider = WalletData & { address: string type: "ens" | "uns" } + const NAMES_CACHE_STRORAGE_KEY = "taho.cachedNames" const MAX_CACHE_AGE = 1000 * 60 * 60 * 24 * 7 // 1 week const resolveAddressPromiseCache: { - [address: string]: Promise + [address: string]: Promise } = {} const getCachedNames = () => { @@ -21,25 +26,29 @@ const getCachedNames = () => { return JSON.parse(cachedNamesUnparsed) } -const addCachedName = ({ name, address, type }: NameWithProvider) => { +const addCachedName = ({ name, avatar, address, type }: NameWithProvider) => { const cachedNames = getCachedNames() const normalizedAddress = normalizeAddress(address) + const newData = name ? { [type]: { name, avatar } } : {} const newCache = JSON.stringify({ ...cachedNames, [normalizedAddress]: { ...(cachedNames[normalizedAddress] ?? {}), - [type]: name, + ...newData, lastUpdate: Date.now(), }, }) + localStorage.setItem(NAMES_CACHE_STRORAGE_KEY, newCache) } const resolveENSPromise = (address: string) => - resolveAddressToENS(address).then((name): string => { - addCachedName({ type: "ens", address, name }) - return name + resolveAddressToENS(address).then((data): WalletData | null => { + if (!data) return null + + addCachedName({ type: "ens", address, ...data }) + return data }) const resolveUNSPromise = (address: string) => @@ -53,25 +62,25 @@ const resolveUnknownNamePromise = () => setTimeout(() => resolve(null), 15000) }) -const resolveAddressToNameWithoutCache = async (address: string) => { +const resolveAddressToWalletDataWithoutCache = async (address: string) => { const normalizedAddress = normalizeAddress(address) if (resolveAddressPromiseCache[normalizedAddress] === undefined) { - resolveAddressPromiseCache[normalizedAddress] = Promise.any([ + resolveAddressPromiseCache[normalizedAddress] = Promise.any([ resolveENSPromise(normalizedAddress), resolveUNSPromise(normalizedAddress), resolveUnknownNamePromise(), - ]) + ]) as Promise } - const resolvedName = await resolveAddressPromiseCache[normalizedAddress] + const { name, avatar } = await resolveAddressPromiseCache[normalizedAddress] - return resolvedName + return { name, avatar } } -export const resolveAddressToName = async ( +export const resolveAddressToWalletData = async ( address: string -): Promise => { +): Promise => { const cachedNames = getCachedNames() const normalizedAddress = normalizeAddress(address) @@ -81,9 +90,11 @@ export const resolveAddressToName = async ( return cachedItem.ens ?? cachedItem.uns } - const name = await resolveAddressToNameWithoutCache(normalizedAddress) + const { name, avatar } = await resolveAddressToWalletDataWithoutCache( + normalizedAddress + ) - return name + return { name, avatar } } export const resolveNameToAddress = async (addressOrName: string) => { diff --git a/src/ui/Island/RealmDetails/LeaderboardList/LeaderboardItem.tsx b/src/ui/Island/RealmDetails/LeaderboardList/LeaderboardItem.tsx index 342f762a2..faf31f9bc 100644 --- a/src/ui/Island/RealmDetails/LeaderboardList/LeaderboardItem.tsx +++ b/src/ui/Island/RealmDetails/LeaderboardList/LeaderboardItem.tsx @@ -4,7 +4,7 @@ import crossIcon from "shared/assets/icons/plus.svg" import classNames from "classnames" import { isSameAddress, - resolveAddressToName, + resolveAddressToWalletData, separateThousandsByComma, truncateAddress, } from "shared/utils" @@ -23,14 +23,18 @@ export default function LeaderboardItem({ const { beneficiary: address, amount } = item const isCurrentUser = isSameAddress(address, currentUser) const avatar = useDappSelector(selectWalletAvatar) + const [username, setUsername] = useState("") + const [walletAvatar, setWalletAvatar] = useState(avatar) useEffect(() => { const getName = async () => { - const name = await resolveAddressToName(address) - if (name) { - setUsername(name) - } + const { name, avatar: userAvatar } = await resolveAddressToWalletData( + address + ) + + if (name) setUsername(name) + if (userAvatar) setWalletAvatar(userAvatar) } getName() }, [address]) @@ -52,7 +56,7 @@ export default function LeaderboardItem({ {isCurrentUser && ( diff --git a/src/ui/Nav/index.tsx b/src/ui/Nav/index.tsx index 092198f21..e976d57fa 100644 --- a/src/ui/Nav/index.tsx +++ b/src/ui/Nav/index.tsx @@ -55,6 +55,7 @@ export default function Nav(): JSX.Element { .rhs_container { margin-left: auto; align-items: center; + height: 40px; } .connect_wallet_btn {