From 70ea12bc8c563301bdbea4a5890762d5991b156a Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Wed, 5 Jan 2022 18:13:26 +0800 Subject: [PATCH 01/11] refactor: track block number & balance by chain --- packages/dashboard/src/web3/context.ts | 15 +- .../background-script/SettingsService.ts | 10 +- .../Collectible/apis/openseaFromSDK.ts | 10 +- .../src/plugins/EVM/UI/Web3State/index.ts | 4 +- .../mask/src/plugins/EVM/storage/index.ts | 2 +- .../Trader/SNSAdaptor/trader/Trader.tsx | 35 +--- .../src/plugins/Wallet/Dashboard/index.tsx | 2 - .../src/plugins/Wallet/SNSAdaptor/index.tsx | 2 - .../Wallet/hooks/useStartWatchChainState.ts | 27 --- .../mask/src/plugins/Wallet/services/chain.ts | 193 ++++++++++-------- packages/mask/src/plugins/Wallet/settings.ts | 43 ++-- packages/mask/src/settings/listener.ts | 10 +- packages/mask/src/web3/context.ts | 11 +- packages/plugin-infra/src/web3-types.ts | 23 ++- packages/plugin-infra/src/web3/Context.tsx | 9 +- packages/plugin-infra/src/web3/useBalance.ts | 11 +- .../plugin-infra/src/web3/useBlockNumber.ts | 11 +- .../src/SNSAdaptor/components/TabContent.tsx | 10 +- packages/shared-base/src/Messages/Mask.ts | 8 +- packages/web3-shared/evm/context/index.tsx | 10 +- packages/web3-shared/evm/context/type.ts | 8 +- .../evm/hooks/useAssetsFromChain.ts | 13 +- packages/web3-shared/evm/hooks/useBalance.ts | 47 +---- packages/web3-shared/evm/hooks/useBalances.ts | 5 - .../web3-shared/evm/hooks/useBlockNumber.ts | 8 +- .../evm/hooks/useNativeTokenBalance.ts | 2 +- packages/web3-shared/evm/types/index.ts | 10 +- 27 files changed, 241 insertions(+), 298 deletions(-) delete mode 100644 packages/mask/src/plugins/Wallet/hooks/useStartWatchChainState.ts delete mode 100644 packages/web3-shared/evm/hooks/useBalances.ts diff --git a/packages/dashboard/src/web3/context.ts b/packages/dashboard/src/web3/context.ts index e1d4d70b5824..9835ad5dc476 100644 --- a/packages/dashboard/src/web3/context.ts +++ b/packages/dashboard/src/web3/context.ts @@ -45,16 +45,15 @@ export const Web3Context: Web3ProviderType = { {}, Messages.events.currentTokenPricesSettings.on, ), - balance: createSubscriptionFromAsync(Services.Settings.getBalance, '0', Messages.events.currentBalanceSettings.on), - balances: createSubscriptionFromAsync( - Services.Settings.getBalances, + balanceOfChain: createSubscriptionFromAsync( + Services.Settings.getBalanceOfChain, {}, - Messages.events.currentBalancesSettings.on, + Messages.events.currentBalanceOfChainSettings.on, ), - blockNumber: createSubscriptionFromAsync( - Services.Settings.getBlockNumber, - 0, - Messages.events.currentBlockNumberSettings.on, + blockNumberOfChain: createSubscriptionFromAsync( + Services.Settings.getBlockNumberOfChain, + {}, + Messages.events.currentBlockNumberOfChainSettings.on, ), chainId: createSubscriptionFromAsync( Services.Settings.getChainId, diff --git a/packages/mask/src/extension/background-script/SettingsService.ts b/packages/mask/src/extension/background-script/SettingsService.ts index b8790de613b1..bcd3b0d192a5 100644 --- a/packages/mask/src/extension/background-script/SettingsService.ts +++ b/packages/mask/src/extension/background-script/SettingsService.ts @@ -20,8 +20,6 @@ import { } from '../../plugins/Trader/settings' import { queryMyPersonas } from './IdentityService' import { - currentBalanceSettings, - currentBlockNumberSettings, currentAccountSettings, currentNetworkSettings, currentProviderSettings, @@ -34,7 +32,8 @@ import { currentMaskWalletAccountSettings, currentMaskWalletChainIdSettings, currentMaskWalletNetworkSettings, - currentBalancesSettings, + currentBalanceOfChainSettings, + currentBlockNumberOfChainSettings, } from '../../plugins/Wallet/settings' import { Flags, MaskMessages } from '../../../shared' import { indexedDB_KVStorageBackend, inMemory_KVStorageBackend } from '../../../background/database/kv-storage' @@ -54,9 +53,8 @@ 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 [getBalanceOfChain, setBalanceOfChain] = create(currentBalanceOfChainSettings) +export const [getBlockNumberOfChain, setBlockNumberOfChain] = create(currentBlockNumberOfChainSettings) export const [getTokenPrices, setTokenPrices] = create(currentTokenPricesSettings) export const [getGasOptions, setGasOptions] = create(currentGasOptionsSettings) export const [getGasPrice, setGasPrice] = create(currentGasOptionsSettings) diff --git a/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts b/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts index 5b7108da4ed2..df28bebf0401 100644 --- a/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts +++ b/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts @@ -1,9 +1,8 @@ import { OpenSeaPort } from 'opensea-js' -import type { ChainId } from '@masknet/web3-shared-evm' +import { ChainId } from '@masknet/web3-shared-evm' import { request, requestSend } from '../../../extension/background-script/EthereumService' import { resolveOpenSeaNetwork } from '../pipes' import { OpenSeaAPI_Key, ReferrerAddress } from '../constants' -import { currentChainIdSettings } from '../../Wallet/settings' function createExternalProvider() { return { @@ -26,12 +25,11 @@ function createOpenSeaPortChain(chainId: ChainId.Mainnet | ChainId.Rinkeby) { } 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/index.ts b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts index b7da0c8e6447..349cdc5380bb 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts @@ -36,8 +36,8 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, allowTestnet: context.allowTestnet, chainId: context.chainId, account: context.account, - balance: context.balance, - blockNumber: context.blockNumber, + balanceOfChain: context.balanceOfChain, + blockNumberOfChain: context.blockNumberOfChain, networkType: context.networkType, providerType: context.providerType, walletPrimary: context.walletPrimary, 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/Trader/SNSAdaptor/trader/Trader.tsx b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx index 04f7f3de6b93..6ae39bcc6df0 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/Trader.tsx @@ -15,8 +15,9 @@ import { useChainId, useChainIdValid, useFungibleTokenBalance, - useProviderType, useTokenConstants, + useBalance, + useAccount, useWallet, } from '@masknet/web3-shared-evm' import { isGreaterThan, isLessThan, multipliedBy } from '@masknet/web3-shared-base' @@ -36,8 +37,6 @@ import { isFacebook } from '../../../../social-network-adaptor/facebook.com/base import { useTradeCallback } from '../../trader/useTradeCallback' import { isNativeTokenWrapper } from '../../helpers' import { ConfirmDialog } from './ConfirmDialog' -import Services from '../../../../extension/service' -import { currentBalancesSettings } from '../../../Wallet/settings' import { TargetChainIdContext } from '../../trader/useTargetChainIdContext' import { WalletRPC } from '../../../Wallet/messages' import { PluginTraderMessages } from '../../messages' @@ -45,7 +44,6 @@ import { NetworkType } from '@masknet/public-api' import BigNumber from 'bignumber.js' import { useNativeTokenPrice, useTokenPrice } from '../../../Wallet/hooks/useTokenPrice' import { SettingsDialog } from './SettingsDialog' -import { useAccount } from '@masknet/web3-shared-evm' const useStyles = makeStyles()(() => { return { @@ -71,8 +69,8 @@ export function Trader(props: TraderProps) { const chainId = targetChainId ?? currentChainId const chainIdValid = useChainIdValid() const { NATIVE_TOKEN_ADDRESS } = useTokenConstants() - const currentAccount = useAccount() - const currentProvider = useProviderType() + const account = useAccount() + const balance = useBalance(chainId, account) const classes = useStylesExtends(useStyles(), props) const { t } = useI18N() const { setTargetChainId } = TargetChainIdContext.useContainer() @@ -179,8 +177,8 @@ export function Trader(props: TraderProps) { ]) // Query the balance of native tokens on target chain - useAsync(async () => { - if (!currentAccount) { + useEffect(() => { + if (!account) { dispatchTradeStore({ type: AllProviderTradeActionType.UPDATE_INPUT_TOKEN_BALANCE, balance: '0', @@ -193,24 +191,7 @@ export function Trader(props: TraderProps) { return } - 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, - }, - }) - } - + if (chainId && account) { dispatchTradeStore({ type: AllProviderTradeActionType.UPDATE_INPUT_TOKEN_BALANCE, balance: inputToken?.type === EthereumTokenType.Native ? balance : '0', @@ -225,7 +206,7 @@ export function Trader(props: TraderProps) { : '0', }) } - }, [inputToken, outputToken, currentAccount, currentProvider, chainId, currentChainId]) + }, [inputToken, outputToken, account, chainId, balance]) // #endregion // #region select token 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/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 index bd4d0593997c..3b09b5f82ab7 100644 --- a/packages/mask/src/plugins/Wallet/services/chain.ts +++ b/packages/mask/src/plugins/Wallet/services/chain.ts @@ -1,117 +1,142 @@ -import { throttle } from 'lodash-unified' -import { BalanceOfChains, ProviderType } from '@masknet/web3-shared-evm' -import { pollingTask } from '@masknet/shared-base' +import { throttle, DebouncedFunc, noop, uniq, uniqBy } from 'lodash-unified' +import { EthereumAddress } from 'wallet.ts' +import { getEnumAsArray } from '@dimensiondev/kit' +import { ChainId, ProviderType } from '@masknet/web3-shared-evm' 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, + currentMaskWalletAccountSettings, currentChainIdSettings, - currentMaskWalletBalanceSettings, currentMaskWalletChainIdSettings, currentProviderSettings, - currentBalancesSettings, + currentBalanceOfChainSettings, + currentBlockNumberOfChainSettings, } from '../settings' -let beats = 0 -const { run } = startEffects(import.meta.webpackHot) +//#region updater +class Updater Promise> { + private controller: AbortController | null = null + private cache: Map> = new Map() + + build(createUpdater: (signal: AbortSignal) => T) { + this.controller?.abort() + this.controller = new AbortController() -export async function kickToUpdateChainState() { - beats += 1 + const updater = createUpdater(this.controller.signal) + + getEnumAsArray(ChainId).forEach(({ value }) => { + this.cache.set( + value, + throttle(updater, 30 * 1000, { + trailing: true, + }), + ) + }) + } + + update(chainId: ChainId, ...args: Parameters) { + return this.cache.get(chainId)?.(...args) + } } +//#endregion -export async function updateBalances(data: BalanceOfChains) { - const balancesOfChains = { ...currentBalancesSettings.value } - for (const [key, value] of Object.entries(data)) { - balancesOfChains[key] = { - ...balancesOfChains[key], - ...value, +const { run } = startEffects(import.meta.webpackHot) + +const balanceUpdater = new Updater() +const blockNumberUpdater = new Updater() + +const createBalanceUpdater = (signal: AbortSignal) => { + let last = Date.now() + + return async function updateBalanceOfChain(chainId: ChainId, address: string) { + if (!address || !EthereumAddress.isValid(address)) return + const balance = await getBalance(address, { + chainId, + providerType: ProviderType.MaskWallet, + }) + if (signal.aborted) return + + console.log(`DEBUG: updateBalanceOfChain ${chainId} after ${Date.now() - last}`) + last = Date.now() + + currentBalanceOfChainSettings.value = { + ...currentBalanceOfChainSettings.value, + [chainId]: { + ...currentBalanceOfChainSettings.value[chainId], + [address.toLowerCase()]: balance, + }, } } - - 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() +const createBlockNumberUpdater = (signal: AbortSignal) => { + let last = Date.now() + + return async function updateBlockNumberOfChain(chainId: ChainId) { + const blockNumber = await getBlockNumber({ + chainId, + }) + if (signal.aborted) return + + console.log(`DEBUG: updateBlockNumberOfChain ${chainId} after ${Date.now() - last}`) + last = Date.now() + + currentBlockNumberOfChainSettings.value = { + ...currentBlockNumberOfChainSettings.value, + [chainId]: blockNumber, + } } } -export const updateChainStateThrottled = throttle(updateChainState, 300, { - leading: false, - trailing: true, -}) +export function updateBlockNumber(chainId = currentChainIdSettings.value) { + uniq([chainId, currentChainIdSettings.value, currentMaskWalletChainIdSettings.value]).forEach((chainId) => { + blockNumberUpdater.update(chainId, chainId) + }) +} -let resetPoolTask: () => void = () => {} +export function updateBalance(chainId = currentChainIdSettings.value, account = currentAccountSettings.value) { + const pairs = [ + [account, chainId] as const, + [currentAccountSettings.value, currentChainIdSettings.value] as const, + [currentMaskWalletAccountSettings.value, currentMaskWalletChainIdSettings.value] as const, + ] + uniqBy(pairs, ([account, chainId]) => `${account.toLowerCase()}_${chainId}`).forEach(([account, chainId]) => { + balanceUpdater.update(chainId, chainId, account) + }) +} -// 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 -}) + balanceUpdater.build(createBalanceUpdater) + blockNumberUpdater.build(createBlockNumberUpdater) -// revalidate chain state if the chainId of current provider was changed + setInterval(() => { + updateBalance() + updateBlockNumber() + }, 5000) + return noop +}) run(() => currentChainIdSettings.addListener(() => { - updateChainStateThrottled() + balanceUpdater.build(createBalanceUpdater) + blockNumberUpdater.build(createBlockNumberUpdater) if (currentProviderSettings.value === ProviderType.MaskWallet) resetAllNonce() }), ) run(() => currentMaskWalletChainIdSettings.addListener(() => { - updateChainStateThrottled() + balanceUpdater.build(createBalanceUpdater) + blockNumberUpdater.build(createBlockNumberUpdater) resetAllNonce() }), ) - -// revalidate chain state if the current wallet was changed -run(() => currentAccountSettings.addListener(() => updateChainStateThrottled())) -run(() => currentMaskWalletAccountSettings.addListener(() => updateChainStateThrottled())) +run(() => + currentAccountSettings.addListener(() => { + balanceUpdater.build(createBalanceUpdater) + }), +) +run(() => + currentMaskWalletAccountSettings.addListener(() => { + balanceUpdater.build(createBalanceUpdater) + }), +) diff --git a/packages/mask/src/plugins/Wallet/settings.ts b/packages/mask/src/plugins/Wallet/settings.ts index 177a3bd1407c..42fe7c009c9c 100644 --- a/packages/mask/src/plugins/Wallet/settings.ts +++ b/packages/mask/src/plugins/Wallet/settings.ts @@ -1,3 +1,5 @@ +import { isEqual } from 'lodash-unified' +import type { Web3Plugin } from '@masknet/plugin-infra' import { createGlobalSettings } from '../../settings/createSettings' import { i18n } from '../../../shared-ui/locales_legacy' import { @@ -9,10 +11,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 +31,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 +51,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 +90,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, @@ -124,11 +111,17 @@ export const currentTokenPricesSettings = createGlobalSettings( (a, b) => isEqual(a, b), ) -/** - * ERC20 Token balances - */ -export const currentBalancesSettings = createGlobalSettings( - `${PLUGIN_ID}+balances`, +export const currentBlockNumberOfChainSettings = createGlobalSettings( + `${PLUGIN_ID}+blockNumberOfChain`, + {}, + { + primary: () => 'DO NOT DISPLAY IT IN UI', + }, + (a, b) => isEqual(a, b), +) + +export const currentBalanceOfChainSettings = createGlobalSettings( + `${PLUGIN_ID}+balanceOfChain`, {}, { primary: () => 'DO NOT DISPLAY IT IN UI', diff --git a/packages/mask/src/settings/listener.ts b/packages/mask/src/settings/listener.ts index 95614ff11643..fd3af8d6c1ef 100644 --- a/packages/mask/src/settings/listener.ts +++ b/packages/mask/src/settings/listener.ts @@ -8,9 +8,8 @@ import { import type { MaskSettingsEvents } from '@masknet/shared-base' import { currentAccountSettings, - currentBalanceSettings, - currentBalancesSettings, - currentBlockNumberSettings, + currentBalanceOfChainSettings, + currentBlockNumberOfChainSettings, currentChainIdSettings, currentNonFungibleAssetDataProviderSettings, currentNetworkSettings, @@ -38,9 +37,8 @@ export function ToBeListened(): ToBeListedSettings { languageSettings, debugModeSetting, currentChainIdSettings, - currentBalanceSettings, - currentBalancesSettings, - currentBlockNumberSettings, + currentBalanceOfChainSettings, + currentBlockNumberOfChainSettings, currentTokenPricesSettings, currentDataProviderSettings, currentProviderSettings, diff --git a/packages/mask/src/web3/context.ts b/packages/mask/src/web3/context.ts index ae80a7c7e220..594bba28c5d5 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,8 +22,8 @@ import { currentMaskWalletChainIdSettings, currentMaskWalletNetworkSettings, currentMaskWalletAccountSettings, - currentMaskWalletBalanceSettings, - currentBalancesSettings, + currentBalanceOfChainSettings, + currentBlockNumberOfChainSettings, } from '../plugins/Wallet/settings' import { WalletMessages, WalletRPC } from '../plugins/Wallet/messages' import type { InternalSettings } from '../settings/createSettings' @@ -93,9 +91,8 @@ function createWeb3Context(disablePopup = false, isMask = false): Web3ProviderTy return () => void [a(), b(), c()] }, ), - balance: createSubscriptionFromSettings(isMask ? currentMaskWalletBalanceSettings : currentBalanceSettings), - balances: createSubscriptionFromSettings(currentBalancesSettings), - blockNumber: createSubscriptionFromSettings(currentBlockNumberSettings), + balanceOfChain: createSubscriptionFromSettings(currentBalanceOfChainSettings), + blockNumberOfChain: createSubscriptionFromSettings(currentBlockNumberOfChainSettings), tokenPrices: createSubscriptionFromSettings(currentTokenPricesSettings), walletPrimary: createSubscriptionFromAsync( WalletRPC.getWalletPrimary, diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index 95792e8cef53..c8e3dfb63b12 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -1,7 +1,6 @@ import type { BigNumber } from 'bignumber.js' import type { Subscription } from 'use-subscription' -import type { Pagination, Plugin } from './types' -import type { Pageable } from './types' +import type { Pagination, Plugin, Pageable } from './types' /** * A network plugin defines the way to connect to a single chain. @@ -197,10 +196,20 @@ export declare namespace Web3Plugin { tokens: Token[] } - export type domainAddressBook = { + export type DomainAddressBook = { [chainId: number]: Record | undefined } + export interface BalanceOfChain { + [chainId: string]: { + [account: string]: string + } + } + + export interface BlockNumberOfChain { + [chainId: string]: number + } + export namespace ObjectCapabilities { export interface SharedState { allowTestnet?: Subscription @@ -208,10 +217,10 @@ 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 tracked balance of chain. */ + balanceOfChain?: Subscription + /** The tracked block height of chain. */ + blockNumberOfChain?: Subscription /** The network type. */ networkType?: Subscription /** The wallet provider type. */ diff --git a/packages/plugin-infra/src/web3/Context.tsx b/packages/plugin-infra/src/web3/Context.tsx index 57995c384975..4cbb35ea058b 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,8 @@ function usePluginWeb3State(pluginID: string, context: Record { if (blockNumberOnce === 0 && blockNumber > 0) setBlockNumberOnce(blockNumber) diff --git a/packages/plugins/Debugger/src/SNSAdaptor/components/TabContent.tsx b/packages/plugins/Debugger/src/SNSAdaptor/components/TabContent.tsx index 6a3483bac5fd..85d398a87210 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 balance = useBalance() + const blockNumber = 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 f3ad28372301..d2e8cf26afdb 100644 --- a/packages/shared-base/src/Messages/Mask.ts +++ b/packages/shared-base/src/Messages/Mask.ts @@ -6,9 +6,10 @@ import type { CryptoPrice, NetworkType, ProviderType, - BalanceOfChains, FungibleAssetProvider, NonFungibleAssetProvider, + BalanceOfChain, + BlockNumberOfChain, } from '../../../web3-shared/evm' export interface MaskSettingsEvents { @@ -17,9 +18,8 @@ export interface MaskSettingsEvents { debugModeSetting: boolean pluginIDSettings: string currentChainIdSettings: number - currentBalanceSettings: string - currentBalancesSettings: BalanceOfChains - currentBlockNumberSettings: number + currentBalanceOfChainSettings: BalanceOfChain + currentBlockNumberOfChainSettings: BlockNumberOfChain currentTokenPricesSettings: CryptoPrice currentDataProviderSettings: DataProvider currentProviderSettings: ProviderType diff --git a/packages/web3-shared/evm/context/index.tsx b/packages/web3-shared/evm/context/index.tsx index 209c9ed3fb89..479426ce9251 100644 --- a/packages/web3-shared/evm/context/index.tsx +++ b/packages/web3-shared/evm/context/index.tsx @@ -19,9 +19,8 @@ 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 balanceOfChain = useSubscription(_.balanceOfChain) + const blockNumberOfChain = useSubscription(_.blockNumberOfChain) const tokenPrices = useSubscription(_.tokenPrices) const networkType = useSubscription(_.networkType) const providerType = useSubscription(_.providerType) @@ -34,12 +33,11 @@ export function useWeb3State() { const erc1155Tokens = useSubscription(_.erc1155Tokens) const portfolioProvider = useSubscription(_.portfolioProvider) return { - balances, allowTestnet, account, tokenPrices, - balance, - blockNumber, + balanceOfChain, + blockNumberOfChain, networkType, providerType, walletPrimary, diff --git a/packages/web3-shared/evm/context/type.ts b/packages/web3-shared/evm/context/type.ts index e84400683b85..c2c1aaa1a9c5 100644 --- a/packages/web3-shared/evm/context/type.ts +++ b/packages/web3-shared/evm/context/type.ts @@ -15,17 +15,17 @@ import type { Transaction, AddressName, CryptoPrice, - BalanceOfChains, ERC721TokenCollectionInfo, + BalanceOfChain, + BlockNumberOfChain, } from '../types' export interface Web3ProviderType { allowTestnet: Subscription chainId: Subscription account: Subscription - balance: Subscription - balances: Subscription - blockNumber: Subscription + balanceOfChain: Subscription + blockNumberOfChain: Subscription provider: Subscription networkType: Subscription providerType: Subscription diff --git a/packages/web3-shared/evm/hooks/useAssetsFromChain.ts b/packages/web3-shared/evm/hooks/useAssetsFromChain.ts index 17e7c584254e..68d031ea0265 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 balance = 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..271c86b1232d 100644 --- a/packages/web3-shared/evm/hooks/useBalance.ts +++ b/packages/web3-shared/evm/hooks/useBalance.ts @@ -1,41 +1,10 @@ -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' - -/** - * Get the current block number - */ -export function useBalance() { - return useWeb3StateContext().balance -} - -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]) -} - -export function useChainBalanceList(account: string, providerType: ProviderType) { - const web3 = useWeb3(true) - const chainIdList = Object.keys(NetworkType).map((x) => getChainIdFromNetworkType(x as NetworkType)) - - 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]) +import type { ChainId } from '../types' +import { useAccount, useChainId } from '..' + +export function useBalance(chainId?: ChainId, account?: string) { + const defaultChainId = useChainId() + const defaultAccount = useAccount() + const { balanceOfChain } = useWeb3StateContext() + return balanceOfChain[chainId ?? defaultChainId]?.[account ?? defaultAccount] ?? '0' } 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..cd2bb3816ef7 100644 --- a/packages/web3-shared/evm/hooks/useBlockNumber.ts +++ b/packages/web3-shared/evm/hooks/useBlockNumber.ts @@ -1,11 +1,15 @@ import { useState, useEffect } from 'react' +import { useChainId } from '.' +import type { ChainId } from '..' import { useWeb3StateContext } from '../context' /** * Get the current block number of current chain */ -export function useBlockNumber() { - return useWeb3StateContext().blockNumber +export function useBlockNumber(chainId?: ChainId) { + const defaultChainId = useChainId() + const { blockNumberOfChain } = useWeb3StateContext() + return blockNumberOfChain[chainId ?? defaultChainId] ?? 0 } /** diff --git a/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts b/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts index e67fb3c6d156..08d7b782a687 100644 --- a/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts +++ b/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts @@ -10,7 +10,7 @@ export function useNativeTokenBalance() { const account = useAccount() const balance = useBalance() return useAsyncRetry(async () => { - if (!account) return undefined + if (!account) return return balance }, [account, balance]) } diff --git a/packages/web3-shared/evm/types/index.ts b/packages/web3-shared/evm/types/index.ts index 98a5802b490b..583916671e7f 100644 --- a/packages/web3-shared/evm/types/index.ts +++ b/packages/web3-shared/evm/types/index.ts @@ -28,9 +28,13 @@ export interface BalanceOfChainRecord { [chainId: number]: string } -export interface BalanceOfChains { - [provider: string]: { - [chainId: number]: string +export interface BlockNumberOfChain { + [chainId: string]: number +} + +export interface BalanceOfChain { + [chainId: string]: { + [account: string]: string } } From 79d1786d5c8d395adcf41be5791337b100006eed Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Thu, 6 Jan 2022 23:14:08 +0800 Subject: [PATCH 02/11] refactor: useBeat --- .../src/plugins/MaskBox/hooks/useContext.ts | 14 ++-- .../src/plugins/MaskBox/hooks/useHeartBeat.ts | 11 --- .../src/plugins/Trader/trader/0x/useTrade.ts | 79 ++++++++++--------- .../Trader/trader/balancer/useTrade.ts | 69 ++++++++-------- .../plugins/Trader/trader/bancor/useTrade.ts | 70 ++++++++-------- .../plugins/Trader/trader/dodo/useTrade.ts | 69 ++++++++-------- .../Trader/trader/openocean/useTrade.ts | 69 ++++++++-------- packages/web3-shared/base/hooks/index.ts | 1 + packages/web3-shared/base/hooks/useBeat.ts | 20 +++++ packages/web3-shared/base/index.ts | 1 + packages/web3-shared/base/package.json | 3 +- packages/web3-shared/evm/hooks/index.ts | 1 - .../evm/hooks/useERC20TokenAllowance.ts | 20 ++--- .../evm/hooks/useERC20TokenBalance.ts | 24 +++--- .../evm/hooks/useNativeTokenBalance.ts | 2 +- .../web3-shared/evm/hooks/useTransaction.ts | 34 -------- pnpm-lock.yaml | 3 + 17 files changed, 237 insertions(+), 253 deletions(-) delete mode 100644 packages/mask/src/plugins/MaskBox/hooks/useHeartBeat.ts create mode 100644 packages/web3-shared/base/hooks/index.ts create mode 100644 packages/web3-shared/base/hooks/useBeat.ts delete mode 100644 packages/web3-shared/evm/hooks/useTransaction.ts diff --git a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts index 6307de000073..b32636d287d5 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 { useBeat, isGreaterThanOrEqualTo, isLessThanOrEqualTo, isZero, multipliedBy } 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/Trader/trader/0x/useTrade.ts b/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts index 439254ad5f63..833cda477816 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 { DOUBLE_BLOCK_DELAY, useBeatRetry } from '@masknet/web3-shared-base' export function getNativeTokenLabel(networkType: NetworkType) { switch (networkType) { @@ -50,45 +49,47 @@ 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 () => { - if (!inputToken || !outputToken) return null - const isExactIn = strategy === TradeStrategy.ExactIn - if (inputAmount === '0' && isExactIn) return null - if (outputAmount === '0' && !isExactIn) return null + return useBeatRetry( + async () => { + if (!inputToken || !outputToken) return null + const isExactIn = strategy === TradeStrategy.ExactIn + if (inputAmount === '0' && isExactIn) return null + if (outputAmount === '0' && !isExactIn) return null - const sellToken = isNativeTokenAddress(inputToken) - ? getNativeTokenLabel(getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value) - : inputToken.address - const buyToken = isNativeTokenAddress(outputToken) - ? getNativeTokenLabel(getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value) - : outputToken.address - return PluginTraderRPC.swapQuote( - { - sellToken, - buyToken, - takerAddress: account, - sellAmount: isExactIn ? inputAmount : void 0, - buyAmount: isExactIn ? void 0 : outputAmount, - skipValidation: true, - slippagePercentage: slippage, - affiliateAddress: ZRX_AFFILIATE_ADDRESS, - }, - getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value, - ) - }, [ - NATIVE_TOKEN_ADDRESS, - account, - strategy, - inputAmount, - outputAmount, - inputToken?.address, - outputToken?.address, - slippage, - pools.length, - blockNumber, // refresh api each block - ]) + const sellToken = isNativeTokenAddress(inputToken) + ? getNativeTokenLabel(getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value) + : inputToken.address + const buyToken = isNativeTokenAddress(outputToken) + ? getNativeTokenLabel(getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value) + : outputToken.address + return PluginTraderRPC.swapQuote( + { + sellToken, + buyToken, + takerAddress: account, + sellAmount: isExactIn ? inputAmount : void 0, + buyAmount: isExactIn ? void 0 : outputAmount, + skipValidation: true, + slippagePercentage: slippage, + affiliateAddress: ZRX_AFFILIATE_ADDRESS, + }, + getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value, + ) + }, + DOUBLE_BLOCK_DELAY, + [ + NATIVE_TOKEN_ADDRESS, + account, + strategy, + inputAmount, + outputAmount, + inputToken?.address, + outputToken?.address, + slippage, + pools.length, + ], + ) } diff --git a/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts b/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts index df738baab06f..39d2534f2132 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 { DOUBLE_BLOCK_DELAY, useBeatRetry } from '@masknet/web3-shared-base' +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,37 +12,39 @@ export function useTrade( inputToken?: FungibleTokenDetailed, outputToken?: FungibleTokenDetailed, ) { - const blockNumber = useBlockNumber() const { targetChainId } = TargetChainIdContext.useContainer() const { WNATIVE_ADDRESS } = useTokenConstants(targetChainId) - return useAsyncRetry(async () => { - if (!WNATIVE_ADDRESS) return null - if (!inputToken || !outputToken) return null - const isExactIn = strategy === TradeStrategy.ExactIn - if (inputAmount === '0' && isExactIn) return null - if (outputAmount === '0' && !isExactIn) return null - // the WETH address is used for looking for available pools - const sellToken = isNativeTokenAddress(inputToken) ? WNATIVE_ADDRESS : inputToken.address - const buyToken = isNativeTokenAddress(outputToken) ? WNATIVE_ADDRESS : outputToken.address - const { swaps, routes } = await PluginTraderRPC.getSwaps( - sellToken, - buyToken, - isExactIn ? BALANCER_SWAP_TYPE.EXACT_IN : BALANCER_SWAP_TYPE.EXACT_OUT, - isExactIn ? inputAmount : outputAmount, + return useBeatRetry( + async () => { + if (!WNATIVE_ADDRESS) return null + if (!inputToken || !outputToken) return null + const isExactIn = strategy === TradeStrategy.ExactIn + if (inputAmount === '0' && isExactIn) return null + if (outputAmount === '0' && !isExactIn) return null + // the WETH address is used for looking for available pools + const sellToken = isNativeTokenAddress(inputToken) ? WNATIVE_ADDRESS : inputToken.address + const buyToken = isNativeTokenAddress(outputToken) ? WNATIVE_ADDRESS : outputToken.address + const { swaps, routes } = await PluginTraderRPC.getSwaps( + sellToken, + buyToken, + isExactIn ? BALANCER_SWAP_TYPE.EXACT_IN : BALANCER_SWAP_TYPE.EXACT_OUT, + isExactIn ? inputAmount : outputAmount, + targetChainId, + ) + // no pool found + if (!swaps[0].length) return null + return { swaps, routes } as SwapResponse + }, + DOUBLE_BLOCK_DELAY, + [ + WNATIVE_ADDRESS, + strategy, targetChainId, - ) - // 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 - ]) + 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..2eba1b572360 100644 --- a/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts @@ -1,18 +1,16 @@ 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 { DOUBLE_BLOCK_DELAY, leftShift, useBeatRetry } from '@masknet/web3-shared-base' export function useTrade( strategy: TradeStrategy, @@ -21,7 +19,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,41 +29,44 @@ export function useTrade( const outputAmount = leftShift(outputAmountWei, outputToken?.decimals).toFixed() const isExactIn = strategy === TradeStrategy.ExactIn - return useAsyncRetry(async () => { - if (!inputToken || !outputToken) return null - if (inputAmountWei === '0' && isExactIn) return null - if (outputAmountWei === '0' && !isExactIn) return null - if (![ChainId.Mainnet, ChainId.Ropsten].includes(chainId)) return null + return useBeatRetry( + async () => { + if (!inputToken || !outputToken) return null + if (inputAmountWei === '0' && isExactIn) return null + if (outputAmountWei === '0' && !isExactIn) return null + if (![ChainId.Mainnet, ChainId.Ropsten].includes(chainId)) return null - const fromToken = isNativeTokenAddress(inputToken) - ? { ...inputToken, address: BANCOR_ETH_ADDRESS ?? '' } - : inputToken + const fromToken = isNativeTokenAddress(inputToken) + ? { ...inputToken, address: BANCOR_ETH_ADDRESS ?? '' } + : inputToken - const toToken = isNativeTokenAddress(outputToken) - ? { ...outputToken, address: BANCOR_ETH_ADDRESS ?? '' } - : outputToken + const toToken = isNativeTokenAddress(outputToken) + ? { ...outputToken, address: BANCOR_ETH_ADDRESS ?? '' } + : outputToken - return PluginTraderRPC.swapBancor({ + return PluginTraderRPC.swapBancor({ + strategy, + fromToken, + toToken, + fromAmount: isExactIn ? inputAmount : void 0, + toAmount: isExactIn ? void 0 : outputAmount, + slippage, + user, + chainId: chainId as ChainId.Mainnet | ChainId.Ropsten, + minimumReceived: '', + }) + }, + DOUBLE_BLOCK_DELAY, + [ + NATIVE_TOKEN_ADDRESS, strategy, - fromToken, - toToken, - fromAmount: isExactIn ? inputAmount : void 0, - toAmount: isExactIn ? void 0 : outputAmount, + inputAmountWei, + outputAmountWei, + inputToken?.address, + outputToken?.address, slippage, user, - chainId: chainId as ChainId.Mainnet | ChainId.Ropsten, - minimumReceived: '', - }) - }, [ - NATIVE_TOKEN_ADDRESS, - strategy, - inputAmountWei, - outputAmountWei, - inputToken?.address, - outputToken?.address, - slippage, - blockNumber, // refresh api each block - user, - chainId, - ]) + chainId, + ], + ) } diff --git a/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts b/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts index 130d1de427d4..23af8e6c5d0e 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 { DOUBLE_BLOCK_DELAY, useBeatRetry } from '@masknet/web3-shared-base' 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,36 +28,39 @@ export function useTrade( const { DODO_ETH_ADDRESS } = useTraderConstants(chainId) const account = useAccount() - return useAsyncRetry(async () => { - if (!inputToken || !outputToken) return null - if (inputAmount === '0') return null - const sellToken = isNativeTokenAddress(inputToken) - ? { ...inputToken, address: DODO_ETH_ADDRESS ?? '' } - : inputToken - const buyToken = isNativeTokenAddress(outputToken) - ? { ...outputToken, address: DODO_ETH_ADDRESS ?? '' } - : outputToken - return PluginTraderRPC.swapRoute({ - isNativeSellToken: isNativeTokenAddress(inputToken), - fromToken: sellToken, - toToken: buyToken, - fromAmount: inputAmount, - slippage: slippage / 100, - userAddr: account, - rpc: providerURL, + return useBeatRetry( + async () => { + if (!inputToken || !outputToken) return null + if (inputAmount === '0') return null + const sellToken = isNativeTokenAddress(inputToken) + ? { ...inputToken, address: DODO_ETH_ADDRESS ?? '' } + : inputToken + const buyToken = isNativeTokenAddress(outputToken) + ? { ...outputToken, address: DODO_ETH_ADDRESS ?? '' } + : outputToken + return PluginTraderRPC.swapRoute({ + isNativeSellToken: isNativeTokenAddress(inputToken), + fromToken: sellToken, + toToken: buyToken, + fromAmount: inputAmount, + slippage: slippage / 100, + userAddr: account, + rpc: providerURL, + chainId, + }) + }, + DOUBLE_BLOCK_DELAY, + [ + NATIVE_TOKEN_ADDRESS, + strategy, + inputAmount, + outputAmount, + inputToken?.address, + outputToken?.address, + slippage, + account, + providerURL, chainId, - }) - }, [ - NATIVE_TOKEN_ADDRESS, - strategy, - inputAmount, - outputAmount, - inputToken?.address, - outputToken?.address, - slippage, - blockNumber, // refresh api each block - account, - providerURL, - chainId, - ]) + ], + ) } diff --git a/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts b/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts index 960a788ce0eb..0b688b34645c 100644 --- a/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/openocean/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 { TargetChainIdContext } from '../useTargetChainIdContext' import { useSlippageTolerance } from './useSlippageTolerance' import { first } from 'lodash-unified' +import { DOUBLE_BLOCK_DELAY, useBeatRetry } from '@masknet/web3-shared-base' export function useTrade( strategy: TradeStrategy, @@ -22,7 +21,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) @@ -30,36 +28,39 @@ export function useTrade( const { OPENOCEAN_ETH_ADDRESS } = useTraderConstants(targetChainId) const account = useAccount() - return useAsyncRetry(async () => { - if (!inputToken || !outputToken) return null - if (inputAmount === '0') return null - const sellToken = isNativeTokenAddress(inputToken.address) - ? { ...inputToken, address: OPENOCEAN_ETH_ADDRESS ?? '' } - : inputToken - const buyToken = isNativeTokenAddress(outputToken.address) - ? { ...outputToken, address: OPENOCEAN_ETH_ADDRESS ?? '' } - : outputToken - return PluginTraderRPC.swapOO({ - isNativeSellToken: isNativeTokenAddress(inputToken.address), - fromToken: sellToken, - toToken: buyToken, - fromAmount: inputAmount, + return useBeatRetry( + async () => { + if (!inputToken || !outputToken) return null + if (inputAmount === '0') return null + const sellToken = isNativeTokenAddress(inputToken.address) + ? { ...inputToken, address: OPENOCEAN_ETH_ADDRESS ?? '' } + : inputToken + const buyToken = isNativeTokenAddress(outputToken.address) + ? { ...outputToken, address: OPENOCEAN_ETH_ADDRESS ?? '' } + : outputToken + return PluginTraderRPC.swapOO({ + isNativeSellToken: isNativeTokenAddress(inputToken.address), + fromToken: sellToken, + toToken: buyToken, + fromAmount: inputAmount, + slippage, + userAddr: account, + rpc: providerURL, + chainId: targetChainId, + }) + }, + DOUBLE_BLOCK_DELAY, + [ + NATIVE_TOKEN_ADDRESS, + strategy, + inputAmount, + outputAmount, + inputToken?.address, + outputToken?.address, slippage, - userAddr: account, - rpc: providerURL, - chainId: targetChainId, - }) - }, [ - NATIVE_TOKEN_ADDRESS, - strategy, - inputAmount, - outputAmount, - inputToken?.address, - outputToken?.address, - slippage, - blockNumber, // refresh api each block - account, - providerURL, - targetChainId, - ]) + account, + providerURL, + targetChainId, + ], + ) } diff --git a/packages/web3-shared/base/hooks/index.ts b/packages/web3-shared/base/hooks/index.ts new file mode 100644 index 000000000000..a2121d0d9e81 --- /dev/null +++ b/packages/web3-shared/base/hooks/index.ts @@ -0,0 +1 @@ +export * from './useBeat' diff --git a/packages/web3-shared/base/hooks/useBeat.ts b/packages/web3-shared/base/hooks/useBeat.ts new file mode 100644 index 000000000000..01a268503ac3 --- /dev/null +++ b/packages/web3-shared/base/hooks/useBeat.ts @@ -0,0 +1,20 @@ +import { DependencyList, useState } from 'react' +import { useAsyncRetry, useTimeoutFn } from 'react-use' +import type { AsyncStateRetry } from 'react-use/lib/useAsyncRetry' + +export const SINGLE_BLOCK_DELAY = 15 * 1000 +export const DOUBLE_BLOCK_DELAY = SINGLE_BLOCK_DELAY * 2 + +export function useBeat(delay = 1000) { + const [bit, setBit] = useState(0) + const [, , reset] = useTimeoutFn(() => { + setBit((x) => (x + 1) % Number.MAX_SAFE_INTEGER) + reset() + }, delay) + return bit +} + +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 9c56149efa59..f3723b374bf4 100644 --- a/packages/web3-shared/base/index.ts +++ b/packages/web3-shared/base/index.ts @@ -1 +1,2 @@ +export * from './hooks' export * from './utils' diff --git a/packages/web3-shared/base/package.json b/packages/web3-shared/base/package.json index c09ae1ec6285..992fa4517f44 100644 --- a/packages/web3-shared/base/package.json +++ b/packages/web3-shared/base/package.json @@ -4,6 +4,7 @@ "main": "./dist/index.js", "types": "./dist/index.d.ts", "dependencies": { - "bignumber.js": "9.0.2" + "bignumber.js": "9.0.2", + "react-use": "^17.3.1" } } diff --git a/packages/web3-shared/evm/hooks/index.ts b/packages/web3-shared/evm/hooks/index.ts index a2fcdd16509b..511b73ae2cfd 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/useERC20TokenAllowance.ts b/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts index 9edb167937a8..59a10282cc62 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 { useERC20TokenContract } from '../contracts/useERC20TokenContract' import { useAccount } from './useAccount' import { useChainId } from './useChainId' -import { useBlockNumber } from './useBlockNumber' +import { DOUBLE_BLOCK_DELAY, useBeatRetry } from '@masknet/web3-shared-base' 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, + }) + }, + DOUBLE_BLOCK_DELAY, + [account, chainId, spender, erc20Contract], + ) } diff --git a/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts b/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts index 49587dc6a146..29c1906f0d79 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 { DOUBLE_BLOCK_DELAY, 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 @@ -15,13 +14,16 @@ export function useERC20TokenBalance(address?: string, targetChainId?: ChainId) const account = useAccount() const currentChainId = useChainId() const chainId = targetChainId ?? currentChainId - const blockNumber = useBlockNumber() 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), + }) + }, + DOUBLE_BLOCK_DELAY, + [account, chainId, address, erc20Contract], + ) } diff --git a/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts b/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts index 08d7b782a687..b5f06d9dce11 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' /** 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/pnpm-lock.yaml b/pnpm-lock.yaml index 2608eb3873c0..e919ab81019e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -990,8 +990,10 @@ importers: packages/web3-shared/base: specifiers: bignumber.js: 9.0.2 + react-use: ^17.3.1 dependencies: bignumber.js: 9.0.2 + react-use: 17.3.1_757a802188413a36d4f24237d13b8e90 packages/web3-shared/evm: specifiers: @@ -3433,6 +3435,7 @@ packages: /@dimensiondev/eslint-plugin/0.0.1-20220104011158-0905fa1_eslint@8.5.0: resolution: {integrity: sha512-DyAzOQp2Dp9Nzll6dTbujqyBAXOLhlWXvDdmnfX3+cHixhvaupbMeoh4MmujkOY681N5ohVm2eKWJd/ApC4lrQ==, tarball: download/@dimensiondev/eslint-plugin/0.0.1-20220104011158-0905fa1/931c157d880a7f8a78e87326a2840ad7d4583b5c714f155e045f73a11969fc82} + engines: {node: '>= 14'} peerDependencies: eslint: '>= 8' dependencies: From 31d2fe5231833cb63fb30369825aa777d4ca17b0 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Tue, 18 Jan 2022 13:21:17 +0800 Subject: [PATCH 03/11] refactor: adjust type --- .../mask/src/plugins/Wallet/services/chain.ts | 21 ++++++------------- packages/plugin-infra/src/web3-types.ts | 15 ++++++------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/packages/mask/src/plugins/Wallet/services/chain.ts b/packages/mask/src/plugins/Wallet/services/chain.ts index 3b09b5f82ab7..0168e523232f 100644 --- a/packages/mask/src/plugins/Wallet/services/chain.ts +++ b/packages/mask/src/plugins/Wallet/services/chain.ts @@ -1,4 +1,4 @@ -import { throttle, DebouncedFunc, noop, uniq, uniqBy } from 'lodash-unified' +import { throttle, DebouncedFunc, uniq, uniqBy } from 'lodash-unified' import { EthereumAddress } from 'wallet.ts' import { getEnumAsArray } from '@dimensiondev/kit' import { ChainId, ProviderType } from '@masknet/web3-shared-evm' @@ -58,6 +58,7 @@ const createBalanceUpdater = (signal: AbortSignal) => { if (signal.aborted) return console.log(`DEBUG: updateBalanceOfChain ${chainId} after ${Date.now() - last}`) + last = Date.now() currentBalanceOfChainSettings.value = { @@ -97,25 +98,15 @@ export function updateBlockNumber(chainId = currentChainIdSettings.value) { export function updateBalance(chainId = currentChainIdSettings.value, account = currentAccountSettings.value) { const pairs = [ - [account, chainId] as const, - [currentAccountSettings.value, currentChainIdSettings.value] as const, - [currentMaskWalletAccountSettings.value, currentMaskWalletChainIdSettings.value] as const, + [chainId, account] as const, + [currentChainIdSettings.value, currentAccountSettings.value] as const, + [currentMaskWalletChainIdSettings.value, currentMaskWalletAccountSettings.value] as const, ] - uniqBy(pairs, ([account, chainId]) => `${account.toLowerCase()}_${chainId}`).forEach(([account, chainId]) => { + uniqBy(pairs, ([chainId, account]) => `${account.toLowerCase()}_${chainId}`).forEach(([chainId, account]) => { balanceUpdater.update(chainId, chainId, account) }) } -run(() => { - balanceUpdater.build(createBalanceUpdater) - blockNumberUpdater.build(createBlockNumberUpdater) - - setInterval(() => { - updateBalance() - updateBlockNumber() - }, 5000) - return noop -}) run(() => currentChainIdSettings.addListener(() => { balanceUpdater.build(createBalanceUpdater) diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index 4db6b713fa69..e040428e0498 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 { /** @@ -273,7 +274,7 @@ 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 @@ -331,7 +332,7 @@ export declare namespace Web3Plugin { Shared?: SharedState Asset?: AssetState NameService?: NameServiceState - Token?: TokenManage + Token?: TokenState Transaction?: TransactionState TokenList?: TokenListState Utils?: Others From d6f7fed85d6442be0835756d65daff505f3c3698 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Tue, 18 Jan 2022 17:13:55 +0800 Subject: [PATCH 04/11] refactor: add provider apis --- .../src/plugins/Trader/trader/useTargetBlockNumber.ts | 5 ++--- packages/plugin-infra/src/web3-types.ts | 8 ++++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts b/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts index 4a3149edcecf..13981504c626 100644 --- a/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts +++ b/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts @@ -1,8 +1,7 @@ -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 } from '@masknet/web3-shared-evm' +import Services from '../../../extension/service' export function useTargetBlockNumber(targetChainId?: ChainId): AsyncState { const chainId = useChainId() diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index e040428e0498..fc510790a67f 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -280,7 +280,7 @@ export declare namespace Web3Plugin { trustToken: (token: Token) => Promise blockToken: (token: Token) => Promise } - export interface TransactionState { + export interface ProviderState { /** Get latest transactions of given account. */ getTransactions: ( address: string, @@ -288,6 +288,10 @@ export declare namespace Web3Plugin { network: NetworkDescriptor, pagination?: Pagination, ) => Promise + /** Get latest block number of given chain. */ + getLatestBlockNumber: (chainId: number) => Promise + /** Get latest balance of given account. */ + getLatestBalance: (chainId: number, account: string) => Promise } export interface TokenListState { /** Get the token lists of supported fungible tokens. */ @@ -333,7 +337,7 @@ export declare namespace Web3Plugin { Asset?: AssetState NameService?: NameServiceState Token?: TokenState - Transaction?: TransactionState + Provider?: ProviderState TokenList?: TokenListState Utils?: Others } From d7723a7a5c298c1218092e44daf828e4a870d2aa Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Tue, 18 Jan 2022 17:19:56 +0800 Subject: [PATCH 05/11] refactor: remove balance & block number tracker --- packages/dashboard/src/web3/context.ts | 10 -- .../src/plugins/EVM/UI/Web3State/index.ts | 2 - .../mask/src/plugins/Wallet/services/chain.ts | 133 ------------------ .../mask/src/plugins/Wallet/services/index.ts | 1 - packages/mask/src/plugins/Wallet/settings.ts | 22 --- packages/mask/src/web3/context.ts | 4 - packages/plugin-infra/src/web3-types.ts | 8 -- packages/plugin-infra/src/web3/Context.tsx | 4 - packages/web3-shared/evm/context/index.tsx | 4 - packages/web3-shared/evm/context/type.ts | 4 - packages/web3-shared/evm/types/index.ts | 4 - 11 files changed, 196 deletions(-) delete mode 100644 packages/mask/src/plugins/Wallet/services/chain.ts diff --git a/packages/dashboard/src/web3/context.ts b/packages/dashboard/src/web3/context.ts index a173be250d96..1ec9fd723797 100644 --- a/packages/dashboard/src/web3/context.ts +++ b/packages/dashboard/src/web3/context.ts @@ -46,16 +46,6 @@ export const Web3Context: Web3ProviderType = { {}, Messages.events.currentTokenPricesSettings.on, ), - balanceOfChain: createSubscriptionFromAsync( - Services.Settings.getBalanceOfChain, - {}, - Messages.events.currentBalanceOfChainSettings.on, - ), - blockNumberOfChain: createSubscriptionFromAsync( - Services.Settings.getBlockNumberOfChain, - {}, - Messages.events.currentBlockNumberOfChainSettings.on, - ), chainId: createSubscriptionFromAsync( Services.Settings.getChainId, ChainId.Mainnet, diff --git a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts index 349cdc5380bb..10086c884f46 100644 --- a/packages/mask/src/plugins/EVM/UI/Web3State/index.ts +++ b/packages/mask/src/plugins/EVM/UI/Web3State/index.ts @@ -36,8 +36,6 @@ export function fixWeb3State(state?: Web3Plugin.ObjectCapabilities.Capabilities, allowTestnet: context.allowTestnet, chainId: context.chainId, account: context.account, - balanceOfChain: context.balanceOfChain, - blockNumberOfChain: context.blockNumberOfChain, networkType: context.networkType, providerType: context.providerType, walletPrimary: context.walletPrimary, 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 0168e523232f..000000000000 --- a/packages/mask/src/plugins/Wallet/services/chain.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { throttle, DebouncedFunc, uniq, uniqBy } from 'lodash-unified' -import { EthereumAddress } from 'wallet.ts' -import { getEnumAsArray } from '@dimensiondev/kit' -import { ChainId, ProviderType } from '@masknet/web3-shared-evm' -import { getBalance, getBlockNumber, resetAllNonce } from '../../../extension/background-script/EthereumService' -import { startEffects } from '../../../../utils-pure' -import { - currentAccountSettings, - currentMaskWalletAccountSettings, - currentChainIdSettings, - currentMaskWalletChainIdSettings, - currentProviderSettings, - currentBalanceOfChainSettings, - currentBlockNumberOfChainSettings, -} from '../settings' - -//#region updater -class Updater Promise> { - private controller: AbortController | null = null - private cache: Map> = new Map() - - build(createUpdater: (signal: AbortSignal) => T) { - this.controller?.abort() - this.controller = new AbortController() - - const updater = createUpdater(this.controller.signal) - - getEnumAsArray(ChainId).forEach(({ value }) => { - this.cache.set( - value, - throttle(updater, 30 * 1000, { - trailing: true, - }), - ) - }) - } - - update(chainId: ChainId, ...args: Parameters) { - return this.cache.get(chainId)?.(...args) - } -} -//#endregion - -const { run } = startEffects(import.meta.webpackHot) - -const balanceUpdater = new Updater() -const blockNumberUpdater = new Updater() - -const createBalanceUpdater = (signal: AbortSignal) => { - let last = Date.now() - - return async function updateBalanceOfChain(chainId: ChainId, address: string) { - if (!address || !EthereumAddress.isValid(address)) return - const balance = await getBalance(address, { - chainId, - providerType: ProviderType.MaskWallet, - }) - if (signal.aborted) return - - console.log(`DEBUG: updateBalanceOfChain ${chainId} after ${Date.now() - last}`) - - last = Date.now() - - currentBalanceOfChainSettings.value = { - ...currentBalanceOfChainSettings.value, - [chainId]: { - ...currentBalanceOfChainSettings.value[chainId], - [address.toLowerCase()]: balance, - }, - } - } -} - -const createBlockNumberUpdater = (signal: AbortSignal) => { - let last = Date.now() - - return async function updateBlockNumberOfChain(chainId: ChainId) { - const blockNumber = await getBlockNumber({ - chainId, - }) - if (signal.aborted) return - - console.log(`DEBUG: updateBlockNumberOfChain ${chainId} after ${Date.now() - last}`) - last = Date.now() - - currentBlockNumberOfChainSettings.value = { - ...currentBlockNumberOfChainSettings.value, - [chainId]: blockNumber, - } - } -} - -export function updateBlockNumber(chainId = currentChainIdSettings.value) { - uniq([chainId, currentChainIdSettings.value, currentMaskWalletChainIdSettings.value]).forEach((chainId) => { - blockNumberUpdater.update(chainId, chainId) - }) -} - -export function updateBalance(chainId = currentChainIdSettings.value, account = currentAccountSettings.value) { - const pairs = [ - [chainId, account] as const, - [currentChainIdSettings.value, currentAccountSettings.value] as const, - [currentMaskWalletChainIdSettings.value, currentMaskWalletAccountSettings.value] as const, - ] - uniqBy(pairs, ([chainId, account]) => `${account.toLowerCase()}_${chainId}`).forEach(([chainId, account]) => { - balanceUpdater.update(chainId, chainId, account) - }) -} - -run(() => - currentChainIdSettings.addListener(() => { - balanceUpdater.build(createBalanceUpdater) - blockNumberUpdater.build(createBlockNumberUpdater) - if (currentProviderSettings.value === ProviderType.MaskWallet) resetAllNonce() - }), -) -run(() => - currentMaskWalletChainIdSettings.addListener(() => { - balanceUpdater.build(createBalanceUpdater) - blockNumberUpdater.build(createBlockNumberUpdater) - resetAllNonce() - }), -) -run(() => - currentAccountSettings.addListener(() => { - balanceUpdater.build(createBalanceUpdater) - }), -) -run(() => - currentMaskWalletAccountSettings.addListener(() => { - balanceUpdater.build(createBalanceUpdater) - }), -) 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/settings.ts b/packages/mask/src/plugins/Wallet/settings.ts index 42fe7c009c9c..45c7a5bfebab 100644 --- a/packages/mask/src/plugins/Wallet/settings.ts +++ b/packages/mask/src/plugins/Wallet/settings.ts @@ -1,5 +1,4 @@ import { isEqual } from 'lodash-unified' -import type { Web3Plugin } from '@masknet/plugin-infra' import { createGlobalSettings } from '../../settings/createSettings' import { i18n } from '../../../shared-ui/locales_legacy' import { @@ -99,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`, {}, @@ -110,21 +106,3 @@ export const currentTokenPricesSettings = createGlobalSettings( }, (a, b) => isEqual(a, b), ) - -export const currentBlockNumberOfChainSettings = createGlobalSettings( - `${PLUGIN_ID}+blockNumberOfChain`, - {}, - { - primary: () => 'DO NOT DISPLAY IT IN UI', - }, - (a, b) => isEqual(a, b), -) - -export const currentBalanceOfChainSettings = createGlobalSettings( - `${PLUGIN_ID}+balanceOfChain`, - {}, - { - primary: () => 'DO NOT DISPLAY IT IN UI', - }, - (a, b) => isEqual(a, b), -) diff --git a/packages/mask/src/web3/context.ts b/packages/mask/src/web3/context.ts index 02ada7b47374..0814ec9986a3 100644 --- a/packages/mask/src/web3/context.ts +++ b/packages/mask/src/web3/context.ts @@ -22,8 +22,6 @@ import { currentMaskWalletChainIdSettings, currentMaskWalletNetworkSettings, currentMaskWalletAccountSettings, - currentBalanceOfChainSettings, - currentBlockNumberOfChainSettings, } from '../plugins/Wallet/settings' import { WalletMessages, WalletRPC } from '../plugins/Wallet/messages' import type { InternalSettings } from '../settings/createSettings' @@ -92,8 +90,6 @@ function createWeb3Context(disablePopup = false, isMask = false): Web3ProviderTy return () => void [a(), b(), c()] }, ), - balanceOfChain: createSubscriptionFromSettings(currentBalanceOfChainSettings), - blockNumberOfChain: createSubscriptionFromSettings(currentBlockNumberOfChainSettings), tokenPrices: createSubscriptionFromSettings(currentTokenPricesSettings), walletPrimary: createSubscriptionFromAsync( WalletRPC.getWalletPrimary, diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index fc510790a67f..d4610b8976f4 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -214,10 +214,6 @@ export declare namespace Web3Plugin { } } - export interface BlockNumberOfChain { - [chainId: string]: number - } - export namespace ObjectCapabilities { export interface SharedState { allowTestnet?: Subscription @@ -225,10 +221,6 @@ export declare namespace Web3Plugin { chainId?: Subscription /** The address of the currently chosen wallet. */ account?: Subscription - /** The tracked balance of chain. */ - balanceOfChain?: Subscription - /** The tracked block height of chain. */ - blockNumberOfChain?: Subscription /** The network type. */ networkType?: Subscription /** The wallet provider type. */ diff --git a/packages/plugin-infra/src/web3/Context.tsx b/packages/plugin-infra/src/web3/Context.tsx index 5a0f4a1ce65a..0e2fb578cee0 100644 --- a/packages/plugin-infra/src/web3/Context.tsx +++ b/packages/plugin-infra/src/web3/Context.tsx @@ -31,8 +31,6 @@ function usePluginWeb3State(pluginID: string, context: Record chainId: Subscription account: Subscription - balanceOfChain: Subscription - blockNumberOfChain: Subscription provider: Subscription networkType: Subscription providerType: Subscription diff --git a/packages/web3-shared/evm/types/index.ts b/packages/web3-shared/evm/types/index.ts index 099e462e0378..d5e08d425106 100644 --- a/packages/web3-shared/evm/types/index.ts +++ b/packages/web3-shared/evm/types/index.ts @@ -26,10 +26,6 @@ export interface CryptoPrice { export type ChainIdOptionalRecord = { [k in ChainId]?: T } export type ChainIdRecord = { [k in ChainId]: T } -export interface BlockNumberOfChain { - [chainId: string]: number -} - export interface BalanceOfChain { [chainId: string]: { [account: string]: string From 6b1c90d5336feca25437d7ddbba23f63530af011 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Tue, 18 Jan 2022 18:17:59 +0800 Subject: [PATCH 06/11] refactor: get balance and block number by query provider --- .../background-script/SettingsService.ts | 4 - .../SNSAdaptor/hooks/useAllPoolsAsSeller.ts | 11 ++- .../SNSAdaptor/hooks/useBlockNumberOfChain.ts | 14 ---- .../hooks/useClaimablePoolsByWeb3.ts | 10 +-- .../hooks/useMaskBoxCreationSuccessEvent.ts | 3 +- .../SNSAdaptor/hooks/useRedPacketHistory.ts | 5 +- .../Snapshot/SNSAdaptor/hooks/usePower.ts | 3 +- .../Snapshot/SNSAdaptor/hooks/useVotes.ts | 4 +- .../trader/hooks/useUpdateBalance.ts | 26 ++----- .../src/plugins/Trader/trader/0x/useTrade.ts | 76 +++++++++---------- .../Trader/trader/balancer/useTrade.ts | 52 +++++-------- .../plugins/Trader/trader/bancor/useTrade.ts | 66 ++++++++-------- .../plugins/Trader/trader/dodo/useTrade.ts | 66 ++++++++-------- .../Trader/trader/openocean/useTrade.ts | 9 +-- packages/mask/src/settings/listener.ts | 4 - packages/plugin-infra/src/web3-types.ts | 6 -- packages/plugin-infra/src/web3/useBalance.ts | 16 ++-- .../plugin-infra/src/web3/useBlockNumber.ts | 30 +++----- .../src/SNSAdaptor/components/TabContent.tsx | 4 +- packages/shared-base/src/Messages/Mask.ts | 4 - packages/web3-shared/base/hooks/useBeat.ts | 10 +++ .../evm/hooks/useAssetsFromChain.ts | 2 +- packages/web3-shared/evm/hooks/useBalance.ts | 16 +++- .../web3-shared/evm/hooks/useBlockNumber.ts | 25 ++---- .../evm/hooks/useERC20TokenAllowance.ts | 18 ++--- .../evm/hooks/useERC20TokenBalance.ts | 20 ++--- .../web3-shared/evm/hooks/useMulticall.ts | 4 +- .../evm/hooks/useNativeTokenBalance.ts | 2 +- packages/web3-shared/evm/types/index.ts | 5 -- 29 files changed, 220 insertions(+), 295 deletions(-) delete mode 100644 packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useBlockNumberOfChain.ts diff --git a/packages/mask/src/extension/background-script/SettingsService.ts b/packages/mask/src/extension/background-script/SettingsService.ts index e6e204d08e5f..ba7f0c658cde 100644 --- a/packages/mask/src/extension/background-script/SettingsService.ts +++ b/packages/mask/src/extension/background-script/SettingsService.ts @@ -33,8 +33,6 @@ import { currentMaskWalletAccountSettings, currentMaskWalletChainIdSettings, currentMaskWalletNetworkSettings, - currentBalanceOfChainSettings, - currentBlockNumberOfChainSettings, } from '../../plugins/Wallet/settings' import { Flags, MaskMessages } from '../../../shared' import { indexedDB_KVStorageBackend, inMemory_KVStorageBackend } from '../../../background/database/kv-storage' @@ -54,8 +52,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 [getBalanceOfChain, setBalanceOfChain] = create(currentBalanceOfChainSettings) -export const [getBlockNumberOfChain, setBlockNumberOfChain] = create(currentBlockNumberOfChainSettings) export const [getTokenPrices, setTokenPrices] = create(currentTokenPricesSettings) export const [getGasOptions, setGasOptions] = create(currentGasOptionsSettings) export const [getGasPrice, setGasPrice] = create(currentGasOptionsSettings) diff --git a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useAllPoolsAsSeller.ts b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useAllPoolsAsSeller.ts index 63afdeb494df..b5daa353c1a4 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useAllPoolsAsSeller.ts +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useAllPoolsAsSeller.ts @@ -1,19 +1,24 @@ +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, page: number) { const allPoolsRef = useRef([]) const chainId = useChainId() - const blockNumber = useBlockNumberOnce() + const { value: blockNumber = 0 } = useBlockNumber() useEffect(() => { allPoolsRef.current = [] }, [chainId]) return useAsyncRetry(async () => { + if (!blockNumber) + return { + pools: [], + loadMore: false, + } const _pools = await PluginITO_RPC.getAllPoolsAsSeller(address, page, blockNumber, chainId) const pools = _pools.filter((a) => !allPoolsRef.current.map((b) => b.pool.pid).includes(a.pool.pid)) allPoolsRef.current = allPoolsRef.current.concat(pools) 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/useClaimablePoolsByWeb3.ts b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useClaimablePoolsByWeb3.ts index 068cc236ef2d..a7eaa33d12bd 100644 --- a/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useClaimablePoolsByWeb3.ts +++ b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useClaimablePoolsByWeb3.ts @@ -10,9 +10,9 @@ import { EthereumTokenType, useGetPastLogsParams, ChainId, + useBlockNumber, } from '@masknet/web3-shared-evm' import type { ClaimablePool } from '../../types' -import { useBlockNumberOfChain } from './useBlockNumberOfChain' import Services from '../../../../extension/service' const SWAP_SUCCESS_TOPIC = sha3('SwapSuccess(bytes32,address,address,address,uint256,uint256,uint128,bool)') @@ -28,19 +28,19 @@ const SWAP_SUCCESS_TYPES = [ export function useClaimablePoolsByWeb3(chainId: ChainId) { const web3 = useWeb3() const account = useAccount() - const currentBlock = useBlockNumberOfChain(chainId) + const { value: blockNumber = 0 } = useBlockNumber(chainId) const { ITO2_CONTRACT_CREATION_BLOCK_HEIGHT: fromBlock, ITO2_CONTRACT_ADDRESS: address } = useITOConstants(chainId) // https://github.com/binance-chain/bsc/issues/113 // getPastLogs block range limitations on BSC is only 5000, which is absurd. Sometimes 4500 also fails. const maxBlockRange = chainId === ChainId.BSC ? 4500 : 10000 - const queryParams = useGetPastLogsParams(fromBlock, currentBlock, maxBlockRange, { + const queryParams = useGetPastLogsParams(fromBlock, blockNumber, maxBlockRange, { address, topics: [SWAP_SUCCESS_TOPIC], }) return useAsyncRetry(async () => { - if (!currentBlock) return [] + if (!blockNumber) return [] const logs = flatten( await Promise.all( queryParams.map((queryParam: PastLogsOptions) => @@ -64,5 +64,5 @@ export function useClaimablePoolsByWeb3(chainId: ChainId) { } return acc }, []) - }, [account, address, chainId, JSON.stringify(queryParams), currentBlock]) + }, [account, address, chainId, JSON.stringify(queryParams), blockNumber]) } diff --git a/packages/mask/src/plugins/MaskBox/hooks/useMaskBoxCreationSuccessEvent.ts b/packages/mask/src/plugins/MaskBox/hooks/useMaskBoxCreationSuccessEvent.ts index 29befa81153e..085e8f2d86f4 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 = 5000 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/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..58fd5babd379 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts @@ -1,6 +1,5 @@ -import type { ChainId } from '@masknet/web3-shared-evm' -import { AllProviderTradeActionType, AllProviderTradeContext } from '../../../trader/useAllProviderTradeContext' import { + ChainId, EthereumTokenType, isSameAddress, useAccount, @@ -8,9 +7,8 @@ import { useTokenConstants, } from '@masknet/web3-shared-evm' import { useAsync } from 'react-use' -import { currentBalancesSettings } from '../../../../Wallet/settings' +import { AllProviderTradeActionType, AllProviderTradeContext } from '../../../trader/useAllProviderTradeContext' import Services from '../../../../../extension/service' -import { WalletRPC } from '../../../../Wallet/messages' export function useUpdateBalance(chainId: ChainId, currentChainId: ChainId) { const currentAccount = useAccount() @@ -36,22 +34,10 @@ 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 Services.Ethereum.getBalance(currentAccount, { + chainId: chainId, + providerType: currentProvider, + }) dispatchTradeStore({ type: AllProviderTradeActionType.UPDATE_INPUT_TOKEN_BALANCE, diff --git a/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts b/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts index d2e8f2999b48..0086b666b52d 100644 --- a/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts @@ -15,7 +15,7 @@ import { useTradeProviderSettings } from '../useTradeSettings' import { currentNetworkSettings } from '../../../Wallet/settings' import { TargetChainIdContext } from '../useTargetChainIdContext' import { TradeProvider } from '@masknet/public-api' -import { DOUBLE_BLOCK_DELAY, useBeatRetry } from '@masknet/web3-shared-base' +import { useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' const NATIVE_TOKEN_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' @@ -50,44 +50,40 @@ export function useTrade( const slippage = useSlippageTolerance() const { pools } = useTradeProviderSettings(TradeProvider.ZRX) - return useBeatRetry( - async () => { - if (!inputToken || !outputToken) return null - const isExactIn = strategy === TradeStrategy.ExactIn - if (inputAmount === '0' && isExactIn) return null - if (outputAmount === '0' && !isExactIn) return null + return useDoubleBlockBeatRetry(async () => { + if (!inputToken || !outputToken) return null + const isExactIn = strategy === TradeStrategy.ExactIn + if (inputAmount === '0' && isExactIn) return null + if (outputAmount === '0' && !isExactIn) return null - const sellToken = isNativeTokenAddress(inputToken) - ? getNativeTokenLabel(getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value) - : inputToken.address - const buyToken = isNativeTokenAddress(outputToken) - ? getNativeTokenLabel(getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value) - : outputToken.address - return PluginTraderRPC.swapQuote( - { - sellToken, - buyToken, - takerAddress: account, - sellAmount: isExactIn ? inputAmount : void 0, - buyAmount: isExactIn ? void 0 : outputAmount, - skipValidation: true, - slippagePercentage: slippage, - affiliateAddress: ZRX_AFFILIATE_ADDRESS, - }, - getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value, - ) - }, - DOUBLE_BLOCK_DELAY, - [ - NATIVE_TOKEN_ADDRESS, - account, - strategy, - inputAmount, - outputAmount, - inputToken?.address, - outputToken?.address, - slippage, - pools.length, - ], - ) + const sellToken = isNativeTokenAddress(inputToken) + ? getNativeTokenLabel(getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value) + : inputToken.address + const buyToken = isNativeTokenAddress(outputToken) + ? getNativeTokenLabel(getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value) + : outputToken.address + return PluginTraderRPC.swapQuote( + { + sellToken, + buyToken, + takerAddress: account, + sellAmount: isExactIn ? inputAmount : void 0, + buyAmount: isExactIn ? void 0 : outputAmount, + skipValidation: true, + slippagePercentage: slippage, + affiliateAddress: ZRX_AFFILIATE_ADDRESS, + }, + getNetworkTypeFromChainId(targetChainId) ?? currentNetworkSettings.value, + ) + }, [ + NATIVE_TOKEN_ADDRESS, + account, + strategy, + inputAmount, + outputAmount, + inputToken?.address, + outputToken?.address, + slippage, + pools.length, + ]) } diff --git a/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts b/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts index 39d2534f2132..d978fa3c9410 100644 --- a/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts @@ -1,4 +1,4 @@ -import { DOUBLE_BLOCK_DELAY, useBeatRetry } from '@masknet/web3-shared-base' +import { useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' import { FungibleTokenDetailed, isNativeTokenAddress, useTokenConstants } from '@masknet/web3-shared-evm' import { BALANCER_SWAP_TYPE } from '../../constants' import { PluginTraderRPC } from '../../messages' @@ -15,36 +15,24 @@ export function useTrade( const { targetChainId } = TargetChainIdContext.useContainer() const { WNATIVE_ADDRESS } = useTokenConstants(targetChainId) - return useBeatRetry( - async () => { - if (!WNATIVE_ADDRESS) return null - if (!inputToken || !outputToken) return null - const isExactIn = strategy === TradeStrategy.ExactIn - if (inputAmount === '0' && isExactIn) return null - if (outputAmount === '0' && !isExactIn) return null - // the WETH address is used for looking for available pools - const sellToken = isNativeTokenAddress(inputToken) ? WNATIVE_ADDRESS : inputToken.address - const buyToken = isNativeTokenAddress(outputToken) ? WNATIVE_ADDRESS : outputToken.address - const { swaps, routes } = await PluginTraderRPC.getSwaps( - sellToken, - buyToken, - isExactIn ? BALANCER_SWAP_TYPE.EXACT_IN : BALANCER_SWAP_TYPE.EXACT_OUT, - isExactIn ? inputAmount : outputAmount, - targetChainId, - ) - // no pool found - if (!swaps[0].length) return null - return { swaps, routes } as SwapResponse - }, - DOUBLE_BLOCK_DELAY, - [ - WNATIVE_ADDRESS, - strategy, + return useDoubleBlockBeatRetry(async () => { + if (!WNATIVE_ADDRESS) return null + if (!inputToken || !outputToken) return null + const isExactIn = strategy === TradeStrategy.ExactIn + if (inputAmount === '0' && isExactIn) return null + if (outputAmount === '0' && !isExactIn) return null + // the WETH address is used for looking for available pools + const sellToken = isNativeTokenAddress(inputToken) ? WNATIVE_ADDRESS : inputToken.address + const buyToken = isNativeTokenAddress(outputToken) ? WNATIVE_ADDRESS : outputToken.address + const { swaps, routes } = await PluginTraderRPC.getSwaps( + sellToken, + buyToken, + isExactIn ? BALANCER_SWAP_TYPE.EXACT_IN : BALANCER_SWAP_TYPE.EXACT_OUT, + isExactIn ? inputAmount : outputAmount, targetChainId, - inputAmount, - outputAmount, - inputToken?.address, - outputToken?.address, - ], - ) + ) + // no pool found + if (!swaps[0].length) return null + return { swaps, routes } as SwapResponse + }, [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 2eba1b572360..81ab0830f905 100644 --- a/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts @@ -10,7 +10,7 @@ import { PluginTraderRPC } from '../../messages' import { TradeStrategy } from '../../types' import { useSlippageTolerance } from './useSlippageTolerance' import { TargetChainIdContext } from '../useTargetChainIdContext' -import { DOUBLE_BLOCK_DELAY, leftShift, useBeatRetry } from '@masknet/web3-shared-base' +import { leftShift, useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' export function useTrade( strategy: TradeStrategy, @@ -29,44 +29,40 @@ export function useTrade( const outputAmount = leftShift(outputAmountWei, outputToken?.decimals).toFixed() const isExactIn = strategy === TradeStrategy.ExactIn - return useBeatRetry( - async () => { - if (!inputToken || !outputToken) return null - if (inputAmountWei === '0' && isExactIn) return null - if (outputAmountWei === '0' && !isExactIn) return null - if (![ChainId.Mainnet, ChainId.Ropsten].includes(chainId)) return null + return useDoubleBlockBeatRetry(async () => { + if (!inputToken || !outputToken) return null + if (inputAmountWei === '0' && isExactIn) return null + if (outputAmountWei === '0' && !isExactIn) return null + if (![ChainId.Mainnet, ChainId.Ropsten].includes(chainId)) return null - const fromToken = isNativeTokenAddress(inputToken) - ? { ...inputToken, address: BANCOR_ETH_ADDRESS ?? '' } - : inputToken + const fromToken = isNativeTokenAddress(inputToken) + ? { ...inputToken, address: BANCOR_ETH_ADDRESS ?? '' } + : inputToken - const toToken = isNativeTokenAddress(outputToken) - ? { ...outputToken, address: BANCOR_ETH_ADDRESS ?? '' } - : outputToken + const toToken = isNativeTokenAddress(outputToken) + ? { ...outputToken, address: BANCOR_ETH_ADDRESS ?? '' } + : outputToken - return PluginTraderRPC.swapBancor({ - strategy, - fromToken, - toToken, - fromAmount: isExactIn ? inputAmount : void 0, - toAmount: isExactIn ? void 0 : outputAmount, - slippage, - user, - chainId: chainId as ChainId.Mainnet | ChainId.Ropsten, - minimumReceived: '', - }) - }, - DOUBLE_BLOCK_DELAY, - [ - NATIVE_TOKEN_ADDRESS, + return PluginTraderRPC.swapBancor({ strategy, - inputAmountWei, - outputAmountWei, - inputToken?.address, - outputToken?.address, + fromToken, + toToken, + fromAmount: isExactIn ? inputAmount : void 0, + toAmount: isExactIn ? void 0 : outputAmount, slippage, user, - chainId, - ], - ) + chainId: chainId as ChainId.Mainnet | ChainId.Ropsten, + minimumReceived: '', + }) + }, [ + NATIVE_TOKEN_ADDRESS, + strategy, + inputAmountWei, + outputAmountWei, + inputToken?.address, + outputToken?.address, + slippage, + user, + chainId, + ]) } diff --git a/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts b/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts index 23af8e6c5d0e..f68c768c7db5 100644 --- a/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts @@ -11,7 +11,7 @@ import type { TradeStrategy } from '../../types' import { useSlippageTolerance } from './useSlippageTolerance' import { first } from 'lodash-unified' import { TargetChainIdContext } from '../useTargetChainIdContext' -import { DOUBLE_BLOCK_DELAY, useBeatRetry } from '@masknet/web3-shared-base' +import { useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' export function useTrade( strategy: TradeStrategy, @@ -28,39 +28,35 @@ export function useTrade( const { DODO_ETH_ADDRESS } = useTraderConstants(chainId) const account = useAccount() - return useBeatRetry( - async () => { - if (!inputToken || !outputToken) return null - if (inputAmount === '0') return null - const sellToken = isNativeTokenAddress(inputToken) - ? { ...inputToken, address: DODO_ETH_ADDRESS ?? '' } - : inputToken - const buyToken = isNativeTokenAddress(outputToken) - ? { ...outputToken, address: DODO_ETH_ADDRESS ?? '' } - : outputToken - return PluginTraderRPC.swapRoute({ - isNativeSellToken: isNativeTokenAddress(inputToken), - fromToken: sellToken, - toToken: buyToken, - fromAmount: inputAmount, - slippage: slippage / 100, - userAddr: account, - rpc: providerURL, - chainId, - }) - }, - DOUBLE_BLOCK_DELAY, - [ - NATIVE_TOKEN_ADDRESS, - strategy, - inputAmount, - outputAmount, - inputToken?.address, - outputToken?.address, - slippage, - account, - providerURL, + return useDoubleBlockBeatRetry(async () => { + if (!inputToken || !outputToken) return null + if (inputAmount === '0') return null + const sellToken = isNativeTokenAddress(inputToken) + ? { ...inputToken, address: DODO_ETH_ADDRESS ?? '' } + : inputToken + const buyToken = isNativeTokenAddress(outputToken) + ? { ...outputToken, address: DODO_ETH_ADDRESS ?? '' } + : outputToken + return PluginTraderRPC.swapRoute({ + isNativeSellToken: isNativeTokenAddress(inputToken), + fromToken: sellToken, + toToken: buyToken, + fromAmount: inputAmount, + slippage: slippage / 100, + userAddr: account, + rpc: providerURL, chainId, - ], - ) + }) + }, [ + NATIVE_TOKEN_ADDRESS, + strategy, + inputAmount, + outputAmount, + inputToken?.address, + outputToken?.address, + slippage, + account, + providerURL, + chainId, + ]) } diff --git a/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts b/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts index b441153a7aa4..12f0d3245113 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/web3-shared-base' 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/settings/listener.ts b/packages/mask/src/settings/listener.ts index 857da09a4a83..7bfb4ecd5ab5 100644 --- a/packages/mask/src/settings/listener.ts +++ b/packages/mask/src/settings/listener.ts @@ -8,8 +8,6 @@ import { import type { MaskSettingsEvents } from '@masknet/shared-base' import { currentAccountSettings, - currentBalanceOfChainSettings, - currentBlockNumberOfChainSettings, currentChainIdSettings, currentNonFungibleAssetDataProviderSettings, currentNetworkSettings, @@ -38,8 +36,6 @@ export function ToBeListened(): ToBeListedSettings { languageSettings, debugModeSetting, currentChainIdSettings, - currentBalanceOfChainSettings, - currentBlockNumberOfChainSettings, currentTokenPricesSettings, currentDataProviderSettings, currentProviderSettings, diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index d4610b8976f4..c1c2219e05d1 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -208,12 +208,6 @@ export declare namespace Web3Plugin { [chainId: number]: Record | undefined } - export interface BalanceOfChain { - [chainId: string]: { - [account: string]: string - } - } - export namespace ObjectCapabilities { export interface SharedState { allowTestnet?: Subscription diff --git a/packages/plugin-infra/src/web3/useBalance.ts b/packages/plugin-infra/src/web3/useBalance.ts index 811fca6b3dfe..6286c89b4278 100644 --- a/packages/plugin-infra/src/web3/useBalance.ts +++ b/packages/plugin-infra/src/web3/useBalance.ts @@ -1,10 +1,16 @@ +import { useAsyncRetry } from 'react-use' import { useAccount, useChainId } from '.' -import type { NetworkPluginID } from '..' -import { usePluginWeb3StateContext } from './Context' +import { NetworkPluginID, useWeb3State } from '..' -export function useBalance(chainId?: number, account?: string, pluginID?: NetworkPluginID) { +export function useBalance(expectedChainId?: number, expectedAccount?: string, pluginID?: NetworkPluginID) { + const { Provider } = useWeb3State() const defaultChainId = useChainId(pluginID) const defaultAccount = useAccount(pluginID) - const { balanceOfChain } = usePluginWeb3StateContext(pluginID) - return balanceOfChain?.[chainId ?? defaultChainId]?.[(account ?? defaultAccount).toLowerCase()] ?? '0' + + const chainId = expectedChainId ?? defaultChainId + const account = expectedAccount ?? defaultAccount + + return useAsyncRetry(async () => { + return Provider?.getLatestBalance(chainId, account) ?? '0' + }, [account, chainId, Provider]) } diff --git a/packages/plugin-infra/src/web3/useBlockNumber.ts b/packages/plugin-infra/src/web3/useBlockNumber.ts index 07e3c32d5553..397b54c1f217 100644 --- a/packages/plugin-infra/src/web3/useBlockNumber.ts +++ b/packages/plugin-infra/src/web3/useBlockNumber.ts @@ -1,26 +1,14 @@ -import { useState, useEffect } from 'react' -import { useChainId } from '.' +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(chainId?: number, pluginID?: NetworkPluginID) { +export function useBlockNumber(expectedChainId?: number, pluginID?: NetworkPluginID) { + const { Provider } = useWeb3State() const defaultChainId = useChainId(pluginID) - const { blockNumberOfChain } = usePluginWeb3StateContext(pluginID) - return blockNumberOfChain?.[chainId ?? defaultChainId] ?? 0 -} -/** - * Get the current block number only once - * @returns - */ -export function useBlockNumberOnce(chainId?: number, pluginID?: NetworkPluginID) { - const blockNumber = useBlockNumber(chainId, pluginID) - const [blockNumberOnce, setBlockNumberOnce] = useState(0) - useEffect(() => { - if (blockNumberOnce === 0 && blockNumber > 0) setBlockNumberOnce(blockNumber) - }, [blockNumber]) - return blockNumberOnce + const chainId = expectedChainId ?? defaultChainId + + return useAsyncRetry(async () => { + return Provider?.getLatestBlockNumber(chainId) + }, [Provider, chainId]) } diff --git a/packages/plugins/Debugger/src/SNSAdaptor/components/TabContent.tsx b/packages/plugins/Debugger/src/SNSAdaptor/components/TabContent.tsx index 85d398a87210..4fef779fc705 100644 --- a/packages/plugins/Debugger/src/SNSAdaptor/components/TabContent.tsx +++ b/packages/plugins/Debugger/src/SNSAdaptor/components/TabContent.tsx @@ -66,8 +66,8 @@ export function TabContent({ identity, addressNames }: TabContentProps) { ) } - const balance = useBalance() - const blockNumber = useBlockNumber() + const { value: balance = '0' } = useBalance() + const { value: blockNumber = 0 } = useBlockNumber() return ( <> diff --git a/packages/shared-base/src/Messages/Mask.ts b/packages/shared-base/src/Messages/Mask.ts index 3f21ba925d23..47f432a9f7b9 100644 --- a/packages/shared-base/src/Messages/Mask.ts +++ b/packages/shared-base/src/Messages/Mask.ts @@ -8,8 +8,6 @@ import type { ProviderType, FungibleAssetProvider, NonFungibleAssetProvider, - BalanceOfChain, - BlockNumberOfChain, } from '../../../web3-shared/evm' export interface MaskSettingsEvents { @@ -18,8 +16,6 @@ export interface MaskSettingsEvents { debugModeSetting: boolean pluginIDSettings: string currentChainIdSettings: number - currentBalanceOfChainSettings: BalanceOfChain - currentBlockNumberOfChainSettings: BlockNumberOfChain currentTokenPricesSettings: CryptoPrice currentDataProviderSettings: DataProvider currentProviderSettings: ProviderType diff --git a/packages/web3-shared/base/hooks/useBeat.ts b/packages/web3-shared/base/hooks/useBeat.ts index 01a268503ac3..a4df9dea93d9 100644 --- a/packages/web3-shared/base/hooks/useBeat.ts +++ b/packages/web3-shared/base/hooks/useBeat.ts @@ -18,3 +18,13 @@ export function useBeatRetry(fn: () => Promise, delay = 1000, deps: Depend const beat = useBeat(delay) return useAsyncRetry(fn, [beat].concat(deps)) } + +export function useSingleBlockBeatRetry(fn: () => Promise, deps: DependencyList = []): AsyncStateRetry { + const beat = useBeat(SINGLE_BLOCK_DELAY) + return useAsyncRetry(fn, deps) +} + +export function useDoubleBlockBeatRetry(fn: () => Promise, deps: DependencyList = []): AsyncStateRetry { + const beat = useBeat(DOUBLE_BLOCK_DELAY) + return useAsyncRetry(fn, deps) +} diff --git a/packages/web3-shared/evm/hooks/useAssetsFromChain.ts b/packages/web3-shared/evm/hooks/useAssetsFromChain.ts index 68d031ea0265..4fb1bbd52aca 100644 --- a/packages/web3-shared/evm/hooks/useAssetsFromChain.ts +++ b/packages/web3-shared/evm/hooks/useAssetsFromChain.ts @@ -7,7 +7,7 @@ import { getChainDetailed, EMPTY_LIST } from '../utils' import { useBalance } from '.' export function useAssetsFromChain(tokens: FungibleTokenDetailed[], chainId?: ChainId) { - const balance = useBalance(chainId) + 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 271c86b1232d..7e1c050d41d9 100644 --- a/packages/web3-shared/evm/hooks/useBalance.ts +++ b/packages/web3-shared/evm/hooks/useBalance.ts @@ -1,10 +1,18 @@ -import { useWeb3StateContext } from '../context' import type { ChainId } from '../types' import { useAccount, useChainId } from '..' +import { useWeb3 } from '.' +import { useAsyncRetry } from 'react-use' -export function useBalance(chainId?: ChainId, account?: string) { +export function useBalance(expectedChainId?: ChainId, expectedAccount?: string) { const defaultChainId = useChainId() const defaultAccount = useAccount() - const { balanceOfChain } = useWeb3StateContext() - return balanceOfChain[chainId ?? defaultChainId]?.[account ?? defaultAccount] ?? '0' + + const chainId = expectedChainId ?? defaultChainId + const account = expectedAccount ?? defaultAccount + + const web3 = useWeb3(true, chainId) + + return useAsyncRetry(async () => { + return web3.eth.getBalance(account) + }, [web3, account]) } diff --git a/packages/web3-shared/evm/hooks/useBlockNumber.ts b/packages/web3-shared/evm/hooks/useBlockNumber.ts index cd2bb3816ef7..de169cd07955 100644 --- a/packages/web3-shared/evm/hooks/useBlockNumber.ts +++ b/packages/web3-shared/evm/hooks/useBlockNumber.ts @@ -1,26 +1,15 @@ -import { useState, useEffect } from 'react' -import { useChainId } from '.' +import { useAsyncRetry } from 'react-use' +import { useChainId, useWeb3 } from '.' import type { ChainId } from '..' -import { useWeb3StateContext } from '../context' /** * Get the current block number of current chain */ -export function useBlockNumber(chainId?: ChainId) { +export function useBlockNumber(expectedChainId?: ChainId) { const defaultChainId = useChainId() - const { blockNumberOfChain } = useWeb3StateContext() - return blockNumberOfChain[chainId ?? defaultChainId] ?? 0 -} + const web3 = useWeb3(true, 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/useERC20TokenAllowance.ts b/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts index 59a10282cc62..7b6f3b6380f6 100644 --- a/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts +++ b/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts @@ -1,20 +1,16 @@ import { useERC20TokenContract } from '../contracts/useERC20TokenContract' import { useAccount } from './useAccount' import { useChainId } from './useChainId' -import { DOUBLE_BLOCK_DELAY, useBeatRetry } from '@masknet/web3-shared-base' +import { useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' export function useERC20TokenAllowance(address?: string, spender?: string) { const account = useAccount() const chainId = useChainId() const erc20Contract = useERC20TokenContract(address) - return useBeatRetry( - async () => { - if (!account || !spender || !erc20Contract) return '0' - return erc20Contract.methods.allowance(account, spender).call({ - from: account, - }) - }, - DOUBLE_BLOCK_DELAY, - [account, chainId, spender, erc20Contract], - ) + return useDoubleBlockBeatRetry(async () => { + if (!account || !spender || !erc20Contract) return '0' + return erc20Contract.methods.allowance(account, spender).call({ + from: account, + }) + }, [account, chainId, spender, erc20Contract]) } diff --git a/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts b/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts index 29c1906f0d79..240e2845941e 100644 --- a/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts +++ b/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts @@ -1,5 +1,5 @@ import { toHex } from 'web3-utils' -import { DOUBLE_BLOCK_DELAY, useBeatRetry } from '@masknet/web3-shared-base' +import { useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' import { useAccount } from './useAccount' import { useERC20TokenContract } from '../contracts/useERC20TokenContract' import { useChainId } from './useChainId' @@ -15,15 +15,11 @@ export function useERC20TokenBalance(address?: string, targetChainId?: ChainId) const currentChainId = useChainId() const chainId = targetChainId ?? currentChainId const erc20Contract = useERC20TokenContract(address) - return useBeatRetry( - async () => { - if (!account || !address || !erc20Contract) return undefined - return erc20Contract.methods.balanceOf(account).call({ - from: account, - chainId: toHex(chainId), - }) - }, - DOUBLE_BLOCK_DELAY, - [account, chainId, address, erc20Contract], - ) + return useDoubleBlockBeatRetry(async () => { + if (!account || !address || !erc20Contract) return undefined + return erc20Contract.methods.balanceOf(account).call({ + from: account, + chainId: toHex(chainId), + }) + }, [account, chainId, address, erc20Contract]) } diff --git a/packages/web3-shared/evm/hooks/useMulticall.ts b/packages/web3-shared/evm/hooks/useMulticall.ts index aa584e73ea1f..b00d22c3ce0a 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, diff --git a/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts b/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts index b5f06d9dce11..9eb8443bd951 100644 --- a/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts +++ b/packages/web3-shared/evm/hooks/useNativeTokenBalance.ts @@ -8,7 +8,7 @@ import { useBalance } from './useBalance' */ export function useNativeTokenBalance() { const account = useAccount() - const balance = useBalance() + const { value: balance = '0' } = useBalance() return useAsyncRetry(async () => { if (!account) return return balance diff --git a/packages/web3-shared/evm/types/index.ts b/packages/web3-shared/evm/types/index.ts index d5e08d425106..44e3b9ae7625 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 BalanceOfChain { - [chainId: string]: { - [account: string]: string - } -} // bigint is not in our list. iOS doesn't support that. export type Primitive = string | number | boolean | symbol | undefined | null From 3ff1efe3833f267016f5c7830a55ef4196a3587b Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Tue, 18 Jan 2022 19:19:22 +0800 Subject: [PATCH 07/11] refactor: beat retry hooks --- .../src/plugins/MaskBox/hooks/useContext.ts | 2 +- .../src/plugins/Trader/trader/0x/useTrade.ts | 2 +- .../Trader/trader/balancer/useTrade.ts | 2 +- .../plugins/Trader/trader/bancor/useTrade.ts | 3 ++- .../plugins/Trader/trader/dodo/useTrade.ts | 2 +- .../Trader/trader/openocean/useTrade.ts | 2 +- packages/plugin-infra/package.json | 1 + packages/plugin-infra/src/web3-types.ts | 2 ++ packages/plugin-infra/src/web3/index.ts | 1 + packages/plugin-infra/src/web3/useBeat.ts | 20 ++++++++++++++++ packages/web3-shared/base/hooks/useBeat.ts | 19 +++------------ .../evm/hooks/useERC20TokenAllowance.ts | 18 ++++++++------ .../evm/hooks/useERC20TokenBalance.ts | 24 +++++++++++-------- pnpm-lock.yaml | 2 ++ 14 files changed, 61 insertions(+), 39 deletions(-) create mode 100644 packages/plugin-infra/src/web3/useBeat.ts diff --git a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts index b32636d287d5..3838585001ab 100644 --- a/packages/mask/src/plugins/MaskBox/hooks/useContext.ts +++ b/packages/mask/src/plugins/MaskBox/hooks/useContext.ts @@ -36,7 +36,7 @@ import { formatCountdown } from '../helpers/formatCountdown' import { useOpenBoxTransaction } from './useOpenBoxTransaction' import { useMaskBoxMetadata } from './useMaskBoxMetadata' import { useIsWhitelisted } from './useIsWhitelisted' -import { useBeat, 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() diff --git a/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts b/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts index 0086b666b52d..0f1bc1d3f1d6 100644 --- a/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/0x/useTrade.ts @@ -15,7 +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/web3-shared-base' +import { useDoubleBlockBeatRetry } from '@masknet/plugin-infra' const NATIVE_TOKEN_ADDRESS = '0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee' diff --git a/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts b/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts index d978fa3c9410..5903d1161632 100644 --- a/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/balancer/useTrade.ts @@ -1,4 +1,4 @@ -import { useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' +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' diff --git a/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts b/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts index 81ab0830f905..b08cad56e84a 100644 --- a/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/bancor/useTrade.ts @@ -10,7 +10,8 @@ import { PluginTraderRPC } from '../../messages' import { TradeStrategy } from '../../types' import { useSlippageTolerance } from './useSlippageTolerance' import { TargetChainIdContext } from '../useTargetChainIdContext' -import { leftShift, useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' +import { leftShift } from '@masknet/web3-shared-base' +import { useDoubleBlockBeatRetry } from '@masknet/plugin-infra' export function useTrade( strategy: TradeStrategy, diff --git a/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts b/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts index f68c768c7db5..40421236a45d 100644 --- a/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/dodo/useTrade.ts @@ -11,7 +11,7 @@ import type { TradeStrategy } from '../../types' import { useSlippageTolerance } from './useSlippageTolerance' import { first } from 'lodash-unified' import { TargetChainIdContext } from '../useTargetChainIdContext' -import { useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' +import { useDoubleBlockBeatRetry } from '@masknet/plugin-infra' export function useTrade( strategy: TradeStrategy, diff --git a/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts b/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts index 12f0d3245113..e1fc6adf60db 100644 --- a/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts +++ b/packages/mask/src/plugins/Trader/trader/openocean/useTrade.ts @@ -12,7 +12,7 @@ import type { TradeStrategy } from '../../types' import { TargetChainIdContext } from '../useTargetChainIdContext' import { useSlippageTolerance } from './useSlippageTolerance' import { OPENOCEAN_SUPPORTED_CHAINS } from './constants' -import { useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' +import { useDoubleBlockBeatRetry } from '@masknet/plugin-infra' export function useTrade( strategy: TradeStrategy, 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 c1c2219e05d1..fe204e405e8a 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -317,6 +317,8 @@ 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 diff --git a/packages/plugin-infra/src/web3/index.ts b/packages/plugin-infra/src/web3/index.ts index b2f2d19e7919..e78bb7e9fe2d 100644 --- a/packages/plugin-infra/src/web3/index.ts +++ b/packages/plugin-infra/src/web3/index.ts @@ -2,6 +2,7 @@ export * from './useAccount' export * from './useAllowTestnet' export * from './useAssetType' export * from './useBalance' +export * from './useBeat' export * from './useBlockNumber' export * from './useChainId' export * from './useChainColor' 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/web3-shared/base/hooks/useBeat.ts b/packages/web3-shared/base/hooks/useBeat.ts index a4df9dea93d9..b675feffcb06 100644 --- a/packages/web3-shared/base/hooks/useBeat.ts +++ b/packages/web3-shared/base/hooks/useBeat.ts @@ -2,29 +2,16 @@ import { DependencyList, useState } from 'react' import { useAsyncRetry, useTimeoutFn } from 'react-use' import type { AsyncStateRetry } from 'react-use/lib/useAsyncRetry' -export const SINGLE_BLOCK_DELAY = 15 * 1000 -export const DOUBLE_BLOCK_DELAY = SINGLE_BLOCK_DELAY * 2 - export function useBeat(delay = 1000) { - const [bit, setBit] = useState(0) + const [beat, setBeat] = useState(0) const [, , reset] = useTimeoutFn(() => { - setBit((x) => (x + 1) % Number.MAX_SAFE_INTEGER) + setBeat((x) => (x + 1) % Number.MAX_SAFE_INTEGER) reset() }, delay) - return bit + return beat } export function useBeatRetry(fn: () => Promise, delay = 1000, deps: DependencyList = []): AsyncStateRetry { const beat = useBeat(delay) return useAsyncRetry(fn, [beat].concat(deps)) } - -export function useSingleBlockBeatRetry(fn: () => Promise, deps: DependencyList = []): AsyncStateRetry { - const beat = useBeat(SINGLE_BLOCK_DELAY) - return useAsyncRetry(fn, deps) -} - -export function useDoubleBlockBeatRetry(fn: () => Promise, deps: DependencyList = []): AsyncStateRetry { - const beat = useBeat(DOUBLE_BLOCK_DELAY) - return useAsyncRetry(fn, deps) -} diff --git a/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts b/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts index 7b6f3b6380f6..822c602aa7ce 100644 --- a/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts +++ b/packages/web3-shared/evm/hooks/useERC20TokenAllowance.ts @@ -1,16 +1,20 @@ +import { useBeatRetry } from '@masknet/web3-shared-base' import { useERC20TokenContract } from '../contracts/useERC20TokenContract' import { useAccount } from './useAccount' import { useChainId } from './useChainId' -import { useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' export function useERC20TokenAllowance(address?: string, spender?: string) { const account = useAccount() const chainId = useChainId() const erc20Contract = useERC20TokenContract(address) - return useDoubleBlockBeatRetry(async () => { - if (!account || !spender || !erc20Contract) return '0' - return erc20Contract.methods.allowance(account, spender).call({ - from: account, - }) - }, [account, 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 240e2845941e..d47fa9c99f1c 100644 --- a/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts +++ b/packages/web3-shared/evm/hooks/useERC20TokenBalance.ts @@ -1,5 +1,5 @@ import { toHex } from 'web3-utils' -import { useDoubleBlockBeatRetry } from '@masknet/web3-shared-base' +import { useBeatRetry } from '@masknet/web3-shared-base' import { useAccount } from './useAccount' import { useERC20TokenContract } from '../contracts/useERC20TokenContract' import { useChainId } from './useChainId' @@ -12,14 +12,18 @@ import type { ChainId } from '../types' */ export function useERC20TokenBalance(address?: string, targetChainId?: ChainId) { const account = useAccount() - const currentChainId = useChainId() - const chainId = targetChainId ?? currentChainId + const defaultChainId = useChainId() + const chainId = targetChainId ?? defaultChainId const erc20Contract = useERC20TokenContract(address) - return useDoubleBlockBeatRetry(async () => { - if (!account || !address || !erc20Contract) return undefined - return erc20Contract.methods.balanceOf(account).call({ - from: account, - chainId: toHex(chainId), - }) - }, [account, 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/pnpm-lock.yaml b/pnpm-lock.yaml index 125e836f4860..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 From 455f9e7d2554c79abd1ae79801a186dec4de5788 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Tue, 18 Jan 2022 20:55:07 +0800 Subject: [PATCH 08/11] refactor: reduce tx queries --- .../components/Transfer/TransferERC721.tsx | 1 + .../components/WalletStateBar/index.tsx | 4 +- .../Wallets/hooks/useRecentTransactions.ts | 10 ++--- .../InjectedComponents/ToolboxUnstyled.tsx | 4 +- .../EthereumServices/send.ts | 6 ++- .../src/extension/popups/pages/Swap/index.tsx | 4 +- .../pages/Wallet/hooks/useWalletContext.ts | 6 ++- .../trader/hooks/useUpdateBalance.ts | 10 ++--- .../Trader/trader/useTargetBlockNumber.ts | 10 ++--- .../Wallet/hooks/useRecentTransactions.ts | 10 ++--- .../Wallet/services/transaction/index.ts | 44 +++++++++++++++---- .../Wallet/services/transaction/watcher.ts | 20 ++++++--- 12 files changed, 86 insertions(+), 43 deletions(-) diff --git a/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx b/packages/dashboard/src/pages/Wallets/components/Transfer/TransferERC721.tsx index a3c7027de089..4b16e5317c06 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 c4ad9cc288b5..1d209486b25d 100644 --- a/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx +++ b/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx @@ -49,7 +49,9 @@ export const WalletStateBar = memo(() => { const wallet = useWallet() const networkDescriptor = useNetworkDescriptor() const providerDescriptor = useProviderDescriptor() - const { value: pendingTransactions = [] } = useRecentTransactions(TransactionStatusType.NOT_DEPEND) + const { value: pendingTransactions = [] } = 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/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx b/packages/mask/src/components/InjectedComponents/ToolboxUnstyled.tsx index dd73b57afd5d..509b492a05ac 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 d1488a3750e9..7095b0877541 100644 --- a/packages/mask/src/extension/background-script/EthereumServices/send.ts +++ b/packages/mask/src/extension/background-script/EthereumServices/send.ts @@ -150,7 +150,7 @@ export async function INTERNAL_send( providerType = currentProviderSettings.value, }: SendOverrides = {}, ) { - if (process.env.NODE_ENV === 'development' && debugModeSetting.value) { + if (process.env.NODE_ENV === 'development') { console.table(payload) console.debug(new Error().stack) } @@ -397,7 +397,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/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/hooks/useWalletContext.ts b/packages/mask/src/extension/popups/pages/Wallet/hooks/useWalletContext.ts index 48a4a4c928e2..002df3eadc27 100644 --- a/packages/mask/src/extension/popups/pages/Wallet/hooks/useWalletContext.ts +++ b/packages/mask/src/extension/popups/pages/Wallet/hooks/useWalletContext.ts @@ -3,12 +3,16 @@ import { createContainer } from 'unstated-next' import { useAssets, useTrustedERC20Tokens, Asset, useChainDetailed } from '@masknet/web3-shared-evm' import { useRecentTransactions } from '../../../../../plugins/Wallet/hooks/useRecentTransactions' import type { RecentTransaction } from '../../../../../plugins/Wallet/services' +import { tr } from 'date-fns/locale' 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/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts index 58fd5babd379..8e15c60b4ad2 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts @@ -5,12 +5,13 @@ import { useAccount, useProviderType, useTokenConstants, + useWeb3, } from '@masknet/web3-shared-evm' import { useAsync } from 'react-use' import { AllProviderTradeActionType, AllProviderTradeContext } from '../../../trader/useAllProviderTradeContext' -import Services from '../../../../../extension/service' export function useUpdateBalance(chainId: ChainId, currentChainId: ChainId) { + const web3 = useWeb3(true, chainId) const currentAccount = useAccount() const currentProvider = useProviderType() const { NATIVE_TOKEN_ADDRESS } = useTokenConstants() @@ -34,10 +35,7 @@ export function useUpdateBalance(chainId: ChainId, currentChainId: ChainId) { } if (chainId && currentProvider && currentAccount) { - const balance = await Services.Ethereum.getBalance(currentAccount, { - chainId: chainId, - providerType: currentProvider, - }) + const balance = await web3.eth.getBalance(currentAccount) dispatchTradeStore({ type: AllProviderTradeActionType.UPDATE_INPUT_TOKEN_BALANCE, @@ -53,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/trader/useTargetBlockNumber.ts b/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts index 13981504c626..7e01004ad7c7 100644 --- a/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts +++ b/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts @@ -1,14 +1,12 @@ import { useAsync } from 'react-use' import type { AsyncState } from 'react-use/lib/useAsyncFn' -import { ChainId, useChainId } from '@masknet/web3-shared-evm' -import Services from '../../../extension/service' +import { ChainId, useChainId, useWeb3 } from '@masknet/web3-shared-evm' export function useTargetBlockNumber(targetChainId?: ChainId): AsyncState { const chainId = useChainId() + const web3 = useWeb3(true, 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/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/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(), + ) } } From 1d311bf5ab9b1109372e321be46ced161550ed9b Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Tue, 18 Jan 2022 21:56:55 +0800 Subject: [PATCH 09/11] refactor: reduce token icon renders --- .../background-script/EthereumServices/send.ts | 2 +- packages/shared/src/UI/components/TokenIcon/index.tsx | 4 +--- packages/shared/src/UI/hooks/useImageFailOver.ts | 11 +++++++++-- .../src/Components/SearchableList/SearchableList.tsx | 4 ++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/mask/src/extension/background-script/EthereumServices/send.ts b/packages/mask/src/extension/background-script/EthereumServices/send.ts index 7095b0877541..4649965b6020 100644 --- a/packages/mask/src/extension/background-script/EthereumServices/send.ts +++ b/packages/mask/src/extension/background-script/EthereumServices/send.ts @@ -150,7 +150,7 @@ export async function INTERNAL_send( providerType = currentProviderSettings.value, }: SendOverrides = {}, ) { - if (process.env.NODE_ENV === 'development') { + if (process.env.NODE_ENV === 'development' && debugModeSetting.value) { console.table(payload) console.debug(new Error().stack) } 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 c457430b10de..23e99173843b 100644 --- a/packages/theme/src/Components/SearchableList/SearchableList.tsx +++ b/packages/theme/src/Components/SearchableList/SearchableList.tsx @@ -118,8 +118,8 @@ export function SearchableList({ Date: Tue, 18 Jan 2022 23:08:19 +0800 Subject: [PATCH 10/11] refactor: createExternalProvider --- packages/dashboard/src/web3/context.ts | 52 +-------------- .../Wallet/GasSetting/GasSetting1559.tsx | 2 +- .../Wallet/GasSetting/Prior1559GasSetting.tsx | 2 +- .../pages/Wallet/hooks/useWalletContext.ts | 1 - .../Collectible/apis/openseaFromSDK.ts | 29 +++------ .../plugins/EVM/UI/Web3State/getAssetsFn.ts | 52 ++++++++------- .../src/plugins/EVM/UI/Web3State/index.ts | 25 +++++-- .../FindTruman/SNSAdaptor/OptionsCard.tsx | 4 +- .../Gitcoin/hooks/useDonateCallback.ts | 8 +-- .../plugins/ITO/SNSAdaptor/hooks/useFill.ts | 2 +- .../RedPacket/SNSAdaptor/RedPacket/index.tsx | 1 + .../trader/hooks/useUpdateBalance.ts | 2 +- .../balancer/useExchangeProxyContract.ts | 4 +- .../contracts/uniswap/usePairContract.ts | 4 +- .../contracts/uniswap/usePoolContract.ts | 2 +- .../contracts/uniswap/useQuoterContract.ts | 2 +- .../contracts/uniswap/useRouterV2Contract.ts | 4 +- .../uniswap/useSwapRouterContract.ts | 4 +- .../Trader/trader/0x/useTradeCallback.ts | 2 +- .../Trader/trader/bancor/useTradeCallback.ts | 2 +- .../Trader/trader/bancor/useTradeGasLimit.ts | 16 ++--- .../Trader/trader/dodo/useTradeCallback.ts | 2 +- .../Trader/trader/dodo/useTradeGasLimit.ts | 2 +- .../trader/openocean/useTradeGasLimit.ts | 2 +- .../Trader/trader/uniswap/useTradeCallback.ts | 2 +- .../Trader/trader/uniswap/useTradeGasLimit.ts | 2 +- .../Trader/trader/useTargetBlockNumber.ts | 2 +- packages/mask/src/web3/context.ts | 36 +++++----- packages/mask/src/web3/helpers.ts | 41 ------------ packages/plugin-infra/src/web3-types.ts | 7 +- packages/plugin-infra/src/web3/useBalance.ts | 6 +- .../plugin-infra/src/web3/useBlockNumber.ts | 6 +- packages/web3-shared/evm/context/type.ts | 13 +++- .../contracts/useERC20TokenBytes32Contract.ts | 4 +- .../evm/contracts/useERC20TokenContract.ts | 8 +-- .../evm/contracts/useERC721TokenContract.ts | 6 +- packages/web3-shared/evm/hooks/useBalance.ts | 2 +- .../web3-shared/evm/hooks/useBlockNumber.ts | 2 +- packages/web3-shared/evm/hooks/useContract.ts | 18 ++--- .../evm/hooks/useERC20TokenDetailed.ts | 4 +- .../hooks/useERC721TokenDetailedOwnerList.ts | 2 +- packages/web3-shared/evm/hooks/useGasPrice.ts | 2 +- .../web3-shared/evm/hooks/useMulticall.ts | 2 +- .../web3-shared/evm/hooks/useResolveENS.ts | 3 +- packages/web3-shared/evm/hooks/useWeb3.ts | 21 ++---- .../web3-shared/evm/hooks/useWeb3Provider.ts | 24 +++++-- packages/web3-shared/evm/utils/index.ts | 1 + packages/web3-shared/evm/utils/provider.ts | 65 +++++++++++++++++++ 48 files changed, 239 insertions(+), 266 deletions(-) delete mode 100644 packages/mask/src/web3/helpers.ts create mode 100644 packages/web3-shared/evm/utils/provider.ts diff --git a/packages/dashboard/src/web3/context.ts b/packages/dashboard/src/web3/context.ts index 1ec9fd723797..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 () => {} }), @@ -97,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, @@ -108,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/extension/popups/pages/Wallet/GasSetting/GasSetting1559.tsx b/packages/mask/src/extension/popups/pages/Wallet/GasSetting/GasSetting1559.tsx index 481da3c42819..4395c70ed967 100644 --- a/packages/mask/src/extension/popups/pages/Wallet/GasSetting/GasSetting1559.tsx +++ b/packages/mask/src/extension/popups/pages/Wallet/GasSetting/GasSetting1559.tsx @@ -112,9 +112,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 525daf15e196..80b33c77ef69 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 002df3eadc27..993afe13c84e 100644 --- a/packages/mask/src/extension/popups/pages/Wallet/hooks/useWalletContext.ts +++ b/packages/mask/src/extension/popups/pages/Wallet/hooks/useWalletContext.ts @@ -3,7 +3,6 @@ import { createContainer } from 'unstated-next' import { useAssets, useTrustedERC20Tokens, Asset, useChainDetailed } from '@masknet/web3-shared-evm' import { useRecentTransactions } from '../../../../../plugins/Wallet/hooks/useRecentTransactions' import type { RecentTransaction } from '../../../../../plugins/Wallet/services' -import { tr } from 'date-fns/locale' function useWalletContext() { const chainDetailed = useChainDetailed() diff --git a/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts b/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts index df28bebf0401..be0954b9b489 100644 --- a/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts +++ b/packages/mask/src/plugins/Collectible/apis/openseaFromSDK.ts @@ -1,27 +1,18 @@ import { OpenSeaPort } from 'opensea-js' -import { 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' -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) { 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 10086c884f46..9cdd3494ac15 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' @@ -49,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 @@ -60,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) @@ -83,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 @@ -93,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) @@ -114,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, @@ -131,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/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 ca2929aadb6f..3409c3a3423b 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 { EthereumTokenType, @@ -7,10 +9,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' /** @@ -23,7 +22,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() @@ -99,7 +97,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/useFill.ts b/packages/mask/src/plugins/ITO/SNSAdaptor/hooks/useFill.ts index 68644311a714..5bc3c91e5c43 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/RedPacket/SNSAdaptor/RedPacket/index.tsx b/packages/mask/src/plugins/RedPacket/SNSAdaptor/RedPacket/index.tsx index ec910f7fa819..a2b465e7160b 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/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts index 8e15c60b4ad2..3a994d6ad047 100644 --- a/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts +++ b/packages/mask/src/plugins/Trader/SNSAdaptor/trader/hooks/useUpdateBalance.ts @@ -11,7 +11,7 @@ import { useAsync } from 'react-use' import { AllProviderTradeActionType, AllProviderTradeContext } from '../../../trader/useAllProviderTradeContext' export function useUpdateBalance(chainId: ChainId, currentChainId: ChainId) { - const web3 = useWeb3(true, chainId) + const web3 = useWeb3(chainId) const currentAccount = useAccount() const currentProvider = useProviderType() const { NATIVE_TOKEN_ADDRESS } = useTokenConstants() 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/useTradeCallback.ts b/packages/mask/src/plugins/Trader/trader/0x/useTradeCallback.ts index c099d237ba1c..a201d3ec5cd0 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/bancor/useTradeCallback.ts b/packages/mask/src/plugins/Trader/trader/bancor/useTradeCallback.ts index 4ef89bad20aa..a7b312bc3c8a 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..6eb87d50dc42 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(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/useTradeCallback.ts b/packages/mask/src/plugins/Trader/trader/dodo/useTradeCallback.ts index 5169a9e724df..ff80f0a37cb0 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..e57ef67f5688 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(targetChainId) const account = useAccount() const config = useMemo(() => { if (!account || !tradeComputed?.trade_) return null diff --git a/packages/mask/src/plugins/Trader/trader/openocean/useTradeGasLimit.ts b/packages/mask/src/plugins/Trader/trader/openocean/useTradeGasLimit.ts index 255f1a20de8d..7332061134d2 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(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..3263c17c7b54 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(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..ee8272f1a586 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(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 7e01004ad7c7..4691f618d470 100644 --- a/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts +++ b/packages/mask/src/plugins/Trader/trader/useTargetBlockNumber.ts @@ -4,7 +4,7 @@ import { ChainId, useChainId, useWeb3 } from '@masknet/web3-shared-evm' export function useTargetBlockNumber(targetChainId?: ChainId): AsyncState { const chainId = useChainId() - const web3 = useWeb3(true, chainId) + const web3 = useWeb3(chainId) return useAsync(async () => { if (targetChainId === chainId) return undefined return web3.eth.getBlockNumber() diff --git a/packages/mask/src/web3/context.ts b/packages/mask/src/web3/context.ts index 0814ec9986a3..dd3f6cd093cf 100644 --- a/packages/mask/src/web3/context.ts +++ b/packages/mask/src/web3/context.ts @@ -26,31 +26,11 @@ import { 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( @@ -117,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/mask/src/web3/helpers.ts b/packages/mask/src/web3/helpers.ts deleted file mode 100644 index 50a0d73139d1..000000000000 --- a/packages/mask/src/web3/helpers.ts +++ /dev/null @@ -1,41 +0,0 @@ -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' - -export function createExternalProvider(getOverrides?: () => SendOverrides, getOptions?: () => RequestOptions) { - const send = (payload: JsonRpcPayload, callback: (error: Error | null, response?: JsonRpcResponse) => void) => { - Services.Ethereum.request( - { - method: payload.method, - params: payload.params, - }, - getOverrides?.(), - getOptions?.(), - ).then( - (result) => { - callback(null, { - jsonrpc: '2.0', - id: payload.id as number, - result, - }) - }, - (error: unknown) => { - if (error instanceof Error) callback(error) - }, - ) - } - const request = (requestArguments: RequestArguments) => - Services.Ethereum.request(requestArguments, getOverrides?.(), getOptions?.()) - - return { - isMetaMask: false, - isMask: true, - isStatus: true, - host: '', - path: '', - request: request, - send, - sendAsync: send, - } -} diff --git a/packages/plugin-infra/src/web3-types.ts b/packages/plugin-infra/src/web3-types.ts index fe204e405e8a..dfa026805014 100644 --- a/packages/plugin-infra/src/web3-types.ts +++ b/packages/plugin-infra/src/web3-types.ts @@ -274,10 +274,6 @@ export declare namespace Web3Plugin { network: NetworkDescriptor, pagination?: Pagination, ) => Promise - /** Get latest block number of given chain. */ - getLatestBlockNumber: (chainId: number) => Promise - /** Get latest balance of given account. */ - getLatestBalance: (chainId: number, account: string) => Promise } export interface TokenListState { /** Get the token lists of supported fungible tokens. */ @@ -296,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 diff --git a/packages/plugin-infra/src/web3/useBalance.ts b/packages/plugin-infra/src/web3/useBalance.ts index 6286c89b4278..513b55a4806b 100644 --- a/packages/plugin-infra/src/web3/useBalance.ts +++ b/packages/plugin-infra/src/web3/useBalance.ts @@ -3,7 +3,7 @@ import { useAccount, useChainId } from '.' import { NetworkPluginID, useWeb3State } from '..' export function useBalance(expectedChainId?: number, expectedAccount?: string, pluginID?: NetworkPluginID) { - const { Provider } = useWeb3State() + const { Utils } = useWeb3State() const defaultChainId = useChainId(pluginID) const defaultAccount = useAccount(pluginID) @@ -11,6 +11,6 @@ export function useBalance(expectedChainId?: number, expectedAccount?: string, p const account = expectedAccount ?? defaultAccount return useAsyncRetry(async () => { - return Provider?.getLatestBalance(chainId, account) ?? '0' - }, [account, chainId, Provider]) + return Utils?.getLatestBalance?.(chainId, account) ?? '0' + }, [account, chainId, Utils]) } diff --git a/packages/plugin-infra/src/web3/useBlockNumber.ts b/packages/plugin-infra/src/web3/useBlockNumber.ts index 397b54c1f217..b3970cecd4f4 100644 --- a/packages/plugin-infra/src/web3/useBlockNumber.ts +++ b/packages/plugin-infra/src/web3/useBlockNumber.ts @@ -3,12 +3,12 @@ import { useChainId, useWeb3State } from '.' import type { NetworkPluginID } from '..' export function useBlockNumber(expectedChainId?: number, pluginID?: NetworkPluginID) { - const { Provider } = useWeb3State() + const { Utils } = useWeb3State() const defaultChainId = useChainId(pluginID) const chainId = expectedChainId ?? defaultChainId return useAsyncRetry(async () => { - return Provider?.getLatestBlockNumber(chainId) - }, [Provider, chainId]) + return Utils?.getLatestBlockNumber?.(chainId) + }, [Utils, chainId]) } diff --git a/packages/web3-shared/evm/context/type.ts b/packages/web3-shared/evm/context/type.ts index c04ea209cfa8..5609a61ad3f4 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 { provider as Provider, RequestArguments } from 'web3-core' import type { Subscription } from 'use-subscription' import type { ChainId, @@ -16,6 +16,8 @@ import type { AddressName, CryptoPrice, ERC721TokenCollectionInfo, + SendOverrides, + RequestOptions, } from '../types' import type { ProviderProxy } from '@masknet/web3-shared-base' @@ -23,7 +25,6 @@ export interface Web3ProviderType { allowTestnet: Subscription chainId: Subscription account: Subscription - provider: Subscription networkType: Subscription providerType: Subscription tokenPrices: Subscription @@ -39,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/useBalance.ts b/packages/web3-shared/evm/hooks/useBalance.ts index 7e1c050d41d9..af2e368bcd12 100644 --- a/packages/web3-shared/evm/hooks/useBalance.ts +++ b/packages/web3-shared/evm/hooks/useBalance.ts @@ -10,7 +10,7 @@ export function useBalance(expectedChainId?: ChainId, expectedAccount?: string) const chainId = expectedChainId ?? defaultChainId const account = expectedAccount ?? defaultAccount - const web3 = useWeb3(true, chainId) + const web3 = useWeb3(chainId) return useAsyncRetry(async () => { return web3.eth.getBalance(account) diff --git a/packages/web3-shared/evm/hooks/useBlockNumber.ts b/packages/web3-shared/evm/hooks/useBlockNumber.ts index de169cd07955..1b6d3ebcd46b 100644 --- a/packages/web3-shared/evm/hooks/useBlockNumber.ts +++ b/packages/web3-shared/evm/hooks/useBlockNumber.ts @@ -7,7 +7,7 @@ import type { ChainId } from '..' */ export function useBlockNumber(expectedChainId?: ChainId) { const defaultChainId = useChainId() - const web3 = useWeb3(true, expectedChainId ?? defaultChainId) + const web3 = useWeb3(expectedChainId ?? defaultChainId) return useAsyncRetry(async () => { return web3.eth.getBlockNumber() diff --git a/packages/web3-shared/evm/hooks/useContract.ts b/packages/web3-shared/evm/hooks/useContract.ts index 62ec14ef299f..b74e105cf236 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/useERC20TokenDetailed.ts b/packages/web3-shared/evm/hooks/useERC20TokenDetailed.ts index 484b9588e0b9..8a02b443f9ef 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 5139159ada39..c4cdc677fba2 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..20345f843fee 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 b00d22c3ce0a..036e7cdfb5b6 100644 --- a/packages/web3-shared/evm/hooks/useMulticall.ts +++ b/packages/web3-shared/evm/hooks/useMulticall.ts @@ -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/useResolveENS.ts b/packages/web3-shared/evm/hooks/useResolveENS.ts index 602044603c70..d3c7bc957367 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.Mainnet) return useAsyncRetry(async () => { if (!name) return return web3.eth.ens.getAddress(name) diff --git a/packages/web3-shared/evm/hooks/useWeb3.ts b/packages/web3-shared/evm/hooks/useWeb3.ts index c15f4d19969a..43e46c17ed0c 100644 --- a/packages/web3-shared/evm/hooks/useWeb3.ts +++ b/packages/web3-shared/evm/hooks/useWeb3.ts @@ -1,24 +1,11 @@ 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' -function useWeb3Instance() { - const provider = useWeb3Provider() +export function useWeb3(chainId?: ChainId) { + const provider = useWeb3Provider({ + chainId, + }) 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/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/web3-shared/evm/utils/provider.ts b/packages/web3-shared/evm/utils/provider.ts new file mode 100644 index 000000000000..0743e2226c28 --- /dev/null +++ b/packages/web3-shared/evm/utils/provider.ts @@ -0,0 +1,65 @@ +import Web3 from 'web3' +import type { RequestArguments } from 'web3-core' +import type { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers' +import type { RequestOptions, SendOverrides } from '../types' + +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) => { + request( + { + method: payload.method, + params: payload.params, + }, + getOverrides?.(), + getOptions?.(), + ).then( + (result) => { + callback(null, { + jsonrpc: '2.0', + id: payload.id as number, + result, + }) + }, + (error: unknown) => { + if (error instanceof Error) callback(error) + }, + ) + } + + return { + isMetaMask: false, + isMask: true, + isStatus: true, + host: '', + path: '', + request: (requestArguments: RequestArguments) => request(requestArguments, getOverrides?.(), getOptions?.()), + send, + sendAsync: send, + } +} + +export function createWeb3( + request: ( + requestArguments: RequestArguments, + overrides?: SendOverrides, + options?: RequestOptions, + ) => Promise, + overrides?: SendOverrides, + options?: RequestOptions, +) { + return new Web3( + createExternalProvider( + request, + () => overrides ?? {}, + () => options ?? {}, + ), + ) +} From cf54f9b4c4c8c4ac970a34b834eddf1e58383ff2 Mon Sep 17 00:00:00 2001 From: guanbinrui Date: Tue, 25 Jan 2022 10:11:58 +0800 Subject: [PATCH 11/11] refactor: empty list --- .../src/pages/Wallets/components/WalletStateBar/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx b/packages/dashboard/src/pages/Wallets/components/WalletStateBar/index.tsx index 539a4332d4be..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,7 @@ export const WalletStateBar = memo(() => { const wallet = useWallet() const networkDescriptor = useNetworkDescriptor() const providerDescriptor = useProviderDescriptor() - const { value: pendingTransactions = [] } = useRecentTransactions({ + const { value: pendingTransactions = EMPTY_LIST } = useRecentTransactions({ status: TransactionStatusType.NOT_DEPEND, })