Convert token metadata logic into SWR fetcher

This commit is contained in:
Willian Mitsuda 2022-08-23 17:29:54 -03:00
parent 21a549b3e1
commit 9683edf050
No known key found for this signature in database
4 changed files with 58 additions and 42 deletions

View File

@ -6,24 +6,21 @@ import TransactionAddress from "./components/TransactionAddress";
import ValueHighlighter from "./components/ValueHighlighter";
import FormattedBalance from "./components/FormattedBalance";
import USDAmount from "./components/USDAmount";
import { AddressContext, TokenMeta, TokenTransfer } from "./types";
import { RuntimeContext } from "./useRuntime";
import { useBlockNumberContext } from "./useBlockTagContext";
import { useTokenMetadata } from "./useErigonHooks";
import { useTokenUSDOracle } from "./usePriceOracle";
import { AddressContext, TokenTransfer } from "./types";
type TokenTransferItemProps = {
t: TokenTransfer;
tokenMeta?: TokenMeta | null | undefined;
};
// TODO: handle partial
const TokenTransferItem: React.FC<TokenTransferItemProps> = ({
t,
tokenMeta,
}) => {
const TokenTransferItem: React.FC<TokenTransferItemProps> = ({ t }) => {
const { provider } = useContext(RuntimeContext);
const blockNumber = useBlockNumberContext();
const [quote, decimals] = useTokenUSDOracle(provider, blockNumber, t.token);
const tokenMeta = useTokenMetadata(provider, t.token);
return (
<div className="flex items-baseline space-x-2 px-2 py-1 truncate hover:bg-gray-100">

View File

@ -285,11 +285,7 @@ const Details: React.FC<DetailsProps> = ({ txData }) => {
{txData.tokenTransfers.length > 0 && (
<InfoRow title={`Tokens Transferred (${txData.tokenTransfers.length})`}>
{txData.tokenTransfers.map((t, i) => (
<TokenTransferItem
key={i}
t={t}
tokenMeta={txData.tokenMetas[t.token]}
/>
<TokenTransferItem key={i} t={t} />
))}
</InfoRow>
)}

View File

@ -37,7 +37,6 @@ export type TransactionData = {
to?: string;
value: BigNumber;
tokenTransfers: TokenTransfer[];
tokenMetas: TokenMetas;
type: number;
maxFeePerGas?: BigNumber | undefined;
maxPriorityFeePerGas?: BigNumber | undefined;

View File

@ -13,13 +13,13 @@ import { arrayify, hexDataSlice, isHexString } from "@ethersproject/bytes";
import useSWR from "swr";
import useSWRImmutable from "swr/immutable";
import {
TokenMetas,
TokenTransfer,
TransactionData,
InternalOperation,
ProcessedTransaction,
OperationType,
ChecksummedAddress,
TokenMeta,
} from "./types";
import erc20 from "./erc20.json";
@ -216,40 +216,12 @@ export const useTxData = (
}
}
// Extract token meta
const tokenMetas: TokenMetas = {};
for (const t of tokenTransfers) {
if (tokenMetas[t.token] !== undefined) {
continue;
}
const erc20Contract = new Contract(t.token, erc20, provider);
try {
const [name, symbol, decimals] = await Promise.all([
erc20Contract.name(),
erc20Contract.symbol(),
erc20Contract.decimals(),
]);
tokenMetas[t.token] = {
name,
symbol,
decimals,
};
} catch (err) {
tokenMetas[t.token] = null;
console.warn(
`Couldn't get token ${t.token} metadata; ignoring`,
err
);
}
}
setTxData({
transactionHash: _response.hash,
from: _response.from,
to: _response.to,
value: _response.value,
tokenTransfers,
tokenMetas,
type: _response.type ?? 0,
maxFeePerGas: _response.maxFeePerGas,
maxPriorityFeePerGas: _response.maxPriorityFeePerGas,
@ -665,3 +637,55 @@ export const useHasCode = (
}
return data as boolean | undefined;
};
const tokenMetadataFetcher =
(provider: JsonRpcProvider | undefined) =>
async (
_: "tokenmeta",
address: ChecksummedAddress
): Promise<TokenMeta | null> => {
const erc20Contract = new Contract(address, erc20, provider);
try {
const name = (await erc20Contract.name()) as string;
if (!name.trim()) {
return null;
}
const [symbol, decimals] = (await Promise.all([
erc20Contract.symbol(),
erc20Contract.decimals(),
])) as [string, number];
// Prevent faulty tokens with empty name/symbol
if (!symbol.trim()) {
return null;
}
return {
name,
symbol,
decimals,
};
} catch (err) {
// Ignore on purpose; this indicates the probe failed and the address
// is not a token
return null;
}
};
export const useTokenMetadata = (
provider: JsonRpcProvider | undefined,
address: ChecksummedAddress | undefined
): TokenMeta | null | undefined => {
const fetcher = tokenMetadataFetcher(provider);
const { data, error } = useSWRImmutable(
provider !== undefined && address !== undefined
? ["tokenmeta", address]
: null,
fetcher
);
if (error) {
return undefined;
}
return data;
};