Merge branch 'feature/initial-ens-support' into develop
This commit is contained in:
commit
f4d74494c6
|
@ -1,5 +1,6 @@
|
|||
import React, { useState, useEffect, useMemo } from "react";
|
||||
import { useParams, useLocation, useHistory } from "react-router-dom";
|
||||
import { ethers } from "ethers";
|
||||
import queryString from "query-string";
|
||||
import Blockies from "react-blockies";
|
||||
import StandardFrame from "./StandardFrame";
|
||||
|
@ -12,10 +13,10 @@ import PendingResults from "./search/PendingResults";
|
|||
import TransactionItem from "./search/TransactionItem";
|
||||
import { SearchController } from "./search/search";
|
||||
import { useFeeToggler } from "./search/useFeeToggler";
|
||||
import { ethers } from "ethers";
|
||||
import { provider } from "./ethersconfig";
|
||||
|
||||
type BlockParams = {
|
||||
address: string;
|
||||
addressOrName: string;
|
||||
direction?: string;
|
||||
};
|
||||
|
||||
|
@ -33,13 +34,37 @@ const AddressTransactions: React.FC = () => {
|
|||
hash = qs.h as string;
|
||||
}
|
||||
|
||||
const [checksummedAddress, setChecksummedAddress] = useState<string>();
|
||||
const [isENS, setENS] = useState<boolean>();
|
||||
const [error, setError] = useState<boolean>();
|
||||
|
||||
// If it looks like it is an ENS name, try to resolve it
|
||||
useEffect(() => {
|
||||
if (ethers.utils.isAddress(params.addressOrName)) {
|
||||
// Normalize to checksummed address
|
||||
const checksummedAddress = useMemo(
|
||||
() => ethers.utils.getAddress(params.address),
|
||||
[params.address]
|
||||
);
|
||||
if (params.address !== checksummedAddress) {
|
||||
console.log("NORMALIZE");
|
||||
setChecksummedAddress(ethers.utils.getAddress(params.addressOrName));
|
||||
return;
|
||||
}
|
||||
|
||||
const resolveName = async () => {
|
||||
const resolvedAddress = await provider.resolveName(params.addressOrName);
|
||||
if (resolvedAddress !== null) {
|
||||
setENS(true);
|
||||
setChecksummedAddress(resolvedAddress);
|
||||
setError(false);
|
||||
} else {
|
||||
setError(true);
|
||||
}
|
||||
};
|
||||
resolveName();
|
||||
}, [params.addressOrName]);
|
||||
|
||||
// Request came with a non-checksummed address; fix the URL
|
||||
if (
|
||||
!isENS &&
|
||||
checksummedAddress &&
|
||||
params.addressOrName !== checksummedAddress
|
||||
) {
|
||||
history.replace(
|
||||
`/address/${checksummedAddress}${
|
||||
params.direction ? "/" + params.direction : ""
|
||||
|
@ -49,6 +74,10 @@ const AddressTransactions: React.FC = () => {
|
|||
|
||||
const [controller, setController] = useState<SearchController>();
|
||||
useEffect(() => {
|
||||
if (!checksummedAddress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const readFirstPage = async () => {
|
||||
const _controller = await SearchController.firstPage(checksummedAddress);
|
||||
setController(_controller);
|
||||
|
@ -100,24 +129,36 @@ const AddressTransactions: React.FC = () => {
|
|||
|
||||
const page = useMemo(() => controller?.getPage(), [controller]);
|
||||
|
||||
document.title = `Address ${params.address} | Otterscan`;
|
||||
document.title = `Address ${params.addressOrName} | Otterscan`;
|
||||
|
||||
const [feeDisplay, feeDisplayToggler] = useFeeToggler();
|
||||
|
||||
return (
|
||||
<StandardFrame>
|
||||
{error ? (
|
||||
<span className="text-base">
|
||||
"{params.addressOrName}" is not an ETH address or ENS name.
|
||||
</span>
|
||||
) : (
|
||||
checksummedAddress && (
|
||||
<>
|
||||
<StandardSubtitle>
|
||||
<div className="flex space-x-2 items-baseline">
|
||||
<Blockies
|
||||
className="self-center rounded"
|
||||
seed={params.address.toLowerCase()}
|
||||
seed={checksummedAddress.toLowerCase()}
|
||||
scale={3}
|
||||
/>
|
||||
<span>Address</span>
|
||||
<span className="font-address text-base text-gray-500">
|
||||
{params.address}
|
||||
{checksummedAddress}
|
||||
</span>
|
||||
<Copy value={params.address} rounded />
|
||||
<Copy value={checksummedAddress} rounded />
|
||||
{isENS && (
|
||||
<span className="rounded-lg px-2 py-1 bg-gray-200 text-gray-500 text-xs">
|
||||
ENS: {params.addressOrName}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</StandardSubtitle>
|
||||
<ContentFrame>
|
||||
|
@ -130,7 +171,7 @@ const AddressTransactions: React.FC = () => {
|
|||
)}
|
||||
</div>
|
||||
<UndefinedPageControl
|
||||
address={params.address}
|
||||
address={params.addressOrName}
|
||||
isFirst={controller?.isFirst}
|
||||
isLast={controller?.isLast}
|
||||
prevHash={page ? page[0].hash : ""}
|
||||
|
@ -148,7 +189,7 @@ const AddressTransactions: React.FC = () => {
|
|||
<TransactionItem
|
||||
key={tx.hash}
|
||||
tx={tx}
|
||||
selectedAddress={params.address}
|
||||
selectedAddress={checksummedAddress}
|
||||
feeDisplay={feeDisplay}
|
||||
/>
|
||||
))}
|
||||
|
@ -159,7 +200,7 @@ const AddressTransactions: React.FC = () => {
|
|||
)}
|
||||
</div>
|
||||
<UndefinedPageControl
|
||||
address={params.address}
|
||||
address={params.addressOrName}
|
||||
isFirst={controller.isFirst}
|
||||
isLast={controller.isLast}
|
||||
prevHash={page ? page[0].hash : ""}
|
||||
|
@ -171,6 +212,9 @@ const AddressTransactions: React.FC = () => {
|
|||
<PendingResults />
|
||||
)}
|
||||
</ContentFrame>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
</StandardFrame>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -30,7 +30,7 @@ const App = () => (
|
|||
<Route path="/tx/:txhash">
|
||||
<Transaction />
|
||||
</Route>
|
||||
<Route path="/address/:address/:direction?">
|
||||
<Route path="/address/:addressOrName/:direction?">
|
||||
<AddressTransactions />
|
||||
</Route>
|
||||
</Route>
|
||||
|
|
|
@ -64,8 +64,9 @@ const Home: React.FC = () => {
|
|||
className="w-full border rounded focus:outline-none px-2 py-1 mb-10"
|
||||
type="text"
|
||||
size={50}
|
||||
placeholder="Search by address / txn hash / block number"
|
||||
placeholder="Search by address / txn hash / block number / ENS name"
|
||||
onChange={handleChange}
|
||||
autoFocus
|
||||
></input>
|
||||
<button
|
||||
className="mx-auto px-3 py-1 mb-10 rounded bg-gray-100 hover:bg-gray-200 focus:outline-none"
|
||||
|
|
|
@ -27,7 +27,8 @@ const Search: React.FC = () => {
|
|||
return <></>;
|
||||
}
|
||||
|
||||
history.replace("/");
|
||||
// Assume it is an ENS name
|
||||
history.replace(`/address/${q}`);
|
||||
return <></>;
|
||||
};
|
||||
|
||||
|
|
|
@ -50,8 +50,8 @@ const Title: React.FC = () => {
|
|||
<input
|
||||
className="w-full border-t border-b border-l rounded-l focus:outline-none px-2 py-1 text-sm"
|
||||
type="text"
|
||||
size={50}
|
||||
placeholder='Type "/" to search by address / txn hash / block number'
|
||||
size={60}
|
||||
placeholder='Type "/" to search by address / txn hash / block number / ENS name'
|
||||
onChange={handleChange}
|
||||
ref={searchRef}
|
||||
/>
|
||||
|
|
Loading…
Reference in New Issue