Avoid rebuilding/parsing ABI the same contract objects every time

This commit is contained in:
Willian Mitsuda 2022-08-23 19:01:30 -03:00
parent 682549fa4c
commit 18a7989a8b
No known key found for this signature in database
6 changed files with 68 additions and 31 deletions

View File

@ -1,18 +1,18 @@
import { BaseProvider } from "@ethersproject/providers"; import { BaseProvider } from "@ethersproject/providers";
import { Contract } from "@ethersproject/contracts"; import { Contract } from "@ethersproject/contracts";
import { Interface } from "@ethersproject/abi"; import { AddressZero } from "@ethersproject/constants";
import { IAddressResolver } from "./address-resolver"; import { IAddressResolver } from "./address-resolver";
import erc20 from "../../erc20.json"; import erc20 from "../../erc20.json";
import { TokenMeta } from "../../types"; import { TokenMeta } from "../../types";
const erc20Interface = new Interface(erc20); const ERC20_PROTOTYPE = new Contract(AddressZero, erc20);
export class ERCTokenResolver implements IAddressResolver<TokenMeta> { export class ERCTokenResolver implements IAddressResolver<TokenMeta> {
async resolveAddress( async resolveAddress(
provider: BaseProvider, provider: BaseProvider,
address: string address: string
): Promise<TokenMeta | undefined> { ): Promise<TokenMeta | undefined> {
const erc20Contract = new Contract(address, erc20Interface, provider); const erc20Contract = ERC20_PROTOTYPE.connect(provider).attach(address);
try { try {
const name = (await erc20Contract.name()) as string; const name = (await erc20Contract.name()) as string;
if (!name.trim()) { if (!name.trim()) {

View File

@ -12,6 +12,11 @@ const UNISWAP_V1_FACTORY_ABI = [
const NULL_ADDRESS = "0x0000000000000000000000000000000000000000"; const NULL_ADDRESS = "0x0000000000000000000000000000000000000000";
const UNISWAP_V1_FACTORY_PROTOTYPE = new Contract(
UNISWAP_V1_FACTORY,
UNISWAP_V1_FACTORY_ABI
);
export type UniswapV1TokenMeta = { export type UniswapV1TokenMeta = {
address: ChecksummedAddress; address: ChecksummedAddress;
} & TokenMeta; } & TokenMeta;
@ -28,11 +33,7 @@ export class UniswapV1Resolver implements IAddressResolver<UniswapV1PairMeta> {
provider: BaseProvider, provider: BaseProvider,
address: string address: string
): Promise<UniswapV1PairMeta | undefined> { ): Promise<UniswapV1PairMeta | undefined> {
const factoryContract = new Contract( const factoryContract = UNISWAP_V1_FACTORY_PROTOTYPE.connect(provider);
UNISWAP_V1_FACTORY,
UNISWAP_V1_FACTORY_ABI,
provider
);
try { try {
// First, probe the getToken() function; if it responds with an UniswapV1 exchange // First, probe the getToken() function; if it responds with an UniswapV1 exchange

View File

@ -1,5 +1,6 @@
import { BaseProvider } from "@ethersproject/providers"; import { BaseProvider } from "@ethersproject/providers";
import { Contract } from "@ethersproject/contracts"; import { Contract } from "@ethersproject/contracts";
import { AddressZero } from "@ethersproject/constants";
import { IAddressResolver } from "./address-resolver"; import { IAddressResolver } from "./address-resolver";
import { ChecksummedAddress, TokenMeta } from "../../types"; import { ChecksummedAddress, TokenMeta } from "../../types";
import { ERCTokenResolver } from "./ERCTokenResolver"; import { ERCTokenResolver } from "./ERCTokenResolver";
@ -16,6 +17,16 @@ const UNISWAP_V2_PAIR_ABI = [
"function token1() external view returns (address)", "function token1() external view returns (address)",
]; ];
const UNISWAP_V2_FACTORY_PROTOTYPE = new Contract(
UNISWAP_V2_FACTORY,
UNISWAP_V2_FACTORY_ABI
);
const UNISWAP_V2_PAIR_PROTOTYPE = new Contract(
AddressZero,
UNISWAP_V2_PAIR_ABI
);
export type UniswapV2TokenMeta = { export type UniswapV2TokenMeta = {
address: ChecksummedAddress; address: ChecksummedAddress;
} & TokenMeta; } & TokenMeta;
@ -33,12 +44,9 @@ export class UniswapV2Resolver implements IAddressResolver<UniswapV2PairMeta> {
provider: BaseProvider, provider: BaseProvider,
address: string address: string
): Promise<UniswapV2PairMeta | undefined> { ): Promise<UniswapV2PairMeta | undefined> {
const pairContract = new Contract(address, UNISWAP_V2_PAIR_ABI, provider); const pairContract =
const factoryContract = new Contract( UNISWAP_V2_PAIR_PROTOTYPE.connect(provider).attach(address);
UNISWAP_V2_FACTORY, const factoryContract = UNISWAP_V2_FACTORY_PROTOTYPE.connect(provider);
UNISWAP_V2_FACTORY_ABI,
provider
);
try { try {
// First, probe the factory() function; if it responds with UniswapV2 factory // First, probe the factory() function; if it responds with UniswapV2 factory

View File

@ -1,5 +1,6 @@
import { BaseProvider } from "@ethersproject/providers"; import { BaseProvider } from "@ethersproject/providers";
import { Contract } from "@ethersproject/contracts"; import { Contract } from "@ethersproject/contracts";
import { AddressZero } from "@ethersproject/constants";
import { IAddressResolver } from "./address-resolver"; import { IAddressResolver } from "./address-resolver";
import { ChecksummedAddress, TokenMeta } from "../../types"; import { ChecksummedAddress, TokenMeta } from "../../types";
import { ERCTokenResolver } from "./ERCTokenResolver"; import { ERCTokenResolver } from "./ERCTokenResolver";
@ -17,6 +18,16 @@ const UNISWAP_V3_PAIR_ABI = [
"function fee() external view returns (uint24)", "function fee() external view returns (uint24)",
]; ];
const UNISWAP_V3_FACTORY_PROTOTYPE = new Contract(
UNISWAP_V3_FACTORY,
UNISWAP_V3_FACTORY_ABI
);
const UNISWAP_V3_PAIR_PROTOTYPE = new Contract(
AddressZero,
UNISWAP_V3_PAIR_ABI
);
export type UniswapV3TokenMeta = { export type UniswapV3TokenMeta = {
address: ChecksummedAddress; address: ChecksummedAddress;
} & TokenMeta; } & TokenMeta;
@ -35,12 +46,9 @@ export class UniswapV3Resolver implements IAddressResolver<UniswapV3PairMeta> {
provider: BaseProvider, provider: BaseProvider,
address: string address: string
): Promise<UniswapV3PairMeta | undefined> { ): Promise<UniswapV3PairMeta | undefined> {
const poolContract = new Contract(address, UNISWAP_V3_PAIR_ABI, provider); const poolContract =
const factoryContract = new Contract( UNISWAP_V3_PAIR_PROTOTYPE.connect(provider).attach(address);
UNISWAP_V3_FACTORY, const factoryContract = UNISWAP_V3_FACTORY_PROTOTYPE.connect(provider);
UNISWAP_V3_FACTORY_ABI,
provider
);
try { try {
// First, probe the factory() function; if it responds with UniswapV2 factory // First, probe the factory() function; if it responds with UniswapV2 factory

View File

@ -10,6 +10,7 @@ import { Contract } from "@ethersproject/contracts";
import { defaultAbiCoder } from "@ethersproject/abi"; import { defaultAbiCoder } from "@ethersproject/abi";
import { BigNumber } from "@ethersproject/bignumber"; import { BigNumber } from "@ethersproject/bignumber";
import { arrayify, hexDataSlice, isHexString } from "@ethersproject/bytes"; import { arrayify, hexDataSlice, isHexString } from "@ethersproject/bytes";
import { AddressZero } from "@ethersproject/constants";
import useSWR from "swr"; import useSWR from "swr";
import useSWRImmutable from "swr/immutable"; import useSWRImmutable from "swr/immutable";
import { import {
@ -638,13 +639,19 @@ export const useHasCode = (
return data as boolean | undefined; return data as boolean | undefined;
}; };
const ERC20_PROTOTYPE = new Contract(AddressZero, erc20);
const tokenMetadataFetcher = const tokenMetadataFetcher =
(provider: JsonRpcProvider | undefined) => (provider: JsonRpcProvider | undefined) =>
async ( async (
_: "tokenmeta", _: "tokenmeta",
address: ChecksummedAddress address: ChecksummedAddress
): Promise<TokenMeta | null> => { ): Promise<TokenMeta | null> => {
const erc20Contract = new Contract(address, erc20, provider); if (provider === undefined) {
return null;
}
const erc20Contract = ERC20_PROTOTYPE.connect(provider).attach(address);
try { try {
const name = (await erc20Contract.name()) as string; const name = (await erc20Contract.name()) as string;
if (!name.trim()) { if (!name.trim()) {

View File

@ -1,6 +1,7 @@
import { JsonRpcProvider, BlockTag } from "@ethersproject/providers"; import { JsonRpcProvider, BlockTag } from "@ethersproject/providers";
import { Contract } from "@ethersproject/contracts"; import { Contract } from "@ethersproject/contracts";
import { BigNumber } from "@ethersproject/bignumber"; import { BigNumber } from "@ethersproject/bignumber";
import { AddressZero } from "@ethersproject/constants";
import AggregatorV3Interface from "@chainlink/contracts/abi/v0.8/AggregatorV3Interface.json"; import AggregatorV3Interface from "@chainlink/contracts/abi/v0.8/AggregatorV3Interface.json";
import FeedRegistryInterface from "@chainlink/contracts/abi/v0.8/FeedRegistryInterface.json"; import FeedRegistryInterface from "@chainlink/contracts/abi/v0.8/FeedRegistryInterface.json";
import { Fetcher } from "swr"; import { Fetcher } from "swr";
@ -26,11 +27,20 @@ const feedRegistryFetcherKey = (
return [tokenAddress, blockTag]; return [tokenAddress, blockTag];
}; };
const FEED_REGISTRY_MAINNET_PROTOTYPE = new Contract(
FEED_REGISTRY_MAINNET,
FeedRegistryInterface
);
const feedRegistryFetcher = const feedRegistryFetcher =
( (
provider: JsonRpcProvider | undefined provider: JsonRpcProvider | undefined
): Fetcher<FeedRegistryFetcherData, FeedRegistryFetcherKey> => ): Fetcher<FeedRegistryFetcherData, FeedRegistryFetcherKey> =>
async (tokenAddress, blockTag) => { async (tokenAddress, blockTag) => {
if (provider === undefined) {
return [undefined, undefined];
}
// It work works on ethereum mainnet and kovan, see: // It work works on ethereum mainnet and kovan, see:
// https://docs.chain.link/docs/feed-registry/ // https://docs.chain.link/docs/feed-registry/
if (provider!.network.chainId !== 1) { if (provider!.network.chainId !== 1) {
@ -38,11 +48,7 @@ const feedRegistryFetcher =
} }
// Let SWR handle error // Let SWR handle error
const feedRegistry = new Contract( const feedRegistry = FEED_REGISTRY_MAINNET_PROTOTYPE.connect(provider);
FEED_REGISTRY_MAINNET,
FeedRegistryInterface,
provider
);
const priceData = await feedRegistry.latestRoundData(tokenAddress, USD, { const priceData = await feedRegistry.latestRoundData(tokenAddress, USD, {
blockTag, blockTag,
}); });
@ -76,6 +82,8 @@ const ethUSDFetcherKey = (blockTag: BlockTag | undefined) => {
return ["ethusd", blockTag]; return ["ethusd", blockTag];
}; };
const ETH_USD_FEED_PROTOTYPE = new Contract(AddressZero, AggregatorV3Interface);
const ethUSDFetcher = const ethUSDFetcher =
( (
provider: JsonRpcProvider | undefined provider: JsonRpcProvider | undefined
@ -84,7 +92,9 @@ const ethUSDFetcher =
if (provider?.network.chainId !== 1) { if (provider?.network.chainId !== 1) {
return undefined; return undefined;
} }
const c = new Contract("eth-usd.data.eth", AggregatorV3Interface, provider);
const c =
ETH_USD_FEED_PROTOTYPE.connect(provider).attach("eth-usd.data.eth");
const priceData = await c.latestRoundData({ blockTag }); const priceData = await c.latestRoundData({ blockTag });
return priceData; return priceData;
}; };
@ -120,6 +130,11 @@ const fastGasFetcherKey = (blockTag: BlockTag | undefined) => {
return ["gasgwei", blockTag]; return ["gasgwei", blockTag];
}; };
const FAST_GAS_FEED_PROTOTYPE = new Contract(
AddressZero,
AggregatorV3Interface
);
const fastGasFetcher = const fastGasFetcher =
( (
provider: JsonRpcProvider | undefined provider: JsonRpcProvider | undefined
@ -128,10 +143,8 @@ const fastGasFetcher =
if (provider?.network.chainId !== 1) { if (provider?.network.chainId !== 1) {
return undefined; return undefined;
} }
const c = new Contract( const c = FAST_GAS_FEED_PROTOTYPE.connect(provider).attach(
"fast-gas-gwei.data.eth", "fast-gas-gwei.data.eth"
AggregatorV3Interface,
provider
); );
const priceData = await c.latestRoundData({ blockTag }); const priceData = await c.latestRoundData({ blockTag });
return priceData; return priceData;