From d286452af0bc526199fc3ccf80b09e0c3a1029b3 Mon Sep 17 00:00:00 2001 From: Jack Works <5390719+Jack-Works@users.noreply.github.com> Date: Mon, 18 May 2026 13:00:39 +0000 Subject: [PATCH] refactor: reduce 1 use of createContract in createNftRedpacketContract --- .../src/SiteAdaptor/NftRedPacket/index.tsx | 6 +- .../components/NftRedPacketRecord.tsx | 8 +- .../hooks/useAvailabilityNftRedPacket.ts | 32 +-- .../hooks/useCreateNftRedpacketCallback.ts | 59 +++--- .../hooks/useNftAvailabilityComputed.ts | 6 +- .../hooks/useNftRedPacketContract.ts | 10 +- .../SiteAdaptor/views/NftRedPacketConfirm.tsx | 6 +- .../SelectGasSettingsToolbar/index.tsx | 8 +- .../Web3/EVM/apis/ConnectionReadonlyAPI.ts | 4 + .../src/Web3/EVM/apis/RequestReadonlyAPI.ts | 6 + .../src/helpers/createViemClient.ts | 187 ++++++++++++++++++ .../evm/src/libs/AccountTransaction.ts | 2 +- .../evm/src/libs/ContractTransaction.ts | 42 ++-- packages/web3-shared/evm/src/types/index.ts | 5 - 14 files changed, 293 insertions(+), 88 deletions(-) create mode 100644 packages/web3-providers/src/helpers/createViemClient.ts diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/NftRedPacket/index.tsx b/packages/plugins/RedPacket/src/SiteAdaptor/NftRedPacket/index.tsx index 2ade5965f6a7..91b3131681ea 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/NftRedPacket/index.tsx +++ b/packages/plugins/RedPacket/src/SiteAdaptor/NftRedPacket/index.tsx @@ -69,7 +69,7 @@ export function NftRedPacket({ payload, currentPluginID }: NftRedPacketProps) { isPending: loading, refetch: retryAvailability, error: availabilityError, - } = useAvailabilityNftRedPacket(payload.id, account, payload.chainId) + } = useAvailabilityNftRedPacket(payload.id as HexString, account as HexString, payload.chainId) const [{ loading: isClaiming }, claimCallback] = useClaimNftRedpacketCallback(payload, availability?.totalAmount) @@ -93,7 +93,7 @@ export function NftRedPacket({ payload, currentPluginID }: NftRedPacketProps) { const { data: claimedAsset, error: assetError } = useNonFungibleAsset( NetworkPluginID.PLUGIN_EVM, payload.contractAddress, - availability?.claimed_id, + availability?.claimed_id === undefined ? undefined : String(availability.claimed_id), { chainId: payload.chainId, sourceType: SourceType.SimpleHash, @@ -181,7 +181,7 @@ export function NftRedPacket({ payload, currentPluginID }: NftRedPacketProps) { creator={payload.senderName} chainId={payload.chainId} address={payload.contractAddress} - tokenId={availability.claimed_id} + tokenId={availability.claimed_id === undefined ? undefined : String(availability.claimed_id)} shares={availability.totalAmount} claimedCount={+availability.claimedAmount} total={availability.totalAmount} diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/components/NftRedPacketRecord.tsx b/packages/plugins/RedPacket/src/SiteAdaptor/components/NftRedPacketRecord.tsx index 178836657b88..9ed6aa374bc0 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/components/NftRedPacketRecord.tsx +++ b/packages/plugins/RedPacket/src/SiteAdaptor/components/NftRedPacketRecord.tsx @@ -181,7 +181,7 @@ export const NftRedPacketRecord = memo(function NftRedPacketRecord({ backgroundIcon: networkDescriptor ? `url("${networkDescriptor.icon}")` : undefined, }) - const { canSend, isPasswordValid, password } = useNftAvailabilityComputed(account, patchedHistory) + const { canSend, isPasswordValid, password } = useNftAvailabilityComputed(account as HexString | '', patchedHistory) const collection = collections.find((x) => isSameAddress(x.address, patchedHistory.token_address)) @@ -190,7 +190,11 @@ export const NftRedPacketRecord = memo(function NftRedPacketRecord({ onSend({ ...patchedHistory, password: patchedHistory.password || password }, collection) }, [onSend, canSend, patchedHistory, collection, isPasswordValid, password]) - const { data: redpacketStatus } = useAvailabilityNftRedPacket(rpid, account, patchedHistory.chainId) + const { data: redpacketStatus } = useAvailabilityNftRedPacket( + rpid as HexString | '', + account as HexString | '', + patchedHistory.chainId, + ) const bitStatusList = redpacketStatus ? redpacketStatus.bitStatusList : fill(Array(patchedHistory.token_ids.length), false) const locale = useLingui().i18n.locale diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useAvailabilityNftRedPacket.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useAvailabilityNftRedPacket.ts index 8fc2a40c0d6e..a738622075d8 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useAvailabilityNftRedPacket.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useAvailabilityNftRedPacket.ts @@ -1,31 +1,31 @@ import type { ChainId } from '@masknet/web3-shared-evm' import { useQuery } from '@tanstack/react-query' -import { BigNumber } from 'bignumber.js' import { createNftRedpacketContract } from './useNftRedPacketContract.js' -export function useAvailabilityNftRedPacket(id: string, from: string, chainId?: ChainId) { +export function useAvailabilityNftRedPacket(id: HexString | '', from: HexString | '', chainId?: ChainId) { return useQuery({ queryKey: ['nft-redpacket', 'availability', chainId, from, id], queryFn: async () => { const nftRedPacketContract = createNftRedpacketContract(chainId) if (!id || !nftRedPacketContract) return null - const availability = await nftRedPacketContract.methods.check_availability(id).call({ - // check availability is ok w/o account - from, - }) + const [token_address, balance, total_pkts, expired, claimed_id, bit_status] = + await nftRedPacketContract.read.check_availability([id], { + // check availability is ok w/o account + account: from || undefined, + }) - const result = await nftRedPacketContract.methods.check_erc721_remain_ids(id).call({ + const [bit_status2, erc721_token_ids] = await nftRedPacketContract.read.check_erc721_remain_ids([id], { // check availability is ok w/o account - from, + account: from || undefined, }) - const isClaimed = availability.claimed_id !== '0' - const totalAmount = result.erc721_token_ids.length - const bits = new BigNumber(result.bit_status).toString(2).split('') + const isClaimed = claimed_id !== 0n + const totalAmount = erc721_token_ids.length + const bits = bit_status2.toString(2).split('') const claimedAmount = bits.filter((bit) => bit === '1').length const isClaimedAll = totalAmount === claimedAmount const isCompleted = isClaimedAll && !isClaimed - const isEnd = isCompleted || availability.expired + const isEnd = isCompleted || expired const bitStatusList = bits.reverse().map((bit) => bit === '1') @@ -40,8 +40,12 @@ export function useAvailabilityNftRedPacket(id: string, from: string, chainId?: isCompleted, isEnd, bitStatusList, - ...availability, - claimed_id: availability.claimed_id === '0' ? undefined : availability.claimed_id, + token_address, + balance, + total_pkts, + expired, + bit_status, + claimed_id: claimed_id === 0n ? undefined : claimed_id, } }, }) diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketCallback.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketCallback.ts index 3a7b4e9148ca..fa85e61a2e9a 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketCallback.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useCreateNftRedpacketCallback.ts @@ -1,5 +1,5 @@ import { toHex, type NetworkPluginID } from '@masknet/shared-base' -import { NftRedPacketAbi, type NftRedPacket } from '@masknet/web3-contracts/types/NftRedPacket.js' +import { NftRedPacketAbi } from '@masknet/web3-contracts/types/NftRedPacket.js' import { useChainContext } from '@masknet/web3-hooks-base' import { useGasConfig } from '@masknet/web3-hooks-evm' import { EVMWeb3 } from '@masknet/web3-providers' @@ -17,14 +17,15 @@ import { BigNumber } from 'bignumber.js' import { useMemo } from 'react' import { useAsyncFn } from 'react-use' import { createNftRedpacketContract } from './useNftRedPacketContract.js' -import { keccak256 } from 'viem' +import { encodeFunctionData, keccak256 } from 'viem' +import type { AbiParametersToPrimitiveTypes, ExtractAbiFunction } from 'abitype' interface Options { - publicKey: string + publicKey: HexString duration: number message: string creator: string - contractAddress: string + contractAddress: HexString tokenIds: string[] gasOption?: GasConfig } @@ -39,15 +40,19 @@ export function useCreateNftRedpacketCallback({ gasOption, }: Options) { const { account, chainId } = useChainContext() - const params: Parameters = useMemo(() => { + const params = useMemo((): AbiParametersToPrimitiveTypes< + ExtractAbiFunction['inputs'], + 'inputs', + true + > => { return [ publicKey, - duration, + BigInt(duration), keccak256(toHex(Math.random().toString())), message, creator, contractAddress, - tokenIds, + tokenIds.map(BigInt), ] }, [publicKey, duration, message, creator, contractAddress, tokenIds]) @@ -66,13 +71,13 @@ export function useCreateNftRedpacketCallback({ ], refetchInterval: 10, queryFn: async () => { - if (!account) return null + if (!account || !contractAddress) return null const nftRedPacketContract = createNftRedpacketContract(chainId) if (!nftRedPacketContract) return null - const gasLimit = await nftRedPacketContract.methods - .create_red_packet(...params) - .estimateGas({ from: account }) + const gasLimit = await nftRedPacketContract.estimateGas.create_red_packet(params, { + account: account as HexString, + }) return gasLimit }, }) @@ -81,7 +86,7 @@ export function useCreateNftRedpacketCallback({ const estimateGasFee = useMemo(() => { if (!gasLimit) return undefined if (!gasPrice || gasPrice === '0') return undefined - return new BigNumber(gasPrice).multipliedBy(gasLimit).multipliedBy(1.5).toFixed() + return new BigNumber(gasPrice).multipliedBy(String(gasLimit)).multipliedBy(1.5).toFixed() }, [gasLimit, gasPrice]) const [{ loading }, createCallback] = useAsyncFn(async (): Promise< @@ -99,22 +104,24 @@ export function useCreateNftRedpacketCallback({ } // #region check ownership - const checkParams: Parameters = [tokenIds, contractAddress] - - const isOwner = await nftRedPacketContract.methods.check_ownership(...checkParams).call({ from: account }) + const isOwner = await nftRedPacketContract.read.check_ownership([tokenIds.map(BigInt), contractAddress], { + account: (account || undefined) as HexString | undefined, + }) if (!isOwner) return // #endregion - - const tx = await new ContractTransaction(nftRedPacketContract.options.address).fillAll( - nftRedPacketContract.methods.create_red_packet(...params), - { - from: account, - chainId, - ...gasOption, - gas: addGasMargin(BigNumber.max(gasLimit, gasOption?.gas ?? 0), 0.3), - }, - ) + const tx = ContractTransaction.normalizeTransaction({ + from: account, + chainId, + ...gasOption, + gas: addGasMargin(BigNumber.max(String(gasLimit), gasOption?.gas ?? 0), 0.3), + to: nftRedPacketContract.address, + data: encodeFunctionData({ + abi: NftRedPacketAbi, + functionName: 'create_red_packet', + args: params, + }), + }) const hash = await EVMWeb3.sendTransaction(tx, { paymentToken: gasOption?.gasCurrency, @@ -129,7 +136,7 @@ export function useCreateNftRedpacketCallback({ } } return { hash, receipt, events: undefined } - }, [duration, message, creator, contractAddress, tokenIds, account, chainId, gasOption, gasLimit]) + }, [duration, message, creator, contractAddress, tokenIds, account, chainId, gasOption, gasLimit, params]) return { gasLimit, estimateGasFee, loading, createCallback } } diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftAvailabilityComputed.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftAvailabilityComputed.ts index d20d77ebeddf..ba069c36f172 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftAvailabilityComputed.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftAvailabilityComputed.ts @@ -11,7 +11,11 @@ import { useAvailabilityNftRedPacket } from './useAvailabilityNftRedPacket.js' */ export function useNftAvailabilityComputed(account: string, payload: NftRedPacketJSONPayload) { const { chainId } = useChainContext() - const { data: availability } = useAvailabilityNftRedPacket(payload?.rpid, account, chainId) + const { data: availability } = useAvailabilityNftRedPacket( + payload?.rpid as HexString | '', + account as HexString | '', + chainId, + ) if (!availability) { return { diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftRedPacketContract.ts b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftRedPacketContract.ts index f880c2839bdb..92047445e194 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftRedPacketContract.ts +++ b/packages/plugins/RedPacket/src/SiteAdaptor/hooks/useNftRedPacketContract.ts @@ -1,7 +1,8 @@ -import { ChainId, createContract, getNftRedPacketConstant, useNftRedPacketConstants } from '@masknet/web3-shared-evm' +import { ChainId, getNftRedPacketConstant, useNftRedPacketConstants } from '@masknet/web3-shared-evm' import { NftRedPacketAbi, type NftRedPacket } from '@masknet/web3-contracts/types/NftRedPacket.js' import { useContract } from '@masknet/web3-hooks-evm' import { EVMWeb3 } from '@masknet/web3-providers' +import { getContract } from 'viem' export function useNftRedPacketContract(chainId: ChainId) { const { RED_PACKET_NFT_ADDRESS } = useNftRedPacketConstants(chainId) @@ -10,5 +11,10 @@ export function useNftRedPacketContract(chainId: ChainId) { 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) + if (!RED_PACKET_NFT_ADDRESS) return null + return getContract({ + abi: NftRedPacketAbi, + client: EVMWeb3.getViem({ chainId }), + address: RED_PACKET_NFT_ADDRESS as HexString, + }) } diff --git a/packages/plugins/RedPacket/src/SiteAdaptor/views/NftRedPacketConfirm.tsx b/packages/plugins/RedPacket/src/SiteAdaptor/views/NftRedPacketConfirm.tsx index 54de92beff0c..b60e5f6eadf4 100644 --- a/packages/plugins/RedPacket/src/SiteAdaptor/views/NftRedPacketConfirm.tsx +++ b/packages/plugins/RedPacket/src/SiteAdaptor/views/NftRedPacketConfirm.tsx @@ -131,11 +131,11 @@ export function NftRedPacketConfirm() { estimateGasFee, createCallback, } = useCreateNftRedpacketCallback({ - publicKey: redpacketPubkey, + publicKey: redpacketPubkey as HexString, duration, message, creator, - contractAddress: collection?.address ?? '', + contractAddress: collection?.address as HexString, tokenIds, gasOption, }) @@ -240,7 +240,7 @@ export function NftRedPacketConfirm() { nativeToken={nativeTokenDetailed} nativeTokenPrice={nativeTokenPrice} gasConfig={gasOption} - gasLimit={gasLimit ?? 0} + gasLimit={gasLimit} onChange={setGasOption} estimateGasFee={estimateGasFee} editMode diff --git a/packages/shared/src/UI/components/SelectGasSettingsToolbar/index.tsx b/packages/shared/src/UI/components/SelectGasSettingsToolbar/index.tsx index 51512d4a108c..2bfdeb29979e 100644 --- a/packages/shared/src/UI/components/SelectGasSettingsToolbar/index.tsx +++ b/packages/shared/src/UI/components/SelectGasSettingsToolbar/index.tsx @@ -25,7 +25,7 @@ export interface SelectGasSettingsToolbarProps { if (!gasOption || !gasLimit) return ZERO - const result = GasEditor.fromConfig(chainId as ChainId, gasOption).getGasFee(gasLimit) + const result = GasEditor.fromConfig(chainId as ChainId, gasOption).getGasFee(String(gasLimit)) return result }, [gasLimit, gasOption, nativeToken]) diff --git a/packages/web3-providers/src/Web3/EVM/apis/ConnectionReadonlyAPI.ts b/packages/web3-providers/src/Web3/EVM/apis/ConnectionReadonlyAPI.ts index eddee833ad7b..beac2b80ce1b 100644 --- a/packages/web3-providers/src/Web3/EVM/apis/ConnectionReadonlyAPI.ts +++ b/packages/web3-providers/src/Web3/EVM/apis/ConnectionReadonlyAPI.ts @@ -98,6 +98,10 @@ export class EVMConnectionReadonlyAPI return this.Request.getWeb3(initial) } + getViem(initial?: EVMConnectionOptions) { + return this.Request.getViem(initial) + } + getWeb3Provider(initial?: EVMConnectionOptions) { return this.Request.getWeb3Provider(initial) } diff --git a/packages/web3-providers/src/Web3/EVM/apis/RequestReadonlyAPI.ts b/packages/web3-providers/src/Web3/EVM/apis/RequestReadonlyAPI.ts index 2844e06a2423..fd071348f50e 100644 --- a/packages/web3-providers/src/Web3/EVM/apis/RequestReadonlyAPI.ts +++ b/packages/web3-providers/src/Web3/EVM/apis/RequestReadonlyAPI.ts @@ -11,6 +11,7 @@ import type { EVMConnectionOptions } from '../types/index.js' import { createWeb3FromURL } from '../../../helpers/createWeb3FromURL.js' import { createWeb3ProviderFromURL } from '../../../helpers/createWeb3ProviderFromURL.js' import type { ConnectionOptionsProvider } from '../../Base/apis/ConnectionOptions.js' +import { createViemClientFromURL } from '../../../helpers/createViemClient.js' export class EVMRequestReadonlyAPI { static Default = new EVMRequestReadonlyAPI() @@ -32,6 +33,11 @@ export class EVMRequestReadonlyAPI { return createWeb3FromURL(options.providerURL ?? ProviderURL.from(options.chainId)) } + getViem(initial?: EVMConnectionOptions) { + const options = this.ConnectionOptions.fill(initial) + return createViemClientFromURL(options.chainId, options.providerURL ?? ProviderURL.from(options.chainId)) + } + getWeb3Provider(initial?: EVMConnectionOptions) { const options = this.ConnectionOptions.fill(initial) return createWeb3ProviderFromURL(options.providerURL ?? ProviderURL.from(options.chainId)) diff --git a/packages/web3-providers/src/helpers/createViemClient.ts b/packages/web3-providers/src/helpers/createViemClient.ts new file mode 100644 index 000000000000..edef5522feea --- /dev/null +++ b/packages/web3-providers/src/helpers/createViemClient.ts @@ -0,0 +1,187 @@ +import { createWalletClient, defineChain, type Chain, custom, publicActions } from 'viem' +import { + CHAIN_DESCRIPTORS, + ChainId, + createJsonRpcRequest, + ErrorEditor, + type RequestArguments, +} from '@masknet/web3-shared-evm' +import { fetchJsonRpcResponse } from './fetchJsonRpcResponse.js' +import * as chains from 'viem/chains' + +export function createViemClient(chain: Chain | undefined, request: (arg: RequestArguments) => Promise) { + const client = createWalletClient({ + chain, + transport: custom({ request }), + pollingInterval: Number.MAX_SAFE_INTEGER, + }).extend(publicActions) + return client +} + +export function createViemClientFromURL(chain: ChainId, url: string) { + return createViemClient(chainIdToChain(chain), async (requestArguments) => { + const response = await fetchJsonRpcResponse(url, createJsonRpcRequest(0, requestArguments)) + const editor = ErrorEditor.from(null, response) + if (editor.presence) throw editor.error + if ('result' in response) return response.result + return undefined + }) +} + +export function chainIdToChain(chainId: ChainId) { + switch (chainId) { + case ChainId.Mainnet: + return chains.mainnet + case ChainId.Ropsten: + return createChainFromDescriptor(chainId) + case ChainId.Rinkeby: + return createChainFromDescriptor(chainId) + case ChainId.Gorli: + return chains.goerli + case ChainId.Kovan: + return createChainFromDescriptor(chainId) + case ChainId.Base: + return chains.base + case ChainId.Base_Goerli: + return chains.baseGoerli + case ChainId.BSC: + return chains.bsc + case ChainId.BSCT: + return chains.bscTestnet + case ChainId.Polygon: + return chains.polygon + case ChainId.Mumbai: + return chains.polygonMumbai + case ChainId.Arbitrum: + return chains.arbitrum + case ChainId.Arbitrum_Rinkeby: + return createChainFromDescriptor(chainId) + case ChainId.Arbitrum_Nova: + return chains.arbitrumNova + case ChainId.xDai: + return chains.gnosis + case ChainId.Avalanche: + return chains.avalanche + case ChainId.Avalanche_Fuji: + return chains.avalancheFuji + case ChainId.Celo: + return chains.celo + case ChainId.Fantom: + return chains.fantom + case ChainId.Aurora: + return chains.aurora + case ChainId.Aurora_Testnet: + return chains.auroraTestnet + case ChainId.Fuse: + return chains.fuse + case ChainId.Boba: + return chains.boba + case ChainId.Metis: + return chains.metis + case ChainId.Metis_Sepolia: + return chains.metisSepolia + case ChainId.Sei: + return chains.sei + case ChainId.Optimism: + return chains.optimism + case ChainId.Optimism_Kovan: + return createChainFromDescriptor(chainId) + case ChainId.Optimism_Goerli: + return chains.optimismGoerli + case ChainId.Conflux: + return chains.confluxESpace + case ChainId.Astar: + return chains.astar + case ChainId.Scroll: + return chains.scroll + case ChainId.ZKSync_Alpha_Testnet: + return createChainFromDescriptor(chainId) + case ChainId.Crossbell: + return chains.crossbell + case ChainId.Moonbeam: + return chains.moonbeam + case ChainId.Pulse: + return createChainFromDescriptor(chainId) + case ChainId.Klaytn: + return createChainFromDescriptor(chainId) + case ChainId.Harmony: + return chains.harmonyOne + case ChainId.Moonriver: + return createChainFromDescriptor(chainId) + case ChainId.Cronos: + return chains.cronos + case ChainId.Brise: + return createChainFromDescriptor(chainId) + case ChainId.Canto: + return chains.canto + case ChainId.DFK: + return chains.dfk + case ChainId.Doge: + return createChainFromDescriptor(chainId) + case ChainId.Evmos: + return chains.evmos + case ChainId.HuobiEco: + return createChainFromDescriptor(chainId) + case ChainId.IoTex: + return createChainFromDescriptor(chainId) + case ChainId.Kava: + return chains.kava + case ChainId.Kcc: + return createChainFromDescriptor(chainId) + case ChainId.Milkomeda: + return createChainFromDescriptor(chainId) + case ChainId.OKXChain: + return createChainFromDescriptor(chainId) + case ChainId.Palm: + return createChainFromDescriptor(chainId) + case ChainId.RSK: + return createChainFromDescriptor(chainId) + case ChainId.SmartBitcoinCash: + return createChainFromDescriptor(chainId) + case ChainId.Shiden: + return chains.shiden + case ChainId.SongbirdCanary: + return createChainFromDescriptor(chainId) + case ChainId.Step: + return createChainFromDescriptor(chainId) + case ChainId.Telos: + return createChainFromDescriptor(chainId) + case ChainId.Wanchain: + return createChainFromDescriptor(chainId) + case ChainId.XLayer: + return chains.xLayer + case ChainId.XLayer_Testnet: + return chains.xLayerTestnet + case ChainId.BitTorrent: + return chains.bitTorrent + case ChainId.Zora: + return chains.zora + case ChainId.Invalid: + return undefined + } +} + +function createChainFromDescriptor(chainId: ChainId): Chain | undefined { + const descriptor = CHAIN_DESCRIPTORS.find((x) => x.chainId === chainId) + if (!descriptor) return undefined + + return defineChain({ + id: descriptor.chainId, + name: descriptor.fullName || descriptor.name, + nativeCurrency: descriptor.nativeCurrency, + rpcUrls: { + default: { http: [] }, + public: { http: [] }, + }, + blockExplorers: + descriptor.explorerUrl?.url ? + { + default: { + name: 'Explorer', + url: descriptor.explorerUrl.url, + }, + } + : undefined, + testnet: descriptor.network !== 'mainnet', + }) +} diff --git a/packages/web3-shared/evm/src/libs/AccountTransaction.ts b/packages/web3-shared/evm/src/libs/AccountTransaction.ts index 21bf34fa7ccd..968449160e03 100644 --- a/packages/web3-shared/evm/src/libs/AccountTransaction.ts +++ b/packages/web3-shared/evm/src/libs/AccountTransaction.ts @@ -4,7 +4,7 @@ import { isEmptyHex } from '../helpers/address.js' import { ChainId, type Transaction } from '../types/index.js' import { toHex } from '@masknet/shared-base' -function normalizeHex(value: string | number) { +function normalizeHex(value: string | number | bigint) { if (typeof value === 'string' && value.startsWith('0x')) return toHex(BigInt(value)) return toHex(value) } diff --git a/packages/web3-shared/evm/src/libs/ContractTransaction.ts b/packages/web3-shared/evm/src/libs/ContractTransaction.ts index 5ef5177e7a98..276600587a23 100644 --- a/packages/web3-shared/evm/src/libs/ContractTransaction.ts +++ b/packages/web3-shared/evm/src/libs/ContractTransaction.ts @@ -10,32 +10,16 @@ import type { Transaction } from '../types/index.js' export class ContractTransaction { constructor(private contractAddress: string) {} - /** - * Fill the transaction without gas (for calling a readonly transaction) - * @param transaction - * @param overrides - * @returns - */ - private fill( - transaction: PayableTransactionObject | NonPayableTransactionObject | undefined, - overrides?: Partial, - ): Transaction { - return pickBy( - { - from: overrides?.from ?? '', - to: this.contractAddress, - data: transaction?.encodeABI(), - value: overrides?.value ? toHex(overrides.value) : undefined, - gas: overrides?.gas ? toHex(overrides.gas) : undefined, - gasPrice: overrides?.gasPrice ? toHex(overrides.gasPrice) : undefined, - maxPriorityFeePerGas: - 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, - ) + static normalizeTransaction(transaction: Transaction): Transaction { + const normalized: Transaction = { ...transaction } + const { value, gas, gasPrice, maxPriorityFeePerGas, maxFeePerGas } = transaction + if (value) normalized.value = toHex(value) + if (gas) normalized.gas = toHex(gas) + if (gasPrice) normalized.gasPrice = toHex(gasPrice) + if (maxPriorityFeePerGas) normalized.maxPriorityFeePerGas = toHex(maxPriorityFeePerGas) + if (maxFeePerGas) normalized.maxFeePerGas = toHex(maxFeePerGas) + // drop all falsy fields + return pickBy(normalized, identity) } /** @@ -48,7 +32,11 @@ export class ContractTransaction { transaction: PayableTransactionObject | NonPayableTransactionObject | undefined, overrides?: Partial, ) { - const transactionEncoded = this.fill(transaction, overrides) + const transactionEncoded = ContractTransaction.normalizeTransaction({ + ...overrides, + to: this.contractAddress, + data: transaction?.encodeABI(), + }) // estimate gas if (!transactionEncoded.gas) { diff --git a/packages/web3-shared/evm/src/types/index.ts b/packages/web3-shared/evm/src/types/index.ts index e73e1169806e..df81dac059dc 100644 --- a/packages/web3-shared/evm/src/types/index.ts +++ b/packages/web3-shared/evm/src/types/index.ts @@ -406,11 +406,6 @@ export interface Transaction { from?: string to?: string value?: string - // value?: bigint - // gas?: bigint - // gasPrice?: bigint - // maxPriorityFeePerGas?: bigint - // maxFeePerGas?: bigint gas?: string gasPrice?: string maxPriorityFeePerGas?: string