Avoid rebuilding/parsing ABI the same contract objects every time
This commit is contained in:
parent
682549fa4c
commit
18a7989a8b
|
@ -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()) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue