diff --git a/src/TokenTransferItem.tsx b/src/TokenTransferItem.tsx index 59fffbb..9e49ee4 100644 --- a/src/TokenTransferItem.tsx +++ b/src/TokenTransferItem.tsx @@ -31,8 +31,8 @@ const TokenTransferItem: React.FC = ({ -
-
+
+
From = ({ metadata={metadatas[t.from]} />
-
+
To { + async resolveAddress( + provider: BaseProvider, + address: string + ): Promise { + const pairContract = new Contract(address, UNISWAP_V2_PAIR_ABI, provider); + const factoryContract = new Contract( + UNISWAP_V2_FACTORY, + UNISWAP_V2_FACTORY_ABI, + provider + ); + + try { + // First, probe the factory() function; if it responds with UniswapV2 factory + // address, it may be a pair + const factoryAddress = (await pairContract.factory()) as string; + if (factoryAddress !== UNISWAP_V2_FACTORY) { + return undefined; + } + + // Probe the token0/token1 + const [token0, token1] = await Promise.all([ + pairContract.token0() as string, + pairContract.token1() as string, + ]); + + // Probe the factory to ensure it is a legit pair + const expectedPairAddress = await factoryContract.getPair(token0, token1); + if (expectedPairAddress !== address) { + return undefined; + } + + console.log(`Found pair: ${token0}/${token1}`); + const [meta0, meta1] = await Promise.all([ + ercResolver.resolveAddress(provider, token0), + ercResolver.resolveAddress(provider, token1), + ]); + if (meta0 === undefined || meta1 === undefined) { + return undefined; + } + + return { + pair: address, + token0: { address: token0, ...meta0 }, + token1: { address: token1, ...meta1 }, + }; + } catch (err) { + // Ignore on purpose; this indicates the probe failed and the address + // is not a token + } + return undefined; + } +} diff --git a/src/api/address-resolver/index.ts b/src/api/address-resolver/index.ts index f1514be..ba96106 100644 --- a/src/api/address-resolver/index.ts +++ b/src/api/address-resolver/index.ts @@ -2,12 +2,14 @@ import { BaseProvider } from "@ethersproject/providers"; import { ensRenderer } from "../../components/ENSName"; import { plainStringRenderer } from "../../components/PlainString"; import { tokenRenderer } from "../../components/TokenName"; +import { uniswapV2PairRenderer } from "../../components/UniswapV2PairName"; import { IAddressResolver, ResolvedAddressRenderer } from "./address-resolver"; import { CompositeAddressResolver, SelectedResolvedName, } from "./CompositeAddressResolver"; import { ENSAddressResolver } from "./ENSAddressResolver"; +import { UniswapV2Resolver } from "./UniswapV2Resolver"; import { ERCTokenResolver } from "./ERCTokenResolver"; import { HardcodedAddressResolver } from "./HardcodedAddressResolver"; @@ -15,11 +17,13 @@ export type ResolvedAddresses = Record>; // Create and configure the main resolver export const ensResolver = new ENSAddressResolver(); +export const uniswapV2Resolver = new UniswapV2Resolver(); export const ercTokenResolver = new ERCTokenResolver(); export const hardcodedResolver = new HardcodedAddressResolver(); const _mainResolver = new CompositeAddressResolver(); _mainResolver.addResolver(ensResolver); +_mainResolver.addResolver(uniswapV2Resolver); _mainResolver.addResolver(ercTokenResolver); _mainResolver.addResolver(hardcodedResolver); @@ -31,6 +35,7 @@ export const resolverRendererRegistry = new Map< ResolvedAddressRenderer >(); resolverRendererRegistry.set(ensResolver, ensRenderer); +resolverRendererRegistry.set(uniswapV2Resolver, uniswapV2PairRenderer); resolverRendererRegistry.set(ercTokenResolver, tokenRenderer); resolverRendererRegistry.set(hardcodedResolver, plainStringRenderer); diff --git a/src/components/UniswapV2PairName.tsx b/src/components/UniswapV2PairName.tsx new file mode 100644 index 0000000..f4520b7 --- /dev/null +++ b/src/components/UniswapV2PairName.tsx @@ -0,0 +1,110 @@ +import React from "react"; +import { NavLink } from "react-router-dom"; +import TokenLogo from "./TokenLogo"; +import { ResolvedAddressRenderer } from "../api/address-resolver/address-resolver"; +import { + UniswapV2PairMeta, + UniswapV2TokenMeta, +} from "../api/address-resolver/UniswapV2Resolver"; +import { ChecksummedAddress } from "../types"; + +type UniswapV2PairNameProps = { + address: string; + token0: UniswapV2TokenMeta; + token1: UniswapV2TokenMeta; + linkable: boolean; + dontOverrideColors?: boolean; +}; + +const UniswapV2PairName: React.FC = ({ + address, + token0, + token1, + linkable, + dontOverrideColors, +}) => { + if (linkable) { + return ( + + Uniswap V2 LP: + + / + + + ); + } + + return ( +
+ Uniswap V2 LP: + + / + +
+ ); +}; + +type ContentProps = { + linkable: boolean; + address: ChecksummedAddress; + name: string; + symbol: string; +}; + +const Content: React.FC = ({ + address, + name, + symbol, + linkable, +}) => ( + <> +
+ +
+ {symbol} + +); + +export const uniswapV2PairRenderer: ResolvedAddressRenderer = + (address, tokenMeta, linkable, dontOverrideColors) => ( + + ); + +export default UniswapV2PairName;