diff --git a/packages/mask/src/extension/background-script/EthereumServices/request.ts b/packages/mask/src/extension/background-script/EthereumServices/request.ts index 04cc98cbee00..8e7ebbc9264a 100644 --- a/packages/mask/src/extension/background-script/EthereumServices/request.ts +++ b/packages/mask/src/extension/background-script/EthereumServices/request.ts @@ -55,30 +55,7 @@ function isSendMethod(method: EthereumMethodType) { return method === EthereumMethodType.ETH_SEND_TRANSACTION } -export function request( - requestArguments: RequestArguments, - overrides?: SendOverrides, - options?: RequestOptions, -) { - return new Promise((resolve, reject) => { - requestSend( - { - jsonrpc: '2.0', - id, - params: [], - ...requestArguments, - }, - (error, response) => { - if (error || response?.error) reject(error ?? response?.error) - else resolve(response?.result) - }, - overrides, - options, - ) - }) -} - -export async function requestSend( +async function requestSend( payload: JsonRpcPayload, callback: (error: Error | null, response?: JsonRpcResponse) => void, overrides?: SendOverrides, @@ -177,6 +154,29 @@ export async function requestSend( getSendMethod()(payload_, hijackedCallback, overrides) } +export async function request( + requestArguments: RequestArguments, + overrides?: SendOverrides, + options?: RequestOptions, +) { + return new Promise(async (resolve, reject) => { + requestSend( + { + jsonrpc: '2.0', + id, + params: [], + ...requestArguments, + }, + (error, response) => { + if (error || response?.error) reject(error ?? response?.error) + else resolve(response?.result) + }, + overrides, + options, + ) + }) +} + export async function confirmRequest(payload: JsonRpcPayload) { const pid = getPayloadId(payload) if (!pid) return diff --git a/packages/web3-shared/evm/utils/provider.ts b/packages/web3-shared/evm/utils/provider.ts index fdf81c247868..a9cf64d7258a 100644 --- a/packages/web3-shared/evm/utils/provider.ts +++ b/packages/web3-shared/evm/utils/provider.ts @@ -1,7 +1,48 @@ import Web3 from 'web3' import type { RequestArguments } from 'web3-core' import type { JsonRpcPayload, JsonRpcResponse } from 'web3-core-helpers' -import type { RequestOptions, SendOverrides } from '../types' +import { EthereumMethodType, RequestOptions, SendOverrides } from '../types' + +const cache = new Map>() + +/** + * If it returns a cache id, it means the request can be cached. + * @param requestArguments + * @returns + */ +function getCacheId(requestArguments: RequestArguments, overrides?: SendOverrides) { + // The -1 is not a valid chain id, only used for distinguishing with other explicit chain id. + const chainId = overrides?.chainId ?? -1 + const { method, params } = requestArguments + switch (method) { + case EthereumMethodType.ETH_GET_BALANCE: + const [account, tag = 'latest'] = params as string[] + return [chainId, method, account, tag].join('_') + case EthereumMethodType.ETH_BLOCK_NUMBER: + return [chainId, method].join('_') + default: + return + } +} + +function createSquashedRequest( + request: (requestArguments: RequestArguments, overrides?: SendOverrides, options?: RequestOptions) => Promise, +) { + return async (requestArguments: RequestArguments, overrides?: SendOverrides, options?: RequestOptions) => { + const id = getCacheId(requestArguments, overrides) + + // the request cannot be cached + if (!id) return request(requestArguments, overrides, options) + + // the request is already cached + if (cache.has(id)) return cache.get(id) + + // the request can be cached + const unresolved = request(requestArguments, overrides, options).finally(() => cache.delete(id)) + cache.set(id, unresolved) + return unresolved + } +} export function createExternalProvider( request: ( @@ -12,8 +53,9 @@ export function createExternalProvider( getOverrides?: () => SendOverrides, getOptions?: () => RequestOptions, ) { + const request_ = createSquashedRequest(request) const send = (payload: JsonRpcPayload, callback: (error: Error | null, response?: JsonRpcResponse) => void) => { - request( + request_( { method: payload.method, params: payload.params, @@ -40,7 +82,7 @@ export function createExternalProvider( isStatus: true, host: '', path: '', - request: (requestArguments: RequestArguments) => request(requestArguments, getOverrides?.(), getOptions?.()), + request: (requestArguments: RequestArguments) => request_(requestArguments, getOverrides?.(), getOptions?.()), send, sendAsync: send, }