Merge branch 'feature/uniswap-resolver' into develop
This commit is contained in:
commit
f61b48742c
|
@ -31,8 +31,8 @@ const TokenTransferItem: React.FC<TokenTransferItemProps> = ({
|
||||||
<span className="text-gray-500">
|
<span className="text-gray-500">
|
||||||
<FontAwesomeIcon icon={faCaretRight} size="1x" />
|
<FontAwesomeIcon icon={faCaretRight} size="1x" />
|
||||||
</span>
|
</span>
|
||||||
<div className="grid grid-cols-5 gap-x-1">
|
<div className="grid grid-cols-7 gap-x-1 w-full">
|
||||||
<div className="flex space-x-1">
|
<div className="col-span-2 flex space-x-1">
|
||||||
<span className="font-bold">From</span>
|
<span className="font-bold">From</span>
|
||||||
<TransactionAddress
|
<TransactionAddress
|
||||||
address={t.from}
|
address={t.from}
|
||||||
|
@ -41,7 +41,7 @@ const TokenTransferItem: React.FC<TokenTransferItemProps> = ({
|
||||||
metadata={metadatas[t.from]}
|
metadata={metadatas[t.from]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex space-x-1">
|
<div className="col-span-2 flex space-x-1">
|
||||||
<span className="font-bold">To</span>
|
<span className="font-bold">To</span>
|
||||||
<TransactionAddress
|
<TransactionAddress
|
||||||
address={t.to}
|
address={t.to}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
import { BaseProvider } from "@ethersproject/providers";
|
||||||
|
import { Contract } from "@ethersproject/contracts";
|
||||||
|
import { IAddressResolver } from "./address-resolver";
|
||||||
|
import { ChecksummedAddress, TokenMeta } from "../../types";
|
||||||
|
import { ERCTokenResolver } from "./ERCTokenResolver";
|
||||||
|
|
||||||
|
const UNISWAP_V1_FACTORY = "0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95";
|
||||||
|
|
||||||
|
const UNISWAP_V1_FACTORY_ABI = [
|
||||||
|
"function getToken(address exchange) external view returns (address token)",
|
||||||
|
];
|
||||||
|
|
||||||
|
const NULL_ADDRESS = "0x0000000000000000000000000000000000000000";
|
||||||
|
|
||||||
|
export type UniswapV1TokenMeta = {
|
||||||
|
address: ChecksummedAddress;
|
||||||
|
} & TokenMeta;
|
||||||
|
|
||||||
|
export type UniswapV1PairMeta = {
|
||||||
|
exchange: ChecksummedAddress;
|
||||||
|
token: UniswapV1TokenMeta;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ercResolver = new ERCTokenResolver();
|
||||||
|
|
||||||
|
export class UniswapV1Resolver implements IAddressResolver<UniswapV1PairMeta> {
|
||||||
|
async resolveAddress(
|
||||||
|
provider: BaseProvider,
|
||||||
|
address: string
|
||||||
|
): Promise<UniswapV1PairMeta | undefined> {
|
||||||
|
const factoryContract = new Contract(
|
||||||
|
UNISWAP_V1_FACTORY,
|
||||||
|
UNISWAP_V1_FACTORY_ABI,
|
||||||
|
provider
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// First, probe the getToken() function; if it responds with an UniswapV1 exchange
|
||||||
|
// address, it is a LP
|
||||||
|
const token = (await factoryContract.getToken(address)) as string;
|
||||||
|
if (token === NULL_ADDRESS) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadata = await ercResolver.resolveAddress(provider, token);
|
||||||
|
if (metadata === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
exchange: address,
|
||||||
|
token: { address: token, ...metadata },
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
// Ignore on purpose; this indicates the probe failed and the address
|
||||||
|
// is not a token
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
import { BaseProvider } from "@ethersproject/providers";
|
||||||
|
import { Contract } from "@ethersproject/contracts";
|
||||||
|
import { IAddressResolver } from "./address-resolver";
|
||||||
|
import { ChecksummedAddress, TokenMeta } from "../../types";
|
||||||
|
import { ERCTokenResolver } from "./ERCTokenResolver";
|
||||||
|
|
||||||
|
const UNISWAP_V2_FACTORY = "0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f";
|
||||||
|
|
||||||
|
const UNISWAP_V2_FACTORY_ABI = [
|
||||||
|
"function getPair(address tokenA, address tokenB) external view returns (address pair)",
|
||||||
|
];
|
||||||
|
|
||||||
|
const UNISWAP_V2_PAIR_ABI = [
|
||||||
|
"function factory() external view returns (address)",
|
||||||
|
"function token0() external view returns (address)",
|
||||||
|
"function token1() external view returns (address)",
|
||||||
|
];
|
||||||
|
|
||||||
|
export type UniswapV2TokenMeta = {
|
||||||
|
address: ChecksummedAddress;
|
||||||
|
} & TokenMeta;
|
||||||
|
|
||||||
|
export type UniswapV2PairMeta = {
|
||||||
|
pair: ChecksummedAddress;
|
||||||
|
token0: UniswapV2TokenMeta;
|
||||||
|
token1: UniswapV2TokenMeta;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ercResolver = new ERCTokenResolver();
|
||||||
|
|
||||||
|
export class UniswapV2Resolver implements IAddressResolver<UniswapV2PairMeta> {
|
||||||
|
async resolveAddress(
|
||||||
|
provider: BaseProvider,
|
||||||
|
address: string
|
||||||
|
): Promise<UniswapV2PairMeta | undefined> {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
import { BaseProvider } from "@ethersproject/providers";
|
||||||
|
import { Contract } from "@ethersproject/contracts";
|
||||||
|
import { IAddressResolver } from "./address-resolver";
|
||||||
|
import { ChecksummedAddress, TokenMeta } from "../../types";
|
||||||
|
import { ERCTokenResolver } from "./ERCTokenResolver";
|
||||||
|
|
||||||
|
const UNISWAP_V3_FACTORY = "0x1F98431c8aD98523631AE4a59f267346ea31F984";
|
||||||
|
|
||||||
|
const UNISWAP_V3_FACTORY_ABI = [
|
||||||
|
"function getPool(address tokenA, address tokenB, uint24 fee) external view returns (address pool)",
|
||||||
|
];
|
||||||
|
|
||||||
|
const UNISWAP_V3_PAIR_ABI = [
|
||||||
|
"function factory() external view returns (address)",
|
||||||
|
"function token0() external view returns (address)",
|
||||||
|
"function token1() external view returns (address)",
|
||||||
|
"function fee() external view returns (uint24)",
|
||||||
|
];
|
||||||
|
|
||||||
|
export type UniswapV3TokenMeta = {
|
||||||
|
address: ChecksummedAddress;
|
||||||
|
} & TokenMeta;
|
||||||
|
|
||||||
|
export type UniswapV3PairMeta = {
|
||||||
|
pair: ChecksummedAddress;
|
||||||
|
token0: UniswapV3TokenMeta;
|
||||||
|
token1: UniswapV3TokenMeta;
|
||||||
|
fee: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ercResolver = new ERCTokenResolver();
|
||||||
|
|
||||||
|
export class UniswapV3Resolver implements IAddressResolver<UniswapV3PairMeta> {
|
||||||
|
async resolveAddress(
|
||||||
|
provider: BaseProvider,
|
||||||
|
address: string
|
||||||
|
): Promise<UniswapV3PairMeta | undefined> {
|
||||||
|
const poolContract = new Contract(address, UNISWAP_V3_PAIR_ABI, provider);
|
||||||
|
const factoryContract = new Contract(
|
||||||
|
UNISWAP_V3_FACTORY,
|
||||||
|
UNISWAP_V3_FACTORY_ABI,
|
||||||
|
provider
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// First, probe the factory() function; if it responds with UniswapV2 factory
|
||||||
|
// address, it may be a pair
|
||||||
|
const factoryAddress = (await poolContract.factory()) as string;
|
||||||
|
if (factoryAddress !== UNISWAP_V3_FACTORY) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Probe the token0/token1/fee
|
||||||
|
const [token0, token1, fee] = await Promise.all([
|
||||||
|
poolContract.token0() as string,
|
||||||
|
poolContract.token1() as string,
|
||||||
|
poolContract.fee() as number,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Probe the factory to ensure it is a legit pair
|
||||||
|
const expectedPoolAddress = await factoryContract.getPool(
|
||||||
|
token0,
|
||||||
|
token1,
|
||||||
|
fee
|
||||||
|
);
|
||||||
|
if (expectedPoolAddress !== address) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 },
|
||||||
|
fee,
|
||||||
|
};
|
||||||
|
} catch (err) {
|
||||||
|
// Ignore on purpose; this indicates the probe failed and the address
|
||||||
|
// is not a token
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,17 @@
|
||||||
"0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f": "Uniswap V2: Factory",
|
"0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f": "Uniswap V2: Factory",
|
||||||
"0xf164fC0Ec4E93095b804a4795bBe1e041497b92a": "Uniswap V2: Router 1",
|
"0xf164fC0Ec4E93095b804a4795bBe1e041497b92a": "Uniswap V2: Router 1",
|
||||||
"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D": "Uniswap V2: Router 2",
|
"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D": "Uniswap V2: Router 2",
|
||||||
"0x1F98431c8aD98523631AE4a59f267346ea31F984": "Uniswap V3: Router",
|
"0x1F98431c8aD98523631AE4a59f267346ea31F984": "Uniswap V3: Factory",
|
||||||
|
"0x5BA1e12693Dc8F9c48aAD8770482f4739bEeD696": "Uniswap V3: Multicall2",
|
||||||
|
"0xB753548F6E010e7e680BA186F9Ca1BdAB2E90cf2": "Uniswap V3: ProxyAdmin",
|
||||||
|
"0xbfd8137f7d1516D3ea5cA83523914859ec47F573": "Uniswap V3: TickLens",
|
||||||
|
"0xb27308f9F90D607463bb33eA1BeBb41C27CE5AB6": "Uniswap V3: Quoter",
|
||||||
|
"0xE592427A0AEce92De3Edee1F18E0157C05861564": "Uniswap V3: Router",
|
||||||
|
"0x42B24A95702b9986e82d421cC3568932790A48Ec": "Uniswap V3: NFT Descriptor",
|
||||||
|
"0x91ae842A5Ffd8d12023116943e72A606179294f3": "Uniswap V3: NFT Position Descriptor",
|
||||||
|
"0xEe6A57eC80ea46401049E92587E52f5Ec1c24785": "Uniswap V3: Transparent Upgradeable Proxy",
|
||||||
|
"0xC36442b4a4522E871399CD717aBDD847Ab11FE88": "Uniswap V3: Nonfungible Position Manager",
|
||||||
|
"0xA5644E29708357803b5A882D272c41cC0dF92B34": "Uniswap V3: V3 Migrator",
|
||||||
"0x722122dF12D4e14e13Ac3b6895a86e84145b6967": "Tornado Cash: Proxy",
|
"0x722122dF12D4e14e13Ac3b6895a86e84145b6967": "Tornado Cash: Proxy",
|
||||||
"0x12D66f87A04A9E220743712cE6d9bB1B5616B8Fc": "Tornado Cash: 0.1 ETH",
|
"0x12D66f87A04A9E220743712cE6d9bB1B5616B8Fc": "Tornado Cash: 0.1 ETH",
|
||||||
"0x47CE0C6eD5B0Ce3d3A51fdb1C52DC66a7c3c2936": "Tornado Cash: 1 ETH",
|
"0x47CE0C6eD5B0Ce3d3A51fdb1C52DC66a7c3c2936": "Tornado Cash: 1 ETH",
|
||||||
|
|
|
@ -2,12 +2,18 @@ import { BaseProvider } from "@ethersproject/providers";
|
||||||
import { ensRenderer } from "../../components/ENSName";
|
import { ensRenderer } from "../../components/ENSName";
|
||||||
import { plainStringRenderer } from "../../components/PlainString";
|
import { plainStringRenderer } from "../../components/PlainString";
|
||||||
import { tokenRenderer } from "../../components/TokenName";
|
import { tokenRenderer } from "../../components/TokenName";
|
||||||
|
import { uniswapV1PairRenderer } from "../../components/UniswapV1ExchangeName";
|
||||||
|
import { uniswapV2PairRenderer } from "../../components/UniswapV2PairName";
|
||||||
|
import { uniswapV3PairRenderer } from "../../components/UniswapV3PoolName";
|
||||||
import { IAddressResolver, ResolvedAddressRenderer } from "./address-resolver";
|
import { IAddressResolver, ResolvedAddressRenderer } from "./address-resolver";
|
||||||
import {
|
import {
|
||||||
CompositeAddressResolver,
|
CompositeAddressResolver,
|
||||||
SelectedResolvedName,
|
SelectedResolvedName,
|
||||||
} from "./CompositeAddressResolver";
|
} from "./CompositeAddressResolver";
|
||||||
import { ENSAddressResolver } from "./ENSAddressResolver";
|
import { ENSAddressResolver } from "./ENSAddressResolver";
|
||||||
|
import { UniswapV1Resolver } from "./UniswapV1Resolver";
|
||||||
|
import { UniswapV2Resolver } from "./UniswapV2Resolver";
|
||||||
|
import { UniswapV3Resolver } from "./UniswapV3Resolver";
|
||||||
import { ERCTokenResolver } from "./ERCTokenResolver";
|
import { ERCTokenResolver } from "./ERCTokenResolver";
|
||||||
import { HardcodedAddressResolver } from "./HardcodedAddressResolver";
|
import { HardcodedAddressResolver } from "./HardcodedAddressResolver";
|
||||||
|
|
||||||
|
@ -15,11 +21,17 @@ export type ResolvedAddresses = Record<string, SelectedResolvedName<any>>;
|
||||||
|
|
||||||
// Create and configure the main resolver
|
// Create and configure the main resolver
|
||||||
export const ensResolver = new ENSAddressResolver();
|
export const ensResolver = new ENSAddressResolver();
|
||||||
|
export const uniswapV1Resolver = new UniswapV1Resolver();
|
||||||
|
export const uniswapV2Resolver = new UniswapV2Resolver();
|
||||||
|
export const uniswapV3Resolver = new UniswapV3Resolver();
|
||||||
export const ercTokenResolver = new ERCTokenResolver();
|
export const ercTokenResolver = new ERCTokenResolver();
|
||||||
export const hardcodedResolver = new HardcodedAddressResolver();
|
export const hardcodedResolver = new HardcodedAddressResolver();
|
||||||
|
|
||||||
const _mainResolver = new CompositeAddressResolver();
|
const _mainResolver = new CompositeAddressResolver();
|
||||||
_mainResolver.addResolver(ensResolver);
|
_mainResolver.addResolver(ensResolver);
|
||||||
|
_mainResolver.addResolver(uniswapV3Resolver);
|
||||||
|
_mainResolver.addResolver(uniswapV2Resolver);
|
||||||
|
_mainResolver.addResolver(uniswapV1Resolver);
|
||||||
_mainResolver.addResolver(ercTokenResolver);
|
_mainResolver.addResolver(ercTokenResolver);
|
||||||
_mainResolver.addResolver(hardcodedResolver);
|
_mainResolver.addResolver(hardcodedResolver);
|
||||||
|
|
||||||
|
@ -31,6 +43,9 @@ export const resolverRendererRegistry = new Map<
|
||||||
ResolvedAddressRenderer<any>
|
ResolvedAddressRenderer<any>
|
||||||
>();
|
>();
|
||||||
resolverRendererRegistry.set(ensResolver, ensRenderer);
|
resolverRendererRegistry.set(ensResolver, ensRenderer);
|
||||||
|
resolverRendererRegistry.set(uniswapV1Resolver, uniswapV1PairRenderer);
|
||||||
|
resolverRendererRegistry.set(uniswapV2Resolver, uniswapV2PairRenderer);
|
||||||
|
resolverRendererRegistry.set(uniswapV3Resolver, uniswapV3PairRenderer);
|
||||||
resolverRendererRegistry.set(ercTokenResolver, tokenRenderer);
|
resolverRendererRegistry.set(ercTokenResolver, tokenRenderer);
|
||||||
resolverRendererRegistry.set(hardcodedResolver, plainStringRenderer);
|
resolverRendererRegistry.set(hardcodedResolver, plainStringRenderer);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
import React from "react";
|
||||||
|
import { NavLink } from "react-router-dom";
|
||||||
|
import TokenLogo from "./TokenLogo";
|
||||||
|
import { ResolvedAddressRenderer } from "../api/address-resolver/address-resolver";
|
||||||
|
import { ChecksummedAddress } from "../types";
|
||||||
|
import {
|
||||||
|
UniswapV1PairMeta,
|
||||||
|
UniswapV1TokenMeta,
|
||||||
|
} from "../api/address-resolver/UniswapV1Resolver";
|
||||||
|
|
||||||
|
type UniswapV1ExchangeNameProps = {
|
||||||
|
address: string;
|
||||||
|
token: UniswapV1TokenMeta;
|
||||||
|
linkable: boolean;
|
||||||
|
dontOverrideColors?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const UniswapV1ExchangeName: React.FC<UniswapV1ExchangeNameProps> = ({
|
||||||
|
address,
|
||||||
|
token,
|
||||||
|
linkable,
|
||||||
|
dontOverrideColors,
|
||||||
|
}) => {
|
||||||
|
if (linkable) {
|
||||||
|
return (
|
||||||
|
<NavLink
|
||||||
|
className={`flex items-baseline space-x-1 font-sans ${
|
||||||
|
dontOverrideColors ? "" : "text-link-blue hover:text-link-blue-hover"
|
||||||
|
} truncate`}
|
||||||
|
to={`/address/${address}`}
|
||||||
|
title={`Uniswap V1 LP (${token.symbol}): ${address}`}
|
||||||
|
>
|
||||||
|
<span>Uniswap V1 LP:</span>
|
||||||
|
<Content
|
||||||
|
linkable={true}
|
||||||
|
address={token.address}
|
||||||
|
name={token.name}
|
||||||
|
symbol={token.symbol}
|
||||||
|
/>
|
||||||
|
</NavLink>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex items-baseline space-x-1 font-sans text-gray-700 truncate"
|
||||||
|
title={`Uniswap V1 LP (${token.symbol}): ${address}`}
|
||||||
|
>
|
||||||
|
<span>Uniswap V1 LP:</span>
|
||||||
|
<Content
|
||||||
|
linkable={false}
|
||||||
|
address={token.address}
|
||||||
|
name={token.name}
|
||||||
|
symbol={token.symbol}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
type ContentProps = {
|
||||||
|
linkable: boolean;
|
||||||
|
address: ChecksummedAddress;
|
||||||
|
name: string;
|
||||||
|
symbol: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Content: React.FC<ContentProps> = ({
|
||||||
|
address,
|
||||||
|
name,
|
||||||
|
symbol,
|
||||||
|
linkable,
|
||||||
|
}) => (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={`self-center w-5 h-5 ${linkable ? "" : "filter grayscale"}`}
|
||||||
|
>
|
||||||
|
<TokenLogo address={address} name={name} />
|
||||||
|
</div>
|
||||||
|
<span>{symbol}</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const uniswapV1PairRenderer: ResolvedAddressRenderer<UniswapV1PairMeta> =
|
||||||
|
(address, tokenMeta, linkable, dontOverrideColors) => (
|
||||||
|
<UniswapV1ExchangeName
|
||||||
|
address={address}
|
||||||
|
token={tokenMeta.token}
|
||||||
|
linkable={linkable}
|
||||||
|
dontOverrideColors={dontOverrideColors}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default UniswapV1ExchangeName;
|
|
@ -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<UniswapV2PairNameProps> = ({
|
||||||
|
address,
|
||||||
|
token0,
|
||||||
|
token1,
|
||||||
|
linkable,
|
||||||
|
dontOverrideColors,
|
||||||
|
}) => {
|
||||||
|
if (linkable) {
|
||||||
|
return (
|
||||||
|
<NavLink
|
||||||
|
className={`flex items-baseline space-x-1 font-sans ${
|
||||||
|
dontOverrideColors ? "" : "text-link-blue hover:text-link-blue-hover"
|
||||||
|
} truncate`}
|
||||||
|
to={`/address/${address}`}
|
||||||
|
title={`Uniswap V2 LP (${token0.symbol}/${token1.symbol}): ${address}`}
|
||||||
|
>
|
||||||
|
<span>Uniswap V2 LP:</span>
|
||||||
|
<Content
|
||||||
|
linkable={true}
|
||||||
|
address={token0.address}
|
||||||
|
name={token0.name}
|
||||||
|
symbol={token0.symbol}
|
||||||
|
/>
|
||||||
|
<span>/</span>
|
||||||
|
<Content
|
||||||
|
linkable={true}
|
||||||
|
address={token1.address}
|
||||||
|
name={token1.name}
|
||||||
|
symbol={token1.symbol}
|
||||||
|
/>
|
||||||
|
</NavLink>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex items-baseline space-x-1 font-sans text-gray-700 truncate"
|
||||||
|
title={`Uniswap V2 LP (${token0.symbol}/${token1.symbol}): ${address}`}
|
||||||
|
>
|
||||||
|
<span>Uniswap V2 LP:</span>
|
||||||
|
<Content
|
||||||
|
linkable={false}
|
||||||
|
address={token0.address}
|
||||||
|
name={token0.name}
|
||||||
|
symbol={token0.symbol}
|
||||||
|
/>
|
||||||
|
<span>/</span>
|
||||||
|
<Content
|
||||||
|
linkable={false}
|
||||||
|
address={token1.address}
|
||||||
|
name={token1.name}
|
||||||
|
symbol={token1.symbol}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
type ContentProps = {
|
||||||
|
linkable: boolean;
|
||||||
|
address: ChecksummedAddress;
|
||||||
|
name: string;
|
||||||
|
symbol: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Content: React.FC<ContentProps> = ({
|
||||||
|
address,
|
||||||
|
name,
|
||||||
|
symbol,
|
||||||
|
linkable,
|
||||||
|
}) => (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={`self-center w-5 h-5 ${linkable ? "" : "filter grayscale"}`}
|
||||||
|
>
|
||||||
|
<TokenLogo address={address} name={name} />
|
||||||
|
</div>
|
||||||
|
<span>{symbol}</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const uniswapV2PairRenderer: ResolvedAddressRenderer<UniswapV2PairMeta> =
|
||||||
|
(address, tokenMeta, linkable, dontOverrideColors) => (
|
||||||
|
<UniswapV2PairName
|
||||||
|
address={address}
|
||||||
|
token0={tokenMeta.token0}
|
||||||
|
token1={tokenMeta.token1}
|
||||||
|
linkable={linkable}
|
||||||
|
dontOverrideColors={dontOverrideColors}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default UniswapV2PairName;
|
|
@ -0,0 +1,119 @@
|
||||||
|
import React from "react";
|
||||||
|
import { NavLink } from "react-router-dom";
|
||||||
|
import TokenLogo from "./TokenLogo";
|
||||||
|
import { ResolvedAddressRenderer } from "../api/address-resolver/address-resolver";
|
||||||
|
import {
|
||||||
|
UniswapV3PairMeta,
|
||||||
|
UniswapV3TokenMeta,
|
||||||
|
} from "../api/address-resolver/UniswapV3Resolver";
|
||||||
|
import { ChecksummedAddress } from "../types";
|
||||||
|
|
||||||
|
type UniswapV3PoolNameProps = {
|
||||||
|
address: string;
|
||||||
|
token0: UniswapV3TokenMeta;
|
||||||
|
token1: UniswapV3TokenMeta;
|
||||||
|
fee: number;
|
||||||
|
linkable: boolean;
|
||||||
|
dontOverrideColors?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
const UniswapV3PairName: React.FC<UniswapV3PoolNameProps> = ({
|
||||||
|
address,
|
||||||
|
token0,
|
||||||
|
token1,
|
||||||
|
fee,
|
||||||
|
linkable,
|
||||||
|
dontOverrideColors,
|
||||||
|
}) => {
|
||||||
|
if (linkable) {
|
||||||
|
return (
|
||||||
|
<NavLink
|
||||||
|
className={`flex items-baseline space-x-1 font-sans ${
|
||||||
|
dontOverrideColors ? "" : "text-link-blue hover:text-link-blue-hover"
|
||||||
|
} truncate`}
|
||||||
|
to={`/address/${address}`}
|
||||||
|
title={`Uniswap V3 LP (${token0.symbol}/${token1.symbol}/${
|
||||||
|
fee / 10000
|
||||||
|
}%): ${address}`}
|
||||||
|
>
|
||||||
|
<span>Uniswap V3 LP:</span>
|
||||||
|
<Content
|
||||||
|
linkable={true}
|
||||||
|
address={token0.address}
|
||||||
|
name={token0.name}
|
||||||
|
symbol={token0.symbol}
|
||||||
|
/>
|
||||||
|
<span>/</span>
|
||||||
|
<Content
|
||||||
|
linkable={true}
|
||||||
|
address={token1.address}
|
||||||
|
name={token1.name}
|
||||||
|
symbol={token1.symbol}
|
||||||
|
/>
|
||||||
|
<span>/ {fee / 10000}%</span>
|
||||||
|
</NavLink>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex items-baseline space-x-1 font-sans text-gray-700 truncate"
|
||||||
|
title={`Uniswap V3 LP (${token0.symbol}/${token1.symbol}/${
|
||||||
|
fee / 10000
|
||||||
|
}%): ${address}`}
|
||||||
|
>
|
||||||
|
<span>Uniswap V3 LP:</span>
|
||||||
|
<Content
|
||||||
|
linkable={false}
|
||||||
|
address={token0.address}
|
||||||
|
name={token0.name}
|
||||||
|
symbol={token0.symbol}
|
||||||
|
/>
|
||||||
|
<span>/</span>
|
||||||
|
<Content
|
||||||
|
linkable={false}
|
||||||
|
address={token1.address}
|
||||||
|
name={token1.name}
|
||||||
|
symbol={token1.symbol}
|
||||||
|
/>
|
||||||
|
<span>/ {fee / 10000}%</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
type ContentProps = {
|
||||||
|
linkable: boolean;
|
||||||
|
address: ChecksummedAddress;
|
||||||
|
name: string;
|
||||||
|
symbol: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Content: React.FC<ContentProps> = ({
|
||||||
|
address,
|
||||||
|
name,
|
||||||
|
symbol,
|
||||||
|
linkable,
|
||||||
|
}) => (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={`self-center w-5 h-5 ${linkable ? "" : "filter grayscale"}`}
|
||||||
|
>
|
||||||
|
<TokenLogo address={address} name={name} />
|
||||||
|
</div>
|
||||||
|
<span>{symbol}</span>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const uniswapV3PairRenderer: ResolvedAddressRenderer<UniswapV3PairMeta> =
|
||||||
|
(address, tokenMeta, linkable, dontOverrideColors) => (
|
||||||
|
<UniswapV3PairName
|
||||||
|
address={address}
|
||||||
|
token0={tokenMeta.token0}
|
||||||
|
token1={tokenMeta.token1}
|
||||||
|
fee={tokenMeta.fee}
|
||||||
|
linkable={linkable}
|
||||||
|
dontOverrideColors={dontOverrideColors}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default UniswapV3PairName;
|
Loading…
Reference in New Issue