diff --git a/packages/dashboard/src/web3/context.ts b/packages/dashboard/src/web3/context.ts index 3edcea813c35..7734886bb3c9 100644 --- a/packages/dashboard/src/web3/context.ts +++ b/packages/dashboard/src/web3/context.ts @@ -70,6 +70,7 @@ export const Web3Context: Web3ProviderType = { ), getAssetsList: PluginServices.Wallet.getAssetsList, getAssetsListNFT: PluginServices.Wallet.getAssetsListNFT, + getAddressNamesList: PluginServices.Wallet.getAddressNames, getERC721TokensPaged, getTransactionList: PluginServices.Wallet.getTransactionList, fetchERC20TokensFromTokenLists: Services.Ethereum.fetchERC20TokensFromTokenLists, diff --git a/packages/maskbook/src/components/DataSource/useActivatedUI.ts b/packages/maskbook/src/components/DataSource/useActivatedUI.ts index d06dadeb237e..e3bce67c8066 100644 --- a/packages/maskbook/src/components/DataSource/useActivatedUI.ts +++ b/packages/maskbook/src/components/DataSource/useActivatedUI.ts @@ -1,6 +1,6 @@ +import { useMemo } from 'react' import { ValueRef } from '@dimensiondev/holoflows-kit' import { ProfileIdentifier, useValueRef } from '@masknet/shared' -import { useMemo } from 'react' import type { Profile } from '../../database' import { currentSelectedIdentity } from '../../settings/settings' import type { SocialNetworkUI } from '../../social-network' @@ -14,7 +14,12 @@ export function useFriendsList() { const default_ = new ValueRef({ identifier: ProfileIdentifier.unknown }) export function useLastRecognizedIdentity() { return useValueRef( - activatedSocialNetworkUI.collecting.identityProvider?.lastRecognized || default_, + activatedSocialNetworkUI.collecting.identityProvider?.recognized || default_, + ) +} +export function useCurrentVisitingIdentity() { + return useValueRef( + activatedSocialNetworkUI.collecting.currentVisitingIdentityProvider?.recognized || default_, ) } export function useMyIdentities() { diff --git a/packages/maskbook/src/components/InjectedComponents/SetupGuide.tsx b/packages/maskbook/src/components/InjectedComponents/SetupGuide.tsx index 87fcb348d455..871aeb871622 100644 --- a/packages/maskbook/src/components/InjectedComponents/SetupGuide.tsx +++ b/packages/maskbook/src/components/InjectedComponents/SetupGuide.tsx @@ -551,7 +551,7 @@ function SetupGuideUI(props: SetupGuideUIProps) { const [username, setUsername] = useState(getUsername) useEffect( () => - activatedSocialNetworkUI.collecting.identityProvider?.lastRecognized.addListener((val) => { + activatedSocialNetworkUI.collecting.identityProvider?.recognized.addListener((val) => { if (username === '' && !val.identifier.isUnknown) setUsername(val.identifier.userId) }), [username], diff --git a/packages/maskbook/src/database/Persona/types.ts b/packages/maskbook/src/database/Persona/types.ts index aaa81e9980ff..0182ac7048fc 100644 --- a/packages/maskbook/src/database/Persona/types.ts +++ b/packages/maskbook/src/database/Persona/types.ts @@ -6,6 +6,7 @@ type TypedOmit = Omit export interface Profile extends Readonly> { readonly linkedPersona?: Persona readonly avatar?: string + readonly bio?: string } export interface Persona extends TypedOmit { diff --git a/packages/maskbook/src/plugins/Wallet/apis/ens.ts b/packages/maskbook/src/plugins/Wallet/apis/ens.ts new file mode 100644 index 000000000000..c16b9d2694b4 --- /dev/null +++ b/packages/maskbook/src/plugins/Wallet/apis/ens.ts @@ -0,0 +1,38 @@ +import stringify from 'json-stable-stringify' + +async function fetchFromENSTextResolverSubgraph(query: string) { + const subgraphURL = 'https://api.thegraph.com/subgraphs/name/dimensiondev/ens-text-resolver-subgraph' + const response = await fetch(subgraphURL, { + method: 'POST', + mode: 'cors', + body: stringify({ query }), + }) + const { data } = (await response.json()) as { + data: T + } + return data +} + +export async function fetchAddressNamesByTwitterId(twitterId: string) { + const data = await fetchFromENSTextResolverSubgraph<{ + twitterHandle?: { + domains: { + id: string + owner: string + }[] + } + }>(` + query twitterHandle { + twitterHandle(id: "${twitterId}") { + id + raw + domains { + id + owner + } + } + } + `) + if (!data?.twitterHandle) return [] + return data.twitterHandle.domains +} diff --git a/packages/maskbook/src/plugins/Wallet/services/assets.ts b/packages/maskbook/src/plugins/Wallet/services/assets.ts index 77b7747932d5..85335c45901c 100644 --- a/packages/maskbook/src/plugins/Wallet/services/assets.ts +++ b/packages/maskbook/src/plugins/Wallet/services/assets.ts @@ -47,7 +47,7 @@ export async function getAssetsListNFT( assets: assets .filter( (x) => - x.asset_contract.asset_contract_type === 'non-fungible' || + ['non-fungible', 'semi-fungible'].includes(x.asset_contract.asset_contract_type) || ['ERC721', 'ERC1155'].includes(x.asset_contract.schema_name), ) .map((x) => @@ -62,7 +62,7 @@ export async function getAssetsListNFT( { name: x.name, description: x.description, - image: x.image_url ?? x.image_preview_url ?? '', + image: x.image_url ?? x.image_preview_url ?? x.asset_contract.image_url ?? '', }, x.token_id, ), diff --git a/packages/maskbook/src/plugins/Wallet/services/domain.ts b/packages/maskbook/src/plugins/Wallet/services/domain.ts new file mode 100644 index 000000000000..5d17f9ba7581 --- /dev/null +++ b/packages/maskbook/src/plugins/Wallet/services/domain.ts @@ -0,0 +1,22 @@ +import { memoizePromise, unreachable } from '@dimensiondev/kit' +import { AddressNameType, AddressName } from '@masknet/web3-shared' +import * as ENS from '../apis/ens' + +const fetchAddressNamesByTwitterIdCached = memoizePromise(ENS.fetchAddressNamesByTwitterId, (twitterId) => twitterId) + +export async function getAddressNames(twitterId: string, addressNameType: AddressNameType): Promise { + switch (addressNameType) { + case AddressNameType.ENS: + return (await fetchAddressNamesByTwitterIdCached(twitterId)).map((x) => ({ + label: '', + ownerAddress: x.owner, + resolvedAddress: x.owner, + })) + case AddressNameType.UNS: + throw new Error('To be implemented.') + case AddressNameType.DNS: + throw new Error('To be implemented.') + default: + unreachable(addressNameType) + } +} diff --git a/packages/maskbook/src/plugins/Wallet/services/index.ts b/packages/maskbook/src/plugins/Wallet/services/index.ts index a9a87c546e1c..896048f1afad 100644 --- a/packages/maskbook/src/plugins/Wallet/services/index.ts +++ b/packages/maskbook/src/plugins/Wallet/services/index.ts @@ -11,5 +11,6 @@ export * from './recentTransactions' export * from './rpc' export * from './keystore' export * from './chain' +export * from './domain' export * from './cloud' export { decryptWallet, createEncryptedWalletStore } from '../database/decrypt' diff --git a/packages/maskbook/src/social-network-adaptor/facebook.com/collecting/identity.ts b/packages/maskbook/src/social-network-adaptor/facebook.com/collecting/identity.ts index fa4a3953f8f5..f428d7185aa7 100644 --- a/packages/maskbook/src/social-network-adaptor/facebook.com/collecting/identity.ts +++ b/packages/maskbook/src/social-network-adaptor/facebook.com/collecting/identity.ts @@ -7,9 +7,9 @@ import { ProfileIdentifier } from '../../../database/type' export const IdentityProviderFacebook: SocialNetworkUI.CollectingCapabilities.IdentityResolveProvider = { hasDeprecatedPlaceholderName: true, - lastRecognized: creator.IdentityResolveProviderLastRecognized(), + recognized: creator.EmptyIdentityResolveProviderState(), start(signal) { - resolveLastRecognizedIdentityFacebookInner(this.lastRecognized, signal) + resolveLastRecognizedIdentityFacebookInner(this.recognized, signal) }, } diff --git a/packages/maskbook/src/social-network-adaptor/facebook.com/collecting/posts.tsx b/packages/maskbook/src/social-network-adaptor/facebook.com/collecting/posts.tsx index 75e49d2338da..1ec3e8555870 100644 --- a/packages/maskbook/src/social-network-adaptor/facebook.com/collecting/posts.tsx +++ b/packages/maskbook/src/social-network-adaptor/facebook.com/collecting/posts.tsx @@ -22,7 +22,7 @@ const posts = new LiveSelector().querySelectorAll( ) export const PostProviderFacebook: Next.CollectingCapabilities.PostsProvider = { - posts: creator.PostProviderStore(), + posts: creator.EmptyPostProviderState(), start(signal) { collectPostsFacebookInner(this.posts, signal) }, diff --git a/packages/maskbook/src/social-network-adaptor/facebook.com/ui-provider.ts b/packages/maskbook/src/social-network-adaptor/facebook.com/ui-provider.ts index c3a426fc9be8..ed322c1a3e6f 100644 --- a/packages/maskbook/src/social-network-adaptor/facebook.com/ui-provider.ts +++ b/packages/maskbook/src/social-network-adaptor/facebook.com/ui-provider.ts @@ -100,7 +100,7 @@ const facebookUI: SocialNetworkUI.Definition = { // ! Change this might be a breaking change ! return new ProfileIdentifier( 'facebook.com', - ProfileIdentifier.getUserName(IdentityProviderFacebook.lastRecognized.value.identifier) || + ProfileIdentifier.getUserName(IdentityProviderFacebook.recognized.value.identifier) || ProfileIdentifier.getUserName(currentSelectedIdentity[facebookBase.networkIdentifier].value) || ProfileIdentifier.getUserName(globalUIState.profiles.value[0].identifier) || unreachable('Cannot figure out password' as never), diff --git a/packages/maskbook/src/social-network-adaptor/instagram.com/collecting/identity-provider.ts b/packages/maskbook/src/social-network-adaptor/instagram.com/collecting/identity-provider.ts index 9b42008206d4..5335411a1c44 100644 --- a/packages/maskbook/src/social-network-adaptor/instagram.com/collecting/identity-provider.ts +++ b/packages/maskbook/src/social-network-adaptor/instagram.com/collecting/identity-provider.ts @@ -4,7 +4,7 @@ import { instagramBase } from '../base' import { openDB } from 'idb' export const IdentityProviderInstagram: SocialNetworkUI.CollectingCapabilities.IdentityResolveProvider = { async start(signal) { - const ref = this.lastRecognized + const ref = this.recognized update() async function update() { @@ -14,7 +14,7 @@ export const IdentityProviderInstagram: SocialNetworkUI.CollectingCapabilities.I setTimeout(update, 10 * 1000) } }, - lastRecognized: creator.IdentityResolveProviderLastRecognized(), + recognized: creator.EmptyIdentityResolveProviderState(), } async function query(): Promise { diff --git a/packages/maskbook/src/social-network-adaptor/instagram.com/collecting/posts.ts b/packages/maskbook/src/social-network-adaptor/instagram.com/collecting/posts.ts index 5fb699711609..5f7fdb8221be 100644 --- a/packages/maskbook/src/social-network-adaptor/instagram.com/collecting/posts.ts +++ b/packages/maskbook/src/social-network-adaptor/instagram.com/collecting/posts.ts @@ -13,7 +13,7 @@ const posts = new LiveSelector().querySelectorAll( ) export const PostProviderInstagram: SocialNetworkUI.CollectingCapabilities.PostsProvider = { - posts: creator.PostProviderStore(), + posts: creator.EmptyPostProviderState(), start(signal) { collectPostsInstagramInner(this.posts, signal) }, diff --git a/packages/maskbook/src/social-network-adaptor/minds.com/collecting/identity.ts b/packages/maskbook/src/social-network-adaptor/minds.com/collecting/identity.ts index d1d6015c5390..4cd7247fea4a 100644 --- a/packages/maskbook/src/social-network-adaptor/minds.com/collecting/identity.ts +++ b/packages/maskbook/src/social-network-adaptor/minds.com/collecting/identity.ts @@ -5,7 +5,7 @@ import { mindsBase } from '../base' import { handleSelector, selfInfoSelectors } from '../utils/selector' async function resolveLastRecognizedIdentityInner( - ref: Next.CollectingCapabilities.IdentityResolveProvider['lastRecognized'], + ref: Next.CollectingCapabilities.IdentityResolveProvider['recognized'], cancel: AbortSignal, ) { await untilDocumentReady() @@ -36,8 +36,8 @@ async function resolveLastRecognizedIdentityInner( export const IdentityProviderMinds: Next.CollectingCapabilities.IdentityResolveProvider = { hasDeprecatedPlaceholderName: false, - lastRecognized: creator.IdentityResolveProviderLastRecognized(), + recognized: creator.EmptyIdentityResolveProviderState(), start(cancel) { - resolveLastRecognizedIdentityInner(this.lastRecognized, cancel) + resolveLastRecognizedIdentityInner(this.recognized, cancel) }, } diff --git a/packages/maskbook/src/social-network-adaptor/minds.com/collecting/post.ts b/packages/maskbook/src/social-network-adaptor/minds.com/collecting/post.ts index 1e253c427067..dd2411b8e468 100644 --- a/packages/maskbook/src/social-network-adaptor/minds.com/collecting/post.ts +++ b/packages/maskbook/src/social-network-adaptor/minds.com/collecting/post.ts @@ -18,7 +18,7 @@ import { postParser } from '../utils/fetch' import { postContentSelector } from '../utils/selector' export const PostProviderMinds: Next.CollectingCapabilities.PostsProvider = { - posts: creator.PostProviderStore(), + posts: creator.EmptyPostProviderState(), start(signal) { collectPostsMindsInner(this.posts, signal) }, diff --git a/packages/maskbook/src/social-network-adaptor/minds.com/ui-provider.ts b/packages/maskbook/src/social-network-adaptor/minds.com/ui-provider.ts index e58e89e7e240..7b808c50c299 100644 --- a/packages/maskbook/src/social-network-adaptor/minds.com/ui-provider.ts +++ b/packages/maskbook/src/social-network-adaptor/minds.com/ui-provider.ts @@ -92,7 +92,7 @@ const mindsUI: SocialNetworkUI.Definition = { // ! Change this might be a breaking change ! return new ProfileIdentifier( 'minds.com', - ProfileIdentifier.getUserName(IdentityProviderMinds.lastRecognized.value.identifier) || + ProfileIdentifier.getUserName(IdentityProviderMinds.recognized.value.identifier) || ProfileIdentifier.getUserName(currentSelectedIdentity[mindsBase.networkIdentifier].value) || ProfileIdentifier.getUserName(globalUIState.profiles.value[0].identifier) || unreachable('Cannot figure out password' as never), diff --git a/packages/maskbook/src/social-network-adaptor/twitter.com/collecting/identity.ts b/packages/maskbook/src/social-network-adaptor/twitter.com/collecting/identity.ts index ce786d2efdab..1d8f88b6a45a 100644 --- a/packages/maskbook/src/social-network-adaptor/twitter.com/collecting/identity.ts +++ b/packages/maskbook/src/social-network-adaptor/twitter.com/collecting/identity.ts @@ -1,12 +1,14 @@ -import { selfInfoSelectors } from '../utils/selector' +import { isNil } from 'lodash-es' import { MutationObserverWatcher } from '@dimensiondev/holoflows-kit' +import { selfInfoSelectors, searchProfileTabListSelector } from '../utils/selector' import { ProfileIdentifier } from '../../../database/type' -import { isNil } from 'lodash-es' import { creator, SocialNetworkUI as Next } from '../../../social-network' import { twitterBase } from '../base' +import { getAvatar, getBioDescription, getNickname, getTwitterId } from '../utils/user' +import { delay } from '@masknet/shared-base' function resolveLastRecognizedIdentityInner( - ref: Next.CollectingCapabilities.IdentityResolveProvider['lastRecognized'], + ref: Next.CollectingCapabilities.IdentityResolveProvider['recognized'], cancel: AbortSignal, ) { const selfSelector = selfInfoSelectors().handle @@ -32,10 +34,52 @@ function resolveLastRecognizedIdentityInner( cancel.addEventListener('abort', () => watcher.stopWatch()) } +function resolveCurrentVisitingIdentityInner( + ref: Next.CollectingCapabilities.IdentityResolveProvider['recognized'], + cancel: AbortSignal, +) { + const headerPhotoSelector = searchProfileTabListSelector() + const assign = async () => { + await delay(500) + const bio = getBioDescription() + const nickname = getNickname() + const handle = getTwitterId() + const avatar = getAvatar() + ref.value = { + identifier: new ProfileIdentifier(twitterBase.networkIdentifier, handle), + nickname, + avatar, + bio, + } + } + + const watcher = new MutationObserverWatcher(headerPhotoSelector) + .addListener('onAdd', () => assign()) + .addListener('onChange', () => assign()) + .startWatch({ + childList: true, + subtree: true, + }) + + window.addEventListener('locationchange', assign) + cancel.addEventListener('abort', () => { + window.removeEventListener('locationchange', assign) + watcher.stopWatch() + }) +} + export const IdentityProviderTwitter: Next.CollectingCapabilities.IdentityResolveProvider = { hasDeprecatedPlaceholderName: false, - lastRecognized: creator.IdentityResolveProviderLastRecognized(), + recognized: creator.EmptyIdentityResolveProviderState(), + start(cancel) { + resolveLastRecognizedIdentityInner(this.recognized, cancel) + }, +} + +export const CurrentVisitingIdentityProviderTwitter: Next.CollectingCapabilities.IdentityResolveProvider = { + hasDeprecatedPlaceholderName: false, + recognized: creator.EmptyIdentityResolveProviderState(), start(cancel) { - resolveLastRecognizedIdentityInner(this.lastRecognized, cancel) + resolveCurrentVisitingIdentityInner(this.recognized, cancel) }, } diff --git a/packages/maskbook/src/social-network-adaptor/twitter.com/collecting/post.ts b/packages/maskbook/src/social-network-adaptor/twitter.com/collecting/post.ts index 691a840ae03c..f4907db7e43a 100644 --- a/packages/maskbook/src/social-network-adaptor/twitter.com/collecting/post.ts +++ b/packages/maskbook/src/social-network-adaptor/twitter.com/collecting/post.ts @@ -115,7 +115,7 @@ function registerPostCollectorInner( } export const PostProviderTwitter: Next.CollectingCapabilities.PostsProvider = { - posts: creator.PostProviderStore(), + posts: creator.EmptyPostProviderState(), start(cancel) { registerPostCollectorInner(this.posts, cancel) }, diff --git a/packages/maskbook/src/social-network-adaptor/twitter.com/injection/EnhancedProfileTab.tsx b/packages/maskbook/src/social-network-adaptor/twitter.com/injection/EnhancedProfileTab.tsx index fbdd484bf69a..dc7e217e87be 100644 --- a/packages/maskbook/src/social-network-adaptor/twitter.com/injection/EnhancedProfileTab.tsx +++ b/packages/maskbook/src/social-network-adaptor/twitter.com/injection/EnhancedProfileTab.tsx @@ -49,7 +49,7 @@ const useStyles = makeStyles()((theme, props) => ({ color: props.color, font: props.font, fontSize: props.fontSize, - fontWeight: 700, + fontWeight: 500, '&:hover': { color: props.color, }, diff --git a/packages/maskbook/src/social-network-adaptor/twitter.com/ui-provider.ts b/packages/maskbook/src/social-network-adaptor/twitter.com/ui-provider.ts index 92d2c4df7204..afb8263c8336 100644 --- a/packages/maskbook/src/social-network-adaptor/twitter.com/ui-provider.ts +++ b/packages/maskbook/src/social-network-adaptor/twitter.com/ui-provider.ts @@ -8,7 +8,7 @@ import { openComposeBoxTwitter } from './automation/openComposeBox' import { pasteTextToCompositionTwitter } from './automation/pasteTextToComposition' import { gotoNewsFeedPageTwitter } from './automation/gotoNewsFeedPage' import { gotoProfilePageTwitter } from './automation/gotoProfilePage' -import { IdentityProviderTwitter } from './collecting/identity' +import { IdentityProviderTwitter, CurrentVisitingIdentityProviderTwitter } from './collecting/identity' import { PostProviderTwitter } from './collecting/post' import { PaletteModeProviderTwitter, useThemeTwitterVariant } from './customization/custom' import { injectToolboxHintAtTwitter } from './injection/ToolboxHint' @@ -118,6 +118,7 @@ const twitterUI: SocialNetworkUI.Definition = { }, collecting: { identityProvider: IdentityProviderTwitter, + currentVisitingIdentityProvider: CurrentVisitingIdentityProviderTwitter, postsProvider: PostProviderTwitter, getSearchedKeyword: getSearchedKeywordAtTwitter, }, @@ -168,7 +169,7 @@ const twitterUI: SocialNetworkUI.Definition = { // ! Change this might be a breaking change ! return new ProfileIdentifier( 'twitter.com', - ProfileIdentifier.getUserName(IdentityProviderTwitter.lastRecognized.value.identifier) || + ProfileIdentifier.getUserName(IdentityProviderTwitter.recognized.value.identifier) || ProfileIdentifier.getUserName(currentSelectedIdentity[twitterBase.networkIdentifier].value) || ProfileIdentifier.getUserName(globalUIState.profiles.value[0].identifier) || unreachable('Cannot figure out password' as never), diff --git a/packages/maskbook/src/social-network-adaptor/twitter.com/utils/selector.ts b/packages/maskbook/src/social-network-adaptor/twitter.com/utils/selector.ts index f7b9c8ac855a..2141eea79344 100644 --- a/packages/maskbook/src/social-network-adaptor/twitter.com/utils/selector.ts +++ b/packages/maskbook/src/social-network-adaptor/twitter.com/utils/selector.ts @@ -42,6 +42,10 @@ export const searchNewTweetButtonSelector: () => LiveSelector = () => querySelector('[data-testid="SideNav_NewTweet_Button"]') export const searchNickNameSelector: () => LiveSelector = () => querySelector('[data-testid="UserProfileHeader_Items"]') +export const searchAvatarSelector: () => LiveSelector = () => + querySelector('[data-testid="primaryColumn"] a[role="link"][href$="/photo"] img') +export const searchHeaderPhotoSelector: () => LiveSelector = () => + querySelector('[data-testid="primaryColumn"] a[role="link"][href$=/header_photo] img') export const bioCardSelector = (singleMode = true) => querySelector( [ diff --git a/packages/maskbook/src/social-network-adaptor/twitter.com/utils/user.ts b/packages/maskbook/src/social-network-adaptor/twitter.com/utils/user.ts index afa74e3f37cb..fdd39e4be5a5 100644 --- a/packages/maskbook/src/social-network-adaptor/twitter.com/utils/user.ts +++ b/packages/maskbook/src/social-network-adaptor/twitter.com/utils/user.ts @@ -1,6 +1,6 @@ import { isNull } from 'lodash-es' import type { SocialNetwork } from '../../../social-network' -import { bioDescriptionSelector, searchNickNameSelector } from './selector' +import { bioDescriptionSelector, searchAvatarSelector, searchNickNameSelector } from './selector' /** * @link https://help.twitter.com/en/managing-your-account/twitter-username-rules @@ -40,3 +40,11 @@ export const getBioDescription = () => { const node = bioDescriptionSelector().evaluate() return node?.innerText ?? '' } + +export const getAvatar = () => { + const node = searchAvatarSelector().evaluate() as HTMLImageElement + if (!node) return '' + + const imageURL = node.getAttribute('src') ?? '' + return imageURL.trim() +} diff --git a/packages/maskbook/src/social-network/types.ts b/packages/maskbook/src/social-network/types.ts index deae7cd4aca3..d2aee5cea1d0 100644 --- a/packages/maskbook/src/social-network/types.ts +++ b/packages/maskbook/src/social-network/types.ts @@ -183,13 +183,15 @@ export namespace SocialNetworkUI { export interface Define { /** Resolve the information of who am I on the current network. */ identityProvider?: IdentityResolveProvider + /** Resolve the information of identity on the current page which has been browsing. */ + currentVisitingIdentityProvider?: IdentityResolveProvider /** Maintain all the posts up-to-date. */ postsProvider?: PostsProvider /** Get searched keyword */ getSearchedKeyword?(): string } export type ProfileUI = { bioContent: string } - export type IdentityResolved = Pick + export type IdentityResolved = Pick /** Resolve the information of who am I on the current network. */ export interface IdentityResolveProvider { @@ -200,7 +202,7 @@ export namespace SocialNetworkUI { /** * The account that user is using (may not in the database) */ - readonly lastRecognized: ValueRef + readonly recognized: ValueRef /** * Start to maintain the posts. * It should add new seen posts and remove gone posts. diff --git a/packages/maskbook/src/social-network/ui.ts b/packages/maskbook/src/social-network/ui.ts index 14d476261270..6371d673f77a 100644 --- a/packages/maskbook/src/social-network/ui.ts +++ b/packages/maskbook/src/social-network/ui.ts @@ -72,6 +72,7 @@ export async function activateSocialNetworkUIInner(ui_deferred: SocialNetworkUI. ui.collecting.postsProvider?.start(signal) startPostListener() + ui.collecting.currentVisitingIdentityProvider?.start(signal) ui.injection.pageInspector?.(signal) if (Flags.toolbox_enabled) ui.injection.toolBoxInNavBar?.(signal) ui.injection.setupPrompt?.(signal) @@ -104,7 +105,7 @@ export async function activateSocialNetworkUIInner(ui_deferred: SocialNetworkUI. const provider = ui.collecting.identityProvider provider?.start(signal) if (provider?.hasDeprecatedPlaceholderName) { - provider.lastRecognized.addListener((id) => { + provider.recognized.addListener((id) => { if (signal.aborted) return if (id.identifier.isUnknown) return Services.Identity.resolveIdentity(id.identifier) diff --git a/packages/maskbook/src/social-network/utils.ts b/packages/maskbook/src/social-network/utils.ts index 09343b6ce3b6..f04f7935c327 100644 --- a/packages/maskbook/src/social-network/utils.ts +++ b/packages/maskbook/src/social-network/utils.ts @@ -22,8 +22,9 @@ export function managedStateCreator(): SocialNetworkUI.ManagedState { return {} } export const creator = { - IdentityResolveProviderLastRecognized: - (): SocialNetworkUI.CollectingCapabilities.IdentityResolveProvider['lastRecognized'] => + EmptyIdentityResolveProviderState: + (): SocialNetworkUI.CollectingCapabilities.IdentityResolveProvider['recognized'] => new ValueRef({ identifier: ProfileIdentifier.unknown }), - PostProviderStore: (): SocialNetworkUI.CollectingCapabilities.PostsProvider['posts'] => new ObservableWeakMap(), + EmptyPostProviderState: (): SocialNetworkUI.CollectingCapabilities.PostsProvider['posts'] => + new ObservableWeakMap(), } diff --git a/packages/maskbook/src/utils/native-rpc/Web.ts b/packages/maskbook/src/utils/native-rpc/Web.ts index 3c95a34f91c8..b33cacb68eab 100644 --- a/packages/maskbook/src/utils/native-rpc/Web.ts +++ b/packages/maskbook/src/utils/native-rpc/Web.ts @@ -214,7 +214,7 @@ export const MaskNetworkAPI: MaskNetworkAPIs = { }, async SNSAdaptor_getCurrentDetectedProfile() { const { activatedSocialNetworkUI } = await import('../../social-network') - return activatedSocialNetworkUI.collecting.identityProvider?.lastRecognized.value.identifier.toText() + return activatedSocialNetworkUI.collecting.identityProvider?.recognized.value.identifier.toText() }, } diff --git a/packages/maskbook/src/web3/context.ts b/packages/maskbook/src/web3/context.ts index e4ec66be00de..a82cc7fa8e90 100644 --- a/packages/maskbook/src/web3/context.ts +++ b/packages/maskbook/src/web3/context.ts @@ -50,6 +50,7 @@ export const Web3Context: Web3ProviderType = { portfolioProvider: createSubscriptionFromSettings(currentPortfolioDataProviderSettings), getAssetsList: WalletRPC.getAssetsList, getAssetsListNFT: WalletRPC.getAssetsListNFT, + getAddressNamesList: WalletRPC.getAddressNames, getERC721TokensPaged, fetchERC20TokensFromTokenLists: Services.Ethereum.fetchERC20TokensFromTokenLists, getTransactionList: WalletRPC.getTransactionList, diff --git a/packages/web3-shared/src/context/type.ts b/packages/web3-shared/src/context/type.ts index f3bfe2641873..230d18ca0217 100644 --- a/packages/web3-shared/src/context/type.ts +++ b/packages/web3-shared/src/context/type.ts @@ -11,6 +11,8 @@ import type { Asset, CollectibleProvider, Transaction, + AddressName, + AddressNameType, } from '../types' export interface Web3ProviderType { @@ -38,6 +40,7 @@ export interface Web3ProviderType { page?: number, size?: number, ) => Promise<{ assets: ERC721TokenDetailed[]; hasNextPage: boolean }> + getAddressNamesList: (twitterId: string, addressNameType: AddressNameType) => Promise getERC721TokensPaged: (index: number, count: number, query?: string) => Promise getTransactionList: ( address: string, diff --git a/packages/web3-shared/src/hooks/index.ts b/packages/web3-shared/src/hooks/index.ts index 73abbd4774ac..cc7b18f25d14 100644 --- a/packages/web3-shared/src/hooks/index.ts +++ b/packages/web3-shared/src/hooks/index.ts @@ -10,6 +10,7 @@ export * from './useNonce' export * from './useGasPrice' export * from './useEtherPrice' export * from './useENSLabel' +export * from './useENSDomains' export * from './useERC1155TokenAssetDetailed' export * from './useERC165' export * from './useERC20TokenAllowance' diff --git a/packages/web3-shared/src/hooks/useENSDomains.ts b/packages/web3-shared/src/hooks/useENSDomains.ts new file mode 100644 index 000000000000..d8e7bb495c8a --- /dev/null +++ b/packages/web3-shared/src/hooks/useENSDomains.ts @@ -0,0 +1,10 @@ +import { useAsyncRetry } from 'react-use' +import { AddressNameType, useWeb3Context } from '..' + +export function useAddressNames(twitterId: string) { + const { getAddressNamesList } = useWeb3Context() + + return useAsyncRetry(async () => { + return getAddressNamesList(twitterId, AddressNameType.ENS) + }, [twitterId]) +} diff --git a/packages/web3-shared/src/types/index.ts b/packages/web3-shared/src/types/index.ts index 155e30500c6c..0bc88ed0858c 100644 --- a/packages/web3-shared/src/types/index.ts +++ b/packages/web3-shared/src/types/index.ts @@ -501,3 +501,17 @@ export interface Transaction { gasFee: TransactionGasFee | undefined transactionType: string } + +//#region address name +export enum AddressNameType { + ENS = 'ENS', + UNS = 'UNS', + DNS = 'DNS', +} + +export interface AddressName { + label: string + ownerAddress: string + resolvedAddress?: string +} +//#endregion