From c30a859e4e2befceda92ffe1d39dfd9dcc59b6f9 Mon Sep 17 00:00:00 2001 From: lelenei Date: Mon, 17 Jan 2022 16:56:04 +0800 Subject: [PATCH 01/18] fix: replace gundb --- .../mask/src/plugins/Avatar/Services/gun.ts | 49 ++++--------------- .../mask/src/plugins/Avatar/Services/index.ts | 14 +++--- .../plugins/Avatar/hooks/useCheckAddress.ts | 7 +-- .../src/plugins/Avatar/hooks/useNFTAvatar.ts | 6 ++- .../injection/NFT/NFTAvatarInTwitter.tsx | 15 ++++-- packages/web3-providers/src/index.ts | 2 + packages/web3-providers/src/types.ts | 2 +- 7 files changed, 37 insertions(+), 58 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/gun.ts b/packages/mask/src/plugins/Avatar/Services/gun.ts index 11b40c12d67c..e4151f2d9c07 100644 --- a/packages/mask/src/plugins/Avatar/Services/gun.ts +++ b/packages/mask/src/plugins/Avatar/Services/gun.ts @@ -1,54 +1,23 @@ -import { delay } from '@masknet/shared-base' -import { isSameAddress } from '@masknet/web3-shared-evm' -import { gun2 } from '../../../network/gun/version.2' +import { ChainId, isSameAddress } from '@masknet/web3-shared-evm' import { NFT_AVATAR_GUN_SERVER } from '../constants' +import { KeyValueAPI } from '@masknet/web3-providers' -const NFTAvatarGUN = gun2.get(NFT_AVATAR_GUN_SERVER) +const NFTAvatarDB = new KeyValueAPI().createJSON_Storage(NFT_AVATAR_GUN_SERVER) // After reinstalling the system, it cannot be retrieved for the first time, so it needs to be taken twice -export async function getUserAddress(userId: string) { - let result = await NFTAvatarGUN - //@ts-expect-error - .get(userId).then!() - - if (!result) { - await delay(500) - result = await NFTAvatarGUN - //@ts-expect-error - .get(userId).then!() - } - - return result +export async function getUserAddress(userId: string, chainId?: ChainId) { + const result = await NFTAvatarDB.get>(userId) + return result?.[chainId ?? ChainId.Mainnet] } -export async function setUserAddress(userId: string, address: string) { +export async function setUserAddress(userId: string, address: string, chainId?: ChainId) { try { - // delete userId - await NFTAvatarGUN - //@ts-expect-error - .get(userId) - //@ts-expect-error - .put(null).then!() - - // save userId - await NFTAvatarGUN - // @ts-expect-error - .get(userId) - // @ts-expect-error - .put(address).then!() + await NFTAvatarDB.set>(userId, { [chainId ?? ChainId.Mainnet]: address }) } catch { // do nothing } finally { - const _address = await getUserAddress(userId) + const _address = await getUserAddress(userId, chainId) if (!isSameAddress(_address, address)) throw new Error('Something went wrong, and please check your connection.') } } - -export async function getUserAddresses() { - const NFTAvatarKeys = Object.keys(await NFTAvatarGUN).filter((x) => x !== '_') - const resultPromise = NFTAvatarKeys.map((key) => getUserAddress(key)) - const result = (await Promise.all(resultPromise)).filter((x) => x) - - return result -} diff --git a/packages/mask/src/plugins/Avatar/Services/index.ts b/packages/mask/src/plugins/Avatar/Services/index.ts index 3ed77abe52f8..e7b7e190dd4a 100644 --- a/packages/mask/src/plugins/Avatar/Services/index.ts +++ b/packages/mask/src/plugins/Avatar/Services/index.ts @@ -1,12 +1,13 @@ +import type { ChainId } from '@masknet/web3-shared-evm' import { personalSign } from '../../../extension/background-script/EthereumService' import type { AvatarMetaDB } from '../types' import { getNFTAvatarFromJSON } from './db' import { getUserAddress, setUserAddress } from './gun' import { getNFTAvatarFromRSS, saveNFTAvatarToRSS } from './rss3' -export async function getNFTAvatar(userId: string) { +export async function getNFTAvatar(userId: string, chainId?: ChainId) { let result - const address = await getUserAddress(userId) + const address = await getUserAddress(userId, chainId) if (!address) { result = await getNFTAvatarFromJSON(userId) return result @@ -20,20 +21,19 @@ export async function getNFTAvatar(userId: string) { return result } -export async function saveNFTAvatar(address: string, nft: AvatarMetaDB) { +export async function saveNFTAvatar(address: string, nft: AvatarMetaDB, chainId?: ChainId) { const signature = await personalSign(nft.userId, address) - setUserAddress(nft.userId, address) + setUserAddress(nft.userId, address, chainId) const avatar = await saveNFTAvatarToRSS(address, nft, signature) return avatar } -export async function getAddress(userId: string) { - const address = await getUserAddress(userId) +export async function getAddress(userId: string, chainId?: ChainId) { + const address = await getUserAddress(userId, chainId) return (address ?? '') as string } export { getNFTContractVerifiedFromJSON } from './verified' -export { getUserAddresses } from './gun' export async function getImage(image: string): Promise { const response = await globalThis.fetch(image) diff --git a/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts b/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts index f191651495cf..bb98aab60af2 100644 --- a/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts +++ b/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts @@ -1,17 +1,18 @@ -import { isSameAddress } from '@masknet/web3-shared-evm' +import { isSameAddress, useChainId } from '@masknet/web3-shared-evm' import { useAsync } from 'react-use' import { PluginNFTAvatarRPC } from '../messages' import { getNFTAvatarFromJSON } from '../Services/db' export function useCheckAddress(userId: string, owner: string) { + const chainId = useChainId() return useAsync(async () => { if (!userId) return false - const address = await PluginNFTAvatarRPC.getAddress(userId) + const address = await PluginNFTAvatarRPC.getAddress(userId, chainId) if (!address) { const avatar = await getNFTAvatarFromJSON(userId) return !!avatar } return isSameAddress(address, owner) - }, [userId, owner]).value + }, [userId, owner, chainId]).value } diff --git a/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts b/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts index 472de6042782..54dbf64e3cb8 100644 --- a/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts +++ b/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts @@ -1,12 +1,14 @@ +import { useChainId } from '@masknet/web3-shared-evm' import { useAsync } from 'react-use' import type { AsyncState } from 'react-use/lib/useAsyncFn' import { PluginNFTAvatarRPC } from '../messages' import type { AvatarMetaDB } from '../types' export function useNFTAvatar(userId: string): AsyncState { + const chainId = useChainId() return useAsync(async () => { if (!userId) return if (userId === '$unknown') return - return PluginNFTAvatarRPC.getNFTAvatar(userId) - }, [userId]) + return PluginNFTAvatarRPC.getNFTAvatar(userId, chainId) + }, [userId, chainId]) } diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx index 34850160d6d8..1e6f6dec60a1 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx @@ -4,7 +4,7 @@ import { MutationObserverWatcher } from '@dimensiondev/holoflows-kit' import { makeStyles } from '@masknet/theme' import { useState, useEffect, useMemo, useRef } from 'react' import { useCurrentVisitingIdentity } from '../../../../components/DataSource/useActivatedUI' -import { resolveOpenSeaLink, useWallet } from '@masknet/web3-shared-evm' +import { resolveOpenSeaLink, useChainId, useWallet } from '@masknet/web3-shared-evm' import type { AvatarMetaDB } from '../../../../plugins/Avatar/types' import { useNFTAvatar } from '../../../../plugins/Avatar/hooks' import { getAvatarId } from '../../utils/user' @@ -49,6 +49,7 @@ function NFTAvatarInTwitter() { const [avatar, setAvatar] = useState() const windowSize = useWindowSize() const location = useLocation() + const chainId = useChainId() const showAvatar = useMemo( () => getAvatarId(identity.avatar ?? '') === avatar?.avatarId && avatar.avatarId, @@ -86,10 +87,14 @@ function NFTAvatarInTwitter() { return } - const avatar = await PluginNFTAvatarRPC.saveNFTAvatar(wallet.address, { - ...NFTEvent, - avatarId: getAvatarId(identity.avatar ?? ''), - } as AvatarMetaDB) + const avatar = await PluginNFTAvatarRPC.saveNFTAvatar( + wallet.address, + { + ...NFTEvent, + avatarId: getAvatarId(identity.avatar ?? ''), + } as AvatarMetaDB, + chainId, + ) setAvatar(avatar) MaskMessages.events.NFTAvatarTimelineUpdated.sendToAll( diff --git a/packages/web3-providers/src/index.ts b/packages/web3-providers/src/index.ts index d164b0078261..e3b6b7b20eec 100644 --- a/packages/web3-providers/src/index.ts +++ b/packages/web3-providers/src/index.ts @@ -6,6 +6,8 @@ import { NativeExplorerAPI } from './explorer' import { RSS3API } from './rss3' import { KeyValueAPI } from './kv' +export * from './kv' + export * from './types' export * from './opensea/utils' diff --git a/packages/web3-providers/src/types.ts b/packages/web3-providers/src/types.ts index 1c29b698bb38..ab6800e60039 100644 --- a/packages/web3-providers/src/types.ts +++ b/packages/web3-providers/src/types.ts @@ -291,7 +291,7 @@ export namespace NonFungibleTokenAPI { export namespace StorageAPI { export interface Storage { set(key: string, value: T): Promise - get(key: string): Promise + get(key: string): Promise delete?: (key: string) => Promise } From a495eaca6168260c23f28dcd63dafaa3fbc2fd70 Mon Sep 17 00:00:00 2001 From: lelenei Date: Mon, 17 Jan 2022 19:13:00 +0800 Subject: [PATCH 02/18] fix: use plugin id and chain id as key --- .../mask/src/plugins/Avatar/Services/gun.ts | 34 +++++++++++++++---- .../mask/src/plugins/Avatar/Services/index.ts | 18 ++++++---- .../plugins/Avatar/hooks/useCheckAddress.ts | 6 ++-- .../src/plugins/Avatar/hooks/useNFTAvatar.ts | 6 ++-- .../injection/NFT/NFTAvatarInTwitter.tsx | 3 ++ 5 files changed, 50 insertions(+), 17 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/gun.ts b/packages/mask/src/plugins/Avatar/Services/gun.ts index e4151f2d9c07..1f73117ae691 100644 --- a/packages/mask/src/plugins/Avatar/Services/gun.ts +++ b/packages/mask/src/plugins/Avatar/Services/gun.ts @@ -1,22 +1,42 @@ import { ChainId, isSameAddress } from '@masknet/web3-shared-evm' import { NFT_AVATAR_GUN_SERVER } from '../constants' import { KeyValueAPI } from '@masknet/web3-providers' +import { NetworkPluginID } from '@masknet/plugin-infra' +import addSeconds from 'date-fns/addSeconds' +import isBefore from 'date-fns/isBefore' const NFTAvatarDB = new KeyValueAPI().createJSON_Storage(NFT_AVATAR_GUN_SERVER) -// After reinstalling the system, it cannot be retrieved for the first time, so it needs to be taken twice -export async function getUserAddress(userId: string, chainId?: ChainId) { - const result = await NFTAvatarDB.get>(userId) - return result?.[chainId ?? ChainId.Mainnet] +const cache = new Map, Date]>() + +async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: ChainId) { + const result = await NFTAvatarDB.get>(userId) + return result?.[`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`] +} + +export async function getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: ChainId) { + let c = cache.get(userId) + if (!c || isBefore(new Date(), c[1])) { + cache.set(userId, [_getUserAddress(userId, networkPluginId, chainId), addSeconds(new Date(), 60)]) + } + c = cache.get(userId) + return c?.[0] } -export async function setUserAddress(userId: string, address: string, chainId?: ChainId) { +export async function setUserAddress( + userId: string, + address: string, + networkPluginId?: NetworkPluginID, + chainId?: ChainId, +) { try { - await NFTAvatarDB.set>(userId, { [chainId ?? ChainId.Mainnet]: address }) + await NFTAvatarDB.set>(userId, { + [`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`]: address, + }) } catch { // do nothing } finally { - const _address = await getUserAddress(userId, chainId) + const _address = await getUserAddress(userId, networkPluginId, chainId) if (!isSameAddress(_address, address)) throw new Error('Something went wrong, and please check your connection.') } diff --git a/packages/mask/src/plugins/Avatar/Services/index.ts b/packages/mask/src/plugins/Avatar/Services/index.ts index e7b7e190dd4a..131c08b4c3d1 100644 --- a/packages/mask/src/plugins/Avatar/Services/index.ts +++ b/packages/mask/src/plugins/Avatar/Services/index.ts @@ -1,3 +1,4 @@ +import type { NetworkPluginID } from '@masknet/plugin-infra' import type { ChainId } from '@masknet/web3-shared-evm' import { personalSign } from '../../../extension/background-script/EthereumService' import type { AvatarMetaDB } from '../types' @@ -5,9 +6,9 @@ import { getNFTAvatarFromJSON } from './db' import { getUserAddress, setUserAddress } from './gun' import { getNFTAvatarFromRSS, saveNFTAvatarToRSS } from './rss3' -export async function getNFTAvatar(userId: string, chainId?: ChainId) { +export async function getNFTAvatar(userId: string, networkPluginId?: NetworkPluginID, chainId?: ChainId) { let result - const address = await getUserAddress(userId, chainId) + const address = await getUserAddress(userId, networkPluginId, chainId) if (!address) { result = await getNFTAvatarFromJSON(userId) return result @@ -21,15 +22,20 @@ export async function getNFTAvatar(userId: string, chainId?: ChainId) { return result } -export async function saveNFTAvatar(address: string, nft: AvatarMetaDB, chainId?: ChainId) { +export async function saveNFTAvatar( + address: string, + nft: AvatarMetaDB, + networkPluginId?: NetworkPluginID, + chainId?: ChainId, +) { const signature = await personalSign(nft.userId, address) - setUserAddress(nft.userId, address, chainId) + setUserAddress(nft.userId, address, networkPluginId, chainId) const avatar = await saveNFTAvatarToRSS(address, nft, signature) return avatar } -export async function getAddress(userId: string, chainId?: ChainId) { - const address = await getUserAddress(userId, chainId) +export async function getAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: ChainId) { + const address = await getUserAddress(userId, networkPluginId, chainId) return (address ?? '') as string } diff --git a/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts b/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts index bb98aab60af2..2740defe031e 100644 --- a/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts +++ b/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts @@ -1,3 +1,4 @@ +import { usePluginIDContext } from '@masknet/plugin-infra' import { isSameAddress, useChainId } from '@masknet/web3-shared-evm' import { useAsync } from 'react-use' import { PluginNFTAvatarRPC } from '../messages' @@ -5,14 +6,15 @@ import { getNFTAvatarFromJSON } from '../Services/db' export function useCheckAddress(userId: string, owner: string) { const chainId = useChainId() + const currentPluginId = usePluginIDContext() return useAsync(async () => { if (!userId) return false - const address = await PluginNFTAvatarRPC.getAddress(userId, chainId) + const address = await PluginNFTAvatarRPC.getAddress(userId, currentPluginId, chainId) if (!address) { const avatar = await getNFTAvatarFromJSON(userId) return !!avatar } return isSameAddress(address, owner) - }, [userId, owner, chainId]).value + }, [userId, owner, chainId, currentPluginId]).value } diff --git a/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts b/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts index 54dbf64e3cb8..5df2cf6c7a77 100644 --- a/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts +++ b/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts @@ -1,3 +1,4 @@ +import { usePluginIDContext } from '@masknet/plugin-infra' import { useChainId } from '@masknet/web3-shared-evm' import { useAsync } from 'react-use' import type { AsyncState } from 'react-use/lib/useAsyncFn' @@ -6,9 +7,10 @@ import type { AvatarMetaDB } from '../types' export function useNFTAvatar(userId: string): AsyncState { const chainId = useChainId() + const currentPluginId = usePluginIDContext() return useAsync(async () => { if (!userId) return if (userId === '$unknown') return - return PluginNFTAvatarRPC.getNFTAvatar(userId, chainId) - }, [userId, chainId]) + return PluginNFTAvatarRPC.getNFTAvatar(userId, currentPluginId, chainId) + }, [userId, chainId, currentPluginId]) } diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx index 1e6f6dec60a1..45c0ec88e54f 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx @@ -14,6 +14,7 @@ import { NFTAvatar } from '../../../../plugins/Avatar/SNSAdaptor/NFTAvatar' import { useAsync, useLocation, useUpdateEffect, useWindowSize } from 'react-use' import { rainbowBorderKeyFrames } from '../../../../plugins/Avatar/SNSAdaptor/RainbowBox' import { trim } from 'lodash-unified' +import { usePluginIDContext } from '@masknet/plugin-infra' export function injectNFTAvatarInTwitter(signal: AbortSignal) { const watcher = new MutationObserverWatcher(searchTwitterAvatarSelector()) @@ -50,6 +51,7 @@ function NFTAvatarInTwitter() { const windowSize = useWindowSize() const location = useLocation() const chainId = useChainId() + const currentPluginId = usePluginIDContext() const showAvatar = useMemo( () => getAvatarId(identity.avatar ?? '') === avatar?.avatarId && avatar.avatarId, @@ -93,6 +95,7 @@ function NFTAvatarInTwitter() { ...NFTEvent, avatarId: getAvatarId(identity.avatar ?? ''), } as AvatarMetaDB, + currentPluginId, chainId, ) From 6536ecd41a3e95b92d4feb0cec806a59f430cb46 Mon Sep 17 00:00:00 2001 From: lelenei Date: Mon, 17 Jan 2022 19:18:42 +0800 Subject: [PATCH 03/18] fix: reply review --- packages/mask/src/plugins/Avatar/Services/gun.ts | 4 ++-- packages/web3-providers/src/index.ts | 2 -- packages/web3-providers/src/types.ts | 6 +++--- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/gun.ts b/packages/mask/src/plugins/Avatar/Services/gun.ts index 1f73117ae691..b612aacfeda3 100644 --- a/packages/mask/src/plugins/Avatar/Services/gun.ts +++ b/packages/mask/src/plugins/Avatar/Services/gun.ts @@ -1,11 +1,11 @@ import { ChainId, isSameAddress } from '@masknet/web3-shared-evm' import { NFT_AVATAR_GUN_SERVER } from '../constants' -import { KeyValueAPI } from '@masknet/web3-providers' import { NetworkPluginID } from '@masknet/plugin-infra' import addSeconds from 'date-fns/addSeconds' import isBefore from 'date-fns/isBefore' +import { KeyValue } from '@masknet/web3-providers' -const NFTAvatarDB = new KeyValueAPI().createJSON_Storage(NFT_AVATAR_GUN_SERVER) +const NFTAvatarDB = KeyValue.createJSON_Storage(NFT_AVATAR_GUN_SERVER) const cache = new Map, Date]>() diff --git a/packages/web3-providers/src/index.ts b/packages/web3-providers/src/index.ts index e3b6b7b20eec..d164b0078261 100644 --- a/packages/web3-providers/src/index.ts +++ b/packages/web3-providers/src/index.ts @@ -6,8 +6,6 @@ import { NativeExplorerAPI } from './explorer' import { RSS3API } from './rss3' import { KeyValueAPI } from './kv' -export * from './kv' - export * from './types' export * from './opensea/utils' diff --git a/packages/web3-providers/src/types.ts b/packages/web3-providers/src/types.ts index ab6800e60039..eea092766515 100644 --- a/packages/web3-providers/src/types.ts +++ b/packages/web3-providers/src/types.ts @@ -292,11 +292,11 @@ export namespace StorageAPI { export interface Storage { set(key: string, value: T): Promise get(key: string): Promise - delete?: (key: string) => Promise + delete?(key: string): Promise } export interface Provider { - createJSON_Storage?: (key: string) => Storage - createBinaryStorage?: (key: string) => Storage + createJSON_Storage?(key: string): Storage + createBinaryStorage?(key: string): Storage } } From ccb72c4b9125e2ddb2dde6f687248abc8cf0f5ff Mon Sep 17 00:00:00 2001 From: lelenei Date: Mon, 17 Jan 2022 19:38:44 +0800 Subject: [PATCH 04/18] fix: rename --- .../src/plugins/Avatar/Services/{gun.ts => bind.ts} | 10 +++++----- packages/mask/src/plugins/Avatar/Services/index.ts | 9 ++++----- packages/mask/src/plugins/Avatar/constants.ts | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) rename packages/mask/src/plugins/Avatar/Services/{gun.ts => bind.ts} (86%) diff --git a/packages/mask/src/plugins/Avatar/Services/gun.ts b/packages/mask/src/plugins/Avatar/Services/bind.ts similarity index 86% rename from packages/mask/src/plugins/Avatar/Services/gun.ts rename to packages/mask/src/plugins/Avatar/Services/bind.ts index b612aacfeda3..639b37d73506 100644 --- a/packages/mask/src/plugins/Avatar/Services/gun.ts +++ b/packages/mask/src/plugins/Avatar/Services/bind.ts @@ -1,20 +1,20 @@ import { ChainId, isSameAddress } from '@masknet/web3-shared-evm' -import { NFT_AVATAR_GUN_SERVER } from '../constants' import { NetworkPluginID } from '@masknet/plugin-infra' import addSeconds from 'date-fns/addSeconds' import isBefore from 'date-fns/isBefore' import { KeyValue } from '@masknet/web3-providers' +import { NFT_AVATAR_DB_NAME } from '../constants' -const NFTAvatarDB = KeyValue.createJSON_Storage(NFT_AVATAR_GUN_SERVER) +const NFTAvatarDB = KeyValue.createJSON_Storage(NFT_AVATAR_DB_NAME) const cache = new Map, Date]>() -async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: ChainId) { +async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { const result = await NFTAvatarDB.get>(userId) return result?.[`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`] } -export async function getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: ChainId) { +export async function getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { let c = cache.get(userId) if (!c || isBefore(new Date(), c[1])) { cache.set(userId, [_getUserAddress(userId, networkPluginId, chainId), addSeconds(new Date(), 60)]) @@ -27,7 +27,7 @@ export async function setUserAddress( userId: string, address: string, networkPluginId?: NetworkPluginID, - chainId?: ChainId, + chainId?: number, ) { try { await NFTAvatarDB.set>(userId, { diff --git a/packages/mask/src/plugins/Avatar/Services/index.ts b/packages/mask/src/plugins/Avatar/Services/index.ts index 131c08b4c3d1..168f84505a20 100644 --- a/packages/mask/src/plugins/Avatar/Services/index.ts +++ b/packages/mask/src/plugins/Avatar/Services/index.ts @@ -1,12 +1,11 @@ import type { NetworkPluginID } from '@masknet/plugin-infra' -import type { ChainId } from '@masknet/web3-shared-evm' import { personalSign } from '../../../extension/background-script/EthereumService' import type { AvatarMetaDB } from '../types' import { getNFTAvatarFromJSON } from './db' -import { getUserAddress, setUserAddress } from './gun' +import { getUserAddress, setUserAddress } from './bind' import { getNFTAvatarFromRSS, saveNFTAvatarToRSS } from './rss3' -export async function getNFTAvatar(userId: string, networkPluginId?: NetworkPluginID, chainId?: ChainId) { +export async function getNFTAvatar(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { let result const address = await getUserAddress(userId, networkPluginId, chainId) if (!address) { @@ -26,7 +25,7 @@ export async function saveNFTAvatar( address: string, nft: AvatarMetaDB, networkPluginId?: NetworkPluginID, - chainId?: ChainId, + chainId?: number, ) { const signature = await personalSign(nft.userId, address) setUserAddress(nft.userId, address, networkPluginId, chainId) @@ -34,7 +33,7 @@ export async function saveNFTAvatar( return avatar } -export async function getAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: ChainId) { +export async function getAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { const address = await getUserAddress(userId, networkPluginId, chainId) return (address ?? '') as string } diff --git a/packages/mask/src/plugins/Avatar/constants.ts b/packages/mask/src/plugins/Avatar/constants.ts index a367a3274058..b72a3bc36b52 100644 --- a/packages/mask/src/plugins/Avatar/constants.ts +++ b/packages/mask/src/plugins/Avatar/constants.ts @@ -1,7 +1,7 @@ import { PluginId } from '@masknet/plugin-infra' export const NFT_AVATAR_JSON_SERVER = 'https://configuration.r2d2.to/com.maskbook.avatar.json' -export const NFT_AVATAR_GUN_SERVER = 'com.maskbook.user' +export const NFT_AVATAR_DB_NAME = 'com.maskbook.user' export const NFT_CONTRACT_JSON_VERIFIED_SERVER = 'https://configuration.r2d2.to/com.maskbook.verified_nft.json' export const PLUGIN_ID = PluginId.Avatar From 713888ec7c9a4f788276cf0253d433508e7e687b Mon Sep 17 00:00:00 2001 From: lelenei Date: Mon, 17 Jan 2022 21:23:40 +0800 Subject: [PATCH 05/18] fix: cache key --- .../mask/src/plugins/Avatar/Services/bind.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/bind.ts b/packages/mask/src/plugins/Avatar/Services/bind.ts index 639b37d73506..ba6afc548e7f 100644 --- a/packages/mask/src/plugins/Avatar/Services/bind.ts +++ b/packages/mask/src/plugins/Avatar/Services/bind.ts @@ -1,13 +1,12 @@ import { ChainId, isSameAddress } from '@masknet/web3-shared-evm' import { NetworkPluginID } from '@masknet/plugin-infra' import addSeconds from 'date-fns/addSeconds' -import isBefore from 'date-fns/isBefore' import { KeyValue } from '@masknet/web3-providers' import { NFT_AVATAR_DB_NAME } from '../constants' const NFTAvatarDB = KeyValue.createJSON_Storage(NFT_AVATAR_DB_NAME) -const cache = new Map, Date]>() +const cache = new Map, number]>() async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { const result = await NFTAvatarDB.get>(userId) @@ -15,11 +14,17 @@ async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID } export async function getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { - let c = cache.get(userId) - if (!c || isBefore(new Date(), c[1])) { - cache.set(userId, [_getUserAddress(userId, networkPluginId, chainId), addSeconds(new Date(), 60)]) + let c = cache.get(`${userId}-${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`) + + if (!c || Date.now() > c[1]) { + try { + cache.set(userId, [_getUserAddress(userId, networkPluginId, chainId), addSeconds(new Date(), 60).getTime()]) + } catch (err) { + console.log(err) + } } - c = cache.get(userId) + c = cache.get(`${userId}-${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`) + return c?.[0] } From 24f523627d135269e7b4a4bae63918e25bd67057 Mon Sep 17 00:00:00 2001 From: lelenei Date: Mon, 17 Jan 2022 21:41:35 +0800 Subject: [PATCH 06/18] fix: cache key --- packages/mask/src/plugins/Avatar/Services/bind.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/bind.ts b/packages/mask/src/plugins/Avatar/Services/bind.ts index ba6afc548e7f..62ffe8f1bc56 100644 --- a/packages/mask/src/plugins/Avatar/Services/bind.ts +++ b/packages/mask/src/plugins/Avatar/Services/bind.ts @@ -14,16 +14,16 @@ async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID } export async function getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { - let c = cache.get(`${userId}-${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`) - + const key = `${userId}-${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}` + let c = cache.get(key) if (!c || Date.now() > c[1]) { try { - cache.set(userId, [_getUserAddress(userId, networkPluginId, chainId), addSeconds(new Date(), 60).getTime()]) + cache.set(key, [_getUserAddress(userId, networkPluginId, chainId), addSeconds(new Date(), 60).getTime()]) } catch (err) { console.log(err) } } - c = cache.get(`${userId}-${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`) + c = cache.get(key) return c?.[0] } From f3b64f87586b39a6fff706b8950d454b836b0c76 Mon Sep 17 00:00:00 2001 From: lelenei Date: Tue, 18 Jan 2022 09:40:07 +0800 Subject: [PATCH 07/18] fix: only support mainnet --- .../src/plugins/Avatar/hooks/useCheckAddress.ts | 9 +++------ .../mask/src/plugins/Avatar/hooks/useNFTAvatar.ts | 8 ++------ .../injection/NFT/NFTAvatarInTwitter.tsx | 13 ++++--------- 3 files changed, 9 insertions(+), 21 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts b/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts index 2740defe031e..f191651495cf 100644 --- a/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts +++ b/packages/mask/src/plugins/Avatar/hooks/useCheckAddress.ts @@ -1,20 +1,17 @@ -import { usePluginIDContext } from '@masknet/plugin-infra' -import { isSameAddress, useChainId } from '@masknet/web3-shared-evm' +import { isSameAddress } from '@masknet/web3-shared-evm' import { useAsync } from 'react-use' import { PluginNFTAvatarRPC } from '../messages' import { getNFTAvatarFromJSON } from '../Services/db' export function useCheckAddress(userId: string, owner: string) { - const chainId = useChainId() - const currentPluginId = usePluginIDContext() return useAsync(async () => { if (!userId) return false - const address = await PluginNFTAvatarRPC.getAddress(userId, currentPluginId, chainId) + const address = await PluginNFTAvatarRPC.getAddress(userId) if (!address) { const avatar = await getNFTAvatarFromJSON(userId) return !!avatar } return isSameAddress(address, owner) - }, [userId, owner, chainId, currentPluginId]).value + }, [userId, owner]).value } diff --git a/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts b/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts index 5df2cf6c7a77..472de6042782 100644 --- a/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts +++ b/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts @@ -1,16 +1,12 @@ -import { usePluginIDContext } from '@masknet/plugin-infra' -import { useChainId } from '@masknet/web3-shared-evm' import { useAsync } from 'react-use' import type { AsyncState } from 'react-use/lib/useAsyncFn' import { PluginNFTAvatarRPC } from '../messages' import type { AvatarMetaDB } from '../types' export function useNFTAvatar(userId: string): AsyncState { - const chainId = useChainId() - const currentPluginId = usePluginIDContext() return useAsync(async () => { if (!userId) return if (userId === '$unknown') return - return PluginNFTAvatarRPC.getNFTAvatar(userId, currentPluginId, chainId) - }, [userId, chainId, currentPluginId]) + return PluginNFTAvatarRPC.getNFTAvatar(userId) + }, [userId]) } diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx index 45c0ec88e54f..e4fe0844b1d7 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx @@ -89,15 +89,10 @@ function NFTAvatarInTwitter() { return } - const avatar = await PluginNFTAvatarRPC.saveNFTAvatar( - wallet.address, - { - ...NFTEvent, - avatarId: getAvatarId(identity.avatar ?? ''), - } as AvatarMetaDB, - currentPluginId, - chainId, - ) + const avatar = await PluginNFTAvatarRPC.saveNFTAvatar(wallet.address, { + ...NFTEvent, + avatarId: getAvatarId(identity.avatar ?? ''), + } as AvatarMetaDB) setAvatar(avatar) MaskMessages.events.NFTAvatarTimelineUpdated.sendToAll( From b8431c1543cbf01433bd5cc5f99f2172b08f593f Mon Sep 17 00:00:00 2001 From: lelenei Date: Tue, 18 Jan 2022 09:55:22 +0800 Subject: [PATCH 08/18] fix: fallback json --- packages/mask/src/plugins/Avatar/Services/bind.ts | 8 ++++++-- packages/mask/src/plugins/Avatar/Services/index.ts | 14 +++----------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/bind.ts b/packages/mask/src/plugins/Avatar/Services/bind.ts index 62ffe8f1bc56..a944c468fc8c 100644 --- a/packages/mask/src/plugins/Avatar/Services/bind.ts +++ b/packages/mask/src/plugins/Avatar/Services/bind.ts @@ -9,8 +9,12 @@ const NFTAvatarDB = KeyValue.createJSON_Storage(NFT_AVATAR_DB_NAME) const cache = new Map, number]>() async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { - const result = await NFTAvatarDB.get>(userId) - return result?.[`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`] + try { + const result = await NFTAvatarDB.get>(userId) + return result?.[`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`] + } catch { + return + } } export async function getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { diff --git a/packages/mask/src/plugins/Avatar/Services/index.ts b/packages/mask/src/plugins/Avatar/Services/index.ts index 168f84505a20..be4dda7c0be5 100644 --- a/packages/mask/src/plugins/Avatar/Services/index.ts +++ b/packages/mask/src/plugins/Avatar/Services/index.ts @@ -6,19 +6,11 @@ import { getUserAddress, setUserAddress } from './bind' import { getNFTAvatarFromRSS, saveNFTAvatarToRSS } from './rss3' export async function getNFTAvatar(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { - let result const address = await getUserAddress(userId, networkPluginId, chainId) - if (!address) { - result = await getNFTAvatarFromJSON(userId) - return result + if (address) { + return getNFTAvatarFromRSS(userId, address) } - - result = await getNFTAvatarFromRSS(userId, address) - if (!result) { - result = await getNFTAvatarFromJSON(userId) - } - - return result + return getNFTAvatarFromJSON(userId) } export async function saveNFTAvatar( From a95955af2db0c93d740ed5c92f68807f7bbef3c8 Mon Sep 17 00:00:00 2001 From: lelenei Date: Tue, 18 Jan 2022 17:32:27 +0800 Subject: [PATCH 09/18] fix: simple nft avatar signing process --- .../plugins/Avatar/SNSAdaptor/NFTAvatar.tsx | 7 ++- .../mask/src/plugins/Avatar/Services/bind.ts | 19 ++++++-- .../mask/src/plugins/Avatar/Services/index.ts | 12 +++-- .../mask/src/plugins/Avatar/Services/rss3.ts | 46 +++---------------- packages/mask/src/plugins/Avatar/constants.ts | 1 + .../injection/NFT/NFTAvatarInTwitter.tsx | 14 ++++-- packages/web3-providers/src/helpers.ts | 1 + packages/web3-providers/src/opensea/index.ts | 1 + 8 files changed, 48 insertions(+), 53 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTAvatar.tsx b/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTAvatar.tsx index b05b29c89c96..b21702dc7c39 100644 --- a/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTAvatar.tsx +++ b/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTAvatar.tsx @@ -98,7 +98,12 @@ export function NFTAvatar(props: NFTAvatarProps) { const [open_, setOpen_] = useState(false) const [collectibles_, setCollectibles_] = useState([]) const { t } = useI18N() - const { data: collectibles, error, retry, state } = useCollectibles(account, ChainId.Mainnet) + const { + data: collectibles, + error, + retry, + state, + } = useCollectibles('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', ChainId.Mainnet) const onClick = useCallback(async () => { if (!selectedToken) return diff --git a/packages/mask/src/plugins/Avatar/Services/bind.ts b/packages/mask/src/plugins/Avatar/Services/bind.ts index a944c468fc8c..78803c0cbcf9 100644 --- a/packages/mask/src/plugins/Avatar/Services/bind.ts +++ b/packages/mask/src/plugins/Avatar/Services/bind.ts @@ -2,16 +2,21 @@ import { ChainId, isSameAddress } from '@masknet/web3-shared-evm' import { NetworkPluginID } from '@masknet/plugin-infra' import addSeconds from 'date-fns/addSeconds' import { KeyValue } from '@masknet/web3-providers' -import { NFT_AVATAR_DB_NAME } from '../constants' +import { NFT_AVATAR_DB_NAME, NFT_AVATAR_DB_NAME_STORAGE } from '../constants' const NFTAvatarDB = KeyValue.createJSON_Storage(NFT_AVATAR_DB_NAME) +const NFTAvatarDBStorage = KeyValue.createJSON_Storage(NFT_AVATAR_DB_NAME_STORAGE) const cache = new Map, number]>() async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { try { - const result = await NFTAvatarDB.get>(userId) - return result?.[`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`] + const result = await NFTAvatarDB.get<{ networkPluginId: string; chainId: number; address: string }>(userId) + if (!result || !result?.address) { + const result = await NFTAvatarDBStorage.get>(userId) + return result?.[`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`] + } + return result.address } catch { return } @@ -39,9 +44,15 @@ export async function setUserAddress( chainId?: number, ) { try { - await NFTAvatarDB.set>(userId, { + await NFTAvatarDBStorage.set>(userId, { [`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`]: address, }) + + await NFTAvatarDB.set<{ networkPluginId: string; chainId: number; address: string }>(userId, { + networkPluginId: networkPluginId ?? NetworkPluginID.PLUGIN_EVM, + chainId: chainId ?? ChainId.Mainnet, + address, + }) } catch { // do nothing } finally { diff --git a/packages/mask/src/plugins/Avatar/Services/index.ts b/packages/mask/src/plugins/Avatar/Services/index.ts index be4dda7c0be5..0ed87f37b32e 100644 --- a/packages/mask/src/plugins/Avatar/Services/index.ts +++ b/packages/mask/src/plugins/Avatar/Services/index.ts @@ -1,5 +1,4 @@ import type { NetworkPluginID } from '@masknet/plugin-infra' -import { personalSign } from '../../../extension/background-script/EthereumService' import type { AvatarMetaDB } from '../types' import { getNFTAvatarFromJSON } from './db' import { getUserAddress, setUserAddress } from './bind' @@ -19,10 +18,13 @@ export async function saveNFTAvatar( networkPluginId?: NetworkPluginID, chainId?: number, ) { - const signature = await personalSign(nft.userId, address) - setUserAddress(nft.userId, address, networkPluginId, chainId) - const avatar = await saveNFTAvatarToRSS(address, nft, signature) - return avatar + try { + const avatar = await saveNFTAvatarToRSS(address, nft, '') + setUserAddress(nft.userId, address, networkPluginId, chainId) + return avatar + } catch (error) { + throw error + } } export async function getAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { diff --git a/packages/mask/src/plugins/Avatar/Services/rss3.ts b/packages/mask/src/plugins/Avatar/Services/rss3.ts index 552200519e40..5f3a5aa2388d 100644 --- a/packages/mask/src/plugins/Avatar/Services/rss3.ts +++ b/packages/mask/src/plugins/Avatar/Services/rss3.ts @@ -1,5 +1,3 @@ -import Web3 from 'web3' -import { isSameAddress } from '@masknet/web3-shared-evm' import { personalSign } from '../../../extension/background-script/EthereumService' import type { AvatarMetaDB } from '../types' import addSeconds from 'date-fns/addSeconds' @@ -10,61 +8,29 @@ interface NFTRSSNode { nft: AvatarMetaDB } -const cache = new Map< - string, - [Promise<{ type: string; nfts: Record | NFTRSSNode } | undefined>, number] ->() +const cache = new Map, number]>() export async function getNFTAvatarFromRSS(userId: string, address: string) { let v = cache.get(address) if (!v || Date.now() > v[1]) { - cache.set(address, [_getNFTAvatarFromRSS(address), addSeconds(Date.now(), 60).getTime()]) + cache.set(address, [_getNFTAvatarFromRSS(userId, address), addSeconds(Date.now(), 60).getTime()]) } v = cache.get(address) const result = await v?.[0] - if (!result) return - const { type, nfts } = result - - const web3 = new Web3() - let nft: NFTRSSNode - if (type === 'NFTS') { - const data = nfts as Record - nft = data[userId] - } else { - nft = nfts as NFTRSSNode - } - - try { - const sig_address = web3.eth.accounts.recover(nft.nft.userId, nft.signature) - if (!isSameAddress(sig_address, address)) return - return nft.nft - } catch { - throw new Error('Failed to recover signature.') - } + return result?.nft } -async function _getNFTAvatarFromRSS( - address: string, -): Promise<{ type: string; nfts: Record | NFTRSSNode } | undefined> { +async function _getNFTAvatarFromRSS(userId: string, address: string): Promise { const rss = RSS3.createRSS3(address, async (message: string) => { return personalSign(message, address) }) const nfts = await RSS3.getFileData>(rss, address, '_nfts') if (nfts) { - return { - type: 'NFTS', - nfts, - } - } else { - const nft = await RSS3.getFileData(rss, address, '_nft') - if (!nft) return - return { - type: 'NFT', - nfts: nft, - } + return nfts[userId] } + return RSS3.getFileData(rss, address, '_nft') } export async function saveNFTAvatarToRSS(address: string, nft: AvatarMetaDB, signature: string) { diff --git a/packages/mask/src/plugins/Avatar/constants.ts b/packages/mask/src/plugins/Avatar/constants.ts index b72a3bc36b52..ec2a44085c2a 100644 --- a/packages/mask/src/plugins/Avatar/constants.ts +++ b/packages/mask/src/plugins/Avatar/constants.ts @@ -2,6 +2,7 @@ import { PluginId } from '@masknet/plugin-infra' export const NFT_AVATAR_JSON_SERVER = 'https://configuration.r2d2.to/com.maskbook.avatar.json' export const NFT_AVATAR_DB_NAME = 'com.maskbook.user' +export const NFT_AVATAR_DB_NAME_STORAGE = 'com.maskbook.user.storage' export const NFT_CONTRACT_JSON_VERIFIED_SERVER = 'https://configuration.r2d2.to/com.maskbook.verified_nft.json' export const PLUGIN_ID = PluginId.Avatar diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx index e4fe0844b1d7..c81052e638fc 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx @@ -1,7 +1,7 @@ import { createReactRootShadowed, MaskMessages, NFTAvatarEvent, startWatch } from '../../../../utils' import { searchTwitterAvatarLinkSelector, searchTwitterAvatarSelector } from '../../utils/selector' import { MutationObserverWatcher } from '@dimensiondev/holoflows-kit' -import { makeStyles } from '@masknet/theme' +import { makeStyles, useCustomSnackbar } from '@masknet/theme' import { useState, useEffect, useMemo, useRef } from 'react' import { useCurrentVisitingIdentity } from '../../../../components/DataSource/useActivatedUI' import { resolveOpenSeaLink, useChainId, useWallet } from '@masknet/web3-shared-evm' @@ -52,6 +52,7 @@ function NFTAvatarInTwitter() { const location = useLocation() const chainId = useChainId() const currentPluginId = usePluginIDContext() + const { showSnackbar } = useCustomSnackbar() const showAvatar = useMemo( () => getAvatarId(identity.avatar ?? '') === avatar?.avatarId && avatar.avatarId, @@ -92,7 +93,14 @@ function NFTAvatarInTwitter() { const avatar = await PluginNFTAvatarRPC.saveNFTAvatar(wallet.address, { ...NFTEvent, avatarId: getAvatarId(identity.avatar ?? ''), - } as AvatarMetaDB) + } as AvatarMetaDB).catch((error) => { + showSnackbar(error.message, { variant: 'error' }) + return + }) + if (!avatar) { + showSnackbar('save nft avatar Error', { variant: 'error' }) + return + } setAvatar(avatar) MaskMessages.events.NFTAvatarTimelineUpdated.sendToAll( @@ -105,7 +113,7 @@ function NFTAvatarInTwitter() { ) setNFTEvent(undefined) - }, [identity.avatar]) + }, [identity.avatar, showSnackbar, NFTEvent]) useEffect(() => { setAvatar(_avatar) diff --git a/packages/web3-providers/src/helpers.ts b/packages/web3-providers/src/helpers.ts index b4f0bf6359fd..86f2704f8898 100644 --- a/packages/web3-providers/src/helpers.ts +++ b/packages/web3-providers/src/helpers.ts @@ -1,4 +1,5 @@ export async function fetchJSON(requestInfo: RequestInfo, requestInit?: RequestInit): Promise { const res = await globalThis.fetch(requestInfo, requestInit) + if (res.status === 404) return {} as T return res.json() } diff --git a/packages/web3-providers/src/opensea/index.ts b/packages/web3-providers/src/opensea/index.ts index 9c456d5f6c24..f9e76a00620b 100644 --- a/packages/web3-providers/src/opensea/index.ts +++ b/packages/web3-providers/src/opensea/index.ts @@ -34,6 +34,7 @@ async function fetchFromOpenSea(url: string, chainId: ChainId, apiKey?: strin headers: { 'x-api-key': apiKey ?? OPENSEA_API_KEY, Accept: 'application/json' }, ...(currentEnv === NonFungibleTokenAPI.APIEnv.browser && { mode: 'cors' }), }) + if (response.status === 404) return return response.json() as Promise } catch { return From f2d62eca7c55196f4d30569f355717556feb06a7 Mon Sep 17 00:00:00 2001 From: lelenei Date: Tue, 18 Jan 2022 17:37:31 +0800 Subject: [PATCH 10/18] fix: remove account --- packages/mask/src/plugins/Avatar/SNSAdaptor/NFTAvatar.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTAvatar.tsx b/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTAvatar.tsx index b21702dc7c39..b05b29c89c96 100644 --- a/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTAvatar.tsx +++ b/packages/mask/src/plugins/Avatar/SNSAdaptor/NFTAvatar.tsx @@ -98,12 +98,7 @@ export function NFTAvatar(props: NFTAvatarProps) { const [open_, setOpen_] = useState(false) const [collectibles_, setCollectibles_] = useState([]) const { t } = useI18N() - const { - data: collectibles, - error, - retry, - state, - } = useCollectibles('0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045', ChainId.Mainnet) + const { data: collectibles, error, retry, state } = useCollectibles(account, ChainId.Mainnet) const onClick = useCallback(async () => { if (!selectedToken) return From bf505fb8d0d5642bdb6fcedd48cc68d2b788aac3 Mon Sep 17 00:00:00 2001 From: lelenei Date: Wed, 19 Jan 2022 11:49:55 +0800 Subject: [PATCH 11/18] fix: fallback gun --- .../mask/src/plugins/Avatar/Services/bind.ts | 21 ++++++++++++++++++- .../injection/NFT/NFTAvatarInTwitter.tsx | 14 ++++++++++--- .../twitter.com/injection/ProfileTab.tsx | 2 +- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/bind.ts b/packages/mask/src/plugins/Avatar/Services/bind.ts index 78803c0cbcf9..69b297bb53f2 100644 --- a/packages/mask/src/plugins/Avatar/Services/bind.ts +++ b/packages/mask/src/plugins/Avatar/Services/bind.ts @@ -3,18 +3,37 @@ import { NetworkPluginID } from '@masknet/plugin-infra' import addSeconds from 'date-fns/addSeconds' import { KeyValue } from '@masknet/web3-providers' import { NFT_AVATAR_DB_NAME, NFT_AVATAR_DB_NAME_STORAGE } from '../constants' +import { gun2 } from '../../../network/gun/version.2' +import { delay } from '@masknet/shared-base' + +const NFTAvatarGUN = gun2.get(NFT_AVATAR_DB_NAME) +const READ_GUN_RETRIES = 10 const NFTAvatarDB = KeyValue.createJSON_Storage(NFT_AVATAR_DB_NAME) const NFTAvatarDBStorage = KeyValue.createJSON_Storage(NFT_AVATAR_DB_NAME_STORAGE) const cache = new Map, number]>() +async function getUserAddressFromGUN(userId: string): Promise { + // eslint-disable-next-line no-plusplus + for (let i = 0; i < READ_GUN_RETRIES; i++) { + const result = await NFTAvatarGUN + //@ts-expect-error + .get(userId).then!() + if (result) return result + await delay(500) + } + return +} + async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { try { const result = await NFTAvatarDB.get<{ networkPluginId: string; chainId: number; address: string }>(userId) if (!result || !result?.address) { const result = await NFTAvatarDBStorage.get>(userId) - return result?.[`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`] + const address = result?.[`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`] + if (address) return address + return getUserAddressFromGUN(userId) } return result.address } catch { diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx index c81052e638fc..160effd20425 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx @@ -39,6 +39,9 @@ const useStyles = makeStyles()(() => ({ width: '19px !important', height: '19px !important', }, + snackbar: { + position: 'relative', + }, })) function NFTAvatarInTwitter() { @@ -94,11 +97,16 @@ function NFTAvatarInTwitter() { ...NFTEvent, avatarId: getAvatarId(identity.avatar ?? ''), } as AvatarMetaDB).catch((error) => { - showSnackbar(error.message, { variant: 'error' }) + console.log(error.message) + showSnackbar(error.message, { + variant: 'error', + }) return }) if (!avatar) { - showSnackbar('save nft avatar Error', { variant: 'error' }) + showSnackbar('Failed to save NFT Avatar.', { + variant: 'error', + }) return } @@ -113,7 +121,7 @@ function NFTAvatarInTwitter() { ) setNFTEvent(undefined) - }, [identity.avatar, showSnackbar, NFTEvent]) + }, [identity.avatar]) useEffect(() => { setAvatar(_avatar) diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/ProfileTab.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/ProfileTab.tsx index e3572ae5c7a8..0a2f2be0ed99 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/ProfileTab.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/ProfileTab.tsx @@ -135,11 +135,11 @@ export function ProfileTabAtTwitter() { } export function injectProfileTabAtTwitter(signal: AbortSignal) { - const watcher = new MutationObserverWatcher(searchProfileTabListLastChildSelector()) let tabInjected = false const contentWatcher = new MutationObserverWatcher(searchProfileTabPageSelector()).useForeach((node, key, meta) => { const elePage = searchProfileTabPageSelector().evaluate() if (elePage && !tabInjected) { + const watcher = new MutationObserverWatcher(searchProfileTabListLastChildSelector()) startWatch(watcher, signal) createReactRootShadowed(watcher.firstDOMProxy.afterShadow, { signal }).render() tabInjected = true From 01d6a2c4498000fbfaeb5f1d68f7780776f7aadd Mon Sep 17 00:00:00 2001 From: lelenei Date: Wed, 19 Jan 2022 16:13:35 +0800 Subject: [PATCH 12/18] fix: reply review --- .../mask/src/plugins/Avatar/Services/bind.ts | 18 ++++++++++++------ .../mask/src/plugins/Avatar/Services/index.ts | 2 +- .../injection/NFT/NFTAvatarInTwitter.tsx | 1 - 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/bind.ts b/packages/mask/src/plugins/Avatar/Services/bind.ts index 69b297bb53f2..0437389d3faf 100644 --- a/packages/mask/src/plugins/Avatar/Services/bind.ts +++ b/packages/mask/src/plugins/Avatar/Services/bind.ts @@ -26,12 +26,16 @@ async function getUserAddressFromGUN(userId: string): Promise(userId) if (!result || !result?.address) { const result = await NFTAvatarDBStorage.get>(userId) - const address = result?.[`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`] + const address = result?.[getKey(networkPluginId, chainId)] if (address) return address return getUserAddressFromGUN(userId) } @@ -42,16 +46,18 @@ async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID } export async function getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { - const key = `${userId}-${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}` - let c = cache.get(key) + let c = cache.get(getKey(networkPluginId, chainId)) if (!c || Date.now() > c[1]) { try { - cache.set(key, [_getUserAddress(userId, networkPluginId, chainId), addSeconds(new Date(), 60).getTime()]) + cache.set(getKey(networkPluginId, chainId), [ + _getUserAddress(userId, networkPluginId, chainId), + addSeconds(new Date(), 60).getTime(), + ]) } catch (err) { console.log(err) } } - c = cache.get(key) + c = cache.get(getKey(networkPluginId, chainId)) return c?.[0] } @@ -64,7 +70,7 @@ export async function setUserAddress( ) { try { await NFTAvatarDBStorage.set>(userId, { - [`${networkPluginId ?? NetworkPluginID.PLUGIN_EVM}-${chainId ?? ChainId.Mainnet}`]: address, + [getKey(networkPluginId, chainId)]: address, }) await NFTAvatarDB.set<{ networkPluginId: string; chainId: number; address: string }>(userId, { diff --git a/packages/mask/src/plugins/Avatar/Services/index.ts b/packages/mask/src/plugins/Avatar/Services/index.ts index 0ed87f37b32e..0abf57fdebf0 100644 --- a/packages/mask/src/plugins/Avatar/Services/index.ts +++ b/packages/mask/src/plugins/Avatar/Services/index.ts @@ -20,7 +20,7 @@ export async function saveNFTAvatar( ) { try { const avatar = await saveNFTAvatarToRSS(address, nft, '') - setUserAddress(nft.userId, address, networkPluginId, chainId) + await setUserAddress(nft.userId, address, networkPluginId, chainId) return avatar } catch (error) { throw error diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx index 160effd20425..343cbe360759 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx @@ -97,7 +97,6 @@ function NFTAvatarInTwitter() { ...NFTEvent, avatarId: getAvatarId(identity.avatar ?? ''), } as AvatarMetaDB).catch((error) => { - console.log(error.message) showSnackbar(error.message, { variant: 'error', }) From 3ad021b36fd532c622bb2648f6a2399fc80424b9 Mon Sep 17 00:00:00 2001 From: lelenei Date: Wed, 19 Jan 2022 17:32:21 +0800 Subject: [PATCH 13/18] fix: use window alert --- .../mask/src/plugins/Avatar/Services/bind.ts | 4 ++-- .../injection/NFT/NFTAvatarInTwitter.tsx | 19 ++++--------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/bind.ts b/packages/mask/src/plugins/Avatar/Services/bind.ts index 0437389d3faf..ad9cbe01da2c 100644 --- a/packages/mask/src/plugins/Avatar/Services/bind.ts +++ b/packages/mask/src/plugins/Avatar/Services/bind.ts @@ -26,8 +26,8 @@ async function getUserAddressFromGUN(userId: string): Promise ({ width: '19px !important', height: '19px !important', }, - snackbar: { - position: 'relative', - }, })) function NFTAvatarInTwitter() { @@ -53,9 +49,6 @@ function NFTAvatarInTwitter() { const [avatar, setAvatar] = useState() const windowSize = useWindowSize() const location = useLocation() - const chainId = useChainId() - const currentPluginId = usePluginIDContext() - const { showSnackbar } = useCustomSnackbar() const showAvatar = useMemo( () => getAvatarId(identity.avatar ?? '') === avatar?.avatarId && avatar.avatarId, @@ -97,15 +90,11 @@ function NFTAvatarInTwitter() { ...NFTEvent, avatarId: getAvatarId(identity.avatar ?? ''), } as AvatarMetaDB).catch((error) => { - showSnackbar(error.message, { - variant: 'error', - }) + window.alert(error.message) return }) if (!avatar) { - showSnackbar('Failed to save NFT Avatar.', { - variant: 'error', - }) + window.alert('Failed to save NFT Avatar.') return } From 50a13291ef3dd893b8715fad71d35976acdd16c3 Mon Sep 17 00:00:00 2001 From: lelenei Date: Wed, 19 Jan 2022 21:24:39 +0800 Subject: [PATCH 14/18] fix: cache key --- packages/mask/src/plugins/Avatar/Services/bind.ts | 12 ++++++++---- .../mask/src/plugins/Avatar/hooks/useNFTAvatar.ts | 3 +-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/bind.ts b/packages/mask/src/plugins/Avatar/Services/bind.ts index ad9cbe01da2c..245e259c8731 100644 --- a/packages/mask/src/plugins/Avatar/Services/bind.ts +++ b/packages/mask/src/plugins/Avatar/Services/bind.ts @@ -18,7 +18,7 @@ async function getUserAddressFromGUN(userId: string): Promise(userId) @@ -46,10 +50,10 @@ async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID } export async function getUserAddress(userId: string, networkPluginId?: NetworkPluginID, chainId?: number) { - let c = cache.get(getKey(networkPluginId, chainId)) + let c = cache.get(getCacheKey(userId, networkPluginId, chainId)) if (!c || Date.now() > c[1]) { try { - cache.set(getKey(networkPluginId, chainId), [ + cache.set(getCacheKey(userId, networkPluginId, chainId), [ _getUserAddress(userId, networkPluginId, chainId), addSeconds(new Date(), 60).getTime(), ]) @@ -57,7 +61,7 @@ export async function getUserAddress(userId: string, networkPluginId?: NetworkPl console.log(err) } } - c = cache.get(getKey(networkPluginId, chainId)) + c = cache.get(getCacheKey(userId, networkPluginId, chainId)) return c?.[0] } diff --git a/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts b/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts index 472de6042782..6e418345bc87 100644 --- a/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts +++ b/packages/mask/src/plugins/Avatar/hooks/useNFTAvatar.ts @@ -5,8 +5,7 @@ import type { AvatarMetaDB } from '../types' export function useNFTAvatar(userId: string): AsyncState { return useAsync(async () => { - if (!userId) return - if (userId === '$unknown') return + if (!userId || userId === '$unknown') return return PluginNFTAvatarRPC.getNFTAvatar(userId) }, [userId]) } From d53e262f5e40c56853b24c3d84ca0ad9722f4b37 Mon Sep 17 00:00:00 2001 From: lelenei Date: Thu, 20 Jan 2022 11:32:12 +0800 Subject: [PATCH 15/18] fix: when block kv storage, fallback to gun --- packages/mask/src/plugins/Avatar/Services/bind.ts | 2 +- packages/web3-providers/src/helpers.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/bind.ts b/packages/mask/src/plugins/Avatar/Services/bind.ts index 245e259c8731..6bd84f1a8bf6 100644 --- a/packages/mask/src/plugins/Avatar/Services/bind.ts +++ b/packages/mask/src/plugins/Avatar/Services/bind.ts @@ -45,7 +45,7 @@ async function _getUserAddress(userId: string, networkPluginId?: NetworkPluginID } return result.address } catch { - return + return getUserAddressFromGUN(userId) } } diff --git a/packages/web3-providers/src/helpers.ts b/packages/web3-providers/src/helpers.ts index 86f2704f8898..b4f0bf6359fd 100644 --- a/packages/web3-providers/src/helpers.ts +++ b/packages/web3-providers/src/helpers.ts @@ -1,5 +1,4 @@ export async function fetchJSON(requestInfo: RequestInfo, requestInit?: RequestInit): Promise { const res = await globalThis.fetch(requestInfo, requestInit) - if (res.status === 404) return {} as T return res.json() } From 5f9944cbb43ace2d8efcb4beea5d2566ad364fee Mon Sep 17 00:00:00 2001 From: lelenei Date: Thu, 20 Jan 2022 14:14:44 +0800 Subject: [PATCH 16/18] fix: when user refused to sign, clean up avatar --- .../twitter.com/injection/NFT/NFTAvatarInTwitter.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx index 9745eed6d528..ae1bd9f679a8 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx @@ -90,10 +90,14 @@ function NFTAvatarInTwitter() { ...NFTEvent, avatarId: getAvatarId(identity.avatar ?? ''), } as AvatarMetaDB).catch((error) => { + setNFTEvent(undefined) + setAvatar(undefined) window.alert(error.message) return }) if (!avatar) { + setNFTEvent(undefined) + setAvatar(undefined) window.alert('Failed to save NFT Avatar.') return } From 9aa424646b04a6cb7cdba018329e6c29282195a8 Mon Sep 17 00:00:00 2001 From: lelenei Date: Thu, 20 Jan 2022 18:41:19 +0800 Subject: [PATCH 17/18] fix: error message --- packages/mask/src/plugins/Avatar/Services/bind.ts | 2 +- .../twitter.com/injection/NFT/NFTAvatarInTwitter.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mask/src/plugins/Avatar/Services/bind.ts b/packages/mask/src/plugins/Avatar/Services/bind.ts index 6bd84f1a8bf6..4c6a0e96e9f7 100644 --- a/packages/mask/src/plugins/Avatar/Services/bind.ts +++ b/packages/mask/src/plugins/Avatar/Services/bind.ts @@ -87,6 +87,6 @@ export async function setUserAddress( } finally { const _address = await getUserAddress(userId, networkPluginId, chainId) if (!isSameAddress(_address, address)) - throw new Error('Something went wrong, and please check your connection.') + throw new Error('Network issues, please make sure you are connected to the appropriate internet.') } } diff --git a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx index ae1bd9f679a8..af0b79383cca 100644 --- a/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx +++ b/packages/mask/src/social-network-adaptor/twitter.com/injection/NFT/NFTAvatarInTwitter.tsx @@ -98,7 +98,7 @@ function NFTAvatarInTwitter() { if (!avatar) { setNFTEvent(undefined) setAvatar(undefined) - window.alert('Failed to save NFT Avatar.') + window.alert('Sorry, failed to save NFT Avatar. Please set again.') return } From 35554ce1dad46d379f59c2dd2233f915636677d6 Mon Sep 17 00:00:00 2001 From: lelenei Date: Thu, 20 Jan 2022 22:18:35 +0800 Subject: [PATCH 18/18] fix: cspell --- cspell.json | 1 + 1 file changed, 1 insertion(+) diff --git a/cspell.json b/cspell.json index 286d6aecce1b..9dc41c29c4a6 100644 --- a/cspell.json +++ b/cspell.json @@ -175,6 +175,7 @@ "pid", "pids", "Plurinational", + "plusplus", "Polkadot", "Pooltogether", "popper",