diff --git a/.changeset/two-shoes-brush.md b/.changeset/two-shoes-brush.md new file mode 100644 index 00000000..c0a14546 --- /dev/null +++ b/.changeset/two-shoes-brush.md @@ -0,0 +1,5 @@ +--- +'@3loop/transaction-decoder': patch +--- + +Do not cache failed request to meta strategies diff --git a/packages/transaction-decoder/src/contract-meta-loader.ts b/packages/transaction-decoder/src/contract-meta-loader.ts index 00460615..f6dfbfc1 100644 --- a/packages/transaction-decoder/src/contract-meta-loader.ts +++ b/packages/transaction-decoder/src/contract-meta-loader.ts @@ -90,6 +90,8 @@ const getMany = (requests: Array) => const setValue = ({ chainID, address }: ContractMetaLoader, result: ContractData | null) => Effect.gen(function* () { const { set } = yield* ContractMetaStore + if (result == null) return + // NOTE: Now when RPC fails if we store not-found it causes issues and not retries, for now we will just always retry yield* set( { chainID, address }, result == null ? { status: 'not-found', result: null } : { status: 'success', result }, diff --git a/packages/transaction-decoder/src/decoding/log-decode.ts b/packages/transaction-decoder/src/decoding/log-decode.ts index 5dc38845..c81a674c 100644 --- a/packages/transaction-decoder/src/decoding/log-decode.ts +++ b/packages/transaction-decoder/src/decoding/log-decode.ts @@ -45,6 +45,7 @@ const decodedLog = (transaction: GetTransactionReturnType, logItem: Log) => ], { concurrency: 'unbounded', + batching: true, }, ) diff --git a/packages/transaction-decoder/src/meta-strategy/erc20-rpc-strategy.ts b/packages/transaction-decoder/src/meta-strategy/erc20-rpc-strategy.ts index b1c3ec30..cdbd1e25 100644 --- a/packages/transaction-decoder/src/meta-strategy/erc20-rpc-strategy.ts +++ b/packages/transaction-decoder/src/meta-strategy/erc20-rpc-strategy.ts @@ -2,7 +2,8 @@ import { ContractData, ContractType } from '../types.js' import * as RequestModel from './request-model.js' import { Effect, RequestResolver } from 'effect' import { PublicClient } from '../public-client.js' -import { erc20Abi, getContract } from 'viem' +import { erc20Abi } from 'viem' +import { MULTICALL3_ADDRESS } from '../decoding/constants.js' export const ERC20RPCStrategyResolver = (publicClientLive: PublicClient) => RequestResolver.fromEffect(({ chainID, address }: RequestModel.GetContractMetaStrategy) => @@ -10,41 +11,45 @@ export const ERC20RPCStrategyResolver = (publicClientLive: PublicClient) => const service = yield* PublicClient const { client } = yield* service.getPublicClient(chainID) - const inst = getContract({ - abi: erc20Abi, - address, - client, - }) - const fail = new RequestModel.ResolveStrategyMetaError('ERC20RPCStrategy', address, chainID) - const decimals = yield* Effect.tryPromise({ - try: () => inst.read.decimals(), - catch: () => fail, + const [symbolResponse, decimalsResponse, nameResponse] = yield* Effect.tryPromise({ + try: () => + client.multicall({ + multicallAddress: MULTICALL3_ADDRESS, + contracts: [ + { + abi: erc20Abi, + address, + functionName: 'symbol', + }, + { + abi: erc20Abi, + address, + functionName: 'decimals', + }, + { + abi: erc20Abi, + address, + functionName: 'name', + }, + ], + }), + catch: () => { + return fail + }, }) - if (decimals == null) { + if (decimalsResponse.status !== 'success') { return yield* Effect.fail(fail) } - //NOTE: keep for now to support blur pools - const [symbol, name] = yield* Effect.all( - [ - Effect.tryPromise({ try: () => inst.read.symbol().catch(() => ''), catch: () => fail }), - Effect.tryPromise({ try: () => inst.read.name().catch(() => ''), catch: () => fail }), - ], - { - concurrency: 'inherit', - batching: 'inherit', - }, - ) - const meta: ContractData = { address, contractAddress: address, - contractName: name, - tokenSymbol: symbol, - decimals: Number(decimals), + contractName: nameResponse.result, + tokenSymbol: symbolResponse.result, + decimals: Number(decimalsResponse.result), type: 'ERC20' as ContractType, chainID, } diff --git a/packages/transaction-decoder/src/sql/abi-store.ts b/packages/transaction-decoder/src/sql/abi-store.ts index edbcd08c..87241bbc 100644 --- a/packages/transaction-decoder/src/sql/abi-store.ts +++ b/packages/transaction-decoder/src/sql/abi-store.ts @@ -8,7 +8,7 @@ export const make = (strategies: AbiStore['strategies']) => Effect.gen(function* () { const sql = yield* SqlClient.SqlClient - const table = sql('loop_decoder_contract_abi__') + const table = sql('_loop_decoder_contract_abi_') // TODO; add timestamp to the table yield* sql` @@ -19,7 +19,9 @@ export const make = (strategies: AbiStore['strategies']) => signature TEXT, chain INTEGER, abi TEXT, - status TEXT NOT NULL + status TEXT NOT NULL, + timestamp TEXT DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (address, chain) ) `.pipe( Effect.tapError(Effect.logError), diff --git a/packages/transaction-decoder/src/sql/contract-meta-store.ts b/packages/transaction-decoder/src/sql/contract-meta-store.ts index 063e8e8e..e78e642e 100644 --- a/packages/transaction-decoder/src/sql/contract-meta-store.ts +++ b/packages/transaction-decoder/src/sql/contract-meta-store.ts @@ -16,7 +16,7 @@ export const make = () => const sql = yield* SqlClient.SqlClient const publicClient = yield* PublicClient - const table = sql('loop_decoder_contract_meta__') + const table = sql('_loop_decoder_contract_meta_') // TODO; add timestamp to the table yield* sql` @@ -27,7 +27,9 @@ export const make = () => token_symbol TEXT, decimals INTEGER, type TEXT, - status TEXT NOT NULL + status TEXT NOT NULL, + timestamp TEXT DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (address, chain) ) `.pipe( Effect.tapError(Effect.logError),