From 86f3b5a036697a7c08e08f11d753a528edb1a5c6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Wed, 14 Sep 2022 10:05:29 -0700 Subject: [PATCH] feat: caching provider (#4615) * feat: caching providers * feat: clear cache per block --- src/constants/providers.ts | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/constants/providers.ts b/src/constants/providers.ts index ba65b208ab..9b52bea0f4 100644 --- a/src/constants/providers.ts +++ b/src/constants/providers.ts @@ -1,14 +1,49 @@ +import { deepCopy } from '@ethersproject/properties' // This is the only file which should instantiate new Providers. // eslint-disable-next-line @typescript-eslint/no-restricted-imports import { StaticJsonRpcProvider } from '@ethersproject/providers' +import { isPlain } from '@reduxjs/toolkit' import { SupportedChainId } from './chains' import { RPC_URLS } from './networks' class AppJsonRpcProvider extends StaticJsonRpcProvider { + private _blockCache = new Map>() + get blockCache() { + // If the blockCache has not yet been initialized this block, do so by + // setting a listener to clear it on the next block. + if (!this._blockCache.size) { + this.once('block', () => this._blockCache.clear()) + } + return this._blockCache + } + constructor(urls: string[]) { super(urls[0]) } + + send(method: string, params: Array): Promise { + // Only cache eth_call's. + if (method !== 'eth_call') return super.send(method, params) + + // Only cache if params are serializable. + if (!isPlain(params)) return super.send(method, params) + + const key = `call:${JSON.stringify(params)}` + const cached = this.blockCache.get(key) + if (cached) { + this.emit('debug', { + action: 'request', + request: deepCopy({ method, params, id: 'cache' }), + provider: this, + }) + return cached + } + + const result = super.send(method, params) + this.blockCache.set(key, result) + return result + } } /**