diff --git a/.vscode/settings.json b/.vscode/settings.json index b32cb66cdda3..a2360d5e37e6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,8 @@ { - "typescript.tsdk": "node_modules/typescript/lib", - "typescript.preferences.importModuleSpecifierEnding": "js", - "typescript.experimental.useTsgo": true, + "js/ts.tsdk.path": "node_modules/typescript/lib", + "js/ts.preferences.importModuleSpecifierEnding": "js", + // https://github.com/microsoft/typescript-go/issues/2780 + "js/ts.experimental.useTsgo": false, "js/ts.implicitProjectConfig.module": "NodeNext", "js/ts.implicitProjectConfig.target": "ESNext", "editor.formatOnSave": true, diff --git a/eslint.config.js b/eslint.config.js index 20cbdb7c37e2..888f2b8ee49a 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -465,6 +465,12 @@ const moduleSystemRules = { message: 'Avoid using type unsafe methods.', importNames: ['get'], }, + { + name: 'viem', + message: + 'Use toHex from @masknet/shared-base. They have different behaviors on "0x-" strings. If you want to use the original toHex, import it like import { toHex as viem_toHex } from "viem".', + importNames: ['toHex'], + }, { name: 'react-use', importNames: ['useLocalStorage'], diff --git a/packages/mask/background/services/helper/firefly.ts b/packages/mask/background/services/helper/firefly.ts index 1e44ba691c47..2a35be68b170 100644 --- a/packages/mask/background/services/helper/firefly.ts +++ b/packages/mask/background/services/helper/firefly.ts @@ -74,7 +74,7 @@ export async function encrypt(plainText: string, cryptoKey: string): Promise('[data-testid="tweet"]') @@ -122,7 +122,7 @@ function registerPostCollectorInner( const tweetNode = getTweetNode(node) const parentTweetNode = isQuotedTweet(tweetNode) ? getParentTweetNode(tweetNode!) : null if (!tweetNode || shouldSkipDecrypt(node, tweetNode)) { - return `keccak256:${web3_utils.keccak256(node.innerText)}` + return `keccak256:${keccak256(toHex(node.innerText))}` } const parentTweetId = parentTweetNode ? getPostId(parentTweetNode) : '' const tweetId = getPostId(tweetNode) diff --git a/packages/mask/content-script/site-adaptors/twitter.com/utils/fetch.ts b/packages/mask/content-script/site-adaptors/twitter.com/utils/fetch.ts index a63b67cebe23..608199c509f5 100644 --- a/packages/mask/content-script/site-adaptors/twitter.com/utils/fetch.ts +++ b/packages/mask/content-script/site-adaptors/twitter.com/utils/fetch.ts @@ -1,4 +1,3 @@ -import defer * as web3_utils from 'web3-utils' import { flattenDeep } from 'lodash-es' import { normalizeImageURL, parseId } from './url.js' import { @@ -16,6 +15,8 @@ import { } from '@masknet/typed-message' import { collectNodeText, collectTwitterEmoji } from '../../../utils/index.js' import { IMAGE_RENDER_IGNORE } from '../customization/render-fragments.js' +import { keccak256 } from 'viem' +import { toHex } from '@masknet/shared-base' /** * Get post id from dom, including normal tweet, quoted tweet and retweet one @@ -38,9 +39,9 @@ export function getPostId(node: HTMLElement) { } else if (timeNode) { // Quoted tweet in timeline has no a status link to detail page, // so use the timestamp as post id instead - pid = `timestamp-keccak256:${web3_utils.keccak256(timeNode.getAttribute('datetime')!)}` + pid = `timestamp-keccak256:${keccak256(toHex(timeNode.getAttribute('datetime')!))}` } else { - pid = `keccak256:${web3_utils.keccak256(node.innerText)}` + pid = `keccak256:${keccak256(toHex(node.innerText))}` } // You can't retweet a tweet or a retweet, but only cancel retweeting diff --git a/packages/mask/dashboard/pages/CreateMaskWallet/AddDeriveWallet/index.tsx b/packages/mask/dashboard/pages/CreateMaskWallet/AddDeriveWallet/index.tsx index 099cd0035e56..fe3db26f63e1 100644 --- a/packages/mask/dashboard/pages/CreateMaskWallet/AddDeriveWallet/index.tsx +++ b/packages/mask/dashboard/pages/CreateMaskWallet/AddDeriveWallet/index.tsx @@ -3,11 +3,10 @@ import urlcat from 'urlcat' import { memo, useCallback, useMemo, useState } from 'react' import { useAsyncFn } from 'react-use' import { useLocation, useNavigate } from 'react-router-dom' -import defer * as web3_utils from 'web3-utils' import { useQueries, useQuery } from '@tanstack/react-query' import { delay } from '@masknet/kit' import { DeriveWalletTable } from '@masknet/shared' -import { DashboardRoutes, EMPTY_LIST } from '@masknet/shared-base' +import { DashboardRoutes, EMPTY_LIST, toHex } from '@masknet/shared-base' import { makeStyles } from '@masknet/theme' import { useWallet, useWallets } from '@masknet/web3-hooks-base' import { EVMWeb3 } from '@masknet/web3-providers' @@ -28,6 +27,7 @@ import { SetupFrameController } from '../../../components/SetupFrame/index.js' import { ResetWalletContext } from '../context.js' import Services from '#services' import { Trans } from '@lingui/react/macro' +import { keccak256 } from 'viem' const useStyles = makeStyles()((theme) => ({ header: { @@ -85,7 +85,7 @@ export const Component = memo(function AddDeriveWallet() { const { mnemonic, password, isReset } = state // Avoid leaking mnemonic to react-query - const mnemonicHash = web3_utils.sha3(mnemonic) + const mnemonicHash = keccak256(toHex(mnemonic)) const [pathIndexes, setPathIndexes] = useState([]) const { handlePasswordAndWallets } = ResetWalletContext.useContainer() diff --git a/packages/mask/popups/pages/Wallet/GasSetting/GasSetting1559.tsx b/packages/mask/popups/pages/Wallet/GasSetting/GasSetting1559.tsx index 8f88afa62623..b9498e47439b 100644 --- a/packages/mask/popups/pages/Wallet/GasSetting/GasSetting1559.tsx +++ b/packages/mask/popups/pages/Wallet/GasSetting/GasSetting1559.tsx @@ -4,14 +4,13 @@ import { useNavigate } from 'react-router-dom' import { Controller, useForm } from 'react-hook-form' import { isEmpty } from 'lodash-es' import { z as zod } from 'zod' -import defer * as web3_utils from 'web3-utils' import { BigNumber } from 'bignumber.js' import { makeStyles } from '@masknet/theme' import { formatGweiToEther, formatGweiToWei, formatWeiToEther, formatWeiToGwei } from '@masknet/web3-shared-evm' import { zodResolver } from '@hookform/resolvers/zod' import { Typography } from '@mui/material' import { LoadingButton } from '@mui/lab' -import { NetworkPluginID, PopupRoutes, NUMERIC_INPUT_REGEXP_PATTERN } from '@masknet/shared-base' +import { NetworkPluginID, PopupRoutes, NUMERIC_INPUT_REGEXP_PATTERN, toHex } from '@masknet/shared-base' import { formatCurrency, GasOptionType, @@ -31,6 +30,7 @@ import { StyledInput } from '../../../components/StyledInput/index.js' import Services from '#services' import { FormattedCurrency } from '@masknet/shared' import { Trans, useLingui } from '@lingui/react/macro' +import { formatGwei } from 'viem' const useStyles = makeStyles()((theme) => ({ options: { @@ -236,9 +236,9 @@ export const GasSetting1559 = memo(() => { if (value.formatterTransaction._tx.maxFeePerGas && value.formatterTransaction._tx.maxPriorityFeePerGas) { setValue( 'maxPriorityFeePerGas', - web3_utils.fromWei(toFixed(value.formatterTransaction._tx.maxPriorityFeePerGas), 'gwei'), + formatGwei(BigInt(toFixed(value.formatterTransaction._tx.maxPriorityFeePerGas))), ) - setValue('maxFeePerGas', web3_utils.fromWei(toFixed(value.formatterTransaction._tx.maxFeePerGas), 'gwei')) + setValue('maxFeePerGas', formatGwei(BigInt(toFixed(value.formatterTransaction._tx.maxFeePerGas)))) } else { setOption(1) } @@ -268,9 +268,9 @@ export const GasSetting1559 = memo(() => { param === 'latest' ? param : ( { ...Object(param), - gas: web3_utils.toHex(new BigNumber(data.gasLimit).toString()), - maxPriorityFeePerGas: web3_utils.toHex(formatGweiToWei(data.maxPriorityFeePerGas).toFixed(0)), - maxFeePerGas: web3_utils.toHex(formatGweiToWei(data.maxFeePerGas).toFixed(0)), + gas: toHex(data.gasLimit), + maxPriorityFeePerGas: toHex(formatGweiToWei(data.maxPriorityFeePerGas).toFixed(0)), + maxFeePerGas: toHex(formatGweiToWei(data.maxFeePerGas).toFixed(0)), } ), ) diff --git a/packages/mask/popups/pages/Wallet/GasSetting/Prior1559GasSetting.tsx b/packages/mask/popups/pages/Wallet/GasSetting/Prior1559GasSetting.tsx index 2610bc4850e4..fedf570794b2 100644 --- a/packages/mask/popups/pages/Wallet/GasSetting/Prior1559GasSetting.tsx +++ b/packages/mask/popups/pages/Wallet/GasSetting/Prior1559GasSetting.tsx @@ -4,10 +4,9 @@ import { Controller, useForm } from 'react-hook-form' import { useNavigate } from 'react-router-dom' import { BigNumber } from 'bignumber.js' import { isEmpty } from 'lodash-es' -import defer * as web3_utils from 'web3-utils' import { z as zod } from 'zod' import { zodResolver } from '@hookform/resolvers/zod' -import { NetworkPluginID, NUMERIC_INPUT_REGEXP_PATTERN, PopupRoutes } from '@masknet/shared-base' +import { NetworkPluginID, NUMERIC_INPUT_REGEXP_PATTERN, PopupRoutes, toHex } from '@masknet/shared-base' import { Typography } from '@mui/material' import { LoadingButton } from '@mui/lab' import { useChainContext, useGasOptions, useNativeToken, useNativeTokenPrice } from '@masknet/web3-hooks-base' @@ -228,8 +227,8 @@ export const Prior1559GasSetting = memo(() => { if (!value) return const config = value.payload.params!.map((param) => ({ ...Object(param), - gas: web3_utils.toHex(new BigNumber(data.gasLimit).toString()), - gasPrice: web3_utils.toHex(formatGweiToWei(data.gasPrice).toString()), + gas: toHex(data.gasLimit), + gasPrice: toHex(formatGweiToWei(data.gasPrice).toFixed(0)), })) await Services.Wallet.updateUnconfirmedRequest({ ...value.payload, diff --git a/packages/mask/popups/pages/Wallet/Interaction/TransactionRequest.tsx b/packages/mask/popups/pages/Wallet/Interaction/TransactionRequest.tsx index 6cf0d1d87522..0d7def544dba 100644 --- a/packages/mask/popups/pages/Wallet/Interaction/TransactionRequest.tsx +++ b/packages/mask/popups/pages/Wallet/Interaction/TransactionRequest.tsx @@ -1,6 +1,6 @@ import { Trans } from '@lingui/react/macro' import { Icons } from '@masknet/icons' -import { NetworkPluginID } from '@masknet/shared-base' +import { NetworkPluginID, toHex } from '@masknet/shared-base' import { makeStyles } from '@masknet/theme' import { useChainContext, usePrivyWallet, useWallet, useWeb3State } from '@masknet/web3-hooks-base' import { GasOptionType, MessageStateType, TransactionDescriptorType } from '@masknet/web3-shared-base' @@ -15,12 +15,10 @@ import { } from '@masknet/web3-shared-evm' import { Box, Button, Typography } from '@mui/material' import { useQueryClient, useSuspenseQuery } from '@tanstack/react-query' -import { BigNumber } from 'bignumber.js' import { produce } from 'immer' import { compact, mapValues, omit } from 'lodash-es' import { useCallback, useEffect, useState } from 'react' import { useLatest } from 'react-use' -import defer * as web3_utils from 'web3-utils' import { TransactionPreview } from '../../../components/TransactionPreview/index.js' import { UnlockERC20Token } from '../../../components/UnlockERC20Token/index.js' import { UnlockERC721Token } from '../../../components/UnlockERC721Token/index.js' @@ -125,6 +123,8 @@ export function TransactionRequest(props: InteractionItemProps) { if (privyWallet) { const provider = await privyWallet.getEthereumProvider() const result: string = await provider.request(request.request.arguments) + // TODO: + // eslint-disable-next-line react-compiler/react-compiler mockingPrivyPid += 1 await Message?.updateMessage(request.ID, { request: request.request, @@ -175,12 +175,12 @@ export function TransactionRequest(props: InteractionItemProps) { ...(gasConfig ? mapValues(omit(gasConfig, 'gasOptionType'), (value, key) => { if (key === 'gasCurrency' || !value) return - return web3_utils.toHex(value) + return toHex(value) }) : {}), - gasLimit: web3_utils.toHex(new BigNumber(gasConfig?.gas ?? x.gas).toString()), - chainId: web3_utils.toHex(x.chainId), - nonce: web3_utils.toHex(x.nonce), + gasLimit: toHex(gasConfig?.gas ?? x.gas), + chainId: toHex(x.chainId), + nonce: toHex(x.nonce), } }), ) diff --git a/packages/mask/popups/pages/Wallet/utils.ts b/packages/mask/popups/pages/Wallet/utils.ts index 352d963405c4..40f917ed3f8d 100644 --- a/packages/mask/popups/pages/Wallet/utils.ts +++ b/packages/mask/popups/pages/Wallet/utils.ts @@ -1,5 +1,4 @@ import { mapKeys } from 'lodash-es' -import defer * as web3_utils from 'web3-utils' import { EVMWeb3 } from '@masknet/web3-providers' import { ERC20Abi } from '@masknet/web3-contracts/types/ERC20.js' import { toFixed, type RecentTransaction } from '@masknet/web3-shared-base' @@ -12,6 +11,7 @@ import { } from '@masknet/web3-shared-evm' import { ReplaceType, type GasSetting } from './type.js' import { GasSettingModal } from '../../modals/modal-controls.js' +import { toHex } from '@masknet/shared-base' const MaxUint256 = toFixed('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') @@ -38,7 +38,7 @@ export async function modifyTransaction( const newConfig = { ...candidate, ...oldGasSettings, - ...mapKeys(gasSettings, (value) => (typeof value === 'undefined' ? value : web3_utils.toHex(value))), + ...mapKeys(gasSettings, (value) => (typeof value === 'undefined' ? value : toHex(value))), } if (replaceType === ReplaceType.CANCEL) { await EVMWeb3.cancelTransaction(transaction.id, newConfig, { diff --git a/packages/plugins/ArtBlocks/src/hooks/useArtBlocksContract.ts b/packages/plugins/ArtBlocks/src/hooks/useArtBlocksContract.ts index 83f5a3e32f22..30799dbb8890 100644 --- a/packages/plugins/ArtBlocks/src/hooks/useArtBlocksContract.ts +++ b/packages/plugins/ArtBlocks/src/hooks/useArtBlocksContract.ts @@ -1,11 +1,12 @@ -import type { AbiItem } from 'web3-utils' import { useContract } from '@masknet/web3-hooks-evm' import { type ChainId, useArtBlocksConstants } from '@masknet/web3-shared-evm' -import ArtBlocksCoreContractABI from '@masknet/web3-contracts/abis/ArtBlocksMinterContract.json' with { type: 'json' } -import type { ArtBlocksMinterContract } from '@masknet/web3-contracts/types/ArtBlocksMinterContract.js' +import { + ArtBlocksMinterContractAbi, + type ArtBlocksMinterContract, +} from '@masknet/web3-contracts/types/ArtBlocksMinterContract.js' export function useArtBlocksContract(chainId: ChainId) { const { GEN_ART_721_MINTER } = useArtBlocksConstants(chainId) - return useContract(chainId, GEN_ART_721_MINTER, ArtBlocksCoreContractABI as AbiItem[]) + return useContract(chainId, GEN_ART_721_MINTER, ArtBlocksMinterContractAbi) } diff --git a/packages/plugins/Claim/src/hooks/useAirDropActivity.ts b/packages/plugins/Claim/src/hooks/useAirDropActivity.ts index aa29006a08ea..316865ccef15 100644 --- a/packages/plugins/Claim/src/hooks/useAirDropActivity.ts +++ b/packages/plugins/Claim/src/hooks/useAirDropActivity.ts @@ -1,13 +1,14 @@ import { last } from 'lodash-es' -import defer * as web3_utils from 'web3-utils' // cspell:disable-next-line import { MerkleTree } from 'merkletreejs' import { secondsToMilliseconds } from 'date-fns' import { useChainContext } from '@masknet/web3-hooks-base' import { Airdrop } from '@masknet/web3-providers' import { isSameAddress } from '@masknet/web3-shared-base' -import { type ChainId, formatEtherToWei, pack } from '@masknet/web3-shared-evm' +import { type ChainId, formatEtherToWei } from '@masknet/web3-shared-evm' import { useQuery } from '@tanstack/react-query' +import { encodePacked, keccak256, type Hex } from 'viem' +import { toHex } from '@masknet/shared-base' export function useAirDropActivity(chainId: ChainId) { const { account } = useChainContext() @@ -22,13 +23,23 @@ export function useAirDropActivity(chainId: ChainId) { const claimerList = Object.entries(claimers) const claimer = claimerList.find(([address]) => isSameAddress(address, account)) const airdropList = claimerList.map(([address, amount]) => { - return web3_utils.keccak256(pack(['address', 'uint256'], [address, formatEtherToWei(amount)])) + return encodePacked( + ['address', 'uint256'], + [address as Hex, BigInt(formatEtherToWei(amount).toFixed(0))], + ) + }) + const merkleTree = new MerkleTree(airdropList, (value: Buffer) => keccak256(toHex(value)), { + sortPairs: true, }) - const merkleTree = new MerkleTree(airdropList, web3_utils.keccak256, { sortPairs: true }) const amount = claimer ? last(claimer) : undefined const leaf = amount ? - web3_utils.keccak256(pack(['address', 'uint256'], [account, formatEtherToWei(amount)])) + keccak256( + encodePacked( + ['address', 'uint256'], + [account as Hex, BigInt(formatEtherToWei(amount).toFixed(0))], + ), + ) : undefined const merkleProof = leaf ? merkleTree.getHexProof(leaf) : undefined diff --git a/packages/plugins/Claim/src/hooks/useClaimAirdrop.tsx b/packages/plugins/Claim/src/hooks/useClaimAirdrop.tsx index 21fba9a0e715..fb1c7de90b10 100644 --- a/packages/plugins/Claim/src/hooks/useClaimAirdrop.tsx +++ b/packages/plugins/Claim/src/hooks/useClaimAirdrop.tsx @@ -1,9 +1,7 @@ import { useRef, useCallback } from 'react' import { useAsyncFn } from 'react-use' -import type { AbiItem } from 'web3-utils' import { useTheme } from '@mui/material' -import type { AirdropV2 } from '@masknet/web3-contracts/types/AirdropV2.js' -import AirDropV2ABI from '@masknet/web3-contracts/abis/AirdropV2.json' with { type: 'json' } +import { AirdropV2Abi, type AirdropV2 } from '@masknet/web3-contracts/types/AirdropV2.js' import { useChainContext } from '@masknet/web3-hooks-base' import { useContract } from '@masknet/web3-hooks-evm' import { @@ -31,7 +29,7 @@ export function useClaimAirdrop( const theme = useTheme() const { account, providerType, chainId: globalChainId } = useChainContext() const { CONTRACT_ADDRESS } = useAirdropClaimersConstants(chainId) - const airdropContract = useContract(chainId, CONTRACT_ADDRESS, AirDropV2ABI as AbiItem[]) + const airdropContract = useContract(chainId, CONTRACT_ADDRESS, AirdropV2Abi) const { setDialog } = useRemoteControlledDialog(PluginClaimMessage.claimSuccessDialogEvent) diff --git a/packages/plugins/Collectible/src/SiteAdaptor/hooks/getNFTXAssetAddress.ts b/packages/plugins/Collectible/src/SiteAdaptor/hooks/getNFTXAssetAddress.ts index e15b58c8d00f..595803876141 100644 --- a/packages/plugins/Collectible/src/SiteAdaptor/hooks/getNFTXAssetAddress.ts +++ b/packages/plugins/Collectible/src/SiteAdaptor/hooks/getNFTXAssetAddress.ts @@ -1,5 +1,4 @@ import { useQuery } from '@tanstack/react-query' -import type { AbiItem } from 'web3-utils' import { ChainId } from '@masknet/web3-shared-evm' import { EVMContractReadonly } from '@masknet/web3-providers' @@ -24,8 +23,8 @@ export function useNFTXAssetAddress(address: string, enabled: boolean) { stateMutability: 'view', type: 'function', }, - ] - const contract = EVMContractReadonly.getWeb3Contract(address, ABI as AbiItem[], { + ] as const + const contract = EVMContractReadonly.getWeb3Contract(address, ABI, { chainId: ChainId.Mainnet, }) const assetAddress: string = await contract?.methods.assetAddress().call() diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useClaimCallback.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useClaimCallback.ts index 57013b7b7198..158dcbd4f95c 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useClaimCallback.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useClaimCallback.ts @@ -1,4 +1,4 @@ -import type { NetworkPluginID } from '@masknet/shared-base' +import { toHex, type NetworkPluginID } from '@masknet/shared-base' import type { HappyRedPacketV1 } from '@masknet/web3-contracts/types/HappyRedPacketV1.js' import type { HappyRedPacketV4 } from '@masknet/web3-contracts/types/HappyRedPacketV4.js' import { useChainContext } from '@masknet/web3-hooks-base' @@ -6,9 +6,9 @@ import { EVMChainResolver, EVMWeb3 } from '@masknet/web3-providers' import type { RedPacketJSONPayload } from '@masknet/web3-providers/types' import { type ChainId, ContractTransaction } from '@masknet/web3-shared-evm' import { useAsyncFn } from 'react-use' -import defer * as web3_utils from 'web3-utils' import { useRedPacketContract } from './useRedPacketContract.js' import { useSignedMessage } from './useSignedMessage.js' +import { keccak256 } from 'viem' /** * Claim fungible token red packet. @@ -45,7 +45,7 @@ export function useClaimCallback(account: string, payload: RedPacketJSONPayload rpid, signedMsg, account, - web3_utils.sha3(account)!, + keccak256(toHex(account)), ), config, ) diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateCallback.tsx b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateCallback.tsx index c1c9af70cdd5..35c77b326ca5 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateCallback.tsx +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateCallback.tsx @@ -1,8 +1,7 @@ import { useCallback } from 'react' import { useAsync, useAsyncFn } from 'react-use' -import defer * as web3_utils from 'web3-utils' import { omit } from 'lodash-es' -import { NetworkPluginID } from '@masknet/shared-base' +import { NetworkPluginID, toHex } from '@masknet/shared-base' import { useChainContext, useEnvironmentContext } from '@masknet/web3-hooks-base' import type { HappyRedPacketV4 } from '@masknet/web3-contracts/types/HappyRedPacketV4.js' import { type FungibleToken, isLessThan, toFixed } from '@masknet/web3-shared-base' @@ -18,6 +17,7 @@ import { } from '@masknet/web3-shared-evm' import { EVMWeb3 } from '@masknet/web3-providers' import { getRedPacketContractAbi, useRedPacketContract } from './useRedPacketContract.js' +import { keccak256 } from 'viem' export interface RedPacketSettings { shares: number @@ -93,7 +93,7 @@ function useCreateParamsCallback( shares, isRandom, duration, - seed: web3_utils.sha3(seed)!, + seed: keccak256(toHex(seed)), message, name, tokenType, diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketCallback.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketCallback.ts index 70e958ae0946..a3ba0391007e 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketCallback.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketCallback.ts @@ -1,4 +1,4 @@ -import type { NetworkPluginID } from '@masknet/shared-base' +import { toHex, type NetworkPluginID } from '@masknet/shared-base' import { NftRedPacketAbi, type NftRedPacket } from '@masknet/web3-contracts/types/NftRedPacket.js' import { useChainContext } from '@masknet/web3-hooks-base' import { useGasConfig } from '@masknet/web3-hooks-evm' @@ -16,8 +16,8 @@ import { useQuery } from '@tanstack/react-query' import { BigNumber } from 'bignumber.js' import { useMemo } from 'react' import { useAsyncFn } from 'react-use' -import defer * as web3_utils from 'web3-utils' import { createNftRedpacketContract } from './useNftRedPacketContract.js' +import { keccak256 } from 'viem' interface Options { publicKey: string @@ -43,7 +43,7 @@ export function useCreateNftRedpacketCallback({ return [ publicKey, duration, - web3_utils.sha3(Math.random().toString())!, + keccak256(toHex(Math.random().toString())), message, creator, contractAddress, diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketGas.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketGas.ts index ea1a23fbb852..17981c7285e9 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketGas.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketGas.ts @@ -1,12 +1,12 @@ import { useMemo } from 'react' -import defer * as web3_utils from 'web3-utils' -import type { NetworkPluginID } from '@masknet/shared-base' +import { toHex, type NetworkPluginID } from '@masknet/shared-base' import type { NftRedPacket } from '@masknet/web3-contracts/types/NftRedPacket.js' import { useChainContext } from '@masknet/web3-hooks-base' import { toFixed } from '@masknet/web3-shared-base' import { EVMWeb3 } from '@masknet/web3-providers' import { useNftRedPacketContract } from './useNftRedPacketContract.js' import { useQuery } from '@tanstack/react-query' +import { keccak256 } from 'viem' export function useCreateNFTRedpacketGas( message: string, @@ -39,7 +39,7 @@ export function useCreateNFTRedpacketGas( const params: FillMethodParameters = [ publicKey, 60 * 60 * 24, - web3_utils.sha3(Math.random().toString())!, + keccak256(toHex(Math.random().toString())), message, name, contractAddress, diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useDefaultCreateGas.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useDefaultCreateGas.ts index ea29a7e6a5b2..82e54bb1c709 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useDefaultCreateGas.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useDefaultCreateGas.ts @@ -1,13 +1,13 @@ import { useAsync } from 'react-use' -import defer * as web3_utils from 'web3-utils' import { omit } from 'lodash-es' -import type { NetworkPluginID } from '@masknet/shared-base' +import { toHex, type NetworkPluginID } from '@masknet/shared-base' import { ZERO, toFixed } from '@masknet/web3-shared-base' import { useChainContext } from '@masknet/web3-hooks-base' import type { HappyRedPacketV4 } from '@masknet/web3-contracts/types/HappyRedPacketV4.js' import { SchemaType, useTokenConstants } from '@masknet/web3-shared-evm' import { checkParams, type RedPacketSettings, type ParamsObjType, type MethodParameters } from './useCreateCallback.js' import { useRedPacketContract } from './useRedPacketContract.js' +import { keccak256 } from 'viem' export function useDefaultCreateGas( redPacketSettings: RedPacketSettings | undefined, @@ -34,7 +34,7 @@ export function useDefaultCreateGas( shares, isRandom, duration, - seed: web3_utils.sha3(seed)!, + seed: keccak256(toHex(seed)), message, name, tokenType, diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useHandleCreateOrSelect.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useHandleCreateOrSelect.ts index 32c45426b853..cacc5e0ad319 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useHandleCreateOrSelect.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useHandleCreateOrSelect.ts @@ -1,15 +1,15 @@ import { ApplicationBoardModal } from '@masknet/shared' -import { RedPacketMetaKey, type NetworkPluginID } from '@masknet/shared-base' +import { RedPacketMetaKey, toHex, type NetworkPluginID } from '@masknet/shared-base' import { useChainContext } from '@masknet/web3-hooks-base' import { EVMWeb3 } from '@masknet/web3-providers' import type { FireflyRedPacketAPI, RedPacketJSONPayload } from '@masknet/web3-providers/types' import { Telemetry } from '@masknet/web3-telemetry' import { EventID, EventType } from '@masknet/web3-telemetry/types' import { useCallback, useContext } from 'react' -import defer * as web3_utils from 'web3-utils' import { openComposition } from '../openComposition.js' import { reduceUselessPayloadInfo } from '../helpers/reduceUselessPayloadInfo.js' import { CompositionTypeContext } from '../contexts/CompositionTypeContext.js' +import { keccak256 } from 'viem' interface Options { senderName?: string @@ -34,13 +34,9 @@ export function useHandleCreateOrSelect({ senderName, onClose }: Options) { payload.password = prompt('Please enter the password of the lucky drop:', '') ?? '' } else if (payload.contract_version > 1 && payload.contract_version < 4) { // just sign out the password if it is lost. - payload.password = await EVMWeb3.signMessage( - 'message', - web3_utils.sha3(payload.sender.message) ?? '', - { - account, - }, - ) + payload.password = await EVMWeb3.signMessage('message', keccak256(toHex(payload.sender.message)), { + account, + }) payload.password = payload.password.slice(2) } } diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftRedPacketContract.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftRedPacketContract.ts index c7c9f06ed601..ca3acc8ba20b 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftRedPacketContract.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftRedPacketContract.ts @@ -1,20 +1,14 @@ -import type { AbiItem } from 'web3-utils' -import NftRedPacketABI from '@masknet/web3-contracts/abis/NftRedPacket.json' with { type: 'json' } import { ChainId, createContract, getNftRedPacketConstant, useNftRedPacketConstants } from '@masknet/web3-shared-evm' -import type { NftRedPacket } from '@masknet/web3-contracts/types/NftRedPacket.js' +import { NftRedPacketAbi, type NftRedPacket } from '@masknet/web3-contracts/types/NftRedPacket.js' import { useContract } from '@masknet/web3-hooks-evm' import { EVMWeb3 } from '@masknet/web3-providers' export function useNftRedPacketContract(chainId?: ChainId) { const { RED_PACKET_NFT_ADDRESS } = useNftRedPacketConstants(chainId) - return useContract(chainId, RED_PACKET_NFT_ADDRESS, NftRedPacketABI as AbiItem[]) + return useContract(chainId, RED_PACKET_NFT_ADDRESS, NftRedPacketAbi) } export function createNftRedpacketContract(chainId: ChainId | undefined) { const RED_PACKET_NFT_ADDRESS = getNftRedPacketConstant(chainId ?? ChainId.Mainnet, 'RED_PACKET_NFT_ADDRESS') - return createContract( - EVMWeb3.getWeb3({ chainId }), - RED_PACKET_NFT_ADDRESS, - NftRedPacketABI as AbiItem[], - ) + return createContract(EVMWeb3.getWeb3({ chainId }), RED_PACKET_NFT_ADDRESS, NftRedPacketAbi) } diff --git a/packages/plugins/Savings/src/SiteAdaptor/SavingsDialog.tsx b/packages/plugins/Savings/src/SiteAdaptor/SavingsDialog.tsx index e06a75889983..e26759ad81a1 100644 --- a/packages/plugins/Savings/src/SiteAdaptor/SavingsDialog.tsx +++ b/packages/plugins/Savings/src/SiteAdaptor/SavingsDialog.tsx @@ -1,7 +1,6 @@ import { useMemo, useState } from 'react' import { useQuery } from '@tanstack/react-query' import { chunk, compact, flatten } from 'lodash-es' -import type { AbiItem } from 'web3-utils' import { DialogActions, DialogContent, Tab } from '@mui/material' import { TabContext, TabPanel } from '@mui/lab' import { @@ -16,8 +15,10 @@ import { makeStyles, MaskTabList, useTabs } from '@masknet/theme' import { ChainId, getAaveConstant } from '@masknet/web3-shared-evm' import { InjectedDialog, PluginWalletStatusBar, NetworkTab } from '@masknet/shared' import { EVMContract } from '@masknet/web3-providers' -import type { AaveProtocolDataProvider } from '@masknet/web3-contracts/types/AaveProtocolDataProvider.js' -import AaveProtocolDataProviderABI from '@masknet/web3-contracts/abis/AaveProtocolDataProvider.json' with { type: 'json' } +import { + AaveProtocolDataProviderAbi, + type AaveProtocolDataProvider, +} from '@masknet/web3-contracts/types/AaveProtocolDataProvider.js' import { type SavingsProtocol, TabType, type TokenPair } from '../types.js' import { SavingsTable } from './SavingsTable/index.js' import { LidoProtocol } from '../protocols/LDOProtocol.js' @@ -79,7 +80,7 @@ export function SavingsDialog({ open, onClose }: SavingsDialogProps) { const protocolDataContract = EVMContract.getWeb3Contract( address, - AaveProtocolDataProviderABI as AbiItem[], + AaveProtocolDataProviderAbi, { chainId, }, diff --git a/packages/plugins/Savings/src/SiteAdaptor/SavingsForm.tsx b/packages/plugins/Savings/src/SiteAdaptor/SavingsForm.tsx index 1f5566e66495..5aacd223781d 100644 --- a/packages/plugins/Savings/src/SiteAdaptor/SavingsForm.tsx +++ b/packages/plugins/Savings/src/SiteAdaptor/SavingsForm.tsx @@ -2,7 +2,6 @@ import { useMemo, useState } from 'react' import { useAsync, useAsyncFn } from 'react-use' import { useQueryClient } from '@tanstack/react-query' import { BigNumber } from 'bignumber.js' -import type { AbiItem } from 'web3-utils' import { ActionButtonPromise, EthereumERC20TokenApprovedBoundary, @@ -16,8 +15,10 @@ import { } from '@masknet/shared' import { NetworkPluginID } from '@masknet/shared-base' import { LoadingBase, makeStyles } from '@masknet/theme' -import AaveLendingPoolAddressProviderABI from '@masknet/web3-contracts/abis/AaveLendingPoolAddressProvider.json' with { type: 'json' } -import type { AaveLendingPoolAddressProvider } from '@masknet/web3-contracts/types/AaveLendingPoolAddressProvider.js' +import { + AaveLendingPoolAddressProviderAbi, + type AaveLendingPoolAddressProvider, +} from '@masknet/web3-contracts/types/AaveLendingPoolAddressProvider.js' import { useChainContext, useFungibleTokenBalance, @@ -170,7 +171,7 @@ export function SavingsFormDialog({ chainId, protocol, tab, onClose }: SavingsFo const lPoolAddressProviderContract = EVMContract.getWeb3Contract( aavePoolAddress, - AaveLendingPoolAddressProviderABI as AbiItem[], + AaveLendingPoolAddressProviderAbi, ) const token = protocol.bareToken diff --git a/packages/plugins/Savings/src/protocols/AAVEProtocol.ts b/packages/plugins/Savings/src/protocols/AAVEProtocol.ts index 6ae823e981a2..15bcdb4956aa 100644 --- a/packages/plugins/Savings/src/protocols/AAVEProtocol.ts +++ b/packages/plugins/Savings/src/protocols/AAVEProtocol.ts @@ -1,11 +1,10 @@ -import type { AbiItem } from 'web3-utils' import { BigNumber } from 'bignumber.js' -import AaveLendingPoolABI from '@masknet/web3-contracts/abis/AaveLendingPool.json' with { type: 'json' } -import AaveLendingPoolAddressProviderABI from '@masknet/web3-contracts/abis/AaveLendingPoolAddressProvider.json' with { type: 'json' } -import ERC20ABI from '@masknet/web3-contracts/abis/ERC20.json' with { type: 'json' } -import type { AaveLendingPool } from '@masknet/web3-contracts/types/AaveLendingPool.js' -import type { AaveLendingPoolAddressProvider } from '@masknet/web3-contracts/types/AaveLendingPoolAddressProvider.js' -import type { ERC20 } from '@masknet/web3-contracts/types/ERC20.js' +import { AaveLendingPoolAbi, type AaveLendingPool } from '@masknet/web3-contracts/types/AaveLendingPool.js' +import { + AaveLendingPoolAddressProviderAbi, + type AaveLendingPoolAddressProvider, +} from '@masknet/web3-contracts/types/AaveLendingPoolAddressProvider.js' +import { ERC20Abi, type ERC20 } from '@masknet/web3-contracts/types/ERC20.js' import { fetchJSON } from '@masknet/web3-providers/helpers' import { ZERO, pow10, type FungibleToken } from '@masknet/web3-shared-base' import { @@ -132,7 +131,7 @@ export class AAVEProtocol implements SavingsProtocol { }) const aTokenId = response.data.reserves[0].aToken.id - const contract = createContract(web3, aTokenId, ERC20ABI as AbiItem[]) + const contract = createContract(web3, aTokenId, ERC20Abi) return new BigNumber((await contract?.methods.balanceOf(account).call()) ?? '0') } catch (error) { console.error('AAVE BALANCE ERROR:', error) @@ -159,12 +158,12 @@ export class AAVEProtocol implements SavingsProtocol { const lPoolAddressProviderContract = createContract( web3, aaveLPoolAddress, - AaveLendingPoolAddressProviderABI as AbiItem[], + AaveLendingPoolAddressProviderAbi, ) const poolAddress = await lPoolAddressProviderContract?.methods.getLendingPool().call() - const contract = createContract(web3, poolAddress, AaveLendingPoolABI as AbiItem[]) + const contract = createContract(web3, poolAddress, AaveLendingPoolAbi) return contract?.methods.deposit(this.bareToken.address, new BigNumber(value).toFixed(), account, '0') } @@ -192,12 +191,12 @@ export class AAVEProtocol implements SavingsProtocol { const lPoolAddressProviderContract = createContract( web3, getAaveConstant(chainId, 'AAVE_LENDING_POOL_ADDRESSES_PROVIDER_CONTRACT_ADDRESS'), - AaveLendingPoolAddressProviderABI as AbiItem[], + AaveLendingPoolAddressProviderAbi, ) const poolAddress = await lPoolAddressProviderContract?.methods.getLendingPool().call() - const contract = createContract(web3, poolAddress, AaveLendingPoolABI as AbiItem[]) + const contract = createContract(web3, poolAddress, AaveLendingPoolAbi) const gasEstimate = await contract?.methods .withdraw(this.bareToken.address, new BigNumber(value).toFixed(), account) .estimateGas({ @@ -213,13 +212,13 @@ export class AAVEProtocol implements SavingsProtocol { const lPoolAddressProviderContract = createContract( web3, getAaveConstant(chainId, 'AAVE_LENDING_POOL_ADDRESSES_PROVIDER_CONTRACT_ADDRESS'), - AaveLendingPoolAddressProviderABI as AbiItem[], + AaveLendingPoolAddressProviderAbi, ) const poolAddress = await lPoolAddressProviderContract?.methods.getLendingPool().call() const gasEstimate = await this.withdrawEstimate(account, chainId, web3, value) - const contract = createContract(web3, poolAddress, AaveLendingPoolABI as AbiItem[]) + const contract = createContract(web3, poolAddress, AaveLendingPoolAbi) return new Promise((resolve, reject) => { contract?.methods .withdraw(this.bareToken.address, new BigNumber(value).toFixed(), account) diff --git a/packages/plugins/Savings/src/protocols/LDOProtocol.ts b/packages/plugins/Savings/src/protocols/LDOProtocol.ts index 711c4c5832c5..d74e0953c0bf 100644 --- a/packages/plugins/Savings/src/protocols/LDOProtocol.ts +++ b/packages/plugins/Savings/src/protocols/LDOProtocol.ts @@ -1,4 +1,3 @@ -import type { AbiItem } from 'web3-utils' import { BigNumber } from 'bignumber.js' import { type ChainId, @@ -10,14 +9,11 @@ import { splitSignature, } from '@masknet/web3-shared-evm' import { ZERO } from '@masknet/web3-shared-base' -import type { Lido } from '@masknet/web3-contracts/types/Lido.js' -import type { LidoWithdraw } from '@masknet/web3-contracts/types/LidoWithdraw.js' -import type { LidoStETH } from '@masknet/web3-contracts/types/LidoStETH.js' +import { LidoAbi, type Lido } from '@masknet/web3-contracts/types/Lido.js' +import { LidoWithdrawAbi, type LidoWithdraw } from '@masknet/web3-contracts/types/LidoWithdraw.js' +import { LidoStETHAbi, type LidoStETH } from '@masknet/web3-contracts/types/LidoStETH.js' import { EVMWeb3, Lido as LidoAPI } from '@masknet/web3-providers' -import LidoABI from '@masknet/web3-contracts/abis/Lido.json' with { type: 'json' } -import LidoWithdrawABI from '@masknet/web3-contracts/abis/LidoWithdraw.json' with { type: 'json' } -import LidoStEthABI from '@masknet/web3-contracts/abis/LidoStETH.json' with { type: 'json' } import { ProtocolType, type SavingsProtocol, type TokenPair } from '../types.js' const MAX_DEADLINE = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') @@ -44,11 +40,7 @@ export class LidoProtocol implements SavingsProtocol { } async getBalance(chainId: ChainId, web3: Web3, account: string) { try { - const contract = createContract( - web3, - getLidoConstant(chainId, 'LIDO_stETH_ADDRESS'), - LidoABI as AbiItem[], - ) + const contract = createContract(web3, getLidoConstant(chainId, 'LIDO_stETH_ADDRESS'), LidoAbi) return new BigNumber((await contract?.methods.balanceOf(account).call()) ?? 0) } catch {} return ZERO @@ -56,11 +48,7 @@ export class LidoProtocol implements SavingsProtocol { public async depositEstimate(account: string, chainId: ChainId, web3: Web3, value: BigNumber.Value) { try { - const contract = createContract( - web3, - getLidoConstant(chainId, 'LIDO_stETH_ADDRESS'), - LidoABI as AbiItem[], - ) + const contract = createContract(web3, getLidoConstant(chainId, 'LIDO_stETH_ADDRESS'), LidoAbi) const gasEstimate = await contract?.methods .submit(getLidoConstant(chainId, 'LIDO_REFERRAL_ADDRESS') || ZERO_ADDRESS) .estimateGas({ @@ -80,11 +68,7 @@ export class LidoProtocol implements SavingsProtocol { public async deposit(account: string, chainId: ChainId, web3: Web3, value: BigNumber.Value) { const gasEstimate = await this.depositEstimate(account, chainId, web3, value) return new Promise((resolve, reject) => { - const contract = createContract( - web3, - getLidoConstant(chainId, 'LIDO_stETH_ADDRESS'), - LidoABI as AbiItem[], - ) + const contract = createContract(web3, getLidoConstant(chainId, 'LIDO_stETH_ADDRESS'), LidoAbi) contract?.methods .submit(getLidoConstant(chainId, 'LIDO_REFERRAL_ADDRESS') || ZERO_ADDRESS) .send({ @@ -109,7 +93,7 @@ export class LidoProtocol implements SavingsProtocol { const lidoStETHContract = createContract( web3, getLidoConstant(chainId, 'LIDO_stETH_ADDRESS'), - LidoStEthABI as AbiItem[], + LidoStETHAbi, ) const nonces = await lidoStETHContract?.methods.nonces(account).call() @@ -182,7 +166,7 @@ export class LidoProtocol implements SavingsProtocol { const contract = createContract( web3, getLidoConstant(chainId, 'LIDO_WITHDRAW_ADDRESS'), - LidoWithdrawABI as AbiItem[], + LidoWithdrawAbi, ) const result = contract?.methods.requestWithdrawalsWithPermit([value], account, [ diff --git a/packages/plugins/Tips/src/components/TokenSection/useGasLimit.ts b/packages/plugins/Tips/src/components/TokenSection/useGasLimit.ts index efcac410eff6..a69fcabfaaba 100644 --- a/packages/plugins/Tips/src/components/TokenSection/useGasLimit.ts +++ b/packages/plugins/Tips/src/components/TokenSection/useGasLimit.ts @@ -1,8 +1,7 @@ import { useAsync } from 'react-use' -import defer * as web3_utils from 'web3-utils' import { EVMContract } from '@masknet/web3-providers' import { useChainContext } from '@masknet/web3-hooks-base' -import type { NetworkPluginID } from '@masknet/shared-base' +import { toHex, type NetworkPluginID } from '@masknet/shared-base' import { TokenType } from '@masknet/web3-shared-base' import { isNativeTokenAddress } from '@masknet/web3-shared-evm' import { useTip } from '../../contexts/index.js' @@ -25,7 +24,7 @@ export function useGasLimit(fallback = DEFAULT_GAS_LIMIT) { chainId, account, }) - const tx = contract?.methods.transfer(recipientAddress, web3_utils.toHex(amount)) + const tx = contract?.methods.transfer(recipientAddress, toHex(amount)) const estimated = await tx?.estimateGas({ from: account, }) diff --git a/packages/shared-base/src/helpers/pvtsutils.ts b/packages/shared-base/src/helpers/pvtsutils.ts index 4693e3d90901..71c34acc118d 100644 --- a/packages/shared-base/src/helpers/pvtsutils.ts +++ b/packages/shared-base/src/helpers/pvtsutils.ts @@ -1,4 +1,5 @@ import { Convert } from 'pvtsutils' +import { toHex as viem_toHex, type ByteArray } from 'viem' export function fromBase64URL(x: string) { return new Uint8Array(Convert.FromBase64Url(x)) @@ -12,8 +13,12 @@ export function toBase64(x: BufferSource) { return Convert.ToBase64(x) } -export function toHex(x: BufferSource) { - return Convert.ToHex(x) +export function toHex(value: string | number | bigint | boolean | ByteArray) { + if (typeof value === 'string') { + // convert hex to number first, to normalize hex like 0x02 to 0x2 + if (/^\d+$/u.test(value) || /^0x[0-9a-fA-F]+$/u.test(value)) return viem_toHex(BigInt(value)) + } + return viem_toHex(value) } export function fromHex(x: string) { diff --git a/packages/shared/src/UI/components/SettingsBoard/Context.tsx b/packages/shared/src/UI/components/SettingsBoard/Context.tsx index ea6753068a56..c3b3eca1ca9a 100644 --- a/packages/shared/src/UI/components/SettingsBoard/Context.tsx +++ b/packages/shared/src/UI/components/SettingsBoard/Context.tsx @@ -1,18 +1,19 @@ import { useCallback, useEffect, useState } from 'react' import { createContainer } from '@masknet/shared-base-ui' -import { useGasOptions, useNetworkContext, useChainContext, useWeb3Utils } from '@masknet/web3-hooks-base' +import { useGasOptions, useNetworkContext, useChainContext } from '@masknet/web3-hooks-base' import type { Web3Helper } from '@masknet/web3-helpers' import { GasOptionType } from '@masknet/web3-shared-base' import type { NetworkPluginID } from '@masknet/shared-base' import { GasSettingsType } from './types/index.js' import { useLingui } from '@lingui/react/macro' +import stringify from 'json-stable-stringify' const DEFAULT_SLIPPAGE_TOLERANCE = 0.5 const DEFAULT_SLIPPAGE_TOLERANCES = [0.5, 1, 2, 5] const IN_MEMORY_CACHE: { - lastNetworkSignature?: string - lastTransactionSignature?: string + lastNetworkCacheKey?: string + lastTransactionCacheKey?: string lastSelectedGasOptionType: GasOptionType lastSelectedGasSettingsType: GasSettingsType } = { @@ -34,18 +35,17 @@ function useSettingsContext(initial?: { const { chainId } = useChainContext({ chainId: initial?.chainId, }) - const Utils = useWeb3Utils(pluginID) const [transactionOptions, setTransactionOptions] = useState< Web3Helper.Definition[typeof pluginID]['Transaction'] | undefined >(initial?.transaction) const [slippageTolerance, setSlippageTolerance] = useState(initial?.slippageTolerance ?? DEFAULT_SLIPPAGE_TOLERANCE) - const networkSignature = `${pluginID}_${chainId}` - const transactionSignature = Utils.getTransactionSignature!(chainId, transactionOptions) ?? '' + const networkCacheKey = `${pluginID}_${chainId}` + const transactionCacheKey = stringify([chainId, transactionOptions]) const needToResetByNetwork = - !!IN_MEMORY_CACHE.lastNetworkSignature && IN_MEMORY_CACHE.lastNetworkSignature !== networkSignature + !!IN_MEMORY_CACHE.lastNetworkCacheKey && IN_MEMORY_CACHE.lastNetworkCacheKey !== networkCacheKey const needToResetByTransaction = - !!IN_MEMORY_CACHE.lastTransactionSignature && IN_MEMORY_CACHE.lastTransactionSignature !== transactionSignature + !!IN_MEMORY_CACHE.lastTransactionCacheKey && IN_MEMORY_CACHE.lastTransactionCacheKey !== transactionCacheKey const [gasSettingsType, setGasSettingsType] = useState( needToResetByNetwork || needToResetByTransaction ? GasSettingsType.Basic @@ -66,8 +66,8 @@ function useSettingsContext(initial?: { const onClearInMemoryCache = useCallback(() => { // eslint-disable-next-line react-compiler/react-compiler - delete IN_MEMORY_CACHE.lastNetworkSignature - delete IN_MEMORY_CACHE.lastTransactionSignature + delete IN_MEMORY_CACHE.lastNetworkCacheKey + delete IN_MEMORY_CACHE.lastTransactionCacheKey IN_MEMORY_CACHE.lastSelectedGasOptionType = GasOptionType.NORMAL IN_MEMORY_CACHE.lastSelectedGasSettingsType = GasSettingsType.Basic }, []) @@ -82,11 +82,11 @@ function useSettingsContext(initial?: { // sync in-memory cache useEffect(() => { - IN_MEMORY_CACHE.lastNetworkSignature = networkSignature - IN_MEMORY_CACHE.lastTransactionSignature = transactionSignature + IN_MEMORY_CACHE.lastNetworkCacheKey = networkCacheKey + IN_MEMORY_CACHE.lastTransactionCacheKey = transactionCacheKey IN_MEMORY_CACHE.lastSelectedGasOptionType = gasOptionType IN_MEMORY_CACHE.lastSelectedGasSettingsType = gasSettingsType - }, [gasOptionType, gasSettingsType, networkSignature, transactionSignature]) + }, [gasOptionType, gasSettingsType, networkCacheKey, transactionCacheKey]) return { DEFAULT_SLIPPAGE_TOLERANCE, diff --git a/packages/shared/src/UI/modals/GasSettingModal/Prior1559GasSetting.tsx b/packages/shared/src/UI/modals/GasSettingModal/Prior1559GasSetting.tsx index 598ad935c43c..22e2d018e365 100644 --- a/packages/shared/src/UI/modals/GasSettingModal/Prior1559GasSetting.tsx +++ b/packages/shared/src/UI/modals/GasSettingModal/Prior1559GasSetting.tsx @@ -2,7 +2,6 @@ import { memo, useCallback, useEffect, useMemo, useState } from 'react' import { useUpdateEffect } from 'react-use' import { Controller, useForm } from 'react-hook-form' import { isEmpty, noop } from 'lodash-es' -import defer * as web3_utils from 'web3-utils' import { z as zod } from 'zod' import { BigNumber } from 'bignumber.js' import { zodResolver } from '@hookform/resolvers/zod' @@ -20,6 +19,7 @@ import { ActionButton, makeStyles, MaskColorVar } from '@masknet/theme' import { Typography } from '@mui/material' import type { GasSettingProps } from './types.js' import { Trans, useLingui } from '@lingui/react/macro' +import { parseGwei } from 'viem' const minGasPriceOfChain: ChainIdOptionalRecord = { [ChainId.BSC]: pow10(9).multipliedBy(5), @@ -172,7 +172,7 @@ export const Prior1559GasSetting = memo( (data: zod.infer) => { onConfirm({ gasLimit: data.gasLimit as any, - gasPrice: web3_utils.toWei(data.gasPrice, 'gwei'), + gasPrice: parseGwei(data.gasPrice).toString(), gasOption: selectedGasOption, }) }, diff --git a/packages/web3-hooks/evm/src/useContract.ts b/packages/web3-hooks/evm/src/useContract.ts index 5c5a936a850d..ba58f583f9bc 100644 --- a/packages/web3-hooks/evm/src/useContract.ts +++ b/packages/web3-hooks/evm/src/useContract.ts @@ -1,38 +1,17 @@ import { useMemo } from 'react' -import type { AbiItem } from 'web3-utils' import { EMPTY_LIST } from '@masknet/shared-base' import { EVMWeb3 } from '@masknet/web3-providers' import { type ChainId, createContract } from '@masknet/web3-shared-evm' import type { BaseContract } from '@masknet/web3-contracts/types/types.js' +import type { Abi } from 'viem' /** * Create a contract which will forward its all transactions to the * EthereumService in the background page and decode the result of calls automatically * @param address - * @param ABI + * @param abi * @param chainId */ -export function useContract(chainId?: ChainId, address = '', ABI: AbiItem[] = EMPTY_LIST) { - return useMemo(() => createContract(EVMWeb3.getWeb3({ chainId }), address, ABI), [address, ABI]) -} - -/** - * Create many contracts with same ABI - * @param listOfAddress - * @param ABI - * @param chainId - */ -export function useContracts( - chainId?: ChainId, - listOfAddress: string[] = EMPTY_LIST, - ABI: AbiItem[] = EMPTY_LIST, -) { - return useMemo( - () => - listOfAddress - .map((address) => createContract(EVMWeb3.getWeb3({ chainId }), address, ABI)) - .filter(Boolean) as T[], - // eslint-disable-next-line react-compiler/react-compiler - [JSON.stringify(listOfAddress), ABI], - ) +export function useContract(chainId?: ChainId, address = '', abi: Abi = EMPTY_LIST) { + return useMemo(() => createContract(EVMWeb3.getWeb3({ chainId }), address, abi), [address, abi]) } diff --git a/packages/web3-providers/package.json b/packages/web3-providers/package.json index 8fbe49daded8..81a9efcf3204 100644 --- a/packages/web3-providers/package.json +++ b/packages/web3-providers/package.json @@ -66,6 +66,7 @@ "buffer": "^6.0.3", "date-fns": "^3.6.0", "fuse.js": "^7.0.0", + "json-stable-stringify": "^1.1.1", "graphql-request": "^7.0.1", "immer": "^10.1.1", "lru-cache": "^10.3.0", @@ -85,6 +86,7 @@ "devDependencies": { "@types/bn.js": "^5.1.5", "@types/bs58": "^4.0.4", + "@types/json-stable-stringify": "^1.0.36", "@types/socket.io-client": "^1.4.36", "@types/twitter-text": "^3.1.10", "@types/use-subscription": "^1.0.2", diff --git a/packages/web3-providers/src/Alchemy/helpers.ts b/packages/web3-providers/src/Alchemy/helpers.ts index 41af975aeb86..456656e55b5d 100644 --- a/packages/web3-providers/src/Alchemy/helpers.ts +++ b/packages/web3-providers/src/Alchemy/helpers.ts @@ -1,7 +1,7 @@ -import defer * as web3_utils from 'web3-utils' +import { isHex } from 'viem' export function formatAlchemyTokenId(tokenId: string) { - return web3_utils.isHex(tokenId) && tokenId.startsWith('0x') ? web3_utils.hexToNumberString(tokenId) : tokenId + return isHex(tokenId) ? Number(tokenId).toString() : tokenId } export function formatAlchemyTokenAddress(address: string, identifier: string) { diff --git a/packages/web3-providers/src/Web3/Base/apis/Utils.ts b/packages/web3-providers/src/Web3/Base/apis/Utils.ts index 5a87340f3528..90cd72bcb677 100644 --- a/packages/web3-providers/src/Web3/Base/apis/Utils.ts +++ b/packages/web3-providers/src/Web3/Base/apis/Utils.ts @@ -1,56 +1,28 @@ -import type { NetworkPluginID } from '@masknet/shared-base' -import { type FungibleToken, type NonFungibleToken } from '@masknet/web3-shared-base' -import type { ProviderResolver } from './ProviderResolver.js' import type { NetworkResolver } from './NetworkExplorer.js' import type { ChainResolver } from './ChainResolver.js' import type { ExplorerResolver } from './ExplorerResolver.js' -export interface BaseUtils { +export interface BaseUtils { readonly chainResolver: ChainResolver readonly explorerResolver: ExplorerResolver - readonly providerResolver: ProviderResolver readonly networkResolver: NetworkResolver - getNetworkPluginID(): NetworkPluginID - getDefaultChainId(): ChainId - getInvalidChainId?(): ChainId - - getDefaultNetworkType(): NetworkType - - getDefaultProviderType(): ProviderType - - getZeroAddress(): string | undefined - getNativeTokenAddress(chainId?: ChainId): string | undefined getMaskTokenAddress(chainId?: ChainId): string | undefined getAverageBlockDelay?(chainId: ChainId, scale?: number): number - getTransactionSignature?(chainId?: ChainId, transaction?: Transaction | undefined): string | undefined - - isSameAddress(address?: string | undefined, otherAddress?: string | undefined): boolean - - isZeroAddress(address?: string): boolean - isNativeTokenAddress(address?: string): boolean - isValidChain?(chainId: ChainId, testnet?: boolean): boolean - isValidChainId(chainId: ChainId): boolean isValidDomain(domain: string): boolean isValidAddress(address: string): boolean - isNativeTokenSchemaType(schemaType?: SchemaType | undefined): boolean - - isFungibleTokenSchemaType(schemaType?: SchemaType | undefined): boolean - - isNonFungibleTokenSchemaType(schemaType?: SchemaType | undefined): boolean - formatAddress(address: string, size?: number | undefined): string formatTokenId(id?: string | undefined, size?: number | undefined): string @@ -58,27 +30,4 @@ export interface BaseUtils - - createFungibleToken( - chainId: ChainId, - schemaType: SchemaType, - address: string, - name?: string, - symbol?: string, - decimals?: number, - logoURI?: string, - ): FungibleToken - - createNonFungibleToken( - chainId: ChainId, - address: string, - schemaType: SchemaType, - tokenId: string, - ownerId?: string, - metadata?: NonFungibleToken['metadata'], - contract?: NonFungibleToken['contract'], - collection?: NonFungibleToken['collection'], - ): NonFungibleToken } diff --git a/packages/web3-providers/src/Web3/EVM/apis/ConnectionAPI.ts b/packages/web3-providers/src/Web3/EVM/apis/ConnectionAPI.ts index 08f2c4fcc04f..de74618987a0 100644 --- a/packages/web3-providers/src/Web3/EVM/apis/ConnectionAPI.ts +++ b/packages/web3-providers/src/Web3/EVM/apis/ConnectionAPI.ts @@ -1,6 +1,5 @@ -import defer * as web3_utils from 'web3-utils' import { delay } from '@masknet/kit' -import { NetworkPluginID } from '@masknet/shared-base' +import { NetworkPluginID, toHex } from '@masknet/shared-base' import type { Account } from '@masknet/shared-base' import { type AddressType, @@ -100,7 +99,7 @@ export class ConnectionAPI // ERC20 return new ContractTransaction(this.Contract.getERC20Contract(address, options)).send( - (x) => x?.methods.approve(recipient, web3_utils.toHex(amount)), + (x) => x?.methods.approve(recipient, toHex(amount)), options.overrides, ) } @@ -138,8 +137,8 @@ export class ConnectionAPI const tx: Transaction = { from: options.account, to: recipient, - value: web3_utils.toHex(amount), - data: memo ? web3_utils.toHex(memo) : undefined, + value: toHex(amount), + data: memo ? toHex(memo) : undefined, } return this.sendTransaction( { @@ -152,7 +151,7 @@ export class ConnectionAPI // ERC20 return new ContractTransaction(this.Contract.getERC20Contract(address, options)).send( - (x) => x?.methods.transfer(recipient, web3_utils.toHex(amount)), + (x) => x?.methods.transfer(recipient, toHex(amount)), options.overrides, ) } diff --git a/packages/web3-providers/src/Web3/EVM/apis/ConnectionReadonlyAPI.ts b/packages/web3-providers/src/Web3/EVM/apis/ConnectionReadonlyAPI.ts index 262f7d4ce30a..eddee833ad7b 100644 --- a/packages/web3-providers/src/Web3/EVM/apis/ConnectionReadonlyAPI.ts +++ b/packages/web3-providers/src/Web3/EVM/apis/ConnectionReadonlyAPI.ts @@ -1,4 +1,4 @@ -import type { Account, ECKeyIdentifier, Proof } from '@masknet/shared-base' +import { toHex, type Account, type ECKeyIdentifier, type Proof } from '@masknet/shared-base' import { queryClient } from '@masknet/shared-base-ui' import { createNonFungibleToken, @@ -40,7 +40,6 @@ import { type Web3, } from '@masknet/web3-shared-evm' import { first, omit, toNumber } from 'lodash-es' -import defer * as web3_utils from 'web3-utils' import type { BaseConnectionOptions } from '../../../entry-types.js' import { fetchJSON } from '../../../helpers/fetchJSON.js' import type { BaseConnection } from '../../Base/apis/Connection.js' @@ -466,7 +465,7 @@ export class EVMConnectionReadonlyAPI const balances = await contract?.methods.balances([options.account], listOfNonNativeAddress).call({ // cannot check the sender's balance in the same contract from: undefined, - chainId: web3_utils.numberToHex(options.chainId), + chainId: toHex(options.chainId), }) listOfNonNativeAddress.forEach((x, i) => { @@ -514,8 +513,8 @@ export class EVMConnectionReadonlyAPI return createERC20Token( options.chainId, address, - parseStringOrBytes32(name, nameBytes32, 'Unknown Token'), - parseStringOrBytes32(symbol, symbolBytes32, 'UNKNOWN'), + parseStringOrBytes32(name, toHex(nameBytes32), 'Unknown Token'), + parseStringOrBytes32(symbol, toHex(symbolBytes32), 'UNKNOWN'), typeof decimals === 'string' ? Number.parseInt(decimals ? decimals : '0', 10) : decimals, ) } @@ -548,7 +547,7 @@ export class EVMConnectionReadonlyAPI return this.Request.request( { method: EthereumMethodType.eth_getBlockByNumber, - params: [web3_utils.toHex(noOrId), false], + params: [toHex(noOrId), false], }, initial, ) @@ -618,7 +617,7 @@ export class EVMConnectionReadonlyAPI options, ) } catch { - return web3_utils.toHex(fallback) + return toHex(fallback) } } diff --git a/packages/web3-providers/src/Web3/EVM/apis/ContractReadonlyAPI.ts b/packages/web3-providers/src/Web3/EVM/apis/ContractReadonlyAPI.ts index ca04b4458cb0..7aa654868eda 100644 --- a/packages/web3-providers/src/Web3/EVM/apis/ContractReadonlyAPI.ts +++ b/packages/web3-providers/src/Web3/EVM/apis/ContractReadonlyAPI.ts @@ -1,4 +1,3 @@ -import type { AbiItem } from 'web3-utils' import { isUndefined, omitBy } from 'lodash-es' import { createContract } from '@masknet/web3-shared-evm' import type { BalanceChecker } from '@masknet/web3-contracts/types/BalanceChecker.js' @@ -22,6 +21,7 @@ import { WalletAbi as WalletABI } from '@masknet/web3-contracts/types/Wallet.js' import { EVMRequestReadonlyAPI } from './RequestReadonlyAPI.js' import type { EVMConnectionOptions } from '../types/index.js' +import type { Abi } from 'viem' export class EVMContractReadonlyAPI { static Default = new EVMContractReadonlyAPI() @@ -30,11 +30,7 @@ export class EVMContractReadonlyAPI { } protected Request - getWeb3Contract( - address: string | undefined, - ABI: AbiItem[], - initial?: EVMConnectionOptions, - ) { + getWeb3Contract(address: string | undefined, abi: Abi, initial?: EVMConnectionOptions) { const web3 = this.Request.getWeb3(initial) const options = omitBy( { @@ -42,7 +38,7 @@ export class EVMContractReadonlyAPI { }, isUndefined, ) - return createContract(web3, address, ABI, options) + return createContract(web3, address, abi, options) } getERC20Contract(address: string | undefined, initial?: EVMConnectionOptions) { diff --git a/packages/web3-providers/src/Web3/EVM/apis/SignerAPI.ts b/packages/web3-providers/src/Web3/EVM/apis/SignerAPI.ts index 00bbdd10e7b4..7a64d78b141c 100644 --- a/packages/web3-providers/src/Web3/EVM/apis/SignerAPI.ts +++ b/packages/web3-providers/src/Web3/EVM/apis/SignerAPI.ts @@ -2,7 +2,6 @@ import defer * as _metamask_eth_sig_util from '@metamask/eth-sig-util' import { signTransaction } from '@masknet/web3-shared-evm' import { type SignMessage, SignType, toHex } from '@masknet/shared-base' import { unreachable } from '@masknet/kit' -import type { Hex } from 'viem' export class Signer { static async sign({ type, data }: SignMessage, key: Buffer): Promise { @@ -24,7 +23,7 @@ export class Signer { const chainId = transaction.chainId if (!chainId) throw new Error('Invalid chain id.') - const rawTransaction = await signTransaction(transaction, toHex(key) as Hex) + const rawTransaction = await signTransaction(transaction, toHex(key)) if (!rawTransaction) throw new Error('Failed to sign transaction.') return rawTransaction diff --git a/packages/web3-providers/src/Web3/EVM/apis/Utils.ts b/packages/web3-providers/src/Web3/EVM/apis/Utils.ts index bbff9e6d2a7d..e0a4f9a65398 100644 --- a/packages/web3-providers/src/Web3/EVM/apis/Utils.ts +++ b/packages/web3-providers/src/Web3/EVM/apis/Utils.ts @@ -1,27 +1,14 @@ -import { createFungibleToken, createNonFungibleToken, isSameAddress } from '@masknet/web3-shared-base' import { isValidDomain, isValidAddress, - isZeroAddress, isNativeTokenAddress, - isNativeTokenSchemaType, - isFungibleTokenSchemaType, - isNonFungibleTokenSchemaType, formatEthereumAddress, formatDomainName, formatTokenId, - getTransactionSignature, type ChainId, - type ProviderType, type NetworkType, - type Transaction, type SchemaType, - getNetworkPluginID, getDefaultChainId, - getInvalidChainId, - getDefaultNetworkType, - getDefaultProviderType, - getZeroAddress, getMaskTokenAddress, getNativeTokenAddress, getAverageBlockDelay, @@ -29,42 +16,25 @@ import { isValidChainId, } from '@masknet/web3-shared-evm' import type { BaseUtils } from '../../Base/apis/Utils.js' -import { EVMChainResolver, EVMExplorerResolver, EVMProviderResolver, EVMNetworkResolver } from './ResolverAPI.js' +import { EVMChainResolver, EVMExplorerResolver, EVMNetworkResolver } from './ResolverAPI.js' export const EVMUtils = { - isSameAddress, chainResolver: EVMChainResolver, explorerResolver: EVMExplorerResolver, - providerResolver: EVMProviderResolver, networkResolver: EVMNetworkResolver, isValidDomain, isValidChainId, isValidAddress, - isZeroAddress, isNativeTokenAddress, - isNativeTokenSchemaType, - isFungibleTokenSchemaType, - isNonFungibleTokenSchemaType, - getNetworkPluginID, getDefaultChainId, - getInvalidChainId, - getDefaultNetworkType, - getDefaultProviderType, - getZeroAddress, getMaskTokenAddress, getNativeTokenAddress, - getTransactionSignature, getAverageBlockDelay, formatAddress: formatEthereumAddress, formatTokenId, formatDomainName, formatSchemaType, - createNativeToken(chainId: ChainId) { - return EVMChainResolver.nativeCurrency(chainId) - }, - createFungibleToken, - createNonFungibleToken, -} satisfies BaseUtils +} satisfies BaseUtils diff --git a/packages/web3-providers/src/Web3/EVM/interceptors/MaskWallet.ts b/packages/web3-providers/src/Web3/EVM/interceptors/MaskWallet.ts index 207132ada0d6..ac792a81f3c3 100644 --- a/packages/web3-providers/src/Web3/EVM/interceptors/MaskWallet.ts +++ b/packages/web3-providers/src/Web3/EVM/interceptors/MaskWallet.ts @@ -1,5 +1,4 @@ -import defer * as web3_utils from 'web3-utils' -import type { Wallet } from '@masknet/shared-base' +import { toHex, type Wallet } from '@masknet/shared-base' import { EthereumMethodType, type Middleware, isValidAddress } from '@masknet/web3-shared-evm' import type { ConnectionContext } from '../libs/ConnectionContext.js' import { MaskWalletProviderInstance } from '../providers/index.js' @@ -17,7 +16,7 @@ export class MaskWallet implements Middleware { switch (context.request.method) { case EthereumMethodType.eth_chainId: - context.write(web3_utils.toHex(provider.hostedChainId)) + context.write(toHex(provider.hostedChainId)) break case EthereumMethodType.eth_accounts: context.write([provider.hostedAccount]) diff --git a/packages/web3-providers/src/Web3/EVM/interceptors/WalletConnect.ts b/packages/web3-providers/src/Web3/EVM/interceptors/WalletConnect.ts index 7406b94b27ec..40ded4db28b1 100644 --- a/packages/web3-providers/src/Web3/EVM/interceptors/WalletConnect.ts +++ b/packages/web3-providers/src/Web3/EVM/interceptors/WalletConnect.ts @@ -1,6 +1,6 @@ -import defer * as web3_utils from 'web3-utils' import { EthereumMethodType, type Middleware } from '@masknet/web3-shared-evm' import type { ConnectionContext } from '../libs/ConnectionContext.js' +import { toHex } from '@masknet/shared-base' export class WalletConnect implements Middleware { async fn(context: ConnectionContext, next: () => Promise) { @@ -20,7 +20,7 @@ export class WalletConnect implements Middleware { switch (context.request.method) { case EthereumMethodType.eth_chainId: if (typeof context.result === 'number') { - context.result = web3_utils.toHex(context.result) + context.result = toHex(context.result) } break default: diff --git a/packages/web3-providers/src/Web3/EVM/middleware/Nonce.ts b/packages/web3-providers/src/Web3/EVM/middleware/Nonce.ts index 69864f3387cc..595bfdfa12b5 100644 --- a/packages/web3-providers/src/Web3/EVM/middleware/Nonce.ts +++ b/packages/web3-providers/src/Web3/EVM/middleware/Nonce.ts @@ -1,4 +1,3 @@ -import defer * as web3_utils from 'web3-utils' import { type ChainId, EthereumMethodType, @@ -8,6 +7,7 @@ import { } from '@masknet/web3-shared-evm' import type { ConnectionContext } from '../libs/ConnectionContext.js' import { EVMWeb3Readonly } from '../apis/ConnectionReadonlyAPI.js' +import { toHex } from '@masknet/shared-base' class NonceAPI implements Middleware { static INITIAL_NONCE = -1 @@ -48,9 +48,7 @@ class NonceAPI implements Middleware { params: [ { ...context.config, - nonce: web3_utils.toHex( - await this.syncRemoteNonce(context.chainId, context.account, context.providerURL), - ), + nonce: toHex(await this.syncRemoteNonce(context.chainId, context.account, context.providerURL)), }, ], } diff --git a/packages/web3-providers/src/Web3/EVM/providers/Base.ts b/packages/web3-providers/src/Web3/EVM/providers/Base.ts index 50d9f0fc5782..4a77713e1fec 100644 --- a/packages/web3-providers/src/Web3/EVM/providers/Base.ts +++ b/packages/web3-providers/src/Web3/EVM/providers/Base.ts @@ -1,5 +1,4 @@ import { first } from 'lodash-es' -import defer * as web3_utils from 'web3-utils' import { Emitter } from '@servie/events' import { delay } from '@masknet/kit' import { @@ -10,7 +9,7 @@ import { type RequestArguments, isValidChainId, } from '@masknet/web3-shared-evm' -import { type Account, type Wallet, EMPTY_LIST, createConstantSubscription } from '@masknet/shared-base' +import { type Account, type Wallet, EMPTY_LIST, createConstantSubscription, toHex } from '@masknet/shared-base' import { EVMChainResolver } from '../apis/ResolverAPI.js' import { createWeb3ProviderFromRequest } from '../../../helpers/createWeb3ProviderFromRequest.js' import type { WalletAPI } from '../../../entry-types.js' @@ -51,7 +50,7 @@ export abstract class BaseEVMWalletProvider implements EVMWalletProvider { method: EthereumMethodType.wallet_switchEthereumChain, params: [ { - chainId: web3_utils.toHex(chainId), + chainId: toHex(chainId), }, ], }) @@ -70,7 +69,7 @@ export abstract class BaseEVMWalletProvider implements EVMWalletProvider { method: EthereumMethodType.wallet_addEthereumChain, params: [ { - chainId: web3_utils.toHex(chainId), + chainId: toHex(chainId), chainName: EVMChainResolver.chainFullName(chainId) ?? EVMChainResolver.chainName(chainId), nativeCurrency: EVMChainResolver.nativeCurrency(chainId), rpcUrls: [ProviderURL.fromOfficial(chainId)], diff --git a/packages/web3-providers/src/Web3/EVM/providers/BaseHosted.ts b/packages/web3-providers/src/Web3/EVM/providers/BaseHosted.ts index b15dedbdff13..05739dc14c88 100644 --- a/packages/web3-providers/src/Web3/EVM/providers/BaseHosted.ts +++ b/packages/web3-providers/src/Web3/EVM/providers/BaseHosted.ts @@ -1,7 +1,12 @@ import { uniqWith } from 'lodash-es' -import defer * as web3_utils from 'web3-utils' import { delay } from '@masknet/kit' -import { type StorageObject, type UpdatableWallet, type Wallet, CrossIsolationMessages } from '@masknet/shared-base' +import { + type StorageObject, + type UpdatableWallet, + type Wallet, + CrossIsolationMessages, + toHex, +} from '@masknet/shared-base' import { isSameAddress } from '@masknet/web3-shared-base' import { isValidAddress, formatEthereumAddress, type ChainId, type ProviderType } from '@masknet/web3-shared-evm' import { BaseEVMWalletProvider } from './Base.js' @@ -141,12 +146,12 @@ export abstract class BaseHostedProvider extends BaseEVMWalletProvider { this.emitter.emit('accounts', [this.hostedAccount]) await delay(100) - this.emitter.emit('chainId', web3_utils.toHex(this.hostedChainId)) + this.emitter.emit('chainId', toHex(this.hostedChainId)) } private async onChainChanged() { await this.walletStorage.chainId.initializedPromise - if (this.hostedChainId) this.emitter.emit('chainId', web3_utils.toHex(this.hostedChainId)) + if (this.hostedChainId) this.emitter.emit('chainId', toHex(this.hostedChainId)) } async switchAccount(account?: string) { diff --git a/packages/web3-providers/src/Web3/EVM/providers/Opera.ts b/packages/web3-providers/src/Web3/EVM/providers/Opera.ts index 9342bbda4b02..3da4187b86bb 100644 --- a/packages/web3-providers/src/Web3/EVM/providers/Opera.ts +++ b/packages/web3-providers/src/Web3/EVM/providers/Opera.ts @@ -1,5 +1,4 @@ -import defer * as web3_utils from 'web3-utils' -import { Sniffings } from '@masknet/shared-base' +import { Sniffings, toHex } from '@masknet/shared-base' import { injectedOperaProvider } from '@masknet/injected-script' import { type ChainId, EthereumMethodType, ProviderType, isValidChainId } from '@masknet/web3-shared-evm' import { EVMInjectedWalletProvider } from './BaseInjected.js' @@ -26,7 +25,7 @@ export class OperaProvider extends EVMInjectedWalletProvider { method: EthereumMethodType.wallet_switchEthereumChain, params: [ { - chainId: web3_utils.toHex(chainId), + chainId: toHex(chainId), }, ], }) diff --git a/packages/web3-providers/src/Web3/EVM/providers/WalletConnect.ts b/packages/web3-providers/src/Web3/EVM/providers/WalletConnect.ts index a1c35c211c84..385d09eb1437 100644 --- a/packages/web3-providers/src/Web3/EVM/providers/WalletConnect.ts +++ b/packages/web3-providers/src/Web3/EVM/providers/WalletConnect.ts @@ -1,10 +1,9 @@ import { first } from 'lodash-es' -import defer * as web3_utils from 'web3-utils' import type { Emitter } from '@servie/events' import { getSdkError } from '@walletconnect/utils' import { SignClient } from '@walletconnect/sign-client' import { Flags } from '@masknet/flags' -import type { UnboxPromise } from '@masknet/shared-base' +import { toHex, type UnboxPromise } from '@masknet/shared-base' import { ProviderType, ChainId, @@ -49,7 +48,7 @@ class Client { this.client.on('session_update', () => { if (!this.account) return - this.emitter.emit('chainId', web3_utils.toHex(this.account.chainId)) + this.emitter.emit('chainId', toHex(this.account.chainId)) this.emitter.emit('accounts', [this.account.account]) }) diff --git a/packages/web3-providers/src/Web3/EVM/state/TransactionWatcher/checkers/AccountChecker.ts b/packages/web3-providers/src/Web3/EVM/state/TransactionWatcher/checkers/AccountChecker.ts index 07783bffe506..3081f043efcd 100644 --- a/packages/web3-providers/src/Web3/EVM/state/TransactionWatcher/checkers/AccountChecker.ts +++ b/packages/web3-providers/src/Web3/EVM/state/TransactionWatcher/checkers/AccountChecker.ts @@ -1,8 +1,8 @@ -import defer * as web3_utils from 'web3-utils' import { type TransactionChecker, TransactionStatusType } from '@masknet/web3-shared-base' import type { ChainId, Transaction } from '@masknet/web3-shared-evm' import { EtherscanExplorer } from '../../../../../Etherscan/index.js' import type { ExplorerAPI } from '../../../../../entry-types.js' +import { toHex } from '@masknet/shared-base' class TTL { private cache: Record = {} @@ -30,16 +30,15 @@ class AccountCheckerAPI implements TransactionChecker { private ttl = new TTL() - private getExplorerTransactionId(transaction: ExplorerAPI.Transaction | null) { + private getTransactionCacheKey(transaction: ExplorerAPI.Transaction | Transaction | null) { if (!transaction) return '' - const { from, to, input, value } = transaction - return web3_utils.sha3([from, to, input || '0x0', web3_utils.toHex(value || '0x0') || '0x0'].join('_')) ?? '' - } - - private getTransactionId(transaction: Transaction) { - const { from, to, data = '0x0', value = '0x0' } = transaction - if (!from || !to) return '' - return web3_utils.sha3([from, to, data, value].join('_')) ?? '' + const { from, to, value = '0' } = transaction + return JSON.stringify([ + from, + to, + 'input' in transaction ? transaction.input : transaction.data || '0x0', + toHex(value || '0'), + ]) } private async fetchLatestTransactions(chainId: ChainId, account: string) { @@ -58,8 +57,8 @@ class AccountCheckerAPI implements TransactionChecker { const account = transaction.from if (!account) throw new Error('Cannot found account.') const latestTransactions = await this.fetchLatestTransactions(chainId, account) - const txId = this.getTransactionId(transaction) - const tx = latestTransactions.find((x) => x.hash === id || this.getExplorerTransactionId(x) === txId) + const txId = this.getTransactionCacheKey(transaction) + const tx = latestTransactions.find((x) => x.hash === id || this.getTransactionCacheKey(x) === txId) if (!tx) return TransactionStatusType.NOT_DEPEND // '1' for successful transactions and '0' for failed transactions. return tx.status === '1' ? TransactionStatusType.SUCCEED : TransactionStatusType.FAILED diff --git a/packages/web3-providers/src/Web3/EVM/translators/Astar.ts b/packages/web3-providers/src/Web3/EVM/translators/Astar.ts index a157eea2b5e5..3b4684841fc8 100644 --- a/packages/web3-providers/src/Web3/EVM/translators/Astar.ts +++ b/packages/web3-providers/src/Web3/EVM/translators/Astar.ts @@ -1,7 +1,7 @@ import { ChainId } from '@masknet/web3-shared-evm' import type { ConnectionContext } from '../libs/ConnectionContext.js' import { BaseTranslator } from './Base.js' -import defer * as web3_utils from 'web3-utils' +import { toHex } from '@masknet/shared-base' export class AstarTranslator extends BaseTranslator { override async encode(context: ConnectionContext): Promise { @@ -11,9 +11,9 @@ export class AstarTranslator extends BaseTranslator { context.config = { ...context.config, - maxFeePerGas: context.config.maxFeePerGas ? web3_utils.toHex(context.config.maxFeePerGas) : undefined, + maxFeePerGas: context.config.maxFeePerGas ? toHex(context.config.maxFeePerGas) : undefined, maxPriorityFeePerGas: - context.config.maxPriorityFeePerGas ? web3_utils.toHex(context.config.maxPriorityFeePerGas) : undefined, + context.config.maxPriorityFeePerGas ? toHex(context.config.maxPriorityFeePerGas) : undefined, // rpc hack, alchemy rpc must pass gas parameter gas: '0x135168', } diff --git a/packages/web3-providers/src/Web3/EVM/translators/Base.ts b/packages/web3-providers/src/Web3/EVM/translators/Base.ts index ee0974ce3353..41276fea34ff 100644 --- a/packages/web3-providers/src/Web3/EVM/translators/Base.ts +++ b/packages/web3-providers/src/Web3/EVM/translators/Base.ts @@ -1,10 +1,10 @@ import { BigNumber } from 'bignumber.js' -import defer * as web3_utils from 'web3-utils' import { GasOptionType, isLessThan, toFixed } from '@masknet/web3-shared-base' import { ChainId, formatWeiToGwei, PayloadEditor, ProviderType, type Translator } from '@masknet/web3-shared-evm' import type { ConnectionContext } from '../libs/ConnectionContext.js' import { EVMHub } from '../apis/HubAPI.js' import { EVMChainResolver } from '../apis/ResolverAPI.js' +import { toHex } from '@masknet/shared-base' export abstract class BaseTranslator implements Translator { async encode(context: ConnectionContext) { @@ -16,14 +16,13 @@ export abstract class BaseTranslator implements Translator { // add gas margin if (config.gas) { if (context.providerType !== ProviderType.MaskWallet) { - config.gas = web3_utils.toHex( - BigNumber.max( - web3_utils.toHex(config.gas), - context.chainId === ChainId.Optimism ? 25000 : 21000, - ).toFixed(), + config.gas = toHex( + BigNumber.max(toHex(config.gas), context.chainId === ChainId.Optimism ? 25000 : 21000).toFixed( + 0, + ), ) } else { - config.gas = web3_utils.toHex(config.gas) + config.gas = toHex(config.gas) } } @@ -47,17 +46,15 @@ export abstract class BaseTranslator implements Translator { slowOption.suggestedMaxPriorityFeePerGas, ) ) { - config.maxFeePerGas = web3_utils.toHex(toFixed(normalOption.suggestedMaxFeePerGas, 0)) - config.maxPriorityFeePerGas = web3_utils.toHex( - toFixed(normalOption.suggestedMaxPriorityFeePerGas, 0), - ) + config.maxFeePerGas = toHex(toFixed(normalOption.suggestedMaxFeePerGas, 0)) + config.maxPriorityFeePerGas = toHex(toFixed(normalOption.suggestedMaxPriorityFeePerGas, 0)) } } else { delete config.maxFeePerGas delete config.maxPriorityFeePerGas if (slowOption && normalOption && isLessThan(config.gasPrice ?? 0, slowOption.suggestedMaxFeePerGas)) { - config.gasPrice = web3_utils.toHex(toFixed(normalOption.suggestedMaxFeePerGas, 0)) + config.gasPrice = toHex(toFixed(normalOption.suggestedMaxFeePerGas, 0)) } } } catch (err) { @@ -70,12 +67,10 @@ export abstract class BaseTranslator implements Translator { context.config = { ...config, - maxFeePerGas: overrideMaxFeePerGas ? web3_utils.toHex(overrideMaxFeePerGas) : config.maxFeePerGas, + maxFeePerGas: overrideMaxFeePerGas ? toHex(overrideMaxFeePerGas) : config.maxFeePerGas, maxPriorityFeePerGas: - overrideMaxPriorityFeePerGas ? - web3_utils.toHex(overrideMaxPriorityFeePerGas) - : config.maxPriorityFeePerGas, - gasPrice: overrideGasPrice ? web3_utils.toHex(overrideGasPrice) : config.gasPrice, + overrideMaxPriorityFeePerGas ? toHex(overrideMaxPriorityFeePerGas) : config.maxPriorityFeePerGas, + gasPrice: overrideGasPrice ? toHex(overrideGasPrice) : config.gasPrice, } // #endregion } diff --git a/packages/web3-providers/src/Web3/Flow/apis/ResolverAPI.ts b/packages/web3-providers/src/Web3/Flow/apis/ResolverAPI.ts index 72254f824e33..1d032f03903b 100644 --- a/packages/web3-providers/src/Web3/Flow/apis/ResolverAPI.ts +++ b/packages/web3-providers/src/Web3/Flow/apis/ResolverAPI.ts @@ -1,7 +1,6 @@ -import { PROVIDER_DESCRIPTORS, NETWORK_DESCRIPTORS, CHAIN_DESCRIPTORS } from '@masknet/web3-shared-flow' +import { NETWORK_DESCRIPTORS, CHAIN_DESCRIPTORS } from '@masknet/web3-shared-flow' import { ChainResolver } from '../../Base/apis/ChainResolver.js' import { ExplorerResolver } from '../../Base/apis/ExplorerResolver.js' -import { ProviderResolver } from '../../Base/apis/ProviderResolver.js' import { NetworkResolver } from '../../Base/apis/NetworkExplorer.js' export const FlowChainResolver = new ChainResolver(() => CHAIN_DESCRIPTORS) @@ -11,5 +10,4 @@ export const FlowExplorerResolver = new ExplorerResolver(() => CHAIN_DESCRIPTORS fungibleTokenPathname: '/contract/:address', nonFungibleTokenPathname: '/contract/:address', }) -export const FlowProviderResolver = new ProviderResolver(() => PROVIDER_DESCRIPTORS) export const FlowNetworkResolver = new NetworkResolver(() => NETWORK_DESCRIPTORS) diff --git a/packages/web3-providers/src/Web3/Flow/apis/Utils.ts b/packages/web3-providers/src/Web3/Flow/apis/Utils.ts index aa20bf0d9b1f..6736b915f86f 100644 --- a/packages/web3-providers/src/Web3/Flow/apis/Utils.ts +++ b/packages/web3-providers/src/Web3/Flow/apis/Utils.ts @@ -1,56 +1,33 @@ -import { createFungibleToken, createNonFungibleToken, isSameAddress } from '@masknet/web3-shared-base' import { isValidDomain, isValidAddress, - isZeroAddress, isNativeTokenAddress, - isNativeTokenSchemaType, - isFungibleTokenSchemaType, - isNonFungibleTokenSchemaType, type ChainId, formatAddress, formatDomainName, - type ProviderType, type NetworkType, - type Transaction, type SchemaType, getDefaultChainId, - getInvalidChainId, - getDefaultNetworkType, - getDefaultProviderType, - getZeroAddress, getMaskTokenAddress, getNativeTokenAddress, formatSchemaType, formatTokenId, isValidChainId, - getNetworkPluginID, } from '@masknet/web3-shared-flow' import { type BaseUtils } from '../../Base/apis/Utils.js' -import { FlowChainResolver, FlowExplorerResolver, FlowProviderResolver, FlowNetworkResolver } from './ResolverAPI.js' +import { FlowChainResolver, FlowExplorerResolver, FlowNetworkResolver } from './ResolverAPI.js' export const FlowUtils = { - isSameAddress, chainResolver: FlowChainResolver, explorerResolver: FlowExplorerResolver, - providerResolver: FlowProviderResolver, networkResolver: FlowNetworkResolver, isValidDomain, isValidChainId, isValidAddress, - isZeroAddress, isNativeTokenAddress, - isNativeTokenSchemaType, - isFungibleTokenSchemaType, - isNonFungibleTokenSchemaType, - getNetworkPluginID, getDefaultChainId, - getInvalidChainId, - getDefaultNetworkType, - getDefaultProviderType, - getZeroAddress, getNativeTokenAddress, getMaskTokenAddress, @@ -58,9 +35,4 @@ export const FlowUtils = { formatDomainName, formatTokenId, formatSchemaType, - createNativeToken(chainId: ChainId) { - return FlowChainResolver.nativeCurrency(chainId) - }, - createFungibleToken, - createNonFungibleToken, -} satisfies BaseUtils +} satisfies BaseUtils diff --git a/packages/web3-providers/src/Web3/Router/types/index.ts b/packages/web3-providers/src/Web3/Router/types/index.ts index 78d5e82524de..16ad2cc49879 100644 --- a/packages/web3-providers/src/Web3/Router/types/index.ts +++ b/packages/web3-providers/src/Web3/Router/types/index.ts @@ -60,7 +60,5 @@ export interface Utils extends BaseUtils< Web3Helper.Definition[T]['ChainId'], Web3Helper.Definition[T]['SchemaType'], - Web3Helper.Definition[T]['ProviderType'], - Web3Helper.Definition[T]['NetworkType'], - Web3Helper.Definition[T]['Transaction'] + Web3Helper.Definition[T]['NetworkType'] > {} diff --git a/packages/web3-providers/src/Web3/Solana/apis/ResolverAPI.ts b/packages/web3-providers/src/Web3/Solana/apis/ResolverAPI.ts index 75fd5d873880..c5e32907f7f5 100644 --- a/packages/web3-providers/src/Web3/Solana/apis/ResolverAPI.ts +++ b/packages/web3-providers/src/Web3/Solana/apis/ResolverAPI.ts @@ -1,10 +1,8 @@ -import { PROVIDER_DESCRIPTORS, NETWORK_DESCRIPTORS, CHAIN_DESCRIPTORS } from '@masknet/web3-shared-solana' +import { NETWORK_DESCRIPTORS, CHAIN_DESCRIPTORS } from '@masknet/web3-shared-solana' import { ChainResolver } from '../../Base/apis/ChainResolver.js' import { ExplorerResolver } from '../../Base/apis/ExplorerResolver.js' -import { ProviderResolver } from '../../Base/apis/ProviderResolver.js' import { NetworkResolver } from '../../Base/apis/NetworkExplorer.js' export const SolanaChainResolver = new ChainResolver(() => CHAIN_DESCRIPTORS) export const SolanaExplorerResolver = new ExplorerResolver(() => CHAIN_DESCRIPTORS) -export const SolanaProviderResolver = new ProviderResolver(() => PROVIDER_DESCRIPTORS) export const SolanaNetworkResolver = new NetworkResolver(() => NETWORK_DESCRIPTORS) diff --git a/packages/web3-providers/src/Web3/Solana/apis/Utils.ts b/packages/web3-providers/src/Web3/Solana/apis/Utils.ts index 4afbf3da7f98..14ea80997e01 100644 --- a/packages/web3-providers/src/Web3/Solana/apis/Utils.ts +++ b/packages/web3-providers/src/Web3/Solana/apis/Utils.ts @@ -2,61 +2,32 @@ import { formatDomainName } from '@masknet/web3-shared-evm' import { isValidDomain, isValidAddress, - isZeroAddress, isNativeTokenAddress, - isNativeTokenSchemaType, - isFungibleTokenSchemaType, - isNonFungibleTokenSchemaType, type ChainId, - type ProviderType, type NetworkType, - type Transaction, type SchemaType, formatAddress, formatTokenId, - getNetworkPluginID, getDefaultChainId, - getInvalidChainId, - getDefaultNetworkType, - getDefaultProviderType, - getZeroAddress, getMaskTokenAddress, getNativeTokenAddress, formatSchemaType, isValidChainId, } from '@masknet/web3-shared-solana' -import { createFungibleToken, createNonFungibleToken, isSameAddress } from '@masknet/web3-shared-base' import { type BaseUtils } from '../../Base/apis/Utils.js' -import { - SolanaChainResolver, - SolanaExplorerResolver, - SolanaProviderResolver, - SolanaNetworkResolver, -} from './ResolverAPI.js' +import { SolanaChainResolver, SolanaExplorerResolver, SolanaNetworkResolver } from './ResolverAPI.js' export const SolanaUtils = { - isSameAddress, chainResolver: SolanaChainResolver, explorerResolver: SolanaExplorerResolver, - providerResolver: SolanaProviderResolver, networkResolver: SolanaNetworkResolver, isValidDomain, isValidChainId, isValidAddress, - isZeroAddress, isNativeTokenAddress, - isNativeTokenSchemaType, - isFungibleTokenSchemaType, - isNonFungibleTokenSchemaType, - - getNetworkPluginID, getDefaultChainId, - getInvalidChainId, - getDefaultNetworkType, - getDefaultProviderType, - getZeroAddress, getMaskTokenAddress, getNativeTokenAddress, @@ -64,9 +35,4 @@ export const SolanaUtils = { formatDomainName, formatTokenId, formatSchemaType, - createNativeToken(chainId: ChainId) { - return SolanaChainResolver.nativeCurrency(chainId) - }, - createFungibleToken, - createNonFungibleToken, -} satisfies BaseUtils +} satisfies BaseUtils diff --git a/packages/web3-providers/src/helpers/fetchJsonRpcResponse.ts b/packages/web3-providers/src/helpers/fetchJsonRpcResponse.ts index f4275229bb6e..2a6a9cd90631 100644 --- a/packages/web3-providers/src/helpers/fetchJsonRpcResponse.ts +++ b/packages/web3-providers/src/helpers/fetchJsonRpcResponse.ts @@ -1,11 +1,11 @@ import type { JsonRpcRequest, JsonRpcResponse } from 'web3-types' -import { RequestID } from '@masknet/web3-shared-evm' import { fetchSquashedJSON } from './fetchJSON.js' +import stringify from 'json-stable-stringify' async function resolveRequestKey(request: Request) { try { const body: JsonRpcRequest = await request.json() - return RequestID.fromPayload(request.url, body).ID ?? '' + return stringify([request.url, body.method, body.params]) } catch { return '' } diff --git a/packages/web3-shared/evm/src/helpers/address.ts b/packages/web3-shared/evm/src/helpers/address.ts index 11aa9bd584de..1a16d00e75d0 100644 --- a/packages/web3-shared/evm/src/helpers/address.ts +++ b/packages/web3-shared/evm/src/helpers/address.ts @@ -1,5 +1,4 @@ import { memoize } from 'lodash-es' -import defer * as web3_utils from 'web3-utils' import { isSameAddress } from '@masknet/web3-shared-base' import { ChainIdList, @@ -12,24 +11,19 @@ import { ZERO_ADDRESS, } from '../constants/index.js' import { ChainId } from '../types/index.js' +import { isAddress, type Hex } from 'viem' -export function checksumAddress(address: string) { - return web3_utils.toChecksumAddress(address) -} +export { getAddress as checksumAddress } from 'viem' export function isEmptyHex(hex?: string): hex is undefined { return !hex || ['0x', '0x0'].includes(hex) } -export function isZeroString(str?: string): str is undefined { - return !str || str === '0' -} - export const isValidAddress: (address?: string) => address is string = memoize(function isValidAddress( address?: string, -): address is string { +): address is Hex { if (!address) return false - return web3_utils.isAddress(address) + return isAddress(address) }) export function isZeroAddress(address?: string): address is '0x0000000000000000000000000000000000000000' { @@ -70,10 +64,6 @@ export function isRedPacketAddress(address: string, version?: 1 | 2 | 3 | 4) { } } -export function getZeroAddress() { - return ZERO_ADDRESS -} - export const getNativeTokenAddress: (chainId: ChainId) => string = memoize((chainId = ChainId.Mainnet) => { return getTokenConstant(chainId, 'NATIVE_TOKEN_ADDRESS') ?? ZERO_ADDRESS }) diff --git a/packages/web3-shared/evm/src/helpers/createContract.ts b/packages/web3-shared/evm/src/helpers/createContract.ts index 52022ed1c376..99933a14b810 100644 --- a/packages/web3-shared/evm/src/helpers/createContract.ts +++ b/packages/web3-shared/evm/src/helpers/createContract.ts @@ -1,15 +1,15 @@ -import type { AbiItem } from 'web3-utils' import type { ContractOptions } from 'web3-eth-contract' import type { BaseContract } from '@masknet/web3-contracts/types/types.js' import { isValidAddress } from './address.js' import type { Web3 } from '../libs/index.js' +import { type Abi } from 'viem' export function createContract( web3: Web3 | null, address: string | undefined, - ABI: AbiItem[], + abi: Abi, options?: ContractOptions, ) { if (!address || !isValidAddress(address) || !web3) return null - return new web3.eth.Contract(ABI, address, options) as unknown as T + return new web3.eth.Contract(abi as any, address, options) as unknown as T } diff --git a/packages/web3-shared/evm/src/helpers/getTransactionSignature.ts b/packages/web3-shared/evm/src/helpers/getTransactionSignature.ts deleted file mode 100644 index 0ebdb70650d3..000000000000 --- a/packages/web3-shared/evm/src/helpers/getTransactionSignature.ts +++ /dev/null @@ -1,12 +0,0 @@ -import defer * as web3_utils from 'web3-utils' -import type { Transaction, ChainId } from '../types/index.js' - -export function getTransactionSignature(chainId?: ChainId, transaction?: Partial) { - if (!chainId || !transaction) return - const { from, to, data, value } = transaction - return ( - web3_utils.sha3( - [chainId, from, to, data || '0x0', web3_utils.toHex((value as string) || '0x0') || '0x0'].join('_'), - ) ?? undefined - ) -} diff --git a/packages/web3-shared/evm/src/helpers/pack.ts b/packages/web3-shared/evm/src/helpers/pack.ts deleted file mode 100644 index 84140a314767..000000000000 --- a/packages/web3-shared/evm/src/helpers/pack.ts +++ /dev/null @@ -1,31 +0,0 @@ -import defer * as web3_utils from 'web3-utils' - -export function pack(types: string[], values: any[]) { - if (types.length !== values.length) { - throw new Error('Number of types does not match number of values.') - } - - let result = '0x' - - for (let i = 0; i < types.length; i += 1) { - switch (types[i]) { - case 'address': - result += values[i].slice(2).padStart(40, '0') - break - case 'uint256': - result += BigInt(values[i]).toString(16).padStart(64, '0') - break - case 'bytes32': - result += web3_utils.utf8ToHex(values[i]).slice(2).padStart(64, '0') - break - case 'bool': - result += values[i] ? '01' : '00' - break - // ... you can continue adding more cases for other data types - default: - throw new Error(`Unsupported type ${types[i]}`) - } - } - - return result -} diff --git a/packages/web3-shared/evm/src/helpers/parseStringOrBytes32.ts b/packages/web3-shared/evm/src/helpers/parseStringOrBytes32.ts index c614b709123d..c442e2d7e463 100644 --- a/packages/web3-shared/evm/src/helpers/parseStringOrBytes32.ts +++ b/packages/web3-shared/evm/src/helpers/parseStringOrBytes32.ts @@ -1,18 +1,13 @@ -import defer * as web3_utils from 'web3-utils' +import { hexToBytes, type Hex, hexToString } from 'viem' // parse a name or symbol from a token response const BYTES32_REGEX = /^0x[\dA-Fa-f]{64}$/u -export function parseStringOrBytes32( - str: string | undefined, - bytes32: string | undefined, - defaultValue: string, -): string { +export function parseStringOrBytes32(str: string | undefined, bytes32: Hex | undefined, defaultValue: string): string { return ( str && str.length > 0 ? str // need to check for proper bytes string and valid terminator - : bytes32 && BYTES32_REGEX.test(bytes32) && web3_utils.hexToBytes(bytes32)[31] === 0 ? - web3_utils.toAscii(bytes32) - : defaultValue + : bytes32 && BYTES32_REGEX.test(bytes32) && hexToBytes(bytes32)[31] === 0 ? hexToString(bytes32) + : defaultValue ) } diff --git a/packages/web3-shared/evm/src/helpers/resolveNonFungibleTokenIdFromEnsDomain.ts b/packages/web3-shared/evm/src/helpers/resolveNonFungibleTokenIdFromEnsDomain.ts index 58630fc8fc1f..a3ee718bc630 100644 --- a/packages/web3-shared/evm/src/helpers/resolveNonFungibleTokenIdFromEnsDomain.ts +++ b/packages/web3-shared/evm/src/helpers/resolveNonFungibleTokenIdFromEnsDomain.ts @@ -1,6 +1,8 @@ -import defer * as web3_utils from 'web3-utils' -import { BigNumber } from 'bignumber.js' +import { keccak256, toHex as viem_toHex } from 'viem' export function resolveNonFungibleTokenIdFromEnsDomain(domain: string): string { - return new BigNumber(web3_utils.keccak256(domain.replace(/\.\w+$/u, ''))).toFixed() + // Note: viem's toHex is safer than our toHex in this use case. + // our toHex will return the original string if it is already a hex string, which allows a collision attack + // e.g. "0x616263.eth" and "abc.eth" will result to the same token ID if we use our toHex. + return BigInt(keccak256(viem_toHex(domain.replace(/\.\w+$/u, '')))).toString() } diff --git a/packages/web3-shared/evm/src/helpers/splitSignature.ts b/packages/web3-shared/evm/src/helpers/splitSignature.ts index 8d48381dbf69..b71bdc96663c 100644 --- a/packages/web3-shared/evm/src/helpers/splitSignature.ts +++ b/packages/web3-shared/evm/src/helpers/splitSignature.ts @@ -1,4 +1,4 @@ -import defer * as web3_utils from 'web3-utils' +import { hexToNumber } from 'viem' export function splitSignature(signature: string) { if (signature.length !== 132 && !signature.startsWith('0x')) { @@ -8,7 +8,7 @@ export function splitSignature(signature: string) { // Extracting r, s, v from the signature const r = signature.slice(0, 66) const s = '0x' + signature.slice(66, 130) - const v = web3_utils.toDecimal('0x' + signature.slice(130, 132)) + const v = hexToNumber(`0x${signature.slice(130, 132)}`) return { r, s, v } } diff --git a/packages/web3-shared/evm/src/helpers/token.ts b/packages/web3-shared/evm/src/helpers/token.ts index 453df243a6bf..885b117b5074 100644 --- a/packages/web3-shared/evm/src/helpers/token.ts +++ b/packages/web3-shared/evm/src/helpers/token.ts @@ -34,15 +34,3 @@ export const createERC20Tokens = createFungibleTokensFromConstants { - // fix an abnormal hex value like: 0x02c68af0bb140000 - if (typeof value === 'string' && value.length > 3 && value.startsWith('0x0')) - return web3_utils.toHex(new BigNumber(value).toFixed()) - return web3_utils.toHex(value) -}) +import { toHex } from '@masknet/shared-base' export class AccountTransaction { constructor(private transaction?: Transaction) {} @@ -68,12 +60,12 @@ export class AccountTransaction { from, to, data, - value: value ? normalizeHex(value) : undefined, - chainId: chainId && chainId !== ChainId.Astar ? normalizeHex(chainId) : undefined, - gas: gas ? normalizeHex(gas) : undefined, - gasPrice: gasPrice ? normalizeHex(gasPrice) : undefined, - maxPriorityFeePerGas: maxPriorityFeePerGas ? normalizeHex(maxPriorityFeePerGas) : undefined, - maxFeePerGas: maxFeePerGas ? normalizeHex(maxFeePerGas) : undefined, + value: value ? toHex(value) : undefined, + chainId: chainId && chainId !== ChainId.Astar ? toHex(chainId) : undefined, + gas: gas ? toHex(gas) : undefined, + gasPrice: gasPrice ? toHex(gasPrice) : undefined, + maxPriorityFeePerGas: maxPriorityFeePerGas ? toHex(maxPriorityFeePerGas) : undefined, + maxFeePerGas: maxFeePerGas ? toHex(maxFeePerGas) : undefined, nonce, _disableSuccessSnackbar, _disableSnackbar, diff --git a/packages/web3-shared/evm/src/libs/ContractTransaction.ts b/packages/web3-shared/evm/src/libs/ContractTransaction.ts index 964fad25a964..c2ae605e8a0f 100644 --- a/packages/web3-shared/evm/src/libs/ContractTransaction.ts +++ b/packages/web3-shared/evm/src/libs/ContractTransaction.ts @@ -1,6 +1,5 @@ import { identity, pickBy } from 'lodash-es' -import defer * as web3_utils from 'web3-utils' -import { type Unresolved, resolve } from '@masknet/shared-base' +import { type Unresolved, resolve, toHex } from '@masknet/shared-base' import type { BaseContract, PayableTx, @@ -31,14 +30,14 @@ export class ContractTransaction { from: overrides?.from ?? this.contract?.defaultAccount ?? this.contract?.options.from ?? '', to: this.contract?.options.address, data: transaction?.encodeABI(), - value: overrides?.value ? web3_utils.toHex(overrides.value) : undefined, - gas: overrides?.gas ? web3_utils.toHex(overrides.gas) : undefined, - gasPrice: overrides?.gasPrice ? web3_utils.toHex(overrides.gasPrice) : undefined, + value: overrides?.value ? toHex(overrides.value) : undefined, + gas: overrides?.gas ? toHex(overrides.gas) : undefined, + gasPrice: overrides?.gasPrice ? toHex(overrides.gasPrice) : undefined, maxPriorityFeePerGas: - overrides?.maxPriorityFeePerGas ? web3_utils.toHex(overrides.maxPriorityFeePerGas) : undefined, - maxFeePerGas: overrides?.maxFeePerGas ? web3_utils.toHex(overrides.maxFeePerGas) : undefined, - nonce: overrides?.nonce ? web3_utils.toHex(overrides.nonce) : undefined, - chainId: overrides?.chainId ? web3_utils.toHex(overrides.chainId) : undefined, + overrides?.maxPriorityFeePerGas ? toHex(overrides.maxPriorityFeePerGas) : undefined, + maxFeePerGas: overrides?.maxFeePerGas ? toHex(overrides.maxFeePerGas) : undefined, + nonce: overrides?.nonce ? toHex(overrides.nonce) : undefined, + chainId: overrides?.chainId ? toHex(overrides.chainId) : undefined, }, identity, ) @@ -65,7 +64,7 @@ export class ContractTransaction { if (!gas) throw new Error('Estimate gas failed') - transactionEncoded.gas = web3_utils.toHex(gas) + transactionEncoded.gas = toHex(gas) } return transactionEncoded diff --git a/packages/web3-shared/evm/src/libs/GasEditor.ts b/packages/web3-shared/evm/src/libs/GasEditor.ts index ce670c94950d..4c3449742639 100644 --- a/packages/web3-shared/evm/src/libs/GasEditor.ts +++ b/packages/web3-shared/evm/src/libs/GasEditor.ts @@ -1,4 +1,3 @@ -import defer * as web3_utils from 'web3-utils' import { GasOptionType, isZero, multipliedBy, toFixed } from '@masknet/web3-shared-base' import { formatWeiToEther } from '../helpers/formatter.js' import type { @@ -10,6 +9,7 @@ import type { Transaction, } from '../types/index.js' import { CHAIN_DESCRIPTORS } from '../constants/descriptors.js' +import { toHex } from '@masknet/shared-base' export class GasEditor { constructor( @@ -46,16 +46,14 @@ export class GasEditor { const config = fallback as EIP1559GasConfig | undefined return { gasPrice: undefined, - maxFeePerGas: - web3_utils.toHex(this.EIP1559GasOptionConfig.maxFeePerGas) || - web3_utils.toHex(config?.maxFeePerGas || '0'), + maxFeePerGas: toHex(this.EIP1559GasOptionConfig.maxFeePerGas) || toHex(config?.maxFeePerGas || '0'), maxPriorityFeePerGas: - web3_utils.toHex(this.EIP1559GasOptionConfig.maxPriorityFeePerGas) || - web3_utils.toHex(config?.maxPriorityFeePerGas || '1'), + toHex(this.EIP1559GasOptionConfig.maxPriorityFeePerGas) || + toHex(config?.maxPriorityFeePerGas || '1'), gasCurrency: this.EIP1559GasOptionConfig.gasCurrency || fallback?.gasCurrency, gas: this.EIP1559GasOptionConfig.gas && !isZero(this.EIP1559GasOptionConfig.gas) ? - web3_utils.toHex(this.EIP1559GasOptionConfig.gas) + toHex(this.EIP1559GasOptionConfig.gas) : undefined, gasOptionType: this.config.gasOptionType ?? config?.gasOptionType, } @@ -64,9 +62,7 @@ export class GasEditor { const priorConfig = fallback as PriorEIP1559GasConfig | undefined return { - gasPrice: - web3_utils.toHex(this.priorEIP1559GasOptionConfig.gasPrice) || - web3_utils.toHex(priorConfig?.gasPrice || '0'), + gasPrice: toHex(this.priorEIP1559GasOptionConfig.gasPrice) || toHex(priorConfig?.gasPrice || '0'), maxFeePerGas: undefined, maxPriorityFeePerGas: undefined, gasOptionType: this.config.gasOptionType ?? priorConfig?.gasOptionType, diff --git a/packages/web3-shared/evm/src/libs/RequestID.ts b/packages/web3-shared/evm/src/libs/RequestID.ts deleted file mode 100644 index cfba53191dc5..000000000000 --- a/packages/web3-shared/evm/src/libs/RequestID.ts +++ /dev/null @@ -1,75 +0,0 @@ -import defer * as web3_utils from 'web3-utils' -import type { TransactionConfig } from 'web3-core' -import type { JsonRpcRequest } from 'web3-types' -import { EthereumMethodType, type RequestArguments } from '../types/index.js' - -export class RequestID { - /** - * @deprecated Don't new RequestID() - * Use RequestID.from(requestArguments) stead. - */ - constructor( - private url: string, - private requestArguments: RequestArguments, - ) {} - - get ID() { - const { method, params } = this.requestArguments - switch (method) { - case EthereumMethodType.eth_getCode: { - const [address, tag = 'latest'] = params as [string, string] - return web3_utils.sha3([this.url, method, address, tag].join(',')) - } - case EthereumMethodType.eth_blockNumber: { - return web3_utils.sha3([this.url, method].join(',')) - } - case EthereumMethodType.eth_getBlockByNumber: { - const [number, full] = params as [string, boolean] - return web3_utils.sha3([this.url, method, number, full].join(',')) - } - case EthereumMethodType.eth_getBlockByHash: { - const [hash] = params as [string] - return web3_utils.sha3([this.url, method, hash].join(',')) - } - case EthereumMethodType.eth_gasPrice: { - return web3_utils.sha3([this.url, method].join(',')) - } - case EthereumMethodType.eth_getBalance: { - const [account, tag = 'latest'] = params as [string, string] - return web3_utils.sha3([this.url, method, account, tag].join(',')) - } - case EthereumMethodType.eth_getTransactionCount: { - const [account, tag = 'latest'] = params as [string, string] - return web3_utils.sha3([this.url, method, account, tag].join(',')) - } - case EthereumMethodType.eth_call: { - const [config, tag = 'latest'] = params as [TransactionConfig, string] - return web3_utils.sha3([this.url, method, JSON.stringify(config), tag].join(',')) - } - case EthereumMethodType.eth_estimateGas: { - const [config, tag = 'latest'] = params as [TransactionConfig, string] - return web3_utils.sha3([this.url, method, JSON.stringify(config), tag].join(',')) - } - case EthereumMethodType.eth_getTransactionReceipt: { - const [hash] = params as [string] - return web3_utils.sha3([this.url, method, hash].join(',')) - } - case EthereumMethodType.eth_getTransactionByHash: - const [hash] = params as [string] - return web3_utils.sha3([this.url, method, hash].join(',')) - default: - return - } - } - - static from(url: string, requestArguments: RequestArguments) { - return new RequestID(url, requestArguments) - } - - static fromPayload(url: string, payload: JsonRpcRequest) { - return new RequestID(url, { - method: payload.method as EthereumMethodType, - params: payload.params ?? [], - }) - } -} diff --git a/packages/web3-shared/evm/src/libs/index.ts b/packages/web3-shared/evm/src/libs/index.ts index a8b5ba6e1c2b..e6141ae8286e 100644 --- a/packages/web3-shared/evm/src/libs/index.ts +++ b/packages/web3-shared/evm/src/libs/index.ts @@ -7,5 +7,4 @@ export * from './EtherscanURL.js' export * from './GasEditor.js' export * from './PayloadEditor.js' export * from './ProviderURL.js' -export * from './RequestID.js' export * from './Web3.js' diff --git a/packages/web3-shared/evm/tests/helpers/pack.ts b/packages/web3-shared/evm/tests/helpers/pack.ts deleted file mode 100644 index 42da27ff241c..000000000000 --- a/packages/web3-shared/evm/tests/helpers/pack.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { describe, expect, test } from 'vitest' -import { pack } from '../../src/helpers/pack.js' - -const ADDRESS = '0x1234567890123456789012345678901234567890' -const UINT256 = 1 - -const ADDRESS_PACKED = '0x12345678901234567890123456789012345678901234567890123456789012345678901234567890' -const ADDRESS_UINT256_PACKED = - '0x12345678901234567890123456789012345678900000000000000000000000000000000000000000000000000000000000000001' - -describe('pack', () => { - test('should pack address', () => { - expect(pack(['address', 'address'], [ADDRESS, ADDRESS])).toBe(ADDRESS_PACKED) - }) - - test('should pack unit256', () => { - expect(pack(['address', 'uint256'], [ADDRESS, UINT256])).toBe(ADDRESS_UINT256_PACKED) - }) -}) diff --git a/packages/web3-shared/flow/src/helpers/address.ts b/packages/web3-shared/flow/src/helpers/address.ts index 9b69a80e2049..e7aefb70b734 100644 --- a/packages/web3-shared/flow/src/helpers/address.ts +++ b/packages/web3-shared/flow/src/helpers/address.ts @@ -56,10 +56,6 @@ export function getDefaultProviderType() { return ProviderType.None } -export function getZeroAddress() { - return ZERO_ADDRESS -} - export function getContractAddress(address: string) { if (isValidContractAddress(address)) { const [_, contractAddress, ...identifierFragments] = address.split(/\./gu) diff --git a/packages/web3-shared/flow/src/helpers/token.ts b/packages/web3-shared/flow/src/helpers/token.ts index 62a1230fae54..df3630e57aed 100644 --- a/packages/web3-shared/flow/src/helpers/token.ts +++ b/packages/web3-shared/flow/src/helpers/token.ts @@ -43,16 +43,3 @@ export function createFungibleAsset( }, } } - -export function isNativeTokenSchemaType(schemaType?: SchemaType) { - // there is no native token schema on flow network - return false -} - -export function isFungibleTokenSchemaType(schemaType?: SchemaType) { - return schemaType === SchemaType.Fungible -} - -export function isNonFungibleTokenSchemaType(schemaType?: SchemaType) { - return schemaType === SchemaType.NonFungible -} diff --git a/packages/web3-shared/solana/src/helpers/address.ts b/packages/web3-shared/solana/src/helpers/address.ts index 2579991d81c3..8fa6e9cfb6ed 100644 --- a/packages/web3-shared/solana/src/helpers/address.ts +++ b/packages/web3-shared/solana/src/helpers/address.ts @@ -86,10 +86,6 @@ export function getDefaultProviderType() { return ProviderType.None } -export function getZeroAddress() { - return ZERO_ADDRESS -} - export function getMaskTokenAddress(chainId = ChainId.Mainnet) { return '' } diff --git a/packages/web3-shared/solana/src/helpers/token.ts b/packages/web3-shared/solana/src/helpers/token.ts deleted file mode 100644 index ba16d6c0895d..000000000000 --- a/packages/web3-shared/solana/src/helpers/token.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { SchemaType } from '../types.js' - -export function isNativeTokenSchemaType(schemaType?: SchemaType) { - // there is no native token schema on solana network - return false -} - -export function isFungibleTokenSchemaType(schemaType?: SchemaType) { - return schemaType === SchemaType.Fungible -} - -export function isNonFungibleTokenSchemaType(schemaType?: SchemaType) { - return schemaType === SchemaType.NonFungible -} diff --git a/packages/web3-shared/solana/src/index.ts b/packages/web3-shared/solana/src/index.ts index 0f453320c7bb..c494421cc9b7 100644 --- a/packages/web3-shared/solana/src/index.ts +++ b/packages/web3-shared/solana/src/index.ts @@ -6,7 +6,6 @@ export * from './constants/descriptors.js' export * from './constants/primitives.js' export * from './helpers/address.js' -export * from './helpers/token.js' export * from './helpers/domain.js' export * from './helpers/serializeTransaction.js' export * from './helpers/recoverTransaction.js' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 049b437e62d2..044000a939f1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2833,6 +2833,9 @@ importers: immer: specifier: ^10.1.1 version: 10.1.1 + json-stable-stringify: + specifier: ^1.1.1 + version: 1.1.1 lru-cache: specifier: ^10.3.0 version: 10.3.0 @@ -2879,6 +2882,9 @@ importers: '@types/bs58': specifier: ^4.0.4 version: 4.0.4 + '@types/json-stable-stringify': + specifier: ^1.0.36 + version: 1.0.36 '@types/socket.io-client': specifier: ^1.4.36 version: 1.4.36