Add uniswap V1 support

This commit is contained in:
Willian Mitsuda 2021-12-03 10:04:42 -03:00
parent 0233879011
commit 6a15285a48
3 changed files with 158 additions and 0 deletions

View File

@ -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;
}
}

View File

@ -2,6 +2,7 @@ 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 { uniswapV2PairRenderer } from "../../components/UniswapV2PairName";
import { IAddressResolver, ResolvedAddressRenderer } from "./address-resolver"; import { IAddressResolver, ResolvedAddressRenderer } from "./address-resolver";
import { import {
@ -9,6 +10,7 @@ import {
SelectedResolvedName, SelectedResolvedName,
} from "./CompositeAddressResolver"; } from "./CompositeAddressResolver";
import { ENSAddressResolver } from "./ENSAddressResolver"; import { ENSAddressResolver } from "./ENSAddressResolver";
import { UniswapV1Resolver } from "./UniswapV1Resolver";
import { UniswapV2Resolver } from "./UniswapV2Resolver"; import { UniswapV2Resolver } from "./UniswapV2Resolver";
import { ERCTokenResolver } from "./ERCTokenResolver"; import { ERCTokenResolver } from "./ERCTokenResolver";
import { HardcodedAddressResolver } from "./HardcodedAddressResolver"; import { HardcodedAddressResolver } from "./HardcodedAddressResolver";
@ -18,12 +20,14 @@ 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 uniswapV2Resolver = new UniswapV2Resolver(); export const uniswapV2Resolver = new UniswapV2Resolver();
export const uniswapV1Resolver = new UniswapV1Resolver();
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(uniswapV2Resolver); _mainResolver.addResolver(uniswapV2Resolver);
_mainResolver.addResolver(uniswapV1Resolver);
_mainResolver.addResolver(ercTokenResolver); _mainResolver.addResolver(ercTokenResolver);
_mainResolver.addResolver(hardcodedResolver); _mainResolver.addResolver(hardcodedResolver);
@ -36,6 +40,7 @@ export const resolverRendererRegistry = new Map<
>(); >();
resolverRendererRegistry.set(ensResolver, ensRenderer); resolverRendererRegistry.set(ensResolver, ensRenderer);
resolverRendererRegistry.set(uniswapV2Resolver, uniswapV2PairRenderer); resolverRendererRegistry.set(uniswapV2Resolver, uniswapV2PairRenderer);
resolverRendererRegistry.set(uniswapV1Resolver, uniswapV1PairRenderer);
resolverRendererRegistry.set(ercTokenResolver, tokenRenderer); resolverRendererRegistry.set(ercTokenResolver, tokenRenderer);
resolverRendererRegistry.set(hardcodedResolver, plainStringRenderer); resolverRendererRegistry.set(hardcodedResolver, plainStringRenderer);

View File

@ -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;