Skip to content

Commit

Permalink
Retrieve avatar to wallet (#443)
Browse files Browse the repository at this point in the history
Resolves #256 

Solves the problem of avatar not being fetched correctly
  • Loading branch information
Karolina Kosiorowska authored Oct 24, 2023
2 parents 035e044 + 1047c4b commit 35ac8fe
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 33 deletions.
13 changes: 7 additions & 6 deletions src/redux-state/thunks/wallet.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { resolveAddressToName } from "shared/utils"
import { resolveAddressToWalletData } from "shared/utils"
import {
updateBalances,
updateConnectedWallet,
Expand All @@ -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
}
)

Expand Down
14 changes: 10 additions & 4 deletions src/shared/utils/ens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
45 changes: 28 additions & 17 deletions src/shared/utils/names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string | null>
[address: string]: Promise<WalletData>
} = {}

const getCachedNames = () => {
Expand All @@ -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) =>
Expand All @@ -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<string | null>([
resolveAddressPromiseCache[normalizedAddress] = Promise.any([
resolveENSPromise(normalizedAddress),
resolveUNSPromise(normalizedAddress),
resolveUnknownNamePromise(),
])
]) as Promise<WalletData>
}

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<string | null> => {
): Promise<WalletData> => {
const cachedNames = getCachedNames()

const normalizedAddress = normalizeAddress(address)
Expand All @@ -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) => {
Expand Down
16 changes: 10 additions & 6 deletions src/ui/Island/RealmDetails/LeaderboardList/LeaderboardItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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])
Expand All @@ -52,7 +56,7 @@ export default function LeaderboardItem({
{isCurrentUser && (
<Icon
type="image"
src={avatar}
src={walletAvatar}
width="40px"
style={{ borderRadius: "100%", backgroundPosition: "center" }}
/>
Expand Down
1 change: 1 addition & 0 deletions src/ui/Nav/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default function Nav(): JSX.Element {
.rhs_container {
margin-left: auto;
align-items: center;
height: 40px;
}
.connect_wallet_btn {
Expand Down

0 comments on commit 35ac8fe

Please sign in to comment.