diff --git a/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx b/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx index d3c43fee802d..b17608ce430a 100644 --- a/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx +++ b/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx @@ -55,6 +55,7 @@ type FormInputs = { } const GAS_LIMIT = 30000 + export const TransferERC721 = memo(() => { const t = useDashboardI18N() const chainId = useChainId() diff --git a/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx b/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx index c38e1a581104..926b11c2e5e6 100644 --- a/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx @@ -1,6 +1,6 @@ import { FC, memo } from 'react' import { Box, Button, Stack, Typography } from '@mui/material' -import { ProviderType, TransactionStatusType } from '@masknet/web3-shared-evm' +import { EMPTY_LIST, ProviderType, TransactionStatusType } from '@masknet/web3-shared-evm' import { makeStyles, MaskColorVar } from '@masknet/theme' import { FormattedAddress, LoadingAnimation, useRemoteControlledDialog, WalletIcon } from '@masknet/shared' import { @@ -64,7 +64,9 @@ export const WalletStateBar = memo(() => { const wallet = useWallet() const networkDescriptor = useNetworkDescriptor() const providerDescriptor = useProviderDescriptor() - const { value: pendingTransactions = [] } = useRecentTransactions(TransactionStatusType.NOT_DEPEND) + const { value: pendingTransactions = EMPTY_LIST } = useRecentTransactions({ + status: TransactionStatusType.NOT_DEPEND, + }) const { openDialog: openWalletStatusDialog } = useRemoteControlledDialog( PluginMessages.Wallet.events.walletStatusDialogUpdated, diff --git a/packages/dashboard/src/pages/Wallets/hooks/useRecentTransactions.ts b/packages/dashboard/src/pages/Wallets/hooks/useRecentTransactions.ts index 3d4a96b81814..96e38d16f58b 100644 --- a/packages/dashboard/src/pages/Wallets/hooks/useRecentTransactions.ts +++ b/packages/dashboard/src/pages/Wallets/hooks/useRecentTransactions.ts @@ -1,18 +1,18 @@ import { useEffect } from 'react' import { useAsyncRetry } from 'react-use' -import { TransactionStatusType, useAccount, useChainId } from '@masknet/web3-shared-evm' +import { useAccount, useChainId } from '@masknet/web3-shared-evm' import { PluginMessages, PluginServices } from '../../../API' +import type { RecentTransactionOptions } from '../../../../../mask/src/plugins/Wallet/services' // todo: should merge in plugin infra package when plugin infra ready -export function useRecentTransactions(status?: TransactionStatusType) { +export function useRecentTransactions(options?: RecentTransactionOptions) { const account = useAccount() const chainId = useChainId() const result = useAsyncRetry(async () => { if (!account) return [] - const transactions = await PluginServices.Wallet.getRecentTransactions(chainId, account) - return transactions.filter((x) => (typeof status !== 'undefined' ? x.status === status : true)) - }, [chainId, account, status]) + return PluginServices.Wallet.getRecentTransactions(chainId, account, options) + }, [chainId, account, JSON.stringify(options)]) useEffect(() => PluginMessages.Wallet.events.transactionStateUpdated.on(result.retry), [result.retry]) useEffect(() => PluginMessages.Wallet.events.transactionsUpdated.on(result.retry), [result.retry]) diff --git a/packages/dashboard/src/web3/context.ts b/packages/dashboard/src/web3/context.ts index 1e934b902bf4..d37006a3e6c5 100644 --- a/packages/dashboard/src/web3/context.ts +++ b/packages/dashboard/src/web3/context.ts @@ -1,6 +1,4 @@ -import { noop } from 'lodash-unified' import type { Subscription } from 'use-subscription' -import type { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers' import { ChainId, ERC1155TokenDetailed, @@ -11,20 +9,12 @@ import { EthereumTokenType, NetworkType, Web3ProviderType, - SendOverrides, - RequestOptions, isInjectedProvider, } from '@masknet/web3-shared-evm' -import { Services, Messages, PluginServices, PluginMessages } from '../API' import { getProxyWebsocketInstance } from '@masknet/web3-shared-base' - -const Web3Provider = createExternalProvider() +import { Services, Messages, PluginServices, PluginMessages } from '../API' export const Web3Context: Web3ProviderType = { - provider: { - getCurrentValue: () => Web3Provider, - subscribe: () => noop, - }, allowTestnet: createSubscriptionFromAsync(Services.Settings.getWalletAllowTestChain, false, () => { return () => {} }), @@ -46,17 +36,6 @@ export const Web3Context: Web3ProviderType = { {}, Messages.events.currentTokenPricesSettings.on, ), - balance: createSubscriptionFromAsync(Services.Settings.getBalance, '0', Messages.events.currentBalanceSettings.on), - balances: createSubscriptionFromAsync( - Services.Settings.getBalances, - {}, - Messages.events.currentBalancesSettings.on, - ), - blockNumber: createSubscriptionFromAsync( - Services.Settings.getBlockNumber, - 0, - Messages.events.currentBlockNumberSettings.on, - ), chainId: createSubscriptionFromAsync( Services.Settings.getChainId, ChainId.Mainnet, @@ -108,6 +87,8 @@ export const Web3Context: Web3ProviderType = { trustToken: PluginServices.Wallet.trustToken, blockToken: PluginServices.Wallet.blockToken, + request: Services.Ethereum.request, + getAssetsList: PluginServices.Wallet.getAssetsList, getAssetsListNFT: PluginServices.Wallet.getAssetsListNFT, getCollectionsNFT: PluginServices.Wallet.getCollectionsNFT, @@ -119,44 +100,6 @@ export const Web3Context: Web3ProviderType = { ), } -export function createExternalProvider() { - const send = ( - payload: JsonRpcPayload, - callback: (error: Error | null, response?: JsonRpcResponse) => void, - overrides?: SendOverrides, - options?: RequestOptions, - ) => { - Services.Ethereum.request( - { - method: payload.method, - params: payload.params, - }, - overrides, - options, - ).then( - (result) => { - callback(null, { - jsonrpc: '2.0', - id: payload.id as number, - result, - }) - }, - (error) => { - callback(error) - }, - ) - } - return { - isMetaMask: false, - isStatus: true, - host: '', - path: '', - request: Services.Ethereum.request, - send, - sendAsync: send, - } -} - // double check function createSubscriptionFromAsync( f: () => Promise, diff --git a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx index 6bb27ee3f8c4..5ca96db7a8ca 100644 --- a/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx +++ b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx @@ -167,7 +167,9 @@ function useToolbox() { const { Utils } = useWeb3State() // #region recent pending transactions - const { value: pendingTransactions = [] } = useRecentTransactions(TransactionStatusType.NOT_DEPEND) + const { value: pendingTransactions = [] } = useRecentTransactions({ + status: TransactionStatusType.NOT_DEPEND, + }) // #endregion // #region Wallet diff --git a/packages/mask/src/extension/background-script/EthereumServices/send.ts b/packages/mask/src/extension/background-script/EthereumServices/send.ts index 797977f16cbc..133bbf7858f3 100644 --- a/packages/mask/src/extension/background-script/EthereumServices/send.ts +++ b/packages/mask/src/extension/background-script/EthereumServices/send.ts @@ -404,7 +404,9 @@ export async function INTERNAL_send( const [hash] = payload.params as [string] // redirect receipt queries to tx watcher - const transaction = await WalletRPC.getRecentTransaction(chainIdFinally, account, hash) + const transaction = await WalletRPC.getRecentTransaction(chainIdFinally, account, hash, { + receipt: true, + }) try { callback(null, { diff --git a/packages/mask/src/extension/background-script/SettingsService.ts b/packages/mask/src/extension/background-script/SettingsService.ts index b30d4c8d6e0d..2bf7598fd9fd 100644 --- a/packages/mask/src/extension/background-script/SettingsService.ts +++ b/packages/mask/src/extension/background-script/SettingsService.ts @@ -22,8 +22,6 @@ import { } from '../../plugins/Trader/settings' import { queryMyPersonas } from './IdentityService' import { - currentBalanceSettings, - currentBlockNumberSettings, currentAccountSettings, currentNetworkSettings, currentProviderSettings, @@ -36,7 +34,6 @@ import { currentMaskWalletAccountSettings, currentMaskWalletChainIdSettings, currentMaskWalletNetworkSettings, - currentBalancesSettings, } from '../../plugins/Wallet/settings' import { Flags, MaskMessages } from '../../../shared' import { indexedDB_KVStorageBackend, inMemory_KVStorageBackend } from '../../../background/database/kv-storage' @@ -56,9 +53,6 @@ export const [getPluginID, setPluginID] = create(pluginIDSettings) export const [getTheme, setTheme] = create(appearanceSettings) export const [getLanguage, setLanguage] = create(languageSettings) export const [getChainId, setChainId] = create(currentChainIdSettings) -export const [getBalance, setBalance] = create(currentBalanceSettings) -export const [getBalances, setBalances] = create(currentBalancesSettings) -export const [getBlockNumber, setBlockNumber] = create(currentBlockNumberSettings) export const [getTokenPrices, setTokenPrices] = create(currentTokenPricesSettings) export const [getGasOptions, setGasOptions] = create(currentGasOptionsSettings) export const [getGasPrice, setGasPrice] = create(currentGasOptionsSettings) diff --git a/packages/mask/src/extension/popups/pages/Swap/index.tsx b/packages/mask/src/extension/popups/pages/Swap/index.tsx index 367505fc84df..0881e2618dbb 100644 --- a/packages/mask/src/extension/popups/pages/Swap/index.tsx +++ b/packages/mask/src/extension/popups/pages/Swap/index.tsx @@ -64,7 +64,9 @@ export default function SwapPage() { const { t } = useI18N() const { classes } = useStyles() const chainId = useChainId() - const { value: pendingTransactions = [] } = useRecentTransactions(TransactionStatusType.NOT_DEPEND) + const { value: pendingTransactions = [] } = useRecentTransactions({ + status: TransactionStatusType.NOT_DEPEND, + }) const wallet = useWallet() const openPopupsWindow = useCallback(() => { Services.Helper.openPopupWindow(PopupRoutes.SelectWallet, { diff --git a/packages/mask/src/extension/popups/pages/Wallet/GasSetting/GasSetting1559.tsx b/packages/mask/src/extension/popups/pages/Wallet/GasSetting/GasSetting1559.tsx index c32c6b86dcd7..0d89e8c4ab8b 100644 --- a/packages/mask/src/extension/popups/pages/Wallet/GasSetting/GasSetting1559.tsx +++ b/packages/mask/src/extension/popups/pages/Wallet/GasSetting/GasSetting1559.tsx @@ -113,9 +113,9 @@ const useStyles = makeStyles()((theme) => ({ const HIGH_FEE_WARNING_MULTIPLIER = 1.5 export const GasSetting1559 = memo(() => { + const { t } = useI18N() const { classes } = useStyles() const web3 = useWeb3() - const { t } = useI18N() const chainId = useChainId() const history = useHistory() const [selected, setOption] = useState(null) diff --git a/packages/mask/src/extension/popups/pages/Wallet/GasSetting/Prior1559GasSetting.tsx b/packages/mask/src/extension/popups/pages/Wallet/GasSetting/Prior1559GasSetting.tsx index 2f865eb50caa..03c3945aecd2 100644 --- a/packages/mask/src/extension/popups/pages/Wallet/GasSetting/Prior1559GasSetting.tsx +++ b/packages/mask/src/extension/popups/pages/Wallet/GasSetting/Prior1559GasSetting.tsx @@ -96,9 +96,9 @@ const minGasPriceOfChain: ChainIdOptionalRecord = { } export const Prior1559GasSetting = memo(() => { + const { t } = useI18N() const { classes } = useStyles() const web3 = useWeb3() - const { t } = useI18N() const chainId = useChainId() const { value, loading: getValueLoading } = useUnconfirmedRequest() const [getGasLimitError, setGetGasLimitError] = useState(false) diff --git a/packages/mask/src/extension/popups/pages/Wallet/hooks/useWalletContext.ts b/packages/mask/src/extension/popups/pages/Wallet/hooks/useWalletContext.ts index 48a4a4c928e2..993afe13c84e 100644 --- a/packages/mask/src/extension/popups/pages/Wallet/hooks/useWalletContext.ts +++ b/packages/mask/src/extension/popups/pages/Wallet/hooks/useWalletContext.ts @@ -8,7 +8,10 @@ function useWalletContext() { const chainDetailed = useChainDetailed() const erc20Tokens = useTrustedERC20Tokens() const { value: assets, loading } = useAssets(erc20Tokens) - const { value: transactions } = useRecentTransactions() + const { value: transactions } = useRecentTransactions({ + receipt: true, + computedPayload: true, + }) const [currentToken, setCurrentToken] = useState() const [transaction, setTransaction] = useState() diff --git a/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts b/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts index 5b7108da4ed2..be0954b9b489 100644 --- a/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts +++ b/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts @@ -1,37 +1,26 @@ import { OpenSeaPort } from 'opensea-js' -import type { ChainId } from '@masknet/web3-shared-evm' -import { request, requestSend } from '../../../extension/background-script/EthereumService' +import { ChainId, createExternalProvider } from '@masknet/web3-shared-evm' +import { request } from '../../../extension/background-script/EthereumService' import { resolveOpenSeaNetwork } from '../pipes' import { OpenSeaAPI_Key, ReferrerAddress } from '../constants' -import { currentChainIdSettings } from '../../Wallet/settings' - -function createExternalProvider() { - return { - isMetaMask: false, - isStatus: true, - host: '', - path: '', - sendAsync: requestSend, - send: requestSend, - request, - } -} function createOpenSeaPortChain(chainId: ChainId.Mainnet | ChainId.Rinkeby) { - const config = { - networkName: resolveOpenSeaNetwork(chainId), - apiKey: OpenSeaAPI_Key, - } - return new OpenSeaPort(createExternalProvider(), config, console.log) + return new OpenSeaPort( + createExternalProvider(request), + { + networkName: resolveOpenSeaNetwork(chainId), + apiKey: OpenSeaAPI_Key, + }, + console.log, + ) } function createOpenSeaPort(chainId?: ChainId) { - return createOpenSeaPortChain(chainId ?? currentChainIdSettings.value) + return createOpenSeaPortChain(chainId === ChainId.Rinkeby ? ChainId.Rinkeby : ChainId.Mainnet) } -export async function getAssetFromSDK(tokenAddress: string, tokenId: string, chainId?: ChainId) { - chainId = chainId ?? currentChainIdSettings.value - return createOpenSeaPort(chainId).api.getAsset({ tokenAddress, tokenId }) +export async function getAssetFromSDK(tokenAddress: string, tokenId: string) { + return createOpenSeaPort().api.getAsset({ tokenAddress, tokenId }) } export async function createBuyOrder(payload: Parameters[0]) { diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts b/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts index 66192f74dbde..af4a0009ac65 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/getAssetsFn.ts @@ -7,16 +7,16 @@ import { getERC721TokenDetailedFromChain, getERC721TokenAssetFromChain, getEthereumConstants, - getRPCConstants, isSameAddress, Web3ProviderType, FungibleAssetProvider, + createExternalProvider, } from '@masknet/web3-shared-evm' import { Pageable, Pagination, TokenType, Web3Plugin } from '@masknet/plugin-infra' import BalanceCheckerABI from '@masknet/web3-contracts/abis/BalanceChecker.json' import ERC721ABI from '@masknet/web3-contracts/abis/ERC721.json' import type { AbiItem } from 'web3-utils' -import { first, uniqBy } from 'lodash-unified' +import { uniqBy } from 'lodash-unified' import { PLUGIN_NETWORKS } from '../../constants' import { makeSortAssertWithoutChainFn } from '../../utils/token' import type { ERC721 } from '@masknet/web3-contracts/types/ERC721' @@ -25,7 +25,6 @@ export const getFungibleAssetsFn = (context: Web3ProviderType) => async (address: string, providerType: string, network: Web3Plugin.NetworkDescriptor, pagination?: Pagination) => { const chainId = context.chainId.getCurrentValue() - const provider = context.provider.getCurrentValue() const wallet = context.wallets.getCurrentValue().find((x) => isSameAddress(x.address, address)) const socket = await context.providerSocket const networks = PLUGIN_NETWORKS @@ -33,7 +32,9 @@ export const getFungibleAssetsFn = .getCurrentValue() .filter((x) => wallet?.erc20_token_whitelist.has(formatEthereumAddress(x.address))) - const web3 = new Web3(provider) + const web3 = new Web3( + createExternalProvider(context.request, context.getSendOverrides, context.getRequestOptions), + ) const { BALANCE_CHECKER_ADDRESS } = getEthereumConstants(chainId) const socketId = `mask.fetchFungibleTokenAsset_${address}` let dataFromProvider = await socket.sendAsync>({ @@ -138,28 +139,30 @@ export const getNonFungibleTokenFn = let tokenInDb: ERC721TokenDetailed[] = [] // validate and show trusted erc721 token in first page if (pagination?.page === 0) { - const provider = context.provider.getCurrentValue() const trustedTokens = context.erc721Tokens.getCurrentValue() const calls = trustedTokens.map(async (x) => { - const web3 = new Web3(provider) - const { RPC } = getRPCConstants(x.contractDetailed.chainId) - const providerURL = first(RPC) - if (providerURL) { - web3.setProvider(providerURL) - const contract = createContract(web3, x.contractDetailed.address, ERC721ABI as AbiItem[]) - if (!contract) return null - const tokenDetailed = await getERC721TokenDetailedFromChain(x.contractDetailed, contract, x.tokenId) - const info = await getERC721TokenAssetFromChain(tokenDetailed?.info.tokenURI) - if (tokenDetailed && info) - tokenDetailed.info = { - ...info, - ...tokenDetailed.info, - hasTokenDetailed: true, - name: info.name ?? tokenDetailed.info.name, - } - return tokenDetailed - } - return null + const web3 = new Web3( + createExternalProvider( + context.request, + () => ({ + ...context.getSendOverrides?.(), + chainId: x.contractDetailed.chainId, + }), + context.getRequestOptions, + ), + ) + const contract = createContract(web3, x.contractDetailed.address, ERC721ABI as AbiItem[]) + if (!contract) return null + const tokenDetailed = await getERC721TokenDetailedFromChain(x.contractDetailed, contract, x.tokenId) + const info = await getERC721TokenAssetFromChain(tokenDetailed?.info.tokenURI) + if (tokenDetailed && info) + tokenDetailed.info = { + ...info, + ...tokenDetailed.info, + hasTokenDetailed: true, + name: info.name ?? tokenDetailed.info.name, + } + return tokenDetailed }) const fromChain = await Promise.all(calls) @@ -174,7 +177,6 @@ export const getNonFungibleTokenFn = }) const tokenFromProvider = socket.getResult(socketId) - const allData: Web3Plugin.NonFungibleToken[] = [...tokenInDb, ...tokenFromProvider] .map( (x) => diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts index b7da0c8e6447..9c8ef00107ca 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts @@ -1,3 +1,4 @@ +import Ens from 'ethjs-ens' import type { Web3Plugin } from '@masknet/plugin-infra' import { ChainId, @@ -22,8 +23,9 @@ import { resolveDomainLink, formatDomainName, isZeroAddress, + createWeb3, + createExternalProvider, } from '@masknet/web3-shared-evm' -import Ens from 'ethjs-ens' import { getStorage } from '../../storage' import { getFungibleAssetsFn, getNonFungibleTokenFn } from './getAssetsFn' @@ -36,8 +38,6 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, allowTestnet: context.allowTestnet, chainId: context.chainId, account: context.account, - balance: context.balance, - blockNumber: context.blockNumber, networkType: context.networkType, providerType: context.providerType, walletPrimary: context.walletPrimary, @@ -51,7 +51,6 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, lookup: async (domain: string) => { const chainId = context.chainId.getCurrentValue() const network = context.networkType.getCurrentValue() - const provider = context.provider.getCurrentValue() // Only support Ethereum on evm if (network !== NetworkType.Ethereum) return undefined @@ -62,7 +61,7 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, if (cacheAddress && isValidAddress(cacheAddress)) return cacheAddress const address = await new Ens({ - provider, + provider: createExternalProvider(context.request, context.getSendOverrides, context.getRequestOptions), network: chainId, }).lookup(domain) @@ -85,7 +84,6 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, if (!isValidAddress(address)) return undefined const chainId = context.chainId.getCurrentValue() const network = context.networkType.getCurrentValue() - const provider = context.provider.getCurrentValue() // Only support Ethereum on evm if (network !== NetworkType.Ethereum) return undefined @@ -95,7 +93,7 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, if (cacheDomain) return cacheDomain const domain = await new Ens({ - provider, + provider: createExternalProvider(context.request, context.getSendOverrides, context.getRequestOptions), network: chainId, }).reverse(address) @@ -116,6 +114,19 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, }, } state.Utils = state.Utils ?? { + getLatestBalance: (chainId: ChainId, account: string) => { + const web3 = createWeb3(context.request, () => ({ + chainId, + })) + return web3.eth.getBalance(account) + }, + getLatestBlockNumber: (chainId: ChainId) => { + const web3 = createWeb3(context.request, () => ({ + chainId, + })) + return web3.eth.getBlockNumber() + }, + getChainDetailed, isChainIdValid, @@ -133,7 +144,7 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, isValidDomain, resolveDomainLink, formatDomainName, - resolveNonFungibleTokenLink: (chainId: number, address: string, tokenId: string) => + resolveNonFungibleTokenLink: (chainId: ChainId, address: string, tokenId: string) => resolveCollectibleLink(chainId as ChainId, NonFungibleAssetProvider.OPENSEA, { contractDetailed: { address: address }, tokenId: tokenId, diff --git a/packages/mask/src/plugins/EVM/storage/index.ts b/packages/mask/src/plugins/EVM/storage/index.ts index 36027e7316a1..2fcd4ff88276 100644 --- a/packages/mask/src/plugins/EVM/storage/index.ts +++ b/packages/mask/src/plugins/EVM/storage/index.ts @@ -2,7 +2,7 @@ import type { ScopedStorage } from '@masknet/shared-base' import type { Web3Plugin } from '@masknet/plugin-infra' export const StorageDefaultValue = { - domainAddressBook: {} as Web3Plugin.domainAddressBook, + domainAddressBook: {} as Web3Plugin.DomainAddressBook, } let storage: ScopedStorage = null! diff --git a/packages/mask/src/plugins/FindTruman/SNSAdaptor/OptionsCard.tsx b/packages/mask/src/plugins/FindTruman/SNSAdaptor/OptionsCard.tsx index d8f7f2e93b34..a5f3f0f1de4d 100644 --- a/packages/mask/src/plugins/FindTruman/SNSAdaptor/OptionsCard.tsx +++ b/packages/mask/src/plugins/FindTruman/SNSAdaptor/OptionsCard.tsx @@ -92,11 +92,11 @@ export default function OptionsCard(props: OptionsViewProps) { const [unmeetCondition, setUnmeetCondition] = useState([]) const [snackVisible, setSnackVisible] = useState(false) + const { t } = useI18N() const { classes } = useOptionsStyles() const chainId = useChainId() const { address: account } = useContext(FindTrumanContext) - const web3 = useWeb3(false) - const { t } = useI18N() + const web3 = useWeb3() const ref = useRef(null) const parentRef = useRef(null) diff --git a/packages/mask/src/plugins/Gitcoin/hooks/useDonateCallback.ts b/packages/mask/src/plugins/Gitcoin/hooks/useDonateCallback.ts index dbd671e85aa0..b1e20207f16a 100644 --- a/packages/mask/src/plugins/Gitcoin/hooks/useDonateCallback.ts +++ b/packages/mask/src/plugins/Gitcoin/hooks/useDonateCallback.ts @@ -1,3 +1,5 @@ +import BigNumber from 'bignumber.js' +import { useCallback, useMemo } from 'react' import type { PayableTx } from '@masknet/web3-contracts/types/types' import { toFixed } from '@masknet/web3-shared-base' import { @@ -8,10 +10,7 @@ import { useAccount, useGitcoinConstants, useTransactionState, - useWeb3, } from '@masknet/web3-shared-evm' -import BigNumber from 'bignumber.js' -import { useCallback, useMemo } from 'react' import { useBulkCheckoutContract } from '../contracts/useBulkCheckoutWallet' /** @@ -24,7 +23,6 @@ export function useDonateCallback(address: string, amount: string, token?: Fungi const { GITCOIN_ETH_ADDRESS, GITCOIN_TIP_PERCENTAGE } = useGitcoinConstants() const bulkCheckoutContract = useBulkCheckoutContract() - const web3 = useWeb3() const account = useAccount() const [donateState, setDonateState] = useTransactionState() @@ -100,7 +98,7 @@ export function useDonateCallback(address: string, amount: string, token?: Fungi reject(error) }) }) - }, [web3, account, amount, token, donations]) + }, [account, amount, token, donations]) const resetCallback = useCallback(() => { setDonateState({ diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useAllPoolsAsSeller.ts b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useAllPoolsAsSeller.ts index 1f4944dba3d4..b728e91596d4 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useAllPoolsAsSeller.ts +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useAllPoolsAsSeller.ts @@ -1,13 +1,13 @@ +import { useRef, useEffect } from 'react' import { useAsyncRetry } from 'react-use' import { PluginITO_RPC } from '../../messages' import type { PoolFromNetwork } from '../../types' -import { useBlockNumberOnce, useChainId } from '@masknet/web3-shared-evm' -import { useRef, useEffect } from 'react' +import { useBlockNumber, useChainId } from '@masknet/web3-shared-evm' export function useAllPoolsAsSeller(address: string) { const allPoolsRef = useRef([]) const chainId = useChainId() - const blockNumber = useBlockNumberOnce() + const { value: blockNumber = 0 } = useBlockNumber() useEffect(() => { allPoolsRef.current = [] diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useBlockNumberOfChain.ts b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useBlockNumberOfChain.ts deleted file mode 100644 index 47b9a7313076..000000000000 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useBlockNumberOfChain.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { useAsync } from 'react-use' -import { ChainId, EthereumMethodType } from '@masknet/web3-shared-evm' -import Services from '../../../../extension/service' - -/** - * Get the current block number of specified chain - */ -export function useBlockNumberOfChain(chainId: ChainId) { - const { value } = useAsync( - () => Services.Ethereum.request({ method: EthereumMethodType.ETH_BLOCK_NUMBER }, { chainId }), - [chainId], - ) - return value ? Number.parseInt(value, 10) : 0 -} diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useClaimAll.ts b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useClaimAll.ts index 2d5b7191500b..9acf9b6e7b9e 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useClaimAll.ts +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useClaimAll.ts @@ -1,7 +1,7 @@ import { useAsyncRetry } from 'react-use' import { PluginITO_RPC } from '../../messages' import type { SwappedTokenType } from '../../types' -import { useBlockNumberOnce, useChainId } from '@masknet/web3-shared-evm' +import { useBlockNumber, useChainId } from '@masknet/web3-shared-evm' import { useRef, useEffect } from 'react' export function useClaimAll(swapperAddress: string) { @@ -12,7 +12,7 @@ export function useClaimAll(swapperAddress: string) { allPoolsRef.current = [] }, [chainId]) - const blockNumber = useBlockNumberOnce() + const { value: blockNumber = 0 } = useBlockNumber() return useAsyncRetry(async () => { if (allPoolsRef.current.length > 0) return allPoolsRef.current const results = await PluginITO_RPC.getClaimAllPools(chainId, blockNumber, swapperAddress) diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useFill.ts b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useFill.ts index 6a828949128e..cefaf4bad112 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useFill.ts +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useFill.ts @@ -62,11 +62,11 @@ type paramsObjType = { } export function useFillCallback(poolSettings?: PoolSettings) { + const { t } = useI18N() const web3 = useWeb3() const account = useAccount() const chainId = useChainId() const { contract: ITO_Contract } = useITO_Contract() - const { t } = useI18N() const [fillState, setFillState] = useTransactionState() const [fillSettings, setFillSettings] = useState(poolSettings) const paramResult = useFillParams(poolSettings) diff --git a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts index cc825801990c..bb724371a1a0 100644 --- a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts +++ b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts @@ -35,13 +35,12 @@ import { useMaskBoxPurchasedTokens } from './useMaskBoxPurchasedTokens' import { formatCountdown } from '../helpers/formatCountdown' import { useOpenBoxTransaction } from './useOpenBoxTransaction' import { useMaskBoxMetadata } from './useMaskBoxMetadata' -import { useHeartBeat } from './useHeartBeat' import { useIsWhitelisted } from './useIsWhitelisted' -import { isGreaterThanOrEqualTo, isLessThanOrEqualTo, isZero, multipliedBy } from '@masknet/web3-shared-base' +import { isGreaterThanOrEqualTo, isLessThanOrEqualTo, isZero, multipliedBy, useBeat } from '@masknet/web3-shared-base' function useContext(initialState?: { boxId: string }) { const now = new Date() - const heartBeat = useHeartBeat() + const beat = useBeat() const account = useAccount() const chainId = useChainId() const { NATIVE_TOKEN_ADDRESS } = useTokenConstants(ChainId.Mainnet) @@ -148,7 +147,7 @@ function useContext(initialState?: { boxId: string }) { if (boxInfo.startAt > now || !boxInfo.started) return BoxState.NOT_READY if (boxInfo.endAt < now || maskBoxStatus?.expired) return BoxState.EXPIRED return BoxState.READY - }, [boxInfo, loadingBoxInfo, errorBoxInfo, maskBoxInfo, loadingMaskBoxInfo, errorMaskBoxInfo, heartBeat]) + }, [boxInfo, loadingBoxInfo, errorBoxInfo, maskBoxInfo, loadingMaskBoxInfo, errorMaskBoxInfo, beat]) const isWhitelisted = useIsWhitelisted(boxInfo?.qualificationAddress, account) const isQualifiedByContract = @@ -189,7 +188,7 @@ function useContext(initialState?: { boxId: string }) { default: unreachable(boxState) } - }, [boxState, boxInfo?.startAt, heartBeat]) + }, [boxState, boxInfo?.startAt, beat]) useEffect(() => { if (!boxInfo || boxInfo.started) return @@ -197,7 +196,7 @@ function useContext(initialState?: { boxId: string }) { if (boxInfo.startAt < now) { retryMaskBoxStatus() } - }, [boxInfo, heartBeat]) + }, [boxInfo, beat]) // #endregion @@ -258,7 +257,7 @@ function useContext(initialState?: { boxId: string }) { paymentTokenDetailed, openBoxTransactionOverrides, ) - const { value: erc20Allowance } = useERC20TokenAllowance( + const { value: erc20Allowance, retry: retryAllowance } = useERC20TokenAllowance( isNativeToken ? undefined : paymentTokenAddress, MASK_BOX_CONTRACT_ADDRESS, ) @@ -324,6 +323,7 @@ function useContext(initialState?: { boxId: string }) { setOpenBoxTransactionOverrides, // retry callbacks + retryAllowance, retryMaskBoxInfo, retryMaskBoxStatus, retryBoxInfo, diff --git a/packages/mask/src/plugins/MaskBox/hooks/useHeartBeat.ts b/packages/mask/src/plugins/MaskBox/hooks/useHeartBeat.ts deleted file mode 100644 index 8d476c76cb68..000000000000 --- a/packages/mask/src/plugins/MaskBox/hooks/useHeartBeat.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { useState } from 'react' -import { useTimeoutFn } from 'react-use' - -export function useHeartBeat(delay = 1000) { - const [bit, setBit] = useState(0) - const [, , reset] = useTimeoutFn(() => { - setBit((x) => (x + 1) % Number.MAX_SAFE_INTEGER) - reset() - }, delay) - return bit -} diff --git a/packages/mask/src/plugins/MaskBox/hooks/useMaskBoxCreationSuccessEvent.ts b/packages/mask/src/plugins/MaskBox/hooks/useMaskBoxCreationSuccessEvent.ts index 6bbdbb42914a..41ca5aabee95 100644 --- a/packages/mask/src/plugins/MaskBox/hooks/useMaskBoxCreationSuccessEvent.ts +++ b/packages/mask/src/plugins/MaskBox/hooks/useMaskBoxCreationSuccessEvent.ts @@ -9,11 +9,12 @@ const FRAGMENT_SIZE = 3000 const MAX_PAGE_SIZE = 10 export function useMaskBoxCreationSuccessEvent(creatorAddress: string, tokenAddress: string, boxId: string) { - const blockNumber = useBlockNumber() + const { value: blockNumber = 0 } = useBlockNumber() const maskBoxContract = useMaskBoxContract() const { MASK_BOX_CONTRACT_FROM_BLOCK = Math.max(0, blockNumber - FRAGMENT_SIZE) } = useMaskBoxConstants() return useAsyncRetry(async () => { + if (!blockNumber) return null if (!maskBoxContract) return null const getPastEvents = (fromBlock: number, toBlock: number) => { diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacket/index.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacket/index.tsx index fe72510cdba6..56f6846b388a 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacket/index.tsx +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacket/index.tsx @@ -40,6 +40,7 @@ export function RedPacket(props: RedPacketProps) { const { t } = useI18N() const { classes } = useStyles() + // context const web3 = useWeb3() const account = useAccount() diff --git a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRedPacketHistory.ts b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRedPacketHistory.ts index eaf578249b4e..f92452c1e630 100644 --- a/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRedPacketHistory.ts +++ b/packages/mask/src/plugins/RedPacket/SNSAdaptor/hooks/useRedPacketHistory.ts @@ -1,10 +1,11 @@ import { useAsyncRetry } from 'react-use' import { RedPacketRPC } from '../../messages' -import { ChainId, useBlockNumberOnce } from '@masknet/web3-shared-evm' +import { ChainId, useBlockNumber } from '@masknet/web3-shared-evm' export function useRedPacketHistory(address: string, chainId: ChainId) { - const blockNumber = useBlockNumberOnce() + const { value: blockNumber = 0 } = useBlockNumber() return useAsyncRetry(async () => { + if (!blockNumber) return [] return RedPacketRPC.getRedPacketHistory(address, chainId, blockNumber) }, [address, chainId, blockNumber]) } diff --git a/packages/mask/src/plugins/Snapshot/SNSAdaptor/hooks/usePower.ts b/packages/mask/src/plugins/Snapshot/SNSAdaptor/hooks/usePower.ts index e8babc4b109a..ad931aaba7c2 100644 --- a/packages/mask/src/plugins/Snapshot/SNSAdaptor/hooks/usePower.ts +++ b/packages/mask/src/plugins/Snapshot/SNSAdaptor/hooks/usePower.ts @@ -9,9 +9,10 @@ export function usePower(identifier: ProposalIdentifier) { const { payload: proposal } = useProposal(identifier.id) const account = useAccount() - const blockNumber = useBlockNumber() + const { value: blockNumber = 0 } = useBlockNumber() return useAsyncRetry(async () => { if (!account) return 0 + if (!blockNumber) return 0 return ( await PluginSnapshotRPC.getScores( proposal.snapshot, diff --git a/packages/mask/src/plugins/Snapshot/SNSAdaptor/hooks/useVotes.ts b/packages/mask/src/plugins/Snapshot/SNSAdaptor/hooks/useVotes.ts index 45cf46c7f80f..11d00b1adf14 100644 --- a/packages/mask/src/plugins/Snapshot/SNSAdaptor/hooks/useVotes.ts +++ b/packages/mask/src/plugins/Snapshot/SNSAdaptor/hooks/useVotes.ts @@ -14,9 +14,11 @@ export function useVotes(identifier: ProposalIdentifier) { return useSuspense(identifier.id, [identifier], cache, Suspender) } async function Suspender(identifier: ProposalIdentifier) { - const blockNumber = useBlockNumber() + const { value: blockNumber = 0 } = useBlockNumber() const { payload: proposal } = useProposal(identifier.id) + if (!blockNumber) return [] + const voters = proposal.votes.map((v) => v.voter) const scores = await PluginSnapshotRPC.getScores( proposal.snapshot, diff --git a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts index 9c227fd30862..d94244c0f060 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts @@ -1,18 +1,17 @@ -import type { ChainId } from '@masknet/web3-shared-evm' -import { AllProviderTradeActionType, AllProviderTradeContext } from '../../../trader/useAllProviderTradeContext' import { + ChainId, EthereumTokenType, isSameAddress, useAccount, useProviderType, useTokenConstants, + useWeb3, } from '@masknet/web3-shared-evm' import { useAsync } from 'react-use' -import { currentBalancesSettings } from '../../../../Wallet/settings' -import Services from '../../../../../extension/service' -import { WalletRPC } from '../../../../Wallet/messages' +import { AllProviderTradeActionType, AllProviderTradeContext } from '../../../trader/useAllProviderTradeContext' export function useUpdateBalance(chainId: ChainId, currentChainId: ChainId) { + const web3 = useWeb3({ chainId }) const currentAccount = useAccount() const currentProvider = useProviderType() const { NATIVE_TOKEN_ADDRESS } = useTokenConstants() @@ -36,22 +35,7 @@ export function useUpdateBalance(chainId: ChainId, currentChainId: ChainId) { } if (chainId && currentProvider && currentAccount) { - const cacheBalance = currentBalancesSettings.value[currentProvider]?.[chainId] - - let balance: string - - if (cacheBalance) balance = cacheBalance - else { - balance = await Services.Ethereum.getBalance(currentAccount, { - chainId: chainId, - providerType: currentProvider, - }) - await WalletRPC.updateBalances({ - [currentProvider]: { - [chainId]: balance, - }, - }) - } + const balance = await web3.eth.getBalance(currentAccount) dispatchTradeStore({ type: AllProviderTradeActionType.UPDATE_INPUT_TOKEN_BALANCE, @@ -67,5 +51,5 @@ export function useUpdateBalance(chainId: ChainId, currentChainId: ChainId) { : '0', }) } - }, [inputToken, outputToken, currentAccount, currentProvider, chainId, currentChainId, NATIVE_TOKEN_ADDRESS]) + }, [web3, inputToken, outputToken, currentAccount, currentProvider, chainId, currentChainId, NATIVE_TOKEN_ADDRESS]) } diff --git a/packages/mask/src/plugins/Trader/contracts/balancer/useExchangeProxyContract.ts b/packages/mask/src/plugins/Trader/contracts/balancer/useExchangeProxyContract.ts index e3cb26561141..0d2e707df03d 100644 --- a/packages/mask/src/plugins/Trader/contracts/balancer/useExchangeProxyContract.ts +++ b/packages/mask/src/plugins/Trader/contracts/balancer/useExchangeProxyContract.ts @@ -1,9 +1,9 @@ +import type { AbiItem } from 'web3-utils' import ExchangeProxyABI from '@masknet/web3-contracts/abis/ExchangeProxy.json' import type { ExchangeProxy } from '@masknet/web3-contracts/types/ExchangeProxy' import { ChainId, useContract, useTraderConstants } from '@masknet/web3-shared-evm' -import type { AbiItem } from 'web3-utils' export function useExchangeProxyContract(chainId?: ChainId) { const { BALANCER_EXCHANGE_PROXY_ADDRESS } = useTraderConstants(chainId) - return useContract(BALANCER_EXCHANGE_PROXY_ADDRESS, ExchangeProxyABI as AbiItem[], false, chainId) + return useContract(BALANCER_EXCHANGE_PROXY_ADDRESS, ExchangeProxyABI as AbiItem[], chainId) } diff --git a/packages/mask/src/plugins/Trader/contracts/uniswap/usePairContract.ts b/packages/mask/src/plugins/Trader/contracts/uniswap/usePairContract.ts index b551deb216e6..bdb977472aa1 100644 --- a/packages/mask/src/plugins/Trader/contracts/uniswap/usePairContract.ts +++ b/packages/mask/src/plugins/Trader/contracts/uniswap/usePairContract.ts @@ -4,9 +4,9 @@ import PairABI from '@masknet/web3-contracts/abis/Pair.json' import { ChainId, useContract, useContracts } from '@masknet/web3-shared-evm' export function usePairContract(address: string, chainId?: ChainId) { - return useContract(address, PairABI as AbiItem[], false, chainId) + return useContract(address, PairABI as AbiItem[], chainId) } export function usePairContracts(listOfAddress: string[], chainId?: ChainId) { - return useContracts(listOfAddress, PairABI as AbiItem[], false, chainId) + return useContracts(listOfAddress, PairABI as AbiItem[], chainId) } diff --git a/packages/mask/src/plugins/Trader/contracts/uniswap/usePoolContract.ts b/packages/mask/src/plugins/Trader/contracts/uniswap/usePoolContract.ts index 034db0ad33ef..332d2e39585b 100644 --- a/packages/mask/src/plugins/Trader/contracts/uniswap/usePoolContract.ts +++ b/packages/mask/src/plugins/Trader/contracts/uniswap/usePoolContract.ts @@ -8,5 +8,5 @@ export function usePoolContract(address: string) { } export function usePoolContracts(listOfAddress: string[], chainId?: ChainId) { - return useContracts(listOfAddress, PoolStateV3ABI as AbiItem[], false, chainId) + return useContracts(listOfAddress, PoolStateV3ABI as AbiItem[], chainId) } diff --git a/packages/mask/src/plugins/Trader/contracts/uniswap/useQuoterContract.ts b/packages/mask/src/plugins/Trader/contracts/uniswap/useQuoterContract.ts index e7c3b488c0b9..2ff8636ae904 100644 --- a/packages/mask/src/plugins/Trader/contracts/uniswap/useQuoterContract.ts +++ b/packages/mask/src/plugins/Trader/contracts/uniswap/useQuoterContract.ts @@ -5,5 +5,5 @@ import type { AbiItem } from 'web3-utils' export function useQuoterContract(chainId?: ChainId) { const { UNISWAP_V3_QUOTER_ADDRESS } = useTraderConstants(chainId) - return useContract(UNISWAP_V3_QUOTER_ADDRESS, QuoterABI as AbiItem[], false, chainId) + return useContract(UNISWAP_V3_QUOTER_ADDRESS, QuoterABI as AbiItem[], chainId) } diff --git a/packages/mask/src/plugins/Trader/contracts/uniswap/useRouterV2Contract.ts b/packages/mask/src/plugins/Trader/contracts/uniswap/useRouterV2Contract.ts index 90a51cc5e809..07580f224eef 100644 --- a/packages/mask/src/plugins/Trader/contracts/uniswap/useRouterV2Contract.ts +++ b/packages/mask/src/plugins/Trader/contracts/uniswap/useRouterV2Contract.ts @@ -1,8 +1,8 @@ +import type { AbiItem } from 'web3-utils' import RouterV2ABI from '@masknet/web3-contracts/abis/RouterV2.json' import type { RouterV2 } from '@masknet/web3-contracts/types/RouterV2' import { ChainId, useContract } from '@masknet/web3-shared-evm' -import type { AbiItem } from 'web3-utils' export function useRouterV2Contract(address?: string, chainId?: ChainId) { - return useContract(address, RouterV2ABI as AbiItem[], false, chainId) + return useContract(address, RouterV2ABI as AbiItem[], chainId) } diff --git a/packages/mask/src/plugins/Trader/contracts/uniswap/useSwapRouterContract.ts b/packages/mask/src/plugins/Trader/contracts/uniswap/useSwapRouterContract.ts index 4ea98be4b15a..df9b5c1e57e2 100644 --- a/packages/mask/src/plugins/Trader/contracts/uniswap/useSwapRouterContract.ts +++ b/packages/mask/src/plugins/Trader/contracts/uniswap/useSwapRouterContract.ts @@ -1,8 +1,8 @@ +import type { AbiItem } from 'web3-utils' import SwapRouterABI from '@masknet/web3-contracts/abis/SwapRouter.json' import type { SwapRouter } from '@masknet/web3-contracts/types/SwapRouter' import { ChainId, useContract } from '@masknet/web3-shared-evm' -import type { AbiItem } from 'web3-utils' export function useSwapRouterContract(address?: string, chainId?: ChainId) { - return useContract(address, SwapRouterABI as AbiItem[], false, chainId) + return useContract(address, SwapRouterABI as AbiItem[], chainId) } diff --git a/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts b/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts index 644c1f3228d3..a8e5fadbebf0 100644 --- a/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts @@ -4,10 +4,8 @@ import { isNativeTokenAddress, NetworkType, useAccount, - useBlockNumber, useTokenConstants, } from '@masknet/web3-shared-evm' -import { useAsyncRetry } from 'react-use' import { safeUnreachable } from '@dimensiondev/kit' import { ZRX_AFFILIATE_ADDRESS } from '../../constants' import { PluginTraderRPC } from '../../messages' @@ -17,6 +15,7 @@ import { useTradeProviderSettings } from '../useTradeSettings' import { currentNetworkSettings } from '../../../Wallet/settings' import { TargetChainIdContext } from '../useTargetChainIdContext' import { TradeProvider } from '@masknet/public-api' +import { useDoubleBlockBeatRetry } from '@masknet/plugin-infra' const NATIVE_TOKEN_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' @@ -53,11 +52,10 @@ export function useTrade( const account = useAccount() const { targetChainId } = TargetChainIdContext.useContainer() const { NATIVE_TOKEN_ADDRESS } = useTokenConstants(targetChainId) - const blockNumber = useBlockNumber() const slippage = useSlippageTolerance() const { pools } = useTradeProviderSettings(TradeProvider.ZRX) - return useAsyncRetry(async () => { + return useDoubleBlockBeatRetry(async () => { if (!inputToken || !outputToken) return null const isExactIn = strategy === TradeStrategy.ExactIn if (inputAmount === '0' && isExactIn) return null @@ -92,6 +90,5 @@ export function useTrade( outputToken?.address, slippage, pools.length, - blockNumber, // refresh api each block ]) } diff --git a/packages/mask/src/plugins/Trader/trader/0x/useTradeCallback.ts b/packages/mask/src/plugins/Trader/trader/0x/useTradeCallback.ts index c099d237ba1c..a87fd4822a04 100644 --- a/packages/mask/src/plugins/Trader/trader/0x/useTradeCallback.ts +++ b/packages/mask/src/plugins/Trader/trader/0x/useTradeCallback.ts @@ -11,7 +11,7 @@ export function useTradeCallback(tradeComputed: TradeComputed const account = useAccount() const { targetChainId: chainId } = TargetChainIdContext.useContainer() - const web3 = useWeb3(false, chainId) + const web3 = useWeb3({ chainId }) const [tradeState, setTradeState] = useState({ type: TransactionStateType.UNKNOWN, }) diff --git a/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts b/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts index df738baab06f..5903d1161632 100644 --- a/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts @@ -1,10 +1,5 @@ -import { - FungibleTokenDetailed, - isNativeTokenAddress, - useBlockNumber, - useTokenConstants, -} from '@masknet/web3-shared-evm' -import { useAsyncRetry } from 'react-use' +import { useDoubleBlockBeatRetry } from '@masknet/plugin-infra' +import { FungibleTokenDetailed, isNativeTokenAddress, useTokenConstants } from '@masknet/web3-shared-evm' import { BALANCER_SWAP_TYPE } from '../../constants' import { PluginTraderRPC } from '../../messages' import { SwapResponse, TradeStrategy } from '../../types' @@ -17,11 +12,10 @@ export function useTrade( inputToken?: FungibleTokenDetailed, outputToken?: FungibleTokenDetailed, ) { - const blockNumber = useBlockNumber() const { targetChainId } = TargetChainIdContext.useContainer() const { WNATIVE_ADDRESS } = useTokenConstants(targetChainId) - return useAsyncRetry(async () => { + return useDoubleBlockBeatRetry(async () => { if (!WNATIVE_ADDRESS) return null if (!inputToken || !outputToken) return null const isExactIn = strategy === TradeStrategy.ExactIn @@ -40,14 +34,5 @@ export function useTrade( // no pool found if (!swaps[0].length) return null return { swaps, routes } as SwapResponse - }, [ - WNATIVE_ADDRESS, - strategy, - targetChainId, - inputAmount, - outputAmount, - inputToken?.address, - outputToken?.address, - blockNumber, // refresh api each block - ]) + }, [WNATIVE_ADDRESS, strategy, targetChainId, inputAmount, outputAmount, inputToken?.address, outputToken?.address]) } diff --git a/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts b/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts index 6e3e15c73e15..b08cad56e84a 100644 --- a/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts @@ -1,18 +1,17 @@ import { FungibleTokenDetailed, useAccount, - useBlockNumber, useTokenConstants, useTraderConstants, ChainId, isNativeTokenAddress, } from '@masknet/web3-shared-evm' -import { useAsyncRetry } from 'react-use' import { PluginTraderRPC } from '../../messages' import { TradeStrategy } from '../../types' import { useSlippageTolerance } from './useSlippageTolerance' import { TargetChainIdContext } from '../useTargetChainIdContext' import { leftShift } from '@masknet/web3-shared-base' +import { useDoubleBlockBeatRetry } from '@masknet/plugin-infra' export function useTrade( strategy: TradeStrategy, @@ -21,7 +20,6 @@ export function useTrade( inputToken?: FungibleTokenDetailed, outputToken?: FungibleTokenDetailed, ) { - const blockNumber = useBlockNumber() const slippage = useSlippageTolerance() const { targetChainId: chainId } = TargetChainIdContext.useContainer() const { NATIVE_TOKEN_ADDRESS } = useTokenConstants(chainId) @@ -32,7 +30,7 @@ export function useTrade( const outputAmount = leftShift(outputAmountWei, outputToken?.decimals).toFixed() const isExactIn = strategy === TradeStrategy.ExactIn - return useAsyncRetry(async () => { + return useDoubleBlockBeatRetry(async () => { if (!inputToken || !outputToken) return null if (inputAmountWei === '0' && isExactIn) return null if (outputAmountWei === '0' && !isExactIn) return null @@ -65,7 +63,6 @@ export function useTrade( inputToken?.address, outputToken?.address, slippage, - blockNumber, // refresh api each block user, chainId, ]) diff --git a/packages/mask/src/plugins/Trader/trader/bancor/useTradeCallback.ts b/packages/mask/src/plugins/Trader/trader/bancor/useTradeCallback.ts index 4ef89bad20aa..fc65f7159721 100644 --- a/packages/mask/src/plugins/Trader/trader/bancor/useTradeCallback.ts +++ b/packages/mask/src/plugins/Trader/trader/bancor/useTradeCallback.ts @@ -8,7 +8,7 @@ import { TargetChainIdContext } from '../useTargetChainIdContext' export function useTradeCallback(tradeComputed: TradeComputed | null, gasConfig?: GasOptionConfig) { const { targetChainId: chainId } = TargetChainIdContext.useContainer() - const web3 = useWeb3(false, chainId) + const web3 = useWeb3({ chainId }) const account = useAccount() const [tradeState, setTradeState] = useState({ type: TransactionStateType.UNKNOWN, diff --git a/packages/mask/src/plugins/Trader/trader/bancor/useTradeGasLimit.ts b/packages/mask/src/plugins/Trader/trader/bancor/useTradeGasLimit.ts index 72d6715c81c2..36e3e43e97e1 100644 --- a/packages/mask/src/plugins/Trader/trader/bancor/useTradeGasLimit.ts +++ b/packages/mask/src/plugins/Trader/trader/bancor/useTradeGasLimit.ts @@ -1,16 +1,16 @@ -import type { SwapBancorRequest, TradeComputed } from '../../types' -import { useAccount, useWeb3 } from '@masknet/web3-shared-evm' -import { TargetChainIdContext } from '../useTargetChainIdContext' import { useMemo } from 'react' import { useAsync } from 'react-use' -import { PluginTraderRPC } from '../../messages' -import { pick } from 'lodash-unified' import type { AsyncState } from 'react-use/lib/useAsyncFn' +import { pick } from 'lodash-unified' +import { useAccount, useWeb3 } from '@masknet/web3-shared-evm' +import type { SwapBancorRequest, TradeComputed } from '../../types' +import { TargetChainIdContext } from '../useTargetChainIdContext' +import { PluginTraderRPC } from '../../messages' export function useTradeGasLimit(tradeComputed: TradeComputed | null): AsyncState { const { targetChainId } = TargetChainIdContext.useContainer() const account = useAccount() - const web3 = useWeb3(false, targetChainId) + const web3 = useWeb3({ chainId: targetChainId }) const trade: SwapBancorRequest | null = useMemo(() => { if (!account || !tradeComputed?.trade_) return null @@ -27,8 +27,6 @@ export function useTradeGasLimit(tradeComputed: TradeComputed // Note that if approval is required, the API will also return the necessary approval transaction. const tradeTransaction = data.length === 1 ? data[0] : data[1] - const config = pick(tradeTransaction.transaction, ['to', 'data', 'value', 'from']) - - return web3.eth.estimateGas(config) + return web3.eth.estimateGas(pick(tradeTransaction.transaction, ['to', 'data', 'value', 'from'])) }, [trade, account, web3]) } diff --git a/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts b/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts index 130d1de427d4..40421236a45d 100644 --- a/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts @@ -2,17 +2,16 @@ import { FungibleTokenDetailed, isNativeTokenAddress, useAccount, - useBlockNumber, useRPCConstants, useTokenConstants, useTraderConstants, } from '@masknet/web3-shared-evm' -import { useAsyncRetry } from 'react-use' import { PluginTraderRPC } from '../../messages' import type { TradeStrategy } from '../../types' import { useSlippageTolerance } from './useSlippageTolerance' import { first } from 'lodash-unified' import { TargetChainIdContext } from '../useTargetChainIdContext' +import { useDoubleBlockBeatRetry } from '@masknet/plugin-infra' export function useTrade( strategy: TradeStrategy, @@ -21,7 +20,6 @@ export function useTrade( inputToken?: FungibleTokenDetailed, outputToken?: FungibleTokenDetailed, ) { - const blockNumber = useBlockNumber() const slippage = useSlippageTolerance() const { targetChainId: chainId } = TargetChainIdContext.useContainer() const { NATIVE_TOKEN_ADDRESS } = useTokenConstants(chainId) @@ -30,7 +28,7 @@ export function useTrade( const { DODO_ETH_ADDRESS } = useTraderConstants(chainId) const account = useAccount() - return useAsyncRetry(async () => { + return useDoubleBlockBeatRetry(async () => { if (!inputToken || !outputToken) return null if (inputAmount === '0') return null const sellToken = isNativeTokenAddress(inputToken) @@ -57,7 +55,6 @@ export function useTrade( inputToken?.address, outputToken?.address, slippage, - blockNumber, // refresh api each block account, providerURL, chainId, diff --git a/packages/mask/src/plugins/Trader/trader/dodo/useTradeCallback.ts b/packages/mask/src/plugins/Trader/trader/dodo/useTradeCallback.ts index 5169a9e724df..d6c655e0b439 100644 --- a/packages/mask/src/plugins/Trader/trader/dodo/useTradeCallback.ts +++ b/packages/mask/src/plugins/Trader/trader/dodo/useTradeCallback.ts @@ -12,7 +12,7 @@ export function useTradeCallback( ) { const account = useAccount() const { targetChainId: chainId } = TargetChainIdContext.useContainer() - const web3 = useWeb3(false, chainId) + const web3 = useWeb3({ chainId }) const [tradeState, setTradeState] = useState({ type: TransactionStateType.UNKNOWN, diff --git a/packages/mask/src/plugins/Trader/trader/dodo/useTradeGasLimit.ts b/packages/mask/src/plugins/Trader/trader/dodo/useTradeGasLimit.ts index fbd80ff11a33..7d366ffc0877 100644 --- a/packages/mask/src/plugins/Trader/trader/dodo/useTradeGasLimit.ts +++ b/packages/mask/src/plugins/Trader/trader/dodo/useTradeGasLimit.ts @@ -9,7 +9,7 @@ import type { AsyncState } from 'react-use/lib/useAsyncFn' export function useTradeGasLimit(tradeComputed: TradeComputed | null): AsyncState { const { targetChainId } = TargetChainIdContext.useContainer() - const web3 = useWeb3(true, targetChainId) + const web3 = useWeb3({ chainId: targetChainId }) const account = useAccount() const config = useMemo(() => { if (!account || !tradeComputed?.trade_) return null diff --git a/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts b/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts index b441153a7aa4..e1fc6adf60db 100644 --- a/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts @@ -1,19 +1,18 @@ +import { first } from 'lodash-unified' import { FungibleTokenDetailed, isNativeTokenAddress, useAccount, - useBlockNumber, useRPCConstants, useTokenConstants, useTraderConstants, } from '@masknet/web3-shared-evm' -import { useAsyncRetry } from 'react-use' import { PluginTraderRPC } from '../../messages' import type { TradeStrategy } from '../../types' import { TargetChainIdContext } from '../useTargetChainIdContext' import { useSlippageTolerance } from './useSlippageTolerance' import { OPENOCEAN_SUPPORTED_CHAINS } from './constants' -import { first } from 'lodash-unified' +import { useDoubleBlockBeatRetry } from '@masknet/plugin-infra' export function useTrade( strategy: TradeStrategy, @@ -23,7 +22,6 @@ export function useTrade( outputToken?: FungibleTokenDetailed, ) { const { NATIVE_TOKEN_ADDRESS } = useTokenConstants() - const blockNumber = useBlockNumber() const slippage = useSlippageTolerance() const { targetChainId } = TargetChainIdContext.useContainer() const { RPC } = useRPCConstants(targetChainId) @@ -31,7 +29,7 @@ export function useTrade( const { OPENOCEAN_ETH_ADDRESS } = useTraderConstants(targetChainId) const account = useAccount() - return useAsyncRetry(async () => { + return useDoubleBlockBeatRetry(async () => { if (!OPENOCEAN_SUPPORTED_CHAINS.includes(targetChainId)) return null if (!inputToken || !outputToken) return null if (inputAmount === '0') return null @@ -59,7 +57,6 @@ export function useTrade( inputToken?.address, outputToken?.address, slippage, - blockNumber, // refresh api each block account, providerURL, targetChainId, diff --git a/packages/mask/src/plugins/Trader/trader/openocean/useTradeGasLimit.ts b/packages/mask/src/plugins/Trader/trader/openocean/useTradeGasLimit.ts index 255f1a20de8d..4be78c1c26f9 100644 --- a/packages/mask/src/plugins/Trader/trader/openocean/useTradeGasLimit.ts +++ b/packages/mask/src/plugins/Trader/trader/openocean/useTradeGasLimit.ts @@ -11,7 +11,7 @@ import BigNumber from 'bignumber.js' export function useTradeGasLimit(tradeComputed: TradeComputed | null): AsyncState { const { targetChainId } = TargetChainIdContext.useContainer() - const web3 = useWeb3(false, targetChainId) + const web3 = useWeb3({ chainId: targetChainId }) const account = useAccount() const config = useMemo(() => { if (!account || !tradeComputed?.trade_) return null diff --git a/packages/mask/src/plugins/Trader/trader/uniswap/useTradeCallback.ts b/packages/mask/src/plugins/Trader/trader/uniswap/useTradeCallback.ts index 4e5d8e26bd0b..dbb578d547f6 100644 --- a/packages/mask/src/plugins/Trader/trader/uniswap/useTradeCallback.ts +++ b/packages/mask/src/plugins/Trader/trader/uniswap/useTradeCallback.ts @@ -33,7 +33,7 @@ export function useTradeCallback( gasConfig?: GasOptionConfig, ) { const { targetChainId } = TargetChainIdContext.useContainer() - const web3 = useWeb3(false, targetChainId) + const web3 = useWeb3({ chainId: targetChainId }) const account = useAccount() const tradeParameters = useTradeParameters(trade, tradeProvider) diff --git a/packages/mask/src/plugins/Trader/trader/uniswap/useTradeGasLimit.ts b/packages/mask/src/plugins/Trader/trader/uniswap/useTradeGasLimit.ts index 4b1daf5cf5bf..34845e5f4fdb 100644 --- a/packages/mask/src/plugins/Trader/trader/uniswap/useTradeGasLimit.ts +++ b/packages/mask/src/plugins/Trader/trader/uniswap/useTradeGasLimit.ts @@ -31,7 +31,7 @@ interface FailedCall extends SwapCallEstimate { export function useTradeGasLimit(trade: TradeComputed | null, tradeProvider: TradeProvider): AsyncState { const { targetChainId } = TargetChainIdContext.useContainer() - const web3 = useWeb3(false, targetChainId) + const web3 = useWeb3({ chainId: targetChainId }) const account = useAccount() const tradeParameters = useTradeParameters(trade, tradeProvider) diff --git a/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts b/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts index 4a3149edcecf..17b121456374 100644 --- a/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts +++ b/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts @@ -1,15 +1,12 @@ -import type { ChainId } from '@masknet/web3-shared-evm' import { useAsync } from 'react-use' -import { useChainId } from '@masknet/web3-shared-evm' -import Services from '../../../extension/service' import type { AsyncState } from 'react-use/lib/useAsyncFn' +import { ChainId, useChainId, useWeb3 } from '@masknet/web3-shared-evm' export function useTargetBlockNumber(targetChainId?: ChainId): AsyncState { const chainId = useChainId() + const web3 = useWeb3({ chainId }) return useAsync(async () => { if (targetChainId === chainId) return undefined - return Services.Ethereum.getBlockNumber({ - chainId: targetChainId, - }) - }, [targetChainId, chainId]) + return web3.eth.getBlockNumber() + }, [targetChainId, chainId, web3]) } diff --git a/packages/mask/src/plugins/Wallet/Dashboard/index.tsx b/packages/mask/src/plugins/Wallet/Dashboard/index.tsx index 0bf2d4e9775c..9a70a55c4cc2 100644 --- a/packages/mask/src/plugins/Wallet/Dashboard/index.tsx +++ b/packages/mask/src/plugins/Wallet/Dashboard/index.tsx @@ -9,7 +9,6 @@ import { WalletStatusDialog } from '../SNSAdaptor/WalletStatusDialog' import { WalletRenameWalletDialog } from '../SNSAdaptor/RenameWalletDialog' import { TransactionDialog } from '../SNSAdaptor/TransactionDialog' import { ConnectWalletDialog } from '../SNSAdaptor/ConnectWalletDialog' -import { useStartWatchChainState } from '../hooks/useStartWatchChainState' import { WalletRiskWarningDialog } from '../SNSAdaptor/RiskWarningDialog' import { GasSettingDialog } from '../SNSAdaptor/GasSettingDialog' import { TransactionSnackbar } from '../SNSAdaptor/TransactionSnackbar' @@ -19,7 +18,6 @@ const dashboard: Plugin.Dashboard.Definition = { ...base, init(signal) {}, GlobalInjection: function Component() { - useStartWatchChainState() return ( <> diff --git a/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx b/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx index 771f47999906..954cdf2aa90f 100644 --- a/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx +++ b/packages/mask/src/plugins/Wallet/SNSAdaptor/index.tsx @@ -9,7 +9,6 @@ import { WalletStatusDialog } from './WalletStatusDialog' import { WalletRenameWalletDialog } from './RenameWalletDialog' import { TransactionDialog } from './TransactionDialog' import { ConnectWalletDialog } from './ConnectWalletDialog' -import { useStartWatchChainState } from '../hooks/useStartWatchChainState' import { WalletRiskWarningDialog } from './RiskWarningDialog' import { GasSettingDialog } from './GasSettingDialog' import { TransactionSnackbar } from './TransactionSnackbar' @@ -19,7 +18,6 @@ const sns: Plugin.SNSAdaptor.Definition = { ...base, init(signal) {}, GlobalInjection: function Component() { - useStartWatchChainState() return ( <> diff --git a/packages/mask/src/plugins/Wallet/hooks/useRecentTransactions.ts b/packages/mask/src/plugins/Wallet/hooks/useRecentTransactions.ts index b8c79e02bc51..5b200f1baca5 100644 --- a/packages/mask/src/plugins/Wallet/hooks/useRecentTransactions.ts +++ b/packages/mask/src/plugins/Wallet/hooks/useRecentTransactions.ts @@ -1,18 +1,18 @@ import { useEffect } from 'react' import { useAsyncRetry } from 'react-use' -import { TransactionStatusType, useAccount, useChainId } from '@masknet/web3-shared-evm' +import { useAccount, useChainId } from '@masknet/web3-shared-evm' import { WalletRPC } from '../messages' import { WalletMessages } from '@masknet/plugin-wallet' +import type { RecentTransactionOptions } from '../services' -export function useRecentTransactions(status?: TransactionStatusType) { +export function useRecentTransactions(options?: RecentTransactionOptions) { const account = useAccount() const chainId = useChainId() const result = useAsyncRetry(async () => { if (!account) return [] - const transactions = await WalletRPC.getRecentTransactions(chainId, account) - return transactions.filter((x) => (typeof status !== 'undefined' ? x.status === status : true)) - }, [chainId, account, status]) + return WalletRPC.getRecentTransactions(chainId, account, options) + }, [chainId, account, JSON.stringify(options)]) useEffect(() => WalletMessages.events.transactionStateUpdated.on(result.retry), [result.retry]) useEffect(() => WalletMessages.events.transactionsUpdated.on(result.retry), [result.retry]) diff --git a/packages/mask/src/plugins/Wallet/hooks/useStartWatchChainState.ts b/packages/mask/src/plugins/Wallet/hooks/useStartWatchChainState.ts deleted file mode 100644 index 286edf451183..000000000000 --- a/packages/mask/src/plugins/Wallet/hooks/useStartWatchChainState.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { useEffect } from 'react' -import { pollingTask } from '@masknet/shared-base' -import { UPDATE_CHAIN_STATE_DELAY } from '../constants' -import { WalletRPC } from '../messages' - -const task = pollingTask( - async () => { - await WalletRPC.kickToUpdateChainState() - return false - }, - { - autoStart: false, - delay: UPDATE_CHAIN_STATE_DELAY, - }, -) - -export function useStartWatchChainState() { - useEffect(() => { - // emit an updating request immediately - WalletRPC.updateChainState() - }, []) - return useEffect(() => { - // start the polling task - task.reset() - return () => task.cancel() - }, []) -} diff --git a/packages/mask/src/plugins/Wallet/services/chain.ts b/packages/mask/src/plugins/Wallet/services/chain.ts deleted file mode 100644 index bd4d0593997c..000000000000 --- a/packages/mask/src/plugins/Wallet/services/chain.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { throttle } from 'lodash-unified' -import { BalanceOfChains, ProviderType } from '@masknet/web3-shared-evm' -import { pollingTask } from '@masknet/shared-base' -import { getBalance, getBlockNumber, resetAllNonce } from '../../../extension/background-script/EthereumService' -import { startEffects } from '../../../../utils-pure' -import { UPDATE_CHAIN_STATE_DELAY } from '../constants' -import { - currentMaskWalletAccountSettings, - currentAccountSettings, - currentBalanceSettings, - currentBlockNumberSettings, - currentChainIdSettings, - currentMaskWalletBalanceSettings, - currentMaskWalletChainIdSettings, - currentProviderSettings, - currentBalancesSettings, -} from '../settings' - -let beats = 0 -const { run } = startEffects(import.meta.webpackHot) - -export async function kickToUpdateChainState() { - beats += 1 -} - -export async function updateBalances(data: BalanceOfChains) { - const balancesOfChains = { ...currentBalancesSettings.value } - for (const [key, value] of Object.entries(data)) { - balancesOfChains[key] = { - ...balancesOfChains[key], - ...value, - } - } - - currentBalancesSettings.value = balancesOfChains -} - -export async function updateChainState() { - // reset the polling task cause it will be called from service call - resetPoolTask() - - // forget those passed beats - beats = 0 - - // update chain state - try { - ;[currentBlockNumberSettings.value, currentBalanceSettings.value, currentMaskWalletBalanceSettings.value] = - await Promise.all([ - getBlockNumber(), - currentAccountSettings.value - ? getBalance(currentAccountSettings.value, { - chainId: currentChainIdSettings.value, - providerType: currentProviderSettings.value, - }).then((value) => { - updateBalances({ - [currentProviderSettings.value]: { - [currentChainIdSettings.value]: value, - }, - }) - return value - }) - : currentBalanceSettings.value, - currentMaskWalletAccountSettings.value - ? getBalance(currentMaskWalletAccountSettings.value, { - chainId: currentMaskWalletChainIdSettings.value, - providerType: ProviderType.MaskWallet, - }) - : currentMaskWalletBalanceSettings.value, - ]) - } catch { - // do nothing - } finally { - // reset the polling if chain state updated successfully - resetPoolTask() - } -} - -export const updateChainStateThrottled = throttle(updateChainState, 300, { - leading: false, - trailing: true, -}) - -let resetPoolTask: () => void = () => {} - -// poll the newest chain state -run(() => { - const { reset, cancel } = pollingTask( - async () => { - if (beats <= 0) return false - await updateChainState() - return false - }, - { - delay: UPDATE_CHAIN_STATE_DELAY, - }, - ) - resetPoolTask = reset - return cancel -}) - -// revalidate chain state if the chainId of current provider was changed -run(() => - currentChainIdSettings.addListener(() => { - updateChainStateThrottled() - if (currentProviderSettings.value === ProviderType.MaskWallet) resetAllNonce() - }), -) -run(() => - currentMaskWalletChainIdSettings.addListener(() => { - updateChainStateThrottled() - resetAllNonce() - }), -) - -// revalidate chain state if the current wallet was changed -run(() => currentAccountSettings.addListener(() => updateChainStateThrottled())) -run(() => currentMaskWalletAccountSettings.addListener(() => updateChainStateThrottled())) diff --git a/packages/mask/src/plugins/Wallet/services/index.ts b/packages/mask/src/plugins/Wallet/services/index.ts index b24f93f2bd2c..6039539ac5d6 100644 --- a/packages/mask/src/plugins/Wallet/services/index.ts +++ b/packages/mask/src/plugins/Wallet/services/index.ts @@ -1,6 +1,5 @@ export * from './addressBook' export * from './account' -export * from './chain' export * from './assets' export * from './transactions' export * from './transaction' diff --git a/packages/mask/src/plugins/Wallet/services/transaction/index.ts b/packages/mask/src/plugins/Wallet/services/transaction/index.ts index b02453de9acb..eedabfac9580 100644 --- a/packages/mask/src/plugins/Wallet/services/transaction/index.ts +++ b/packages/mask/src/plugins/Wallet/services/transaction/index.ts @@ -9,6 +9,12 @@ import * as helpers from './helpers' export * from './progress' export * from './watcher' +export interface RecentTransactionOptions { + status?: TransactionStatusType + receipt?: boolean + computedPayload?: boolean +} + export interface RecentTransaction { at: Date hash: string @@ -42,12 +48,21 @@ export async function clearRecentTransactions(chainId: ChainId, address: string) await database.clearRecentTransactions(chainId, address) } -export async function getRecentTransaction(chainId: ChainId, address: string, hash: string) { - const transactions = await getRecentTransactions(chainId, address) +export async function getRecentTransaction( + chainId: ChainId, + address: string, + hash: string, + options?: RecentTransactionOptions, +) { + const transactions = await getRecentTransactions(chainId, address, options) return transactions.find((x) => x.hash === hash) } -export async function getRecentTransactions(chainId: ChainId, address: string): Promise { +export async function getRecentTransactions( + chainId: ChainId, + address: string, + options?: RecentTransactionOptions, +): Promise { const transactions = await database.getRecentTransactions(chainId, address) const allSettled = await Promise.allSettled( transactions.map>( @@ -64,22 +79,35 @@ export async function getRecentTransactions(chainId: ChainId, address: string): watcher.watchTransaction(chainId, hashReplacement, payloadReplacement) } - return { + const tx: RecentTransaction = { at, hash, hashReplacement, - status: helpers.getReceiptStatus(receipt), - receipt, payload, payloadReplacement, - computedPayload: await getSendTransactionComputedPayload(payloadReplacement ?? payload), + status: helpers.getReceiptStatus(receipt), + receipt: receipt, + } + + if (!options?.receipt) { + delete tx.receipt } + + if (options?.computedPayload) { + tx.computedPayload = await getSendTransactionComputedPayload(payloadReplacement ?? payload) + } + + return tx }, ), ) // compose result const transaction_: RecentTransaction[] = [] - allSettled.forEach((x) => (x.status === 'fulfilled' ? transaction_.push(x.value) : undefined)) + allSettled.forEach((x) => + x.status === 'fulfilled' && (typeof options?.status !== 'undefined' ? x.value.status === options?.status : true) + ? transaction_.push(x.value) + : undefined, + ) return transaction_ } diff --git a/packages/mask/src/plugins/Wallet/services/transaction/watcher.ts b/packages/mask/src/plugins/Wallet/services/transaction/watcher.ts index 9fcc17b748d4..3b9a2eaf3ac7 100644 --- a/packages/mask/src/plugins/Wallet/services/transaction/watcher.ts +++ b/packages/mask/src/plugins/Wallet/services/transaction/watcher.ts @@ -1,4 +1,4 @@ -import { first } from 'lodash-unified' +import { first, uniqBy } from 'lodash-unified' import type { TransactionReceipt } from 'web3-core' import type { JsonRpcPayload } from 'web3-core-helpers' import { WalletMessages } from '@masknet/plugin-wallet' @@ -57,15 +57,21 @@ class Storage { } public getWatchedAccounts(chainId: ChainId) { - return this.getWatched(chainId) - .map(([_, transaction]) => helpers.getPayloadFrom(transaction.payload)) - .filter(Boolean) as string[] + return uniqBy( + this.getWatched(chainId) + .map(([_, transaction]) => helpers.getPayloadFrom(transaction.payload)) + .filter(Boolean) as string[], + (x) => x.toLowerCase(), + ) } public getUnwatchedAccounts(chainId: ChainId) { - return this.getUnwatched(chainId) - .map(([_, transaction]) => helpers.getPayloadFrom(transaction.payload)) - .filter(Boolean) as string[] + return uniqBy( + this.getUnwatched(chainId) + .map(([_, transaction]) => helpers.getPayloadFrom(transaction.payload)) + .filter(Boolean) as string[], + (x) => x.toLowerCase(), + ) } } diff --git a/packages/mask/src/plugins/Wallet/settings.ts b/packages/mask/src/plugins/Wallet/settings.ts index 177a3bd1407c..45c7a5bfebab 100644 --- a/packages/mask/src/plugins/Wallet/settings.ts +++ b/packages/mask/src/plugins/Wallet/settings.ts @@ -1,3 +1,4 @@ +import { isEqual } from 'lodash-unified' import { createGlobalSettings } from '../../settings/createSettings' import { i18n } from '../../../shared-ui/locales_legacy' import { @@ -9,10 +10,8 @@ import { FungibleAssetProvider, ProviderType, LockStatus, - BalanceOfChains, } from '@masknet/web3-shared-evm' import { PLUGIN_ID } from './constants' -import { isEqual } from 'lodash-unified' export const currentMaskWalletAccountSettings = createGlobalSettings( `${PLUGIN_ID}+selectedMaskWalletAddress`, @@ -31,11 +30,6 @@ export const currentMaskWalletChainIdSettings = createGlobalSettings( }, ) -export const currentMaskWalletBalanceSettings = createGlobalSettings(`${PLUGIN_ID}+maskWalletBalance`, '0', { - primary: () => i18n.t('settings_choose_eth_network'), - secondary: () => 'This only affects the built-in wallet.', -}) - export const currentMaskWalletNetworkSettings = createGlobalSettings( `${PLUGIN_ID}+selectedMaskWalletNetwork`, NetworkType.Ethereum, @@ -56,6 +50,11 @@ export const currentAccountSettings = createGlobalSettings(`${PLUGIN_ID} primary: () => 'DO NOT DISPLAY IT IN UI', }) +export const currentChainIdSettings = createGlobalSettings(`${PLUGIN_ID}+chainId`, ChainId.Mainnet, { + primary: () => i18n.t('settings_choose_eth_network'), + secondary: () => 'This only affects the built-in wallet.', +}) + export const currentNetworkSettings = createGlobalSettings( `${PLUGIN_ID}+selectedWalletNetwork`, NetworkType.Ethereum, @@ -90,19 +89,6 @@ export const currentNonFungibleAssetDataProviderSettings = createGlobalSettings< }, ) -export const currentChainIdSettings = createGlobalSettings(`${PLUGIN_ID}+chainId`, ChainId.Mainnet, { - primary: () => i18n.t('settings_choose_eth_network'), - secondary: () => 'This only affects the built-in wallet.', -}) - -export const currentBlockNumberSettings = createGlobalSettings(`${PLUGIN_ID}+blockNumber`, 0, { - primary: () => 'DO NOT DISPLAY IT IN UI', -}) - -export const currentBalanceSettings = createGlobalSettings(`${PLUGIN_ID}+balance`, '0', { - primary: () => 'DO NOT DISPLAY IT IN UI', -}) - export const currentGasOptionsSettings = createGlobalSettings( `${PLUGIN_ID}+gasOptions`, null, @@ -112,9 +98,6 @@ export const currentGasOptionsSettings = createGlobalSettings (a: GasOptions | null, b: GasOptions | null) => isEqual(a, b), ) -/** - * ERC20 Token prices or native token prices - */ export const currentTokenPricesSettings = createGlobalSettings( `${PLUGIN_ID}+tokenPrices`, {}, @@ -123,15 +106,3 @@ export const currentTokenPricesSettings = createGlobalSettings( }, (a, b) => isEqual(a, b), ) - -/** - * ERC20 Token balances - */ -export const currentBalancesSettings = createGlobalSettings( - `${PLUGIN_ID}+balances`, - {}, - { - primary: () => 'DO NOT DISPLAY IT IN UI', - }, - (a, b) => isEqual(a, b), -) diff --git a/packages/mask/src/settings/listener.ts b/packages/mask/src/settings/listener.ts index 1cf3e2f29dc6..25631cbccb4e 100644 --- a/packages/mask/src/settings/listener.ts +++ b/packages/mask/src/settings/listener.ts @@ -8,9 +8,6 @@ import { import type { MaskSettingsEvents } from '@masknet/shared-base' import { currentAccountSettings, - currentBalanceSettings, - currentBalancesSettings, - currentBlockNumberSettings, currentChainIdSettings, currentNonFungibleAssetDataProviderSettings, currentNetworkSettings, @@ -40,9 +37,6 @@ export function ToBeListened(): ToBeListedSettings { languageSettings, debugModeSetting, currentChainIdSettings, - currentBalanceSettings, - currentBalancesSettings, - currentBlockNumberSettings, currentTokenPricesSettings, currentDataProviderSettings, currentProviderSettings, diff --git a/packages/mask/src/web3/context.ts b/packages/mask/src/web3/context.ts index 42f79c321070..dd3f6cd093cf 100644 --- a/packages/mask/src/web3/context.ts +++ b/packages/mask/src/web3/context.ts @@ -13,8 +13,6 @@ import { import { isPopupPage } from '@masknet/shared-base' import { bridgedCoin98Provider, bridgedEthereumProvider } from '@masknet/injected-script' import { - currentBlockNumberSettings, - currentBalanceSettings, currentAccountSettings, currentNetworkSettings, currentProviderSettings, @@ -24,37 +22,15 @@ import { currentMaskWalletChainIdSettings, currentMaskWalletNetworkSettings, currentMaskWalletAccountSettings, - currentMaskWalletBalanceSettings, - currentBalancesSettings, } from '../plugins/Wallet/settings' import { WalletMessages, WalletRPC } from '../plugins/Wallet/messages' import type { InternalSettings } from '../settings/createSettings' import { Flags } from '../../shared' -import { createExternalProvider } from './helpers' import Services from '../extension/service' import { getProxyWebsocketInstance } from '@masknet/web3-shared-base' function createWeb3Context(disablePopup = false, isMask = false): Web3ProviderType { - const Web3Provider = createExternalProvider( - () => - isMask - ? { - account: currentMaskWalletAccountSettings.value, - chainId: currentMaskWalletChainIdSettings.value, - providerType: ProviderType.MaskWallet, - } - : { - account: currentAccountSettings.value, - chainId: currentChainIdSettings.value, - providerType: currentProviderSettings.value, - }, - () => ({ - popupsWindow: !disablePopup, - }), - ) - return { - provider: createStaticSubscription(() => Web3Provider), allowTestnet: createStaticSubscription(() => Flags.wallet_allow_testnet), chainId: createSubscriptionFromSettings(isMask ? currentMaskWalletChainIdSettings : currentChainIdSettings), account: createSubscriptionFromAsync( @@ -94,9 +70,6 @@ function createWeb3Context(disablePopup = false, isMask = false): Web3ProviderTy return () => void [a(), b(), c()] }, ), - balance: createSubscriptionFromSettings(isMask ? currentMaskWalletBalanceSettings : currentBalanceSettings), - balances: createSubscriptionFromSettings(currentBalancesSettings), - blockNumber: createSubscriptionFromSettings(currentBlockNumberSettings), tokenPrices: createSubscriptionFromSettings(currentTokenPricesSettings), walletPrimary: createSubscriptionFromAsync( WalletRPC.getWalletPrimary, @@ -124,11 +97,27 @@ function createWeb3Context(disablePopup = false, isMask = false): Web3ProviderTy WalletMessages.events.erc1155TokensUpdated.on, ), portfolioProvider: createSubscriptionFromSettings(currentFungibleAssetDataProviderSettings), + addToken: WalletRPC.addToken, removeToken: WalletRPC.removeToken, trustToken: WalletRPC.trustToken, blockToken: WalletRPC.blockToken, + request: Services.Ethereum.request, + getSendOverrides: () => + isMask + ? { + account: currentMaskWalletAccountSettings.value, + chainId: currentMaskWalletChainIdSettings.value, + providerType: ProviderType.MaskWallet, + } + : { + account: currentAccountSettings.value, + chainId: currentChainIdSettings.value, + providerType: currentProviderSettings.value, + }, + getRequestOptions: () => ({ popupsWindow: !disablePopup }), + getAssetsList: WalletRPC.getAssetsList, getAssetsListNFT: WalletRPC.getAssetsListNFT, getCollectionsNFT: WalletRPC.getCollectionsNFT, diff --git a/packages/plugin-infra/package.json b/packages/plugin-infra/package.json index 2f1609320c46..46dd21df56e1 100644 --- a/packages/plugin-infra/package.json +++ b/packages/plugin-infra/package.json @@ -9,6 +9,7 @@ "@dimensiondev/holoflows-kit": "^0.9.0-20210902104757-7c3d0d0", "@masknet/shared": "workspace:*", "@masknet/shared-base": "workspace:*", + "@masknet/web3-shared-base": "workspace:*", "@masknet/theme": "workspace:*", "@servie/events": "^3.0.0", "@types/use-subscription": "^1.0.0", diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index 7d033e61de20..dfa026805014 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -22,11 +22,12 @@ export enum TokenType { NonFungible = 'NonFungible', } -type ColorRGB = `rgb(${number}, ${number}, ${number})` -type ColorRGBA = `rgba(${number}, ${number}, ${number}, ${number})` -type ColorHEX = `#${string}${string}${string}${string}${string}${string}` | `#${string}${string}${string}` -type ColorHSL = `hsl(${number}, ${number}%, ${number}%)` -type Color = ColorRGB | ColorRGBA | ColorHEX | ColorHSL +export type Color = + | `rgb(${number}, ${number}, ${number})` + | `rgba(${number}, ${number}, ${number}, ${number})` + | `#${string}${string}${string}${string}${string}${string}` + | `#${string}${string}${string}` + | `hsl(${number}, ${number}%, ${number}%)` export declare namespace Web3Plugin { /** @@ -203,7 +204,7 @@ export declare namespace Web3Plugin { tokens: Token[] } - export type domainAddressBook = { + export type DomainAddressBook = { [chainId: number]: Record | undefined } @@ -214,10 +215,6 @@ export declare namespace Web3Plugin { chainId?: Subscription /** The address of the currently chosen wallet. */ account?: Subscription - /** The balance of the currently chosen account. */ - balance?: Subscription - /** The currently tracked block height. */ - blockNumber?: Subscription /** The network type. */ networkType?: Subscription /** The wallet provider type. */ @@ -263,13 +260,13 @@ export declare namespace Web3Plugin { lookup?: (domain: string) => Promise reverse?: (address: string) => Promise } - export interface TokenManage { + export interface TokenState { addToken: (token: Token) => Promise removeToken: (token: Token) => Promise trustToken: (token: Token) => Promise blockToken: (token: Token) => Promise } - export interface TransactionState { + export interface ProviderState { /** Get latest transactions of given account. */ getTransactions: ( address: string, @@ -295,6 +292,9 @@ export declare namespace Web3Plugin { ) => Promise } export interface Others { + getLatestBlockNumber?: (chainId: number) => Promise + getLatestBalance?: (chainId: number, account: string) => Promise + isChainIdValid?: (chainId: number, allowTestnet: boolean) => boolean getChainDetailed?: (chainId: number) => ChainDetailed | undefined getFungibleTokenMetadata?: (token: FungibleToken) => Promise @@ -316,13 +316,15 @@ export declare namespace Web3Plugin { resolveDomainLink?: (domain: string) => string isValidDomain?: (domain: string) => boolean formatDomainName?: (domain?: string, size?: number) => string | undefined + + getAverageBlockDelay?: (chainId: number, scale?: number) => number } export interface Capabilities { Shared?: SharedState Asset?: AssetState NameService?: NameServiceState - Token?: TokenManage - Transaction?: TransactionState + Token?: TokenState + Provider?: ProviderState TokenList?: TokenListState Utils?: Others } diff --git a/packages/plugin-infra/src/web3/Context.tsx b/packages/plugin-infra/src/web3/Context.tsx index 4b580c3e0d14..0e2fb578cee0 100644 --- a/packages/plugin-infra/src/web3/Context.tsx +++ b/packages/plugin-infra/src/web3/Context.tsx @@ -10,6 +10,7 @@ const ZERO_STRING = createConstantSubscription('0') const USD_CURRENCY = createConstantSubscription(CurrencyType.USD) const EMPTY_STRING = createConstantSubscription('') const EMPTY_ARRAY = createConstantSubscription([]) +const EMPTY_OBJECT = createConstantSubscription({}) const FALSE = createConstantSubscription(false) const NULL = createConstantSubscription(null) @@ -30,8 +31,6 @@ function usePluginWeb3State(pluginID: string, context: Record { + return Utils?.getLatestBalance?.(chainId, account) ?? '0' + }, [account, chainId, Utils]) } diff --git a/packages/plugin-infra/src/web3/useBeat.ts b/packages/plugin-infra/src/web3/useBeat.ts new file mode 100644 index 000000000000..edaccc761f23 --- /dev/null +++ b/packages/plugin-infra/src/web3/useBeat.ts @@ -0,0 +1,20 @@ +import type { DependencyList } from 'react' +import type { AsyncStateRetry } from 'react-use/lib/useAsyncRetry' +import { useBeatRetry } from '@masknet/web3-shared-base' +import { useWeb3State } from '..' +import { useChainId } from './useChainId' + +const DEFAULT_SINGLE_BLOCK_DELAY = 15 * 1000 +const DEFAULT_DOUBLE_BLOCK_DELAY = DEFAULT_SINGLE_BLOCK_DELAY * 2 + +export function useSingleBlockBeatRetry(fn: () => Promise, deps: DependencyList = []): AsyncStateRetry { + const chainId = useChainId() + const { Utils } = useWeb3State() + return useBeatRetry(fn, Utils?.getAverageBlockDelay?.(chainId) ?? DEFAULT_SINGLE_BLOCK_DELAY, deps) +} + +export function useDoubleBlockBeatRetry(fn: () => Promise, deps: DependencyList = []): AsyncStateRetry { + const chainId = useChainId() + const { Utils } = useWeb3State() + return useBeatRetry(fn, Utils?.getAverageBlockDelay?.(chainId, 2) ?? DEFAULT_DOUBLE_BLOCK_DELAY, deps) +} diff --git a/packages/plugin-infra/src/web3/useBlockNumber.ts b/packages/plugin-infra/src/web3/useBlockNumber.ts index 8ba41eb56e8d..b3970cecd4f4 100644 --- a/packages/plugin-infra/src/web3/useBlockNumber.ts +++ b/packages/plugin-infra/src/web3/useBlockNumber.ts @@ -1,23 +1,14 @@ -import { useState, useEffect } from 'react' +import { useAsyncRetry } from 'react-use' +import { useChainId, useWeb3State } from '.' import type { NetworkPluginID } from '..' -import { usePluginWeb3StateContext } from './Context' -/** - * Get the current block number of current chain - */ -export function useBlockNumber(pluginID?: NetworkPluginID) { - return usePluginWeb3StateContext(pluginID).blockNumber -} +export function useBlockNumber(expectedChainId?: number, pluginID?: NetworkPluginID) { + const { Utils } = useWeb3State() + const defaultChainId = useChainId(pluginID) + + const chainId = expectedChainId ?? defaultChainId -/** - * Get the current block number only once - * @returns - */ -export function useBlockNumberOnce(pluginID?: NetworkPluginID) { - const blockNumber = useBlockNumber(pluginID) - const [blockNumberOnce, setBlockNumberOnce] = useState(0) - useEffect(() => { - if (blockNumberOnce === 0 && blockNumber > 0) setBlockNumberOnce(blockNumber) - }, [blockNumber]) - return blockNumberOnce + return useAsyncRetry(async () => { + return Utils?.getLatestBlockNumber?.(chainId) + }, [Utils, chainId]) } diff --git a/packages/plugins/Debugger/src/SNSAdaptor/components/TabContent.tsx b/packages/plugins/Debugger/src/SNSAdaptor/components/TabContent.tsx index 6a3483bac5fd..4fef779fc705 100644 --- a/packages/plugins/Debugger/src/SNSAdaptor/components/TabContent.tsx +++ b/packages/plugins/Debugger/src/SNSAdaptor/components/TabContent.tsx @@ -1,4 +1,4 @@ -import type { Plugin } from '@masknet/plugin-infra' +import { Plugin, useBalance, useBlockNumber } from '@masknet/plugin-infra' import { Box, List, ListItem, ListItemText, Typography } from '@mui/material' export interface TabContentProps { @@ -66,8 +66,16 @@ export function TabContent({ identity, addressNames }: TabContentProps) { ) } + const { value: balance = '0' } = useBalance() + const { value: blockNumber = 0 } = useBlockNumber() + return ( <> + + Balance {balance}
+ BlockNumber {blockNumber}
+
+ Identity diff --git a/packages/shared-base/src/Messages/Mask.ts b/packages/shared-base/src/Messages/Mask.ts index 1c2d071be436..4e9c3aa50922 100644 --- a/packages/shared-base/src/Messages/Mask.ts +++ b/packages/shared-base/src/Messages/Mask.ts @@ -6,7 +6,6 @@ import type { CryptoPrice, NetworkType, ProviderType, - BalanceOfChains, FungibleAssetProvider, NonFungibleAssetProvider, } from '../../../web3-shared/evm' @@ -17,9 +16,6 @@ export interface MaskSettingsEvents { debugModeSetting: boolean pluginIDSettings: string currentChainIdSettings: number - currentBalanceSettings: string - currentBalancesSettings: BalanceOfChains - currentBlockNumberSettings: number currentTokenPricesSettings: CryptoPrice currentDataProviderSettings: DataProvider currentProviderSettings: ProviderType diff --git a/packages/shared/src/UI/components/TokenIcon/index.tsx b/packages/shared/src/UI/components/TokenIcon/index.tsx index 5e2752ac5023..35586d5f78b1 100644 --- a/packages/shared/src/UI/components/TokenIcon/index.tsx +++ b/packages/shared/src/UI/components/TokenIcon/index.tsx @@ -6,7 +6,6 @@ import { getChainDetailed, getTokenConstants, isSameAddress, - useBlockie, useChainId, useTokenAssetBaseURLConstants, } from '@masknet/web3-shared-evm' @@ -56,7 +55,6 @@ export function TokenIcon(props: TokenIconProps) { const { TOKEN_ASSET_BASE_URI } = useTokenAssetBaseURLConstants(chainId) const fallbackLogos = getFallbackIcons(address, TOKEN_ASSET_BASE_URI ?? []) - const tokenBlockie = useBlockie(address) const images = _logoURI ? Array.isArray(_logoURI) ? [..._logoURI, ...fallbackLogos] @@ -66,7 +64,7 @@ export function TokenIcon(props: TokenIconProps) { return ( () + /** * Request images from different sources and get the image's url of the loaded * @param urls the url of different image sources @@ -9,12 +11,17 @@ import type { AsyncState } from 'react-use/lib/useAsyncFn' */ export function useImageFailOver(urls: readonly string[], suffix: string): AsyncState { return useAsync(async () => { + const cacheKey = `${urls.join()}_${suffix}` + if (cache.has(cacheKey)) return cache.get(cacheKey) + try { const imgs = urls.map((v) => v + suffix) const img = await findAvailableImageURL(imgs) - return urls[imgs.indexOf(img)] + const url = urls[imgs.indexOf(img)] + cache.set(cacheKey, url) + return url } catch { return '' } - }, [urls.join(''), suffix]) + }, [urls.join(), suffix]) } diff --git a/packages/theme/src/Components/SearchableList/SearchableList.tsx b/packages/theme/src/Components/SearchableList/SearchableList.tsx index 0d85d0dc48aa..d78daa29ce29 100644 --- a/packages/theme/src/Components/SearchableList/SearchableList.tsx +++ b/packages/theme/src/Components/SearchableList/SearchableList.tsx @@ -118,8 +118,8 @@ export function SearchableList({ { + setBeat((x) => (x + 1) % Number.MAX_SAFE_INTEGER) + reset() + }, delay) + return beat +} + +export function useBeatRetry(fn: () => Promise, delay = 1000, deps: DependencyList = []): AsyncStateRetry { + const beat = useBeat(delay) + return useAsyncRetry(fn, [beat].concat(deps)) +} diff --git a/packages/web3-shared/base/index.ts b/packages/web3-shared/base/index.ts index d2cace8c6e1e..043d66c81a42 100644 --- a/packages/web3-shared/base/index.ts +++ b/packages/web3-shared/base/index.ts @@ -1,2 +1,3 @@ +export * from './hooks' export * from './utils' export * from './proxy' diff --git a/packages/web3-shared/base/package.json b/packages/web3-shared/base/package.json index 91c7c3c9f2c8..c3bcb43599bb 100644 --- a/packages/web3-shared/base/package.json +++ b/packages/web3-shared/base/package.json @@ -5,6 +5,7 @@ "types": "./dist/index.d.ts", "dependencies": { "bignumber.js": "9.0.2", + "react-use": "^17.3.1", "date-fns": "^2.27.0", "reconnecting-websocket": "^4.4.0" }, diff --git a/packages/web3-shared/evm/context/index.tsx b/packages/web3-shared/evm/context/index.tsx index 209c9ed3fb89..b27b668d0748 100644 --- a/packages/web3-shared/evm/context/index.tsx +++ b/packages/web3-shared/evm/context/index.tsx @@ -19,9 +19,6 @@ export function useWeb3State() { const _ = useWeb3Context() const account = useSubscription(_.account) const allowTestnet = useSubscription(_.allowTestnet) - const balance = useSubscription(_.balance) - const balances = useSubscription(_.balances) - const blockNumber = useSubscription(_.blockNumber) const tokenPrices = useSubscription(_.tokenPrices) const networkType = useSubscription(_.networkType) const providerType = useSubscription(_.providerType) @@ -34,12 +31,9 @@ export function useWeb3State() { const erc1155Tokens = useSubscription(_.erc1155Tokens) const portfolioProvider = useSubscription(_.portfolioProvider) return { - balances, allowTestnet, account, tokenPrices, - balance, - blockNumber, networkType, providerType, walletPrimary, diff --git a/packages/web3-shared/evm/context/type.ts b/packages/web3-shared/evm/context/type.ts index d37be05935a7..1f1d4d2e4fc1 100644 --- a/packages/web3-shared/evm/context/type.ts +++ b/packages/web3-shared/evm/context/type.ts @@ -1,4 +1,4 @@ -import type { provider as Provider } from 'web3-core' +import type { RequestArguments } from 'web3-core' import type { Subscription } from 'use-subscription' import type { ChainId, @@ -15,8 +15,9 @@ import type { Transaction, AddressName, CryptoPrice, - BalanceOfChains, ERC721TokenCollectionInfo, + SendOverrides, + RequestOptions, } from '../types' import type { ProviderProxy } from '@masknet/web3-shared-base' @@ -24,10 +25,6 @@ export interface Web3ProviderType { allowTestnet: Subscription chainId: Subscription account: Subscription - balance: Subscription - balances: Subscription - blockNumber: Subscription - provider: Subscription networkType: Subscription providerType: Subscription tokenPrices: Subscription @@ -43,6 +40,14 @@ export interface Web3ProviderType { trustToken: (address: string, token: ERC20TokenDetailed | NonFungibleTokenDetailed) => Promise blockToken: (address: string, token: ERC20TokenDetailed | NonFungibleTokenDetailed) => Promise + request: ( + requestArguments: RequestArguments, + overrides?: SendOverrides, + options?: RequestOptions, + ) => Promise + getSendOverrides?: () => SendOverrides + getRequestOptions?: () => RequestOptions + getAssetsList: (address: string, provider: FungibleAssetProvider, network?: NetworkType) => Promise getAssetsListNFT: ( address: string, diff --git a/packages/web3-shared/evm/contracts/useERC20TokenBytes32Contract.ts b/packages/web3-shared/evm/contracts/useERC20TokenBytes32Contract.ts index 356b08c6058b..db72ff89e7e1 100644 --- a/packages/web3-shared/evm/contracts/useERC20TokenBytes32Contract.ts +++ b/packages/web3-shared/evm/contracts/useERC20TokenBytes32Contract.ts @@ -7,6 +7,6 @@ export function useERC20TokenBytes32Contract(address?: string) { return useContract(address, ERC20Bytes32ABI as AbiItem[]) } -export function useERC20TokenBytes32Contracts(listOfAddress: string[], readonly = false) { - return useContracts(listOfAddress, ERC20Bytes32ABI as AbiItem[], readonly) +export function useERC20TokenBytes32Contracts(listOfAddress: string[]) { + return useContracts(listOfAddress, ERC20Bytes32ABI as AbiItem[]) } diff --git a/packages/web3-shared/evm/contracts/useERC20TokenContract.ts b/packages/web3-shared/evm/contracts/useERC20TokenContract.ts index 4f8ad85e7e0e..e7e95e4af616 100644 --- a/packages/web3-shared/evm/contracts/useERC20TokenContract.ts +++ b/packages/web3-shared/evm/contracts/useERC20TokenContract.ts @@ -1,12 +1,12 @@ +import type { AbiItem } from 'web3-utils' import ERC20ABI from '@masknet/web3-contracts/abis/ERC20.json' import type { ERC20 } from '@masknet/web3-contracts/types/ERC20' -import type { AbiItem } from 'web3-utils' import { useContract, useContracts } from '../hooks/useContract' -export function useERC20TokenContract(address?: string, readonly = false) { +export function useERC20TokenContract(address?: string) { return useContract(address, ERC20ABI as AbiItem[]) } -export function useERC20TokenContracts(listOfAddress: string[], readonly = false) { - return useContracts(listOfAddress, ERC20ABI as AbiItem[], readonly) +export function useERC20TokenContracts(listOfAddress: string[]) { + return useContracts(listOfAddress, ERC20ABI as AbiItem[]) } diff --git a/packages/web3-shared/evm/contracts/useERC721TokenContract.ts b/packages/web3-shared/evm/contracts/useERC721TokenContract.ts index 5d5a5c9d06e8..49e4e3d2c548 100644 --- a/packages/web3-shared/evm/contracts/useERC721TokenContract.ts +++ b/packages/web3-shared/evm/contracts/useERC721TokenContract.ts @@ -1,8 +1,8 @@ +import type { AbiItem } from 'web3-utils' import ERC721ABI from '@masknet/web3-contracts/abis/ERC721.json' import type { ERC721 } from '@masknet/web3-contracts/types/ERC721' -import type { AbiItem } from 'web3-utils' import { useContract } from '../hooks/useContract' -export function useERC721TokenContract(address?: string, readonly = false) { - return useContract(address, ERC721ABI as AbiItem[], readonly) +export function useERC721TokenContract(address?: string) { + return useContract(address, ERC721ABI as AbiItem[]) } diff --git a/packages/web3-shared/evm/hooks/index.ts b/packages/web3-shared/evm/hooks/index.ts index 263cf63cdd76..82661294abc2 100644 --- a/packages/web3-shared/evm/hooks/index.ts +++ b/packages/web3-shared/evm/hooks/index.ts @@ -41,7 +41,6 @@ export * from './useFungibleTokenDetailed' export * from './useTokenTransferCallback' export * from './useFungibleTokenWatched' export * from './useTokensBalance' -export * from './useTransaction' export * from './useTransactionState' export * from './useTransactionCallback' export * from './useWeb3' diff --git a/packages/web3-shared/evm/hooks/useAssetsFromChain.ts b/packages/web3-shared/evm/hooks/useAssetsFromChain.ts index 17e7c584254e..4fb1bbd52aca 100644 --- a/packages/web3-shared/evm/hooks/useAssetsFromChain.ts +++ b/packages/web3-shared/evm/hooks/useAssetsFromChain.ts @@ -1,20 +1,13 @@ +import { useMemo } from 'react' import { first } from 'lodash-unified' import { Asset, ChainId, EthereumTokenType, FungibleTokenDetailed } from '../types' import { useTokensBalance } from './useTokensBalance' import { useChainDetailed } from './useChainDetailed' -import { useBalance } from './useBalance' import { getChainDetailed, EMPTY_LIST } from '../utils' -import { useProviderType } from './useProviderType' -import { useBalances } from './useBalances' -import { useMemo } from 'react' +import { useBalance } from '.' export function useAssetsFromChain(tokens: FungibleTokenDetailed[], chainId?: ChainId) { - const providerType = useProviderType() - const balances = useBalances() - const currentBalance = useBalance() - - const balance = - chainId && balances && balances[providerType] && providerType ? balances[providerType][chainId] : currentBalance + const { value: balance = '0' } = useBalance(chainId) const chainDetailed = useChainDetailed() const passedChainDetailed = getChainDetailed(chainId) diff --git a/packages/web3-shared/evm/hooks/useBalance.ts b/packages/web3-shared/evm/hooks/useBalance.ts index 3c4af70699ea..0dd53e4b6e4a 100644 --- a/packages/web3-shared/evm/hooks/useBalance.ts +++ b/packages/web3-shared/evm/hooks/useBalance.ts @@ -1,41 +1,18 @@ -import { first } from 'lodash-unified' -import { useAsync } from 'react-use' -import { useWeb3StateContext } from '../context' -import { useWeb3 } from '../hooks' -import { ChainId, ProviderType, NetworkType } from '../types' -import { getChainIdFromNetworkType } from '../utils' -import { getRPCConstants } from '../constants' +import type { ChainId } from '../types' +import { useAccount, useChainId } from '..' +import { useWeb3 } from '.' +import { useAsyncRetry } from 'react-use' -/** - * Get the current block number - */ -export function useBalance() { - return useWeb3StateContext().balance -} +export function useBalance(expectedChainId?: ChainId, expectedAccount?: string) { + const defaultChainId = useChainId() + const defaultAccount = useAccount() -export function useChainBalance(account: string, chainId: ChainId, providerType: ProviderType) { - const web3 = useWeb3(true, chainId) - return useAsync(async () => (account ? web3.eth.getBalance(account) : null), [account, chainId, providerType]) -} + const chainId = expectedChainId ?? defaultChainId + const account = expectedAccount ?? defaultAccount -export function useChainBalanceList(account: string, providerType: ProviderType) { - const web3 = useWeb3(true) - const chainIdList = Object.keys(NetworkType).map((x) => getChainIdFromNetworkType(x as NetworkType)) + const web3 = useWeb3({ chainId }) - return useAsync(async () => { - if (!account) return null - const allRequest = chainIdList.map(async (chainId) => { - const { RPC } = getRPCConstants(chainId) - const providerURL = first(RPC) - let balance = '0' - if (providerURL) { - web3.setProvider(providerURL) - balance = await web3.eth.getBalance(account) - } - return { balance, chainId } - }) - return (await Promise.allSettled(allRequest)) - .map((x) => (x.status === 'fulfilled' ? x.value : undefined)) - .filter((value) => value) as { balance: string; chainId: ChainId }[] - }, [account, providerType]) + return useAsyncRetry(async () => { + return web3.eth.getBalance(account) + }, [web3, account]) } diff --git a/packages/web3-shared/evm/hooks/useBalances.ts b/packages/web3-shared/evm/hooks/useBalances.ts deleted file mode 100644 index 3d7fd4156510..000000000000 --- a/packages/web3-shared/evm/hooks/useBalances.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { useWeb3StateContext } from '../context' - -export function useBalances() { - return useWeb3StateContext().balances -} diff --git a/packages/web3-shared/evm/hooks/useBlockNumber.ts b/packages/web3-shared/evm/hooks/useBlockNumber.ts index b1b76d4c744c..c0c0f92abe61 100644 --- a/packages/web3-shared/evm/hooks/useBlockNumber.ts +++ b/packages/web3-shared/evm/hooks/useBlockNumber.ts @@ -1,22 +1,15 @@ -import { useState, useEffect } from 'react' -import { useWeb3StateContext } from '../context' +import { useAsyncRetry } from 'react-use' +import { useChainId, useWeb3 } from '.' +import type { ChainId } from '..' /** * Get the current block number of current chain */ -export function useBlockNumber() { - return useWeb3StateContext().blockNumber -} +export function useBlockNumber(expectedChainId?: ChainId) { + const defaultChainId = useChainId() + const web3 = useWeb3({ chainId: expectedChainId ?? defaultChainId }) -/** - * Get the current block number only once - * @returns - */ -export function useBlockNumberOnce() { - const blockNumber = useBlockNumber() - const [blockNumberOnce, setBlockNumberOnce] = useState(0) - useEffect(() => { - if (blockNumberOnce === 0 && blockNumber > 0) setBlockNumberOnce(blockNumber) - }, [blockNumber]) - return blockNumberOnce + return useAsyncRetry(async () => { + return web3.eth.getBlockNumber() + }, [web3]) } diff --git a/packages/web3-shared/evm/hooks/useContract.ts b/packages/web3-shared/evm/hooks/useContract.ts index 62ec14ef299f..f850eff62c6c 100644 --- a/packages/web3-shared/evm/hooks/useContract.ts +++ b/packages/web3-shared/evm/hooks/useContract.ts @@ -20,13 +20,8 @@ export function createContract(web3: Web3, address: stri * @param address * @param ABI */ -export function useContract( - address = '', - ABI: AbiItem[] = [], - readonly = false, - chainId?: ChainId, -) { - const web3 = useWeb3(readonly, chainId) +export function useContract(address = '', ABI: AbiItem[] = [], chainId?: ChainId) { + const web3 = useWeb3({ chainId }) return useMemo(() => createContract(web3, address, ABI), [web3, address, ABI]) } @@ -35,13 +30,8 @@ export function useContract( * @param listOfAddress * @param ABI */ -export function useContracts( - listOfAddress: string[], - ABI: AbiItem[] = [], - readonly = false, - chainId?: ChainId, -) { - const web3 = useWeb3(readonly, chainId) +export function useContracts(listOfAddress: string[], ABI: AbiItem[] = [], chainId?: ChainId) { + const web3 = useWeb3({ chainId }) const contracts = useMemo( () => listOfAddress.map((address) => createContract(web3, address, ABI)), [web3, JSON.stringify(listOfAddress), ABI], diff --git a/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts b/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts index 9edb167937a8..822c602aa7ce 100644 --- a/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts +++ b/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts @@ -1,18 +1,20 @@ -import { useAsyncRetry } from 'react-use' +import { useBeatRetry } from '@masknet/web3-shared-base' import { useERC20TokenContract } from '../contracts/useERC20TokenContract' import { useAccount } from './useAccount' import { useChainId } from './useChainId' -import { useBlockNumber } from './useBlockNumber' export function useERC20TokenAllowance(address?: string, spender?: string) { const account = useAccount() const chainId = useChainId() - const blockNumber = useBlockNumber() const erc20Contract = useERC20TokenContract(address) - return useAsyncRetry(async () => { - if (!account || !spender || !erc20Contract) return '0' - return erc20Contract.methods.allowance(account, spender).call({ - from: account, - }) - }, [account, blockNumber, chainId, spender, erc20Contract]) + return useBeatRetry( + async () => { + if (!account || !spender || !erc20Contract) return '0' + return erc20Contract.methods.allowance(account, spender).call({ + from: account, + }) + }, + 30 * 1000, + [account, chainId, spender, erc20Contract], + ) } diff --git a/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts b/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts index 49587dc6a146..d47fa9c99f1c 100644 --- a/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts +++ b/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts @@ -1,10 +1,9 @@ -import { useAsyncRetry } from 'react-use' +import { toHex } from 'web3-utils' +import { useBeatRetry } from '@masknet/web3-shared-base' import { useAccount } from './useAccount' import { useERC20TokenContract } from '../contracts/useERC20TokenContract' import { useChainId } from './useChainId' -import { useBlockNumber } from './useBlockNumber' import type { ChainId } from '../types' -import { toHex } from 'web3-utils' /** * Fetch token balance from chain @@ -13,15 +12,18 @@ import { toHex } from 'web3-utils' */ export function useERC20TokenBalance(address?: string, targetChainId?: ChainId) { const account = useAccount() - const currentChainId = useChainId() - const chainId = targetChainId ?? currentChainId - const blockNumber = useBlockNumber() + const defaultChainId = useChainId() + const chainId = targetChainId ?? defaultChainId const erc20Contract = useERC20TokenContract(address) - return useAsyncRetry(async () => { - if (!account || !address || !erc20Contract) return undefined - return erc20Contract.methods.balanceOf(account).call({ - from: account, - chainId: toHex(chainId), - }) - }, [account, blockNumber, chainId, address, erc20Contract]) + return useBeatRetry( + async () => { + if (!account || !address || !erc20Contract) return undefined + return erc20Contract.methods.balanceOf(account).call({ + from: account, + chainId: toHex(chainId), + }) + }, + 30 * 1000, + [account, chainId, address, erc20Contract], + ) } diff --git a/packages/web3-shared/evm/hooks/useERC20TokenDetailed.ts b/packages/web3-shared/evm/hooks/useERC20TokenDetailed.ts index 625abdc4c10c..7468a641c8e7 100644 --- a/packages/web3-shared/evm/hooks/useERC20TokenDetailed.ts +++ b/packages/web3-shared/evm/hooks/useERC20TokenDetailed.ts @@ -27,8 +27,8 @@ export function useFungibleTokensDetailed(listOfToken: Pick listOfToken.map((t) => t.address), [JSON.stringify(listOfToken)]) - const erc20TokenContracts = useERC20TokenContracts(listOfAddress, true) - const erc20TokenBytes32Contracts = useERC20TokenBytes32Contracts(listOfAddress, true) + const erc20TokenContracts = useERC20TokenContracts(listOfAddress) + const erc20TokenBytes32Contracts = useERC20TokenBytes32Contracts(listOfAddress) return useAsyncRetry( async () => diff --git a/packages/web3-shared/evm/hooks/useERC721TokenDetailedOwnerList.ts b/packages/web3-shared/evm/hooks/useERC721TokenDetailedOwnerList.ts index 554b86378e65..dd36436e2e56 100644 --- a/packages/web3-shared/evm/hooks/useERC721TokenDetailedOwnerList.ts +++ b/packages/web3-shared/evm/hooks/useERC721TokenDetailedOwnerList.ts @@ -15,7 +15,7 @@ export const ERC721_ENUMERABLE_INTERFACE_ID = '0x780e9d63' export function useERC721TokenDetailedOwnerList(contractDetailed: ERC721ContractDetailed | undefined, owner: string) { const { GET_ASSETS_URL } = useOpenseaAPIConstants() const chainId = useChainId() - const erc721TokenContract = useERC721TokenContract(contractDetailed?.address ?? '', true) + const erc721TokenContract = useERC721TokenContract(contractDetailed?.address ?? '') const allListRef = useRef([]) const [refreshing, setRefreshing] = useState(false) diff --git a/packages/web3-shared/evm/hooks/useGasPrice.ts b/packages/web3-shared/evm/hooks/useGasPrice.ts index d841fcdec70e..5fab4ea8a116 100644 --- a/packages/web3-shared/evm/hooks/useGasPrice.ts +++ b/packages/web3-shared/evm/hooks/useGasPrice.ts @@ -4,7 +4,7 @@ import { useChainId } from './useChainId' export function useGasPrice() { const chainId = useChainId() - const web3 = useWeb3(true, chainId) + const web3 = useWeb3({ chainId }) return useAsyncRetry(async () => { return web3.eth.getGasPrice() diff --git a/packages/web3-shared/evm/hooks/useMulticall.ts b/packages/web3-shared/evm/hooks/useMulticall.ts index 0e54dc0d5774..d8d7ea9b60e2 100644 --- a/packages/web3-shared/evm/hooks/useMulticall.ts +++ b/packages/web3-shared/evm/hooks/useMulticall.ts @@ -105,8 +105,8 @@ export type MulticallState = export function useMulticallCallback(targetChainId?: ChainId, targetBlockNumber?: number) { const currentChainId = useChainId() const chainId = targetChainId ?? currentChainId - const currentBlockNumber = useBlockNumber() - const blockNumber = targetBlockNumber ?? currentBlockNumber + const { value: defaultBlockNumber = 0 } = useBlockNumber() + const blockNumber = targetBlockNumber ?? defaultBlockNumber const multicallContract = useMulticallContract(chainId) const [multicallState, setMulticallState] = useState({ type: MulticallStateType.UNKNOWN, @@ -165,7 +165,7 @@ export function useMulticallStateDecoded< K extends keyof T['methods'], R extends UnboxTransactionObject>, >(contracts: T[], names: K[], state: MulticallState, chainId?: ChainId) { - const web3 = useWeb3(false, chainId) + const web3 = useWeb3({ chainId }) type Result = { succeed: boolean; gasUsed: string } & ({ error: any; value: null } | { error: null; value: R }) return useMemo(() => { if (state.type !== MulticallStateType.SUCCEED) return [] diff --git a/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts b/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts index e67fb3c6d156..9eb8443bd951 100644 --- a/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts +++ b/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts @@ -1,5 +1,5 @@ -import { useAccount } from './useAccount' import { useAsyncRetry } from 'react-use' +import { useAccount } from './useAccount' import { useBalance } from './useBalance' /** @@ -8,9 +8,9 @@ import { useBalance } from './useBalance' */ export function useNativeTokenBalance() { const account = useAccount() - const balance = useBalance() + const { value: balance = '0' } = useBalance() return useAsyncRetry(async () => { - if (!account) return undefined + if (!account) return return balance }, [account, balance]) } diff --git a/packages/web3-shared/evm/hooks/useResolveENS.ts b/packages/web3-shared/evm/hooks/useResolveENS.ts index 602044603c70..df7b99a8bf6b 100644 --- a/packages/web3-shared/evm/hooks/useResolveENS.ts +++ b/packages/web3-shared/evm/hooks/useResolveENS.ts @@ -3,8 +3,7 @@ import { ChainId } from '../types' import { useWeb3 } from './useWeb3' export function useResolveENS(name: string) { - const web3 = useWeb3(true, ChainId.Mainnet) - + const web3 = useWeb3({ chainId: ChainId.Mainnet }) return useAsyncRetry(async () => { if (!name) return return web3.eth.ens.getAddress(name) diff --git a/packages/web3-shared/evm/hooks/useTransaction.ts b/packages/web3-shared/evm/hooks/useTransaction.ts deleted file mode 100644 index 62611216349e..000000000000 --- a/packages/web3-shared/evm/hooks/useTransaction.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useState } from 'react' -import { useAsync } from 'react-use' -import type { Transaction, TransactionReceipt } from 'web3-core' -import { useAccount } from './useAccount' -import { useBlockNumber } from './useBlockNumber' -import { useWeb3 } from './useWeb3' - -export function useTransaction(hash: string) { - const web3 = useWeb3() - const account = useAccount() - const [tx, setTx] = useState(null) - useAsync(async () => { - if (tx) return - if (!hash) return - setTx(await web3.eth.getTransaction(hash)) - }, [web3, account, hash, tx]) - return tx -} - -export function useTransactionReceipt(hash: string) { - const web3 = useWeb3() - const [receipt, setReceipt] = useState(null) - const account = useAccount() - const blockNumber = useBlockNumber() - useAsync(async () => { - if (!hash) { - setReceipt(null) - return - } - if (receipt?.transactionHash === hash) return - setReceipt(await web3.eth.getTransactionReceipt(hash)) - }, [web3, account, hash, receipt, blockNumber]) - return receipt -} diff --git a/packages/web3-shared/evm/hooks/useWeb3.ts b/packages/web3-shared/evm/hooks/useWeb3.ts index c15f4d19969a..dac97cb76025 100644 --- a/packages/web3-shared/evm/hooks/useWeb3.ts +++ b/packages/web3-shared/evm/hooks/useWeb3.ts @@ -1,24 +1,9 @@ import Web3 from 'web3' import { useMemo } from 'react' -import { first } from 'lodash-unified' -import { useChainId } from './useChainId' import { useWeb3Provider } from './useWeb3Provider' -import type { ChainId } from '../types' -import { useRPCConstants } from '../constants' +import type { RequestOptions, SendOverrides } from '../types' -function useWeb3Instance() { - const provider = useWeb3Provider() +export function useWeb3(overrides?: SendOverrides, options?: RequestOptions) { + const provider = useWeb3Provider(overrides, options) return useMemo(() => new Web3(provider), [provider]) } - -export function useWeb3(readonly = false, chainId?: ChainId) { - const web3 = useWeb3Instance() - const currentChainId = useChainId() - const { RPC } = useRPCConstants(chainId ?? currentChainId) - - return useMemo(() => { - const providerURL = first(RPC) - if (providerURL && readonly) web3.setProvider(providerURL) - return web3 - }, [web3, RPC, readonly]) -} diff --git a/packages/web3-shared/evm/hooks/useWeb3Provider.ts b/packages/web3-shared/evm/hooks/useWeb3Provider.ts index 557cde450fae..08458f4e5239 100644 --- a/packages/web3-shared/evm/hooks/useWeb3Provider.ts +++ b/packages/web3-shared/evm/hooks/useWeb3Provider.ts @@ -1,9 +1,21 @@ -import type { HttpProvider } from 'web3-core' -import { useSubscription } from 'use-subscription' +import { useMemo } from 'react' import { useWeb3Context } from '../context' +import type { RequestOptions, SendOverrides } from '../types' +import { createExternalProvider } from '../utils' -export function useWeb3Provider() { - const _ = useWeb3Context() - const provider = useSubscription(_.provider) - return provider as HttpProvider +export function useWeb3Provider(overrides?: SendOverrides, options?: RequestOptions) { + const { request, getSendOverrides, getRequestOptions } = useWeb3Context() + return useMemo(() => { + return createExternalProvider( + request, + () => ({ + ...getSendOverrides?.(), + ...overrides, + }), + () => ({ + ...getRequestOptions?.(), + ...options, + }), + ) + }, [request, getSendOverrides, getRequestOptions, JSON.stringify(overrides), JSON.stringify(options)]) } diff --git a/packages/web3-shared/evm/types/index.ts b/packages/web3-shared/evm/types/index.ts index 154d6c523c0f..7837ed1df547 100644 --- a/packages/web3-shared/evm/types/index.ts +++ b/packages/web3-shared/evm/types/index.ts @@ -26,11 +26,6 @@ export interface CryptoPrice { export type ChainIdOptionalRecord = { [k in ChainId]?: T } export type ChainIdRecord = { [k in ChainId]: T } -export interface BalanceOfChains { - [provider: string]: { - [chainId: number]: string - } -} // bigint is not in our list. iOS doesn't support that. export type Primitive = string | number | boolean | symbol | undefined | null diff --git a/packages/web3-shared/evm/utils/index.ts b/packages/web3-shared/evm/utils/index.ts index 223bf5607608..5d5011871555 100644 --- a/packages/web3-shared/evm/utils/index.ts +++ b/packages/web3-shared/evm/utils/index.ts @@ -8,3 +8,4 @@ export * from './transaction' export * from './domain' export * from './payload' export * from './misc' +export * from './provider' diff --git a/packages/mask/src/web3/helpers.ts b/packages/web3-shared/evm/utils/provider.ts similarity index 51% rename from packages/mask/src/web3/helpers.ts rename to packages/web3-shared/evm/utils/provider.ts index 50a0d73139d1..fdf81c247868 100644 --- a/packages/mask/src/web3/helpers.ts +++ b/packages/web3-shared/evm/utils/provider.ts @@ -1,11 +1,19 @@ +import Web3 from 'web3' import type { RequestArguments } from 'web3-core' import type { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers' -import type { RequestOptions, SendOverrides } from '@masknet/web3-shared-evm' -import Services from '../extension/service' +import type { RequestOptions, SendOverrides } from '../types' -export function createExternalProvider(getOverrides?: () => SendOverrides, getOptions?: () => RequestOptions) { +export function createExternalProvider( + request: ( + requestArguments: RequestArguments, + overrides?: SendOverrides, + options?: RequestOptions, + ) => Promise, + getOverrides?: () => SendOverrides, + getOptions?: () => RequestOptions, +) { const send = (payload: JsonRpcPayload, callback: (error: Error | null, response?: JsonRpcResponse) => void) => { - Services.Ethereum.request( + request( { method: payload.method, params: payload.params, @@ -25,8 +33,6 @@ export function createExternalProvider(getOverrides?: () => SendOverrides, getOp }, ) } - const request = (requestArguments: RequestArguments) => - Services.Ethereum.request(requestArguments, getOverrides?.(), getOptions?.()) return { isMetaMask: false, @@ -34,8 +40,20 @@ export function createExternalProvider(getOverrides?: () => SendOverrides, getOp isStatus: true, host: '', path: '', - request: request, + request: (requestArguments: RequestArguments) => request(requestArguments, getOverrides?.(), getOptions?.()), send, sendAsync: send, } } + +export function createWeb3( + request: ( + requestArguments: RequestArguments, + overrides?: SendOverrides, + options?: RequestOptions, + ) => Promise, + getOverrides?: () => SendOverrides, + getOptions?: () => RequestOptions, +) { + return new Web3(createExternalProvider(request, getOverrides, getOptions)) +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 96f0a81ce73d..4f8f3eb2f180 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -570,6 +570,7 @@ importers: '@masknet/shared': workspace:* '@masknet/shared-base': workspace:* '@masknet/theme': workspace:* + '@masknet/web3-shared-base': workspace:* '@servie/events': ^3.0.0 '@types/use-subscription': ^1.0.0 async-call-rpc: ^6.0.1 @@ -582,6 +583,7 @@ importers: '@masknet/shared': link:../shared '@masknet/shared-base': link:../shared-base '@masknet/theme': link:../theme + '@masknet/web3-shared-base': link:../web3-shared/base '@servie/events': 3.0.0 '@types/use-subscription': 1.0.0 async-call-rpc: 6.0.1 @@ -1076,10 +1078,12 @@ importers: date-fns: ^2.27.0 jest-websocket-mock: ^2.2.1 mock-socket: ^9.0.8 + react-use: ^17.3.1 reconnecting-websocket: ^4.4.0 dependencies: bignumber.js: 9.0.2 date-fns: 2.27.0 + react-use: 17.3.1_757a802188413a36d4f24237d13b8e90 reconnecting-websocket: 4.4.0 devDependencies: jest-websocket-mock: 2.2.1_mock-socket@9.0.8