mirror of
https://github.com/oceanprotocol/market.git
synced 2024-12-02 05:57:29 +01:00
ENS names (#860)
* prototype getting ENS names * get ENS name with subgraph * ENS name for publisher line * inject ENS name in profile page * refactor to cover all use cases for profile URLs * fixes for switching between own and other profiles * remove testing ENS libraries * more cleanup * any solves everything * build fix * more profile switching tweaks * link publisher line to ens name * another profile switching fix * show ENS link in meta line
This commit is contained in:
parent
15a29bcb01
commit
212865110e
20
package-lock.json
generated
20
package-lock.json
generated
@ -86,7 +86,6 @@
|
|||||||
"@testing-library/jest-dom": "^5.12.0",
|
"@testing-library/jest-dom": "^5.12.0",
|
||||||
"@testing-library/react": "^11.2.7",
|
"@testing-library/react": "^11.2.7",
|
||||||
"@types/chart.js": "^2.9.32",
|
"@types/chart.js": "^2.9.32",
|
||||||
"@types/classnames": "^2.3.1",
|
|
||||||
"@types/jest": "^26.0.23",
|
"@types/jest": "^26.0.23",
|
||||||
"@types/loadable__component": "^5.13.1",
|
"@types/loadable__component": "^5.13.1",
|
||||||
"@types/lodash.debounce": "^4.0.3",
|
"@types/lodash.debounce": "^4.0.3",
|
||||||
@ -10515,16 +10514,6 @@
|
|||||||
"moment": "^2.10.2"
|
"moment": "^2.10.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/classnames": {
|
|
||||||
"version": "2.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.3.1.tgz",
|
|
||||||
"integrity": "sha512-zeOWb0JGBoVmlQoznvqXbE0tEC/HONsnoUNH19Hc96NFsTAwTXbTqb8FMYkru1F/iqp7a18Ws3nWJvtA1sHD1A==",
|
|
||||||
"deprecated": "This is a stub types definition. classnames provides its own type definitions, so you do not need this installed.",
|
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
|
||||||
"classnames": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@types/clipboard": {
|
"node_modules/@types/clipboard": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/clipboard/-/clipboard-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/clipboard/-/clipboard-2.0.7.tgz",
|
||||||
@ -67020,15 +67009,6 @@
|
|||||||
"moment": "^2.10.2"
|
"moment": "^2.10.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/classnames": {
|
|
||||||
"version": "2.3.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/classnames/-/classnames-2.3.1.tgz",
|
|
||||||
"integrity": "sha512-zeOWb0JGBoVmlQoznvqXbE0tEC/HONsnoUNH19Hc96NFsTAwTXbTqb8FMYkru1F/iqp7a18Ws3nWJvtA1sHD1A==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"classnames": "*"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@types/clipboard": {
|
"@types/clipboard": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/clipboard/-/clipboard-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/clipboard/-/clipboard-2.0.7.tgz",
|
||||||
|
@ -101,7 +101,6 @@
|
|||||||
"@testing-library/jest-dom": "^5.12.0",
|
"@testing-library/jest-dom": "^5.12.0",
|
||||||
"@testing-library/react": "^11.2.7",
|
"@testing-library/react": "^11.2.7",
|
||||||
"@types/chart.js": "^2.9.32",
|
"@types/chart.js": "^2.9.32",
|
||||||
"@types/classnames": "^2.3.1",
|
|
||||||
"@types/jest": "^26.0.23",
|
"@types/jest": "^26.0.23",
|
||||||
"@types/loadable__component": "^5.13.1",
|
"@types/loadable__component": "^5.13.1",
|
||||||
"@types/lodash.debounce": "^4.0.3",
|
"@types/lodash.debounce": "^4.0.3",
|
||||||
|
@ -8,6 +8,7 @@ import { accountTruncate } from '../../../utils/web3'
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import Add from './Add'
|
import Add from './Add'
|
||||||
import { useWeb3 } from '../../../providers/Web3'
|
import { useWeb3 } from '../../../providers/Web3'
|
||||||
|
import { getEnsName } from '../../../utils/ens'
|
||||||
|
|
||||||
const cx = classNames.bind(styles)
|
const cx = classNames.bind(styles)
|
||||||
|
|
||||||
@ -20,27 +21,34 @@ export default function Publisher({
|
|||||||
minimal?: boolean
|
minimal?: boolean
|
||||||
className?: string
|
className?: string
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { networkId, accountId } = useWeb3()
|
const { accountId } = useWeb3()
|
||||||
const [profile, setProfile] = useState<Profile>()
|
const [profile, setProfile] = useState<Profile>()
|
||||||
const [name, setName] = useState<string>()
|
const [name, setName] = useState(accountTruncate(account))
|
||||||
|
const [accountEns, setAccountEns] = useState<string>()
|
||||||
|
|
||||||
const showAdd = account === accountId && !profile
|
const showAdd = account === accountId && !profile
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!account) return
|
if (!account) return
|
||||||
|
|
||||||
setName(accountTruncate(account))
|
|
||||||
const source = axios.CancelToken.source()
|
const source = axios.CancelToken.source()
|
||||||
|
|
||||||
async function get3Box() {
|
async function getExternalName() {
|
||||||
|
// ENS
|
||||||
|
const accountEns = await getEnsName(account)
|
||||||
|
if (accountEns) {
|
||||||
|
setAccountEns(accountEns)
|
||||||
|
setName(accountEns)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3box
|
||||||
const profile = await get3BoxProfile(account, source.token)
|
const profile = await get3BoxProfile(account, source.token)
|
||||||
if (!profile) return
|
if (!profile) return
|
||||||
|
|
||||||
setProfile(profile)
|
setProfile(profile)
|
||||||
const { name, emoji } = profile
|
const { name, emoji } = profile
|
||||||
name && setName(`${emoji || ''} ${name}`)
|
name && setName(`${emoji || ''} ${name}`)
|
||||||
}
|
}
|
||||||
get3Box()
|
getExternalName()
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
source.cancel()
|
source.cancel()
|
||||||
@ -58,7 +66,10 @@ export default function Publisher({
|
|||||||
name
|
name
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Link to={`/profile/${account}`} title="Show profile page.">
|
<Link
|
||||||
|
to={`/profile/${accountEns || account}`}
|
||||||
|
title="Show profile page."
|
||||||
|
>
|
||||||
{name}
|
{name}
|
||||||
</Link>
|
</Link>
|
||||||
{showAdd && <Add />}
|
{showAdd && <Add />}
|
||||||
|
@ -9,7 +9,7 @@ import Blockies from '../../atoms/Blockies'
|
|||||||
// Forward ref for Tippy.js
|
// Forward ref for Tippy.js
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
const Account = React.forwardRef((props, ref: any) => {
|
const Account = React.forwardRef((props, ref: any) => {
|
||||||
const { accountId, web3Modal, connect } = useWeb3()
|
const { accountId, accountEns, web3Modal, connect } = useWeb3()
|
||||||
|
|
||||||
async function handleActivation(e: FormEvent<HTMLButtonElement>) {
|
async function handleActivation(e: FormEvent<HTMLButtonElement>) {
|
||||||
// prevent accidentially submitting a form the button might be in
|
// prevent accidentially submitting a form the button might be in
|
||||||
@ -32,7 +32,7 @@ const Account = React.forwardRef((props, ref: any) => {
|
|||||||
>
|
>
|
||||||
<Blockies accountId={accountId} />
|
<Blockies accountId={accountId} />
|
||||||
<span className={styles.address} title={accountId}>
|
<span className={styles.address} title={accountId}>
|
||||||
{accountTruncate(accountId)}
|
{accountTruncate(accountEns || accountId)}
|
||||||
</span>
|
</span>
|
||||||
<Caret aria-hidden="true" className={styles.caret} />
|
<Caret aria-hidden="true" className={styles.caret} />
|
||||||
</button>
|
</button>
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React, { ReactElement } from 'react'
|
import React, { ReactElement } from 'react'
|
||||||
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
import { useUserPreferences } from '../../../../providers/UserPreferences'
|
||||||
import { accountTruncate } from '../../../../utils/web3'
|
|
||||||
import ExplorerLink from '../../../atoms/ExplorerLink'
|
import ExplorerLink from '../../../atoms/ExplorerLink'
|
||||||
import NetworkName from '../../../atoms/NetworkName'
|
import NetworkName from '../../../atoms/NetworkName'
|
||||||
import jellyfish from '@oceanprotocol/art/creatures/jellyfish/jellyfish-grid.svg'
|
import jellyfish from '@oceanprotocol/art/creatures/jellyfish/jellyfish-grid.svg'
|
||||||
@ -40,12 +39,13 @@ export default function Account({
|
|||||||
</figure>
|
</figure>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className={styles.name}>
|
<h3 className={styles.name}>{profile?.name}</h3>
|
||||||
{profile?.name || accountTruncate(accountId)}
|
|
||||||
</h3>
|
|
||||||
{accountId && (
|
{accountId && (
|
||||||
<code className={styles.accountId}>
|
<code
|
||||||
{accountId} <Copy text={accountId} />
|
className={styles.accountId}
|
||||||
|
title={profile?.accountEns ? accountId : null}
|
||||||
|
>
|
||||||
|
{profile?.accountEns || accountId} <Copy text={accountId} />
|
||||||
</code>
|
</code>
|
||||||
)}
|
)}
|
||||||
<p>
|
<p>
|
||||||
|
@ -11,13 +11,9 @@ const isDescriptionTextClamped = () => {
|
|||||||
if (el) return el.scrollHeight > el.clientHeight
|
if (el) return el.scrollHeight > el.clientHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
const Link3Box = ({ accountId, text }: { accountId: string; text: string }) => {
|
const LinkExternal = ({ url, text }: { url: string; text: string }) => {
|
||||||
return (
|
return (
|
||||||
<a
|
<a href={url} target="_blank" rel="noreferrer">
|
||||||
href={`https://www.3box.io/${accountId}`}
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
>
|
|
||||||
{text}
|
{text}
|
||||||
</a>
|
</a>
|
||||||
)
|
)
|
||||||
@ -46,7 +42,10 @@ export default function AccountHeader({
|
|||||||
<Markdown text={profile?.description} className={styles.description} />
|
<Markdown text={profile?.description} className={styles.description} />
|
||||||
{isDescriptionTextClamped() ? (
|
{isDescriptionTextClamped() ? (
|
||||||
<span className={styles.more} onClick={toogleShowMore}>
|
<span className={styles.more} onClick={toogleShowMore}>
|
||||||
<Link3Box accountId={accountId} text="Read more on 3box" />
|
<LinkExternal
|
||||||
|
url={`https://www.3box.io/${accountId}`}
|
||||||
|
text="Read more on 3box"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
''
|
''
|
||||||
@ -56,7 +55,20 @@ export default function AccountHeader({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.meta}>
|
<div className={styles.meta}>
|
||||||
Profile data from <Link3Box accountId={accountId} text="3Box Hub" />
|
Profile data from{' '}
|
||||||
|
{profile?.accountEns && (
|
||||||
|
<>
|
||||||
|
<LinkExternal
|
||||||
|
url={`https://app.ens.domains/name/${profile.accountEns}`}
|
||||||
|
text="ENS"
|
||||||
|
/>{' '}
|
||||||
|
&{' '}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<LinkExternal
|
||||||
|
url={`https://www.3box.io/${accountId}`}
|
||||||
|
text="3Box Hub"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@ -6,6 +6,7 @@ export interface ProfileLink {
|
|||||||
export interface Profile {
|
export interface Profile {
|
||||||
did?: string
|
did?: string
|
||||||
name?: string
|
name?: string
|
||||||
|
accountEns?: string
|
||||||
description?: string
|
description?: string
|
||||||
emoji?: string
|
emoji?: string
|
||||||
image?: string
|
image?: string
|
||||||
|
@ -1,25 +1,63 @@
|
|||||||
import React, { ReactElement, useEffect, useState } from 'react'
|
import React, { ReactElement, useEffect, useState } from 'react'
|
||||||
import Page from '../../components/templates/Page'
|
import Page from '../../components/templates/Page'
|
||||||
import { graphql, PageProps } from 'gatsby'
|
import { graphql, PageProps, navigate } from 'gatsby'
|
||||||
import ProfilePage from '../../components/pages/Profile'
|
import ProfilePage from '../../components/pages/Profile'
|
||||||
import { accountTruncate } from '../../utils/web3'
|
import { accountTruncate } from '../../utils/web3'
|
||||||
import { useWeb3 } from '../../providers/Web3'
|
import { useWeb3 } from '../../providers/Web3'
|
||||||
import ProfileProvider from '../../providers/Profile'
|
import ProfileProvider from '../../providers/Profile'
|
||||||
|
import { getEnsAddress, getEnsName } from '../../utils/ens'
|
||||||
|
import ethereumAddress from 'ethereum-address'
|
||||||
|
|
||||||
export default function PageGatsbyProfile(props: PageProps): ReactElement {
|
export default function PageGatsbyProfile(props: PageProps): ReactElement {
|
||||||
const { accountId } = useWeb3()
|
const { accountId, accountEns } = useWeb3()
|
||||||
const [finalAccountId, setFinalAccountId] = useState<string>()
|
const [finalAccountId, setFinalAccountId] = useState<string>()
|
||||||
|
const [finalAccountEns, setFinalAccountEns] = useState<string>()
|
||||||
|
|
||||||
// Have accountId in path take over, if not present fall back to web3
|
// Have accountId in path take over, if not present fall back to web3
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const pathAccountId = props.location.pathname.split('/')[2]
|
async function init() {
|
||||||
const finalAccountId = pathAccountId || accountId
|
if (!props?.location?.pathname) return
|
||||||
setFinalAccountId(finalAccountId)
|
|
||||||
}, [props.location.pathname, accountId])
|
// Path is root /profile, have web3 take over
|
||||||
|
if (props.location.pathname === '/profile') {
|
||||||
|
setFinalAccountEns(accountEns)
|
||||||
|
setFinalAccountId(accountId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const pathAccount = props.location.pathname.split('/')[2]
|
||||||
|
|
||||||
|
// Path has ETH addreess
|
||||||
|
if (ethereumAddress.isAddress(pathAccount)) {
|
||||||
|
const finalAccountId = pathAccount || accountId
|
||||||
|
setFinalAccountId(finalAccountId)
|
||||||
|
|
||||||
|
const accountEns = await getEnsName(finalAccountId)
|
||||||
|
if (!accountEns) return
|
||||||
|
setFinalAccountEns(accountEns)
|
||||||
|
} else {
|
||||||
|
// Path has ENS name
|
||||||
|
setFinalAccountEns(pathAccount)
|
||||||
|
const resolvedAccountId = await getEnsAddress(pathAccount)
|
||||||
|
setFinalAccountId(resolvedAccountId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
init()
|
||||||
|
}, [props.location.pathname, accountId, accountEns])
|
||||||
|
|
||||||
|
// Replace pathname with ENS name if present
|
||||||
|
useEffect(() => {
|
||||||
|
if (!finalAccountEns || props.location.pathname === '/profile') return
|
||||||
|
|
||||||
|
const newProfilePath = `/profile/${finalAccountEns}`
|
||||||
|
// make sure we only replace path once
|
||||||
|
if (newProfilePath !== props.location.pathname)
|
||||||
|
navigate(newProfilePath, { replace: true })
|
||||||
|
}, [props.location, finalAccountEns, accountId])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page uri={props.uri} title={accountTruncate(finalAccountId)} noPageHeader>
|
<Page uri={props.uri} title={accountTruncate(finalAccountId)} noPageHeader>
|
||||||
<ProfileProvider accountId={finalAccountId}>
|
<ProfileProvider accountId={finalAccountId} accountEns={finalAccountEns}>
|
||||||
<ProfilePage accountId={finalAccountId} />
|
<ProfilePage accountId={finalAccountId} />
|
||||||
</ProfileProvider>
|
</ProfileProvider>
|
||||||
</Page>
|
</Page>
|
||||||
|
@ -42,9 +42,11 @@ const refreshInterval = 10000 // 10 sec.
|
|||||||
|
|
||||||
function ProfileProvider({
|
function ProfileProvider({
|
||||||
accountId,
|
accountId,
|
||||||
|
accountEns,
|
||||||
children
|
children
|
||||||
}: {
|
}: {
|
||||||
accountId: string
|
accountId: string
|
||||||
|
accountEns: string
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { chainIds } = useUserPreferences()
|
const { chainIds } = useUserPreferences()
|
||||||
@ -62,18 +64,19 @@ function ProfileProvider({
|
|||||||
}, [accountId])
|
}, [accountId])
|
||||||
|
|
||||||
//
|
//
|
||||||
// 3Box
|
// User profile: ENS + 3Box
|
||||||
//
|
//
|
||||||
const [profile, setProfile] = useState<Profile>({
|
const [profile, setProfile] = useState<Profile>()
|
||||||
name: accountTruncate(accountId),
|
|
||||||
image: null,
|
useEffect(() => {
|
||||||
description: null,
|
if (!accountEns) return
|
||||||
links: null
|
Logger.log(`[profile] ENS name found for ${accountId}:`, accountEns)
|
||||||
})
|
}, [accountId, accountEns])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const clearedProfile: Profile = {
|
const clearedProfile: Profile = {
|
||||||
name: null,
|
name: null,
|
||||||
|
accountEns: null,
|
||||||
image: null,
|
image: null,
|
||||||
description: null,
|
description: null,
|
||||||
links: null
|
links: null
|
||||||
@ -86,7 +89,9 @@ function ProfileProvider({
|
|||||||
|
|
||||||
const cancelTokenSource = axios.CancelToken.source()
|
const cancelTokenSource = axios.CancelToken.source()
|
||||||
|
|
||||||
async function getInfoFrom3Box() {
|
async function getInfo() {
|
||||||
|
setProfile({ name: accountEns || accountTruncate(accountId), accountEns })
|
||||||
|
|
||||||
const profile3Box = await get3BoxProfile(
|
const profile3Box = await get3BoxProfile(
|
||||||
accountId,
|
accountId,
|
||||||
cancelTokenSource.token
|
cancelTokenSource.token
|
||||||
@ -100,19 +105,22 @@ function ProfileProvider({
|
|||||||
description,
|
description,
|
||||||
links
|
links
|
||||||
}
|
}
|
||||||
setProfile(newProfile)
|
setProfile((prevState) => ({
|
||||||
|
...prevState,
|
||||||
|
...newProfile
|
||||||
|
}))
|
||||||
Logger.log('[profile] Found and set 3box profile.', newProfile)
|
Logger.log('[profile] Found and set 3box profile.', newProfile)
|
||||||
} else {
|
} else {
|
||||||
setProfile(clearedProfile)
|
// setProfile(clearedProfile)
|
||||||
Logger.log('[profile] No 3box profile found.')
|
Logger.log('[profile] No 3box profile found.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getInfoFrom3Box()
|
getInfo()
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelTokenSource.cancel()
|
cancelTokenSource.cancel()
|
||||||
}
|
}
|
||||||
}, [accountId, isEthAddress])
|
}, [accountId, accountEns, isEthAddress])
|
||||||
|
|
||||||
//
|
//
|
||||||
// POOL SHARES
|
// POOL SHARES
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
getNetworkDataById,
|
getNetworkDataById,
|
||||||
getNetworkDisplayName
|
getNetworkDisplayName
|
||||||
} from '../utils/web3'
|
} from '../utils/web3'
|
||||||
import { graphql } from 'gatsby'
|
import { getEnsName } from '../utils/ens'
|
||||||
import { UserBalance } from '../@types/TokenBalance'
|
import { UserBalance } from '../@types/TokenBalance'
|
||||||
import { getOceanBalance } from '../utils/ocean'
|
import { getOceanBalance } from '../utils/ocean'
|
||||||
import useNetworkMetadata from '../hooks/useNetworkMetadata'
|
import useNetworkMetadata from '../hooks/useNetworkMetadata'
|
||||||
@ -29,6 +29,7 @@ interface Web3ProviderValue {
|
|||||||
web3Modal: Web3Modal
|
web3Modal: Web3Modal
|
||||||
web3ProviderInfo: IProviderInfo
|
web3ProviderInfo: IProviderInfo
|
||||||
accountId: string
|
accountId: string
|
||||||
|
accountEns: string
|
||||||
balance: UserBalance
|
balance: UserBalance
|
||||||
networkId: number
|
networkId: number
|
||||||
chainId: number
|
chainId: number
|
||||||
@ -84,26 +85,6 @@ export const web3ModalOpts = {
|
|||||||
|
|
||||||
const refreshInterval = 20000 // 20 sec.
|
const refreshInterval = 20000 // 20 sec.
|
||||||
|
|
||||||
const networksQuery = graphql`
|
|
||||||
query {
|
|
||||||
allNetworksMetadataJson {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
chain
|
|
||||||
network
|
|
||||||
networkId
|
|
||||||
chainId
|
|
||||||
nativeCurrency {
|
|
||||||
name
|
|
||||||
symbol
|
|
||||||
decimals
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const Web3Context = createContext({} as Web3ProviderValue)
|
const Web3Context = createContext({} as Web3ProviderValue)
|
||||||
|
|
||||||
function Web3Provider({ children }: { children: ReactNode }): ReactElement {
|
function Web3Provider({ children }: { children: ReactNode }): ReactElement {
|
||||||
@ -120,6 +101,7 @@ function Web3Provider({ children }: { children: ReactNode }): ReactElement {
|
|||||||
const [block, setBlock] = useState<number>()
|
const [block, setBlock] = useState<number>()
|
||||||
const [isTestnet, setIsTestnet] = useState<boolean>()
|
const [isTestnet, setIsTestnet] = useState<boolean>()
|
||||||
const [accountId, setAccountId] = useState<string>()
|
const [accountId, setAccountId] = useState<string>()
|
||||||
|
const [accountEns, setAccountEns] = useState<string>()
|
||||||
const [web3Loading, setWeb3Loading] = useState<boolean>(true)
|
const [web3Loading, setWeb3Loading] = useState<boolean>(true)
|
||||||
const [balance, setBalance] = useState<UserBalance>({
|
const [balance, setBalance] = useState<UserBalance>({
|
||||||
eth: '0',
|
eth: '0',
|
||||||
@ -181,6 +163,27 @@ function Web3Provider({ children }: { children: ReactNode }): ReactElement {
|
|||||||
}
|
}
|
||||||
}, [accountId, networkId, web3])
|
}, [accountId, networkId, web3])
|
||||||
|
|
||||||
|
// -----------------------------------
|
||||||
|
// Helper: Get user ENS name
|
||||||
|
// -----------------------------------
|
||||||
|
const getUserEnsName = useCallback(async () => {
|
||||||
|
if (!accountId) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
// const accountEns = await getEnsNameWithWeb3(
|
||||||
|
// accountId,
|
||||||
|
// web3Provider,
|
||||||
|
// `${networkId}`
|
||||||
|
// )
|
||||||
|
const accountEns = await getEnsName(accountId)
|
||||||
|
setAccountEns(accountEns)
|
||||||
|
accountEns &&
|
||||||
|
Logger.log(`[web3] ENS name found for ${accountId}:`, accountEns)
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error('[web3] Error: ', error.message)
|
||||||
|
}
|
||||||
|
}, [accountId])
|
||||||
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
// Create initial Web3Modal instance
|
// Create initial Web3Modal instance
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
@ -229,6 +232,13 @@ function Web3Provider({ children }: { children: ReactNode }): ReactElement {
|
|||||||
}
|
}
|
||||||
}, [getUserBalance])
|
}, [getUserBalance])
|
||||||
|
|
||||||
|
// -----------------------------------
|
||||||
|
// Get and set user ENS name
|
||||||
|
// -----------------------------------
|
||||||
|
useEffect(() => {
|
||||||
|
getUserEnsName()
|
||||||
|
}, [getUserEnsName])
|
||||||
|
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
// Get and set network metadata
|
// Get and set network metadata
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
@ -333,6 +343,7 @@ function Web3Provider({ children }: { children: ReactNode }): ReactElement {
|
|||||||
web3Modal,
|
web3Modal,
|
||||||
web3ProviderInfo,
|
web3ProviderInfo,
|
||||||
accountId,
|
accountId,
|
||||||
|
accountEns,
|
||||||
balance,
|
balance,
|
||||||
networkId,
|
networkId,
|
||||||
chainId,
|
chainId,
|
||||||
|
52
src/utils/ens.ts
Normal file
52
src/utils/ens.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { gql, OperationContext, OperationResult } from 'urql'
|
||||||
|
import { fetchData } from './subgraph'
|
||||||
|
|
||||||
|
// make sure to only query for domains owned by account, so domains
|
||||||
|
// solely set by 3rd parties like *.gitcoin.eth won't show up
|
||||||
|
const UserEnsNames = gql<any>`
|
||||||
|
query UserEnsDomains($accountId: String!) {
|
||||||
|
domains(where: { resolvedAddress: $accountId, owner: $accountId }) {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const UserEnsAddress = gql<any>`
|
||||||
|
query UserEnsDomainsAddress($name: String!) {
|
||||||
|
domains(where: { name: $name }) {
|
||||||
|
resolvedAddress {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const ensSubgraphQueryContext: OperationContext = {
|
||||||
|
url: `https://api.thegraph.com/subgraphs/name/ensdomains/ens`,
|
||||||
|
requestPolicy: 'cache-and-network'
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getEnsName(accountId: string): Promise<string> {
|
||||||
|
const response: OperationResult<any> = await fetchData(
|
||||||
|
UserEnsNames,
|
||||||
|
{ accountId: accountId.toLowerCase() },
|
||||||
|
ensSubgraphQueryContext
|
||||||
|
)
|
||||||
|
if (!response?.data?.domains?.length) return
|
||||||
|
|
||||||
|
// Default order of response.data.domains seems to be by creation time, from oldest to newest.
|
||||||
|
// Pick the last one as that is what direct web3 calls do.
|
||||||
|
const { name } = response.data.domains.slice(-1)[0]
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getEnsAddress(ensName: string): Promise<string> {
|
||||||
|
const response: OperationResult<any> = await fetchData(
|
||||||
|
UserEnsAddress,
|
||||||
|
{ name: ensName },
|
||||||
|
ensSubgraphQueryContext
|
||||||
|
)
|
||||||
|
if (!response?.data?.domains?.length) return
|
||||||
|
const { id } = response.data.domains[0].resolvedAddress
|
||||||
|
return id
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user