-
Notifications
You must be signed in to change notification settings - Fork 81
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3448 from VenusProtocol/feat/web3-user-names
feat: fetch domain names for addresses
- Loading branch information
Showing
22 changed files
with
424 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@venusprotocol/evm": minor | ||
--- | ||
|
||
fetch web3 domain names for addresses |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
apps/evm/src/clients/api/queries/getAddressDomainName/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import { create, windowScheduler } from '@yornaath/batshit'; | ||
import type { ChainId } from 'types'; | ||
import { restService } from 'utilities'; | ||
import type { Address } from 'viem'; | ||
|
||
const getDomainNameFromApi = async ({ | ||
addresses, | ||
chainIds, | ||
}: { addresses: Address[]; chainIds?: ChainId[] }) => { | ||
const response = await restService<GetApiDomainNameResponse>({ | ||
endpoint: '/web3-domain-name', | ||
method: 'GET', | ||
params: { | ||
addresses: JSON.stringify([...new Set(addresses)]), | ||
chainIds: JSON.stringify([...new Set(chainIds)]), | ||
}, | ||
}); | ||
|
||
if (response.data && 'error' in response.data) { | ||
throw new Error(response.data.error); | ||
} | ||
|
||
return response.data; | ||
}; | ||
|
||
const domainNamesBatcher = create({ | ||
fetcher: async (queries: { accountAddress: Address; chainId: ChainId }[]) => | ||
getDomainNameFromApi({ | ||
addresses: queries.map(q => q.accountAddress), | ||
chainIds: queries.map(q => q.chainId), | ||
}), | ||
resolver: (data, query) => data?.[query.accountAddress], | ||
scheduler: windowScheduler(10), | ||
}); | ||
|
||
type ChainIdDomainNameMap = { [Key in ChainId]?: string | null }; | ||
type GetApiDomainNameResponse = Record<Address, ChainIdDomainNameMap>; | ||
|
||
export interface GetAddressDomainNameInput { | ||
accountAddress: Address; | ||
chainId: ChainId; | ||
} | ||
|
||
export type GetAddressDomainNameOutput = ChainIdDomainNameMap; | ||
|
||
const getAddressDomainName = async ({ accountAddress, chainId }: GetAddressDomainNameInput) => { | ||
const response = await domainNamesBatcher.fetch({ accountAddress, chainId }); | ||
|
||
return response || {}; | ||
}; | ||
|
||
export default getAddressDomainName; |
43 changes: 43 additions & 0 deletions
43
apps/evm/src/clients/api/queries/getAddressDomainName/useGetAddressDomainName.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import { type QueryObserverOptions, useQuery } from '@tanstack/react-query'; | ||
|
||
import getAddressDomainName, { | ||
type GetAddressDomainNameInput, | ||
type GetAddressDomainNameOutput, | ||
} from 'clients/api/queries/getAddressDomainName'; | ||
import FunctionKey from 'constants/functionKey'; | ||
|
||
type UseGetAddressDomainNameInput = GetAddressDomainNameInput; | ||
|
||
export type UseGetAddressDomainNameQueryKey = [ | ||
FunctionKey.GET_ADDRESS_DOMAIN_NAME, | ||
GetAddressDomainNameInput, | ||
]; | ||
|
||
type Options = QueryObserverOptions< | ||
GetAddressDomainNameOutput, | ||
Error, | ||
GetAddressDomainNameOutput, | ||
GetAddressDomainNameOutput, | ||
UseGetAddressDomainNameQueryKey | ||
>; | ||
|
||
const useGetAddressDomainName = ( | ||
{ accountAddress, chainId }: UseGetAddressDomainNameInput, | ||
options?: Partial<Options>, | ||
) => { | ||
const queryKey: UseGetAddressDomainNameQueryKey = [ | ||
FunctionKey.GET_ADDRESS_DOMAIN_NAME, | ||
{ | ||
accountAddress, | ||
chainId, | ||
}, | ||
]; | ||
|
||
return useQuery({ | ||
queryKey: queryKey, | ||
queryFn: () => getAddressDomainName({ accountAddress, chainId }), | ||
...options, | ||
}); | ||
}; | ||
|
||
export default useGetAddressDomainName; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import type { SVGProps } from 'react'; | ||
|
||
const SvgEnsLogo = (props: SVGProps<SVGSVGElement>) => ( | ||
<svg | ||
width="16" | ||
height="16" | ||
viewBox="0 0 16 16" | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
{...props} | ||
> | ||
<g clip-path="url(#clip0_47_1749)"> | ||
<path | ||
d="M3.49441 6.7707C3.62296 7.04388 3.94435 7.59024 3.94435 7.59024L7.6242 1.5L4.04076 4.0068C3.83186 4.15142 3.6551 4.34425 3.52655 4.56922C3.18909 5.2602 3.18909 6.06366 3.49441 6.7707Z" | ||
fill="url(#paint0_linear_47_1749)" | ||
/> | ||
<path | ||
d="M2.04824 8.7634C2.12858 9.93646 2.72314 11.0292 3.65516 11.7362L7.62425 14.5001C7.62425 14.5001 5.13353 10.9167 3.04453 7.34931C2.83563 6.97972 2.691 6.56192 2.62673 6.12805C2.59459 5.93522 2.59459 5.74239 2.62673 5.54956C2.57852 5.64598 2.46603 5.85488 2.46603 5.85488C2.25713 6.28874 2.11251 6.75475 2.03217 7.23683C1.98396 7.75104 1.98396 8.26526 2.04824 8.7634Z" | ||
fill="#A0A8D4" | ||
/> | ||
<path | ||
d="M12.1718 9.24531C12.0432 8.97214 11.7218 8.42578 11.7218 8.42578L8.04199 14.4999L11.6415 12.0092C11.8504 11.8646 12.0272 11.6718 12.1557 11.4468C12.4771 10.7558 12.4932 9.95236 12.1718 9.24531Z" | ||
fill="url(#paint1_linear_47_1749)" | ||
/> | ||
<path | ||
d="M13.6341 7.23671C13.5538 6.06366 12.9592 4.97095 12.0272 4.26391L8.05811 1.5C8.05811 1.5 10.5488 5.08344 12.6378 8.6508C12.8467 9.02039 12.9914 9.43819 13.0556 9.87206C13.0878 10.0649 13.0878 10.2577 13.0556 10.4506C13.1038 10.3541 13.2163 10.1452 13.2163 10.1452C13.4252 9.71137 13.5698 9.24536 13.6502 8.77936C13.6823 8.24907 13.6823 7.75093 13.6341 7.23671Z" | ||
fill="#A0A8D4" | ||
/> | ||
<path | ||
d="M3.52673 4.56922C3.65528 4.34425 3.81597 4.15142 4.04094 4.0068L7.62438 1.5L3.94453 7.57417C3.94453 7.57417 3.62314 7.02781 3.49459 6.75464C3.18927 6.06366 3.18927 5.2602 3.52673 4.56922ZM2.04836 8.76329C2.1287 9.93634 2.72326 11.029 3.65528 11.7361L7.62438 14.5C7.62438 14.5 5.13365 10.9166 3.04465 7.3492C2.83575 6.9796 2.69113 6.5618 2.62685 6.12794C2.59471 5.9351 2.59471 5.74227 2.62685 5.54944C2.57864 5.64586 2.46616 5.85476 2.46616 5.85476C2.25726 6.28863 2.11263 6.75464 2.03229 7.23671C1.98408 7.75093 1.98408 8.26514 2.04836 8.76329ZM12.172 9.24536C12.0434 8.97219 11.722 8.42583 11.722 8.42583L8.04218 14.5L11.6417 12.0093C11.8506 11.8646 12.0273 11.6718 12.1559 11.4468C12.4773 10.7559 12.4934 9.95241 12.172 9.24536ZM13.6182 7.25278C13.5379 6.07973 12.9433 4.98702 12.0113 4.27998L8.05825 1.5C8.05825 1.5 10.549 5.08344 12.638 8.6508C12.8469 9.0204 12.9915 9.4382 13.0558 9.87206C13.0879 10.0649 13.0879 10.2577 13.0558 10.4506C13.104 10.3541 13.2165 10.1452 13.2165 10.1452C13.4254 9.71137 13.57 9.24536 13.6503 8.77936C13.6825 8.24907 13.6825 7.75093 13.6182 7.25278Z" | ||
fill="#AAB3CA" | ||
/> | ||
</g> | ||
<defs> | ||
<linearGradient | ||
id="paint0_linear_47_1749" | ||
x1="7.79157" | ||
y1="1.65235" | ||
x2="3.07018" | ||
y2="6.77069" | ||
gradientUnits="userSpaceOnUse" | ||
> | ||
<stop offset="0.58" stop-color="#A0A8D4" /> | ||
<stop offset="0.73" stop-color="#8791C7" /> | ||
<stop offset="0.91" stop-color="#6470B4" /> | ||
</linearGradient> | ||
<linearGradient | ||
id="paint1_linear_47_1749" | ||
x1="7.89072" | ||
y1="14.3583" | ||
x2="12.6103" | ||
y2="9.24361" | ||
gradientUnits="userSpaceOnUse" | ||
> | ||
<stop offset="0.58" stop-color="#A0A8D4" /> | ||
<stop offset="0.73" stop-color="#8791C7" /> | ||
<stop offset="0.91" stop-color="#6470B4" /> | ||
</linearGradient> | ||
<clipPath id="clip0_47_1749"> | ||
<rect width="11.6823" height="13" fill="white" transform="translate(2 1.5)" /> | ||
</clipPath> | ||
</defs> | ||
</svg> | ||
); | ||
|
||
export default SvgEnsLogo; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import type { SVGProps } from 'react'; | ||
|
||
const SvgSpaceId = (props: SVGProps<SVGSVGElement>) => ( | ||
<svg | ||
width="16" | ||
height="16" | ||
viewBox="0 0 16 16" | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
{...props} | ||
> | ||
<path | ||
d="M9.01764 10.1264C9.01764 9.61757 9.42777 9.19985 9.94422 9.19985H10.3164C10.8252 9.19985 11.2354 9.60997 11.2354 10.1264V10.4986C11.2354 11.0074 10.8252 11.4252 10.3088 11.4252H9.93663C9.42777 11.4252 9.01764 11.015 9.01764 10.4986V10.1264ZM9.94422 5.88086C9.43536 5.88086 9.02523 6.29099 9.02523 6.80744V7.17959C9.02523 7.68845 9.43536 8.10618 9.95182 8.10618H10.324C10.8328 8.10618 11.243 7.69605 11.243 7.17959V6.80744C11.243 6.29858 10.8328 5.88086 10.3164 5.88086H9.94422Z" | ||
fill="#AAB3CA" | ||
/> | ||
<path | ||
fill-rule="evenodd" | ||
clip-rule="evenodd" | ||
d="M5.69114 2C3.6481 2 2 3.6557 2 5.69114V10.3089C2 12.3519 3.6557 14 5.69114 14H10.3089C12.3519 14 14 12.3443 14 10.3089V5.69114C14 3.6481 12.3443 2 10.3089 2H5.69114ZM10.3089 3.47342H5.69114C4.46835 3.47342 3.47342 4.46835 3.47342 5.69114V10.3089C3.47342 11.5316 4.46835 12.5266 5.69114 12.5266H10.3089C11.5316 12.5266 12.5266 11.5316 12.5266 10.3089V5.69114C12.5266 4.46835 11.5316 3.47342 10.3089 3.47342Z" | ||
fill="#AAB3CA" | ||
/> | ||
</svg> | ||
); | ||
|
||
export default SvgSpaceId; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { cn } from 'utilities'; | ||
|
||
interface UsernameSpanProps { | ||
className?: string; | ||
username: string; | ||
} | ||
|
||
const UsernameSpan = ({ className, username }: UsernameSpanProps) => ( | ||
<span className={cn('truncate', className)}>{username}</span> | ||
); | ||
|
||
export default UsernameSpan; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { useGetAddressDomainName } from 'clients/api'; | ||
import { Icon, Tooltip } from 'components'; | ||
import EllipseAddress, { type EllipseAddressProps } from 'components/EllipseAddress'; | ||
import { CopyAddressButton } from 'containers/CopyAddressButton'; | ||
import { useTranslation } from 'libs/translations'; | ||
import { useChainId } from 'libs/wallet'; | ||
import { ChainId } from 'types'; | ||
import { truncateAddress } from 'utilities'; | ||
import type { Address } from 'viem'; | ||
import UsernameSpan from './UsernameSpan'; | ||
|
||
type UsernameProps = { | ||
showProvider?: boolean; | ||
showTooltip?: boolean; | ||
showCopyAddress?: boolean; | ||
shouldEllipseAddress?: boolean; | ||
children?: (props: { innerContent: React.ReactNode }) => React.ReactNode; | ||
} & EllipseAddressProps; | ||
|
||
export const Username: React.FC<UsernameProps> = ({ | ||
address, | ||
children, | ||
className, | ||
showCopyAddress = false, | ||
showProvider = true, | ||
showTooltip = true, | ||
shouldEllipseAddress = true, | ||
...ellipseAddressProps | ||
}) => { | ||
const { t } = useTranslation(); | ||
const { chainId } = useChainId(); | ||
const { data: domainNames, isLoading: isGetAddressDomainNameLoading } = useGetAddressDomainName( | ||
{ | ||
accountAddress: address as Address, | ||
chainId, | ||
}, | ||
{ | ||
enabled: !!address, | ||
}, | ||
); | ||
|
||
const chainDomainName = domainNames?.[chainId]; | ||
// Ethereum and Sepolia use ENS, other chains use SpaceID | ||
const providerIcon = | ||
chainId === ChainId.ETHEREUM || chainId === ChainId.SEPOLIA ? 'ensLogo' : 'spaceIdLogo'; | ||
const providerText = | ||
chainId === ChainId.ETHEREUM || chainId === ChainId.SEPOLIA | ||
? t('web3DomainNames.providers.ens') | ||
: t('web3DomainNames.providers.spaceId'); | ||
|
||
const addressComponent = shouldEllipseAddress ? ( | ||
<EllipseAddress className={className} address={address} {...ellipseAddressProps} /> | ||
) : ( | ||
<UsernameSpan className={className} username={address} /> | ||
); | ||
|
||
let dom = children ? children({ innerContent: addressComponent }) : addressComponent; | ||
|
||
if (!isGetAddressDomainNameLoading && chainDomainName) { | ||
const chainDomainNameSpan = <UsernameSpan className={className} username={chainDomainName} />; | ||
const domainNameComponent = children | ||
? children({ innerContent: chainDomainNameSpan }) | ||
: chainDomainNameSpan; | ||
dom = ( | ||
<div className="flex flex-row items-center text-nowrap space-x-1 mr-1"> | ||
{showProvider && ( | ||
<Tooltip title={providerText}> | ||
<Icon className="cursor-pointer" name={providerIcon} /> | ||
</Tooltip> | ||
)} | ||
{domainNameComponent} | ||
{showTooltip && ( | ||
<Tooltip | ||
title={ | ||
<div className="flex flex-col text-center"> | ||
<span className="text-center">{chainDomainName}</span> | ||
<span className="md:hidden"> | ||
{t('web3DomainNames.tooltip.address', { address: truncateAddress(address) })} | ||
</span> | ||
<span className="hidden md:block"> | ||
{t('web3DomainNames.tooltip.address', { address })} | ||
</span> | ||
</div> | ||
} | ||
className="inline-flex" | ||
> | ||
<Icon className="cursor-pointer " name="info" /> | ||
</Tooltip> | ||
)} | ||
</div> | ||
); | ||
} | ||
|
||
return ( | ||
<> | ||
{dom} | ||
{showCopyAddress && ( | ||
<CopyAddressButton className="shrink-0" address={address} showTooltip={!!chainDomainName} /> | ||
)} | ||
</> | ||
); | ||
}; | ||
|
||
export default Username; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.