Extract and generalize ETH address fixing logic

This commit is contained in:
Willian Mitsuda 2021-11-25 16:20:44 -03:00
parent d9592fe196
commit 3bfe0d0055
2 changed files with 85 additions and 51 deletions

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect, useContext } from "react"; import React, { useEffect, useContext, useCallback } from "react";
import { import {
useParams, useParams,
useNavigate, useNavigate,
@ -6,7 +6,6 @@ import {
Route, Route,
useSearchParams, useSearchParams,
} from "react-router-dom"; } from "react-router-dom";
import { getAddress, isAddress } from "@ethersproject/address";
import { Tab } from "@headlessui/react"; import { Tab } from "@headlessui/react";
import Blockies from "react-blockies"; import Blockies from "react-blockies";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@ -21,7 +20,9 @@ import AddressTransactionResults from "./address/AddressTransactionResults";
import Contracts from "./address/Contracts"; import Contracts from "./address/Contracts";
import { RuntimeContext } from "./useRuntime"; import { RuntimeContext } from "./useRuntime";
import { useAppConfigContext } from "./useAppConfig"; import { useAppConfigContext } from "./useAppConfig";
import { useAddressOrENSFromURL } from "./useResolvedAddresses";
import { useSingleMetadata } from "./sourcify/useSourcify"; import { useSingleMetadata } from "./sourcify/useSourcify";
import { ChecksummedAddress } from "./types";
const AddressTransactions: React.FC = () => { const AddressTransactions: React.FC = () => {
const { provider } = useContext(RuntimeContext); const { provider } = useContext(RuntimeContext);
@ -32,56 +33,29 @@ const AddressTransactions: React.FC = () => {
const navigate = useNavigate(); const navigate = useNavigate();
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const urlFixer = useCallback(
(address: ChecksummedAddress) => {
navigate(
`/address/${address}${
direction ? "/" + direction : ""
}?${searchParams.toString()}`,
{ replace: true }
);
},
[navigate, direction, searchParams]
);
const [checksummedAddress, isENS, error] = useAddressOrENSFromURL(
addressOrName,
urlFixer
);
const [checksummedAddress, setChecksummedAddress] = useState<
string | undefined
>();
const [isENS, setENS] = useState<boolean>();
const [error, setError] = useState<boolean>();
// If it looks like it is an ENS name, try to resolve it
useEffect(() => { useEffect(() => {
// TODO: handle and offer fallback to bad checksummed addresses if (isENS || checksummedAddress === undefined) {
if (isAddress(addressOrName)) { document.title = `Address ${addressOrName} | Otterscan`;
setENS(false); } else {
setError(false); document.title = `Address ${checksummedAddress} | Otterscan`;
// Normalize to checksummed address
const _checksummedAddress = getAddress(addressOrName);
if (_checksummedAddress !== addressOrName) {
// Request came with a non-checksummed address; fix the URL
navigate(
`/address/${_checksummedAddress}${
direction ? "/" + direction : ""
}?${searchParams.toString()}`,
{ replace: true }
);
return;
}
setChecksummedAddress(_checksummedAddress);
document.title = `Address ${_checksummedAddress} | Otterscan`;
return;
} }
}, [addressOrName, checksummedAddress, isENS]);
if (!provider) {
return;
}
const resolveName = async () => {
const resolvedAddress = await provider.resolveName(addressOrName);
if (resolvedAddress !== null) {
setENS(true);
setError(false);
setChecksummedAddress(resolvedAddress);
document.title = `Address ${addressOrName} | Otterscan`;
} else {
setENS(false);
setError(true);
setChecksummedAddress(undefined);
}
};
resolveName();
}, [provider, addressOrName, navigate, direction, searchParams]);
const { sourcifySource } = useAppConfigContext(); const { sourcifySource } = useAppConfigContext();
const addressMetadata = useSingleMetadata( const addressMetadata = useSingleMetadata(

View File

@ -1,8 +1,68 @@
import { useState, useEffect, useRef } from "react"; import { useState, useEffect, useRef, useContext } from "react";
import { JsonRpcProvider } from "@ethersproject/providers"; import { JsonRpcProvider } from "@ethersproject/providers";
import { ProcessedTransaction, TransactionData } from "./types"; import { getAddress, isAddress } from "@ethersproject/address";
import { batchPopulate, ResolvedAddresses } from "./api/address-resolver"; import { batchPopulate, ResolvedAddresses } from "./api/address-resolver";
import { TraceGroup } from "./useErigonHooks"; import { TraceGroup } from "./useErigonHooks";
import { RuntimeContext } from "./useRuntime";
import {
ChecksummedAddress,
ProcessedTransaction,
TransactionData,
} from "./types";
export const useAddressOrENSFromURL = (
addressOrName: string,
urlFixer: (address: ChecksummedAddress) => void
): [
ChecksummedAddress | undefined,
boolean | undefined,
boolean | undefined
] => {
const { provider } = useContext(RuntimeContext);
const [checksummedAddress, setChecksummedAddress] = useState<
ChecksummedAddress | undefined
>();
const [isENS, setENS] = useState<boolean>();
const [error, setError] = useState<boolean>();
// If it looks like it is an ENS name, try to resolve it
useEffect(() => {
// TODO: handle and offer fallback to bad checksummed addresses
if (isAddress(addressOrName)) {
// Normalize to checksummed address
const _checksummedAddress = getAddress(addressOrName);
if (_checksummedAddress !== addressOrName) {
// Request came with a non-checksummed address; fix the URL
urlFixer(_checksummedAddress);
return;
}
setENS(false);
setError(false);
setChecksummedAddress(_checksummedAddress);
return;
}
if (!provider) {
return;
}
const resolveName = async () => {
const resolvedAddress = await provider.resolveName(addressOrName);
if (resolvedAddress !== null) {
setENS(true);
setError(false);
setChecksummedAddress(resolvedAddress);
} else {
setENS(false);
setError(true);
setChecksummedAddress(undefined);
}
};
resolveName();
}, [provider, addressOrName, urlFixer]);
return [checksummedAddress, isENS, error];
};
export type AddressCollector = () => string[]; export type AddressCollector = () => string[];