ERC20 Contract Metadata
Code
Fetch ERC20 contract metadata using Effect API
import { Effect, Layer } from "effect";import { ContractData, ContractType, PublicClient, ContractMetaStore,} from "@3loop/transaction-decoder";import { erc20Abi, getAddress, getContract } from "viem";
export const fetchAndCacheErc20Meta = ({ contractAddress, chainID,}: { contractAddress: string; chainID: number;}) => Effect.gen(function* (_) { const service = yield* _(PublicClient); const { client } = yield* _(service.getPublicClient(chainID));
const inst = yield* _( Effect.sync(() => getContract({ address: getAddress(contractAddress), abi: erc20Abi, client, }), ), );
const name = yield* _( Effect.tryPromise(() => inst.read.name() as Promise<string | null>), );
if (name == null) { return null; }
const [symbol, decimals] = yield* _( Effect.all( [ Effect.tryPromise(() => inst.read.symbol() as Promise<string>), Effect.tryPromise(() => inst.read.decimals() as Promise<number>), ], { concurrency: "unbounded", }, ), );
if (symbol == null || decimals == null) { return null; }
const meta: ContractData = { address: contractAddress, contractAddress, contractName: name, tokenSymbol: symbol, decimals: Number(decimals), type: "ERC20" as ContractType, chainID, };
return meta; });
export const ContractMetaStoreLive = Layer.effect( ContractMetaStore, Effect.gen(function* (_) { const rpcProvider = yield* _(RPCProvider);
return ContractMetaStore.of({ get: ({ address, chainID }) => Effect.gen(function* (_) { const normAddress = address.toLowerCase();
const tryERC20 = yield* _( fetchAndCacheErc20Meta({ contractAddress: normAddress, chainID, }).pipe( Effect.provideService(RPCProvider, rpcProvider), Effect.catchAll((_) => Effect.succeed(null)), ), );
if (tryERC20 != null) { return tryERC20; }
return null; }), set: () => Effect.sync(() => null), }); }),);