From 6f43064c6e4c85c030af06decfa38daff4eeab5b Mon Sep 17 00:00:00 2001 From: Gonzalo D'elia Date: Sat, 4 Jan 2025 18:57:11 -0300 Subject: [PATCH 1/4] Fix eth_call calls caching --- webapp/utils/cacheStrategies.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webapp/utils/cacheStrategies.ts b/webapp/utils/cacheStrategies.ts index 0eb07cad..261eac1d 100644 --- a/webapp/utils/cacheStrategies.ts +++ b/webapp/utils/cacheStrategies.ts @@ -1,6 +1,6 @@ // This strategy is used to cache some of the requests done by the OP sdk // when fetching data for withdrawals -import { Hash, keccak256, isHash, toHex } from 'viem' +import { Hash, keccak256, isHex, toHex } from 'viem' type RpcCallParam = { data: Hash @@ -9,7 +9,7 @@ type RpcCallParam = { const isWithdrawalEthCall = function (obj: unknown): obj is RpcCallParam { const casted = obj as RpcCallParam - return casted !== undefined && isHash(casted.data) + return casted !== undefined && isHex(casted.data) } const getSignature = (method: string) => keccak256(toHex(method)).slice(0, 10) From 78bf7a26d57534f5734831ca2e9559c0f5dfff93 Mon Sep 17 00:00:00 2001 From: Gonzalo D'elia Date: Sat, 4 Jan 2025 19:10:19 -0300 Subject: [PATCH 2/4] Move cacheProvider fn out of ui-common --- package-lock.json | 8 ++++---- ui-common/package.json | 4 ---- ui-common/utils/cache.ts | 21 --------------------- webapp/package.json | 2 ++ webapp/utils/providers.ts | 26 +++++++++++++++++++++++++- 5 files changed, 31 insertions(+), 30 deletions(-) delete mode 100644 ui-common/utils/cache.ts diff --git a/package-lock.json b/package-lock.json index 0fc89345..2d0b901b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2029,6 +2029,7 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { "@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-signer": "^5.7.0", @@ -12532,6 +12533,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/eth-rpc-cache/-/eth-rpc-cache-2.0.0.tgz", "integrity": "sha512-GK/w6hJ8IZ1l+LBTZyWKZMokV2uT/kv1jYI84JG69T5J+EsVF17x9iC3Ug9jYOs9HLA+anhDcl8KA8bhxXzYaw==", + "license": "MIT", "dependencies": { "debug": "4.3.4", "json-stable-stringify": "1.0.1", @@ -25014,11 +25016,7 @@ }, "ui-common": { "version": "1.0.0", - "dependencies": { - "eth-rpc-cache": "2.0.0" - }, "devDependencies": { - "@ethersproject/providers": "5.7.2", "next": "14.2.16", "react": "18.2.0", "react-dom": "18.2.0" @@ -25060,6 +25058,7 @@ "crypto-shortener": "1.1.0", "debug": "4.3.7", "esplora-client": "1.2.0", + "eth-rpc-cache": "2.0.0", "hemi-socials": "1.0.0", "hemi-viem": "2.0.0-alpha.1", "javascript-time-ago": "2.5.10", @@ -25087,6 +25086,7 @@ "wagmi-erc20-hooks": "1.0.0" }, "devDependencies": { + "@ethersproject/providers": "5.7.2", "@types/big.js": "6.2.2", "@types/lodash": "4.17.13", "@types/node": "20.12.12", diff --git a/ui-common/package.json b/ui-common/package.json index f8134e96..1623e7f4 100644 --- a/ui-common/package.json +++ b/ui-common/package.json @@ -4,11 +4,7 @@ "scripts": { "tsc:check": "tsc" }, - "dependencies": { - "eth-rpc-cache": "2.0.0" - }, "devDependencies": { - "@ethersproject/providers": "5.7.2", "next": "14.2.16", "react": "18.2.0", "react-dom": "18.2.0" diff --git a/ui-common/utils/cache.ts b/ui-common/utils/cache.ts deleted file mode 100644 index f13189f3..00000000 --- a/ui-common/utils/cache.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { JsonRpcProvider, Web3Provider } from '@ethersproject/providers' -import { - createEthRpcCache, - perBlockStrategy, - permanentStrategy, -} from 'eth-rpc-cache' - -export const cacheProvider = function < - T extends JsonRpcProvider | Web3Provider, ->(provider: T, strategies: (typeof permanentStrategy)[] = []) { - const cached = createEthRpcCache( - (method, params) => provider.send(method, params), - { strategies: [perBlockStrategy, permanentStrategy, ...strategies] }, - ) - const newProvider: T = { - ...provider, - send: (method, params) => cached(method, params), - } - Object.setPrototypeOf(newProvider, Object.getPrototypeOf(provider)) - return newProvider -} diff --git a/webapp/package.json b/webapp/package.json index 9788bca5..8abd1508 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -26,6 +26,7 @@ "crypto-shortener": "1.1.0", "debug": "4.3.7", "esplora-client": "1.2.0", + "eth-rpc-cache": "2.0.0", "hemi-socials": "1.0.0", "hemi-viem": "2.0.0-alpha.1", "javascript-time-ago": "2.5.10", @@ -53,6 +54,7 @@ "wagmi-erc20-hooks": "1.0.0" }, "devDependencies": { + "@ethersproject/providers": "5.7.2", "@types/big.js": "6.2.2", "@types/lodash": "4.17.13", "@types/node": "20.12.12", diff --git a/webapp/utils/providers.ts b/webapp/utils/providers.ts index 1d0ded57..00d82f65 100644 --- a/webapp/utils/providers.ts +++ b/webapp/utils/providers.ts @@ -1,8 +1,32 @@ +import { + type JsonRpcProvider, + type Web3Provider, +} from '@ethersproject/providers' +import { + createEthRpcCache, + perBlockStrategy, + permanentStrategy, +} from 'eth-rpc-cache' import { providers } from 'ethers' -import { cacheProvider } from 'ui-common/utils/cache' import { withdrawalsStrategy } from 'utils/cacheStrategies' import { type Account, type Chain, type HttpTransport } from 'viem' +const cacheProvider = function ( + provider: T, + strategies: (typeof permanentStrategy)[] = [], +) { + const cached = createEthRpcCache( + (method, params) => provider.send(method, params), + { strategies: [perBlockStrategy, permanentStrategy, ...strategies] }, + ) + const newProvider: T = { + ...provider, + send: (method, params) => cached(method, params), + } + Object.setPrototypeOf(newProvider, Object.getPrototypeOf(provider)) + return newProvider +} + const toNetwork = (chain: Chain) => ({ chainId: chain.id, ensAddress: chain.contracts?.ensRegistry?.address, From 64dc36456b62f93aabd04690f35726e12961cd46 Mon Sep 17 00:00:00 2001 From: Gonzalo D'elia Date: Sat, 4 Jan 2025 19:37:46 -0300 Subject: [PATCH 3/4] Add tests for cacheStrategies --- webapp/test/utils/cacheStrategies.test.ts | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 webapp/test/utils/cacheStrategies.test.ts diff --git a/webapp/test/utils/cacheStrategies.test.ts b/webapp/test/utils/cacheStrategies.test.ts new file mode 100644 index 00000000..eb7d1ace --- /dev/null +++ b/webapp/test/utils/cacheStrategies.test.ts @@ -0,0 +1,33 @@ +import { withdrawalsStrategy } from 'utils/cacheStrategies' +import { describe, expect, it } from 'vitest' + +describe('utils/cacheStrategies', function () { + describe('withdrawalsStrategy', function () { + it('should return undefined the RPC call has no parameters', () => { + const result = withdrawalsStrategy.resolver('eth_call', []) + expect(result).toBeUndefined() + }) + + it('should return undefined if data is not a valid hex', function () { + const result = withdrawalsStrategy.resolver('eth_call', [ + { data: 'invalid', to: '0x123' }, + ]) + expect(result).toBeUndefined() + }) + + it('should return a valid caching strategy for the known methods', function () { + const data = '0x54fd4d50' // keccak256 of "version()" + const result = withdrawalsStrategy.resolver('eth_call', [ + { data, to: '0x123' }, + ]) + expect(result).toBe('permanent') + }) + + it('should return undefined for a valid eth_call with unknown method', function () { + const result = withdrawalsStrategy.resolver('eth_call', [ + { data: '0x123456AF', to: '0x123' }, + ]) + expect(result).toBeUndefined() + }) + }) +}) From fa1de877daf7d7cda80b8dd2c5a1933bfbd3731d Mon Sep 17 00:00:00 2001 From: Gonzalo D'elia Date: Mon, 6 Jan 2025 16:42:35 -0300 Subject: [PATCH 4/4] Remove unnecessary isWithdrawalEthCall check --- webapp/test/utils/cacheStrategies.test.ts | 5 ----- webapp/utils/cacheStrategies.ts | 14 +++----------- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/webapp/test/utils/cacheStrategies.test.ts b/webapp/test/utils/cacheStrategies.test.ts index eb7d1ace..ded0e59c 100644 --- a/webapp/test/utils/cacheStrategies.test.ts +++ b/webapp/test/utils/cacheStrategies.test.ts @@ -3,11 +3,6 @@ import { describe, expect, it } from 'vitest' describe('utils/cacheStrategies', function () { describe('withdrawalsStrategy', function () { - it('should return undefined the RPC call has no parameters', () => { - const result = withdrawalsStrategy.resolver('eth_call', []) - expect(result).toBeUndefined() - }) - it('should return undefined if data is not a valid hex', function () { const result = withdrawalsStrategy.resolver('eth_call', [ { data: 'invalid', to: '0x123' }, diff --git a/webapp/utils/cacheStrategies.ts b/webapp/utils/cacheStrategies.ts index 261eac1d..02460427 100644 --- a/webapp/utils/cacheStrategies.ts +++ b/webapp/utils/cacheStrategies.ts @@ -1,17 +1,12 @@ // This strategy is used to cache some of the requests done by the OP sdk // when fetching data for withdrawals -import { Hash, keccak256, isHex, toHex } from 'viem' +import { Hash, keccak256, toHex } from 'viem' type RpcCallParam = { data: Hash to: Hash } -const isWithdrawalEthCall = function (obj: unknown): obj is RpcCallParam { - const casted = obj as RpcCallParam - return casted !== undefined && isHex(casted.data) -} - const getSignature = (method: string) => keccak256(toHex(method)).slice(0, 10) const cachePerMethod = [ @@ -53,11 +48,8 @@ export const withdrawalsStrategy = { methods: ['eth_call'], name: 'withdrawals-strategy', resolver(_: string, params: unknown[]) { - if (!isWithdrawalEthCall(params[0])) { - // doesn't have the structure of eth_call - do not use cache - return undefined - } - const { data } = params[0] + // only eth_call reaches this point + const { data } = params[0] as RpcCallParam return cacheIndexedData[data.slice(0, 10)] }, }