First working prototype of contract tab
This commit is contained in:
parent
3842518e3e
commit
38f76e9e2b
|
@ -30,15 +30,18 @@
|
|||
"@types/react": "^17.0.19",
|
||||
"@types/react-blockies": "^1.4.1",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@types/react-highlight": "^0.12.3",
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
"chart.js": "^3.5.1",
|
||||
"ethers": "^5.4.1",
|
||||
"highlightjs-solidity": "^1.2.0",
|
||||
"query-string": "^7.0.1",
|
||||
"react": "^17.0.2",
|
||||
"react-blockies": "^1.4.1",
|
||||
"react-chartjs-2": "^3.0.4",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-error-boundary": "^3.1.3",
|
||||
"react-highlight": "^0.14.0",
|
||||
"react-image": "^4.0.3",
|
||||
"react-router-dom": "^5.2.1",
|
||||
"react-scripts": "4.0.3",
|
||||
|
@ -3103,6 +3106,14 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-highlight": {
|
||||
"version": "0.12.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-highlight/-/react-highlight-0.12.3.tgz",
|
||||
"integrity": "sha512-mfhuHdE3dUjvRv1lvZIvda2B+VW7rkG1ufnFLKbDcRUp/L73bGUmEuEfpnjgdLgeWYho88ahQZRcMSh9GsZA0g==",
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-router": {
|
||||
"version": "5.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.15.tgz",
|
||||
|
@ -9207,6 +9218,19 @@
|
|||
"version": "1.1.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/highlight.js": {
|
||||
"version": "10.7.3",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/highlightjs-solidity": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-1.2.0.tgz",
|
||||
"integrity": "sha512-KXYcVzBRof3CBWHsxGffsSEAJF0YsPaOk1jgIYv2xSzrBSxkfNUJFXrlE2oZEWvYQKbPqLe4qprJyNbSDV+LZA=="
|
||||
},
|
||||
"node_modules/history": {
|
||||
"version": "4.10.1",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
|
||||
|
@ -14419,6 +14443,18 @@
|
|||
"version": "6.0.9",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/react-highlight": {
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-highlight/-/react-highlight-0.14.0.tgz",
|
||||
"integrity": "sha512-kWE+KXOXidS7SABhVopOgMnowbI3RAfeGZbnrduLNlWrYAED8sycL9l/Fvw3w0PFpIIawB7mRDnyhDcM/cIIGA==",
|
||||
"dependencies": {
|
||||
"highlight.js": "^10.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^15.0.0 || ^16.0.0 || ^17.0.0",
|
||||
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-image": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-image/-/react-image-4.0.3.tgz",
|
||||
|
@ -21465,6 +21501,14 @@
|
|||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-highlight": {
|
||||
"version": "0.12.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-highlight/-/react-highlight-0.12.3.tgz",
|
||||
"integrity": "sha512-mfhuHdE3dUjvRv1lvZIvda2B+VW7rkG1ufnFLKbDcRUp/L73bGUmEuEfpnjgdLgeWYho88ahQZRcMSh9GsZA0g==",
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/react-router": {
|
||||
"version": "5.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.15.tgz",
|
||||
|
@ -25605,6 +25649,16 @@
|
|||
"hex-color-regex": {
|
||||
"version": "1.1.0"
|
||||
},
|
||||
"highlight.js": {
|
||||
"version": "10.7.3",
|
||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
|
||||
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="
|
||||
},
|
||||
"highlightjs-solidity": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/highlightjs-solidity/-/highlightjs-solidity-1.2.0.tgz",
|
||||
"integrity": "sha512-KXYcVzBRof3CBWHsxGffsSEAJF0YsPaOk1jgIYv2xSzrBSxkfNUJFXrlE2oZEWvYQKbPqLe4qprJyNbSDV+LZA=="
|
||||
},
|
||||
"history": {
|
||||
"version": "4.10.1",
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
|
||||
|
@ -29065,6 +29119,14 @@
|
|||
"react-error-overlay": {
|
||||
"version": "6.0.9"
|
||||
},
|
||||
"react-highlight": {
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-highlight/-/react-highlight-0.14.0.tgz",
|
||||
"integrity": "sha512-kWE+KXOXidS7SABhVopOgMnowbI3RAfeGZbnrduLNlWrYAED8sycL9l/Fvw3w0PFpIIawB7mRDnyhDcM/cIIGA==",
|
||||
"requires": {
|
||||
"highlight.js": "^10.5.0"
|
||||
}
|
||||
},
|
||||
"react-image": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-image/-/react-image-4.0.3.tgz",
|
||||
|
|
|
@ -25,15 +25,18 @@
|
|||
"@types/react": "^17.0.19",
|
||||
"@types/react-blockies": "^1.4.1",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"@types/react-highlight": "^0.12.3",
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
"chart.js": "^3.5.1",
|
||||
"ethers": "^5.4.1",
|
||||
"highlightjs-solidity": "^1.2.0",
|
||||
"query-string": "^7.0.1",
|
||||
"react": "^17.0.2",
|
||||
"react-blockies": "^1.4.1",
|
||||
"react-chartjs-2": "^3.0.4",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-error-boundary": "^3.1.3",
|
||||
"react-highlight": "^0.14.0",
|
||||
"react-image": "^4.0.3",
|
||||
"react-router-dom": "^5.2.1",
|
||||
"react-scripts": "4.0.3",
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import React, { useState, useEffect, useMemo, useContext } from "react";
|
||||
import { useParams, useLocation, useHistory } from "react-router-dom";
|
||||
import {
|
||||
useParams,
|
||||
useLocation,
|
||||
useHistory,
|
||||
Switch,
|
||||
Route,
|
||||
} from "react-router-dom";
|
||||
import { BlockTag } from "@ethersproject/abstract-provider";
|
||||
import { getAddress, isAddress } from "@ethersproject/address";
|
||||
import queryString from "query-string";
|
||||
|
@ -8,6 +14,9 @@ import StandardFrame from "./StandardFrame";
|
|||
import StandardSubtitle from "./StandardSubtitle";
|
||||
import Copy from "./components/Copy";
|
||||
import ContentFrame from "./ContentFrame";
|
||||
import TabGroup from "./components/TabGroup";
|
||||
import Tab from "./components/Tab";
|
||||
import Contract from "./address/Contract";
|
||||
import UndefinedPageControl from "./search/UndefinedPageControl";
|
||||
import ResultHeader from "./search/ResultHeader";
|
||||
import PendingResults from "./search/PendingResults";
|
||||
|
@ -194,59 +203,79 @@ const AddressTransactions: React.FC = () => {
|
|||
)}
|
||||
</div>
|
||||
</StandardSubtitle>
|
||||
<ContentFrame>
|
||||
<div className="flex justify-between items-baseline py-3">
|
||||
<div className="text-sm text-gray-500">
|
||||
{page === undefined ? (
|
||||
<>Waiting for search results...</>
|
||||
) : (
|
||||
<>{page.length} transactions on this page</>
|
||||
)}
|
||||
</div>
|
||||
<UndefinedPageControl
|
||||
address={params.addressOrName}
|
||||
isFirst={controller?.isFirst}
|
||||
isLast={controller?.isLast}
|
||||
prevHash={page ? page[0].hash : ""}
|
||||
nextHash={page ? page[page.length - 1].hash : ""}
|
||||
disabled={controller === undefined}
|
||||
/>
|
||||
</div>
|
||||
<ResultHeader
|
||||
feeDisplay={feeDisplay}
|
||||
feeDisplayToggler={feeDisplayToggler}
|
||||
/>
|
||||
{controller ? (
|
||||
<SelectionContext.Provider value={selectionCtx}>
|
||||
{controller.getPage().map((tx) => (
|
||||
<TransactionItem
|
||||
key={tx.hash}
|
||||
tx={tx}
|
||||
ensCache={reverseCache}
|
||||
selectedAddress={checksummedAddress}
|
||||
feeDisplay={feeDisplay}
|
||||
priceMap={priceMap}
|
||||
/>
|
||||
))}
|
||||
<TabGroup>
|
||||
<Tab href={`/address/${checksummedAddress}`}>Overview</Tab>
|
||||
<Tab href={`/address/${checksummedAddress}/contract`}>
|
||||
Contract
|
||||
</Tab>
|
||||
</TabGroup>
|
||||
<Switch>
|
||||
<Route path="/address/:addressOrName" exact>
|
||||
<ContentFrame tabs>
|
||||
<div className="flex justify-between items-baseline py-3">
|
||||
<div className="text-sm text-gray-500">
|
||||
{page !== undefined && (
|
||||
{page === undefined ? (
|
||||
<>Waiting for search results...</>
|
||||
) : (
|
||||
<>{page.length} transactions on this page</>
|
||||
)}
|
||||
</div>
|
||||
<UndefinedPageControl
|
||||
address={params.addressOrName}
|
||||
isFirst={controller.isFirst}
|
||||
isLast={controller.isLast}
|
||||
isFirst={controller?.isFirst}
|
||||
isLast={controller?.isLast}
|
||||
prevHash={page ? page[0].hash : ""}
|
||||
nextHash={page ? page[page.length - 1].hash : ""}
|
||||
disabled={controller === undefined}
|
||||
/>
|
||||
</div>
|
||||
</SelectionContext.Provider>
|
||||
) : (
|
||||
<PendingResults />
|
||||
)}
|
||||
</ContentFrame>
|
||||
<ResultHeader
|
||||
feeDisplay={feeDisplay}
|
||||
feeDisplayToggler={feeDisplayToggler}
|
||||
/>
|
||||
{controller ? (
|
||||
<SelectionContext.Provider value={selectionCtx}>
|
||||
{controller.getPage().map((tx) => (
|
||||
<TransactionItem
|
||||
key={tx.hash}
|
||||
tx={tx}
|
||||
ensCache={reverseCache}
|
||||
selectedAddress={checksummedAddress}
|
||||
feeDisplay={feeDisplay}
|
||||
priceMap={priceMap}
|
||||
/>
|
||||
))}
|
||||
<div className="flex justify-between items-baseline py-3">
|
||||
<div className="text-sm text-gray-500">
|
||||
{page === undefined ? (
|
||||
<>Waiting for search results...</>
|
||||
) : (
|
||||
<>{page.length} transactions on this page</>
|
||||
)}
|
||||
</div>
|
||||
<UndefinedPageControl
|
||||
address={params.addressOrName}
|
||||
isFirst={controller?.isFirst}
|
||||
isLast={controller?.isLast}
|
||||
prevHash={page ? page[0].hash : ""}
|
||||
nextHash={page ? page[page.length - 1].hash : ""}
|
||||
disabled={controller === undefined}
|
||||
/>
|
||||
</div>
|
||||
<ResultHeader
|
||||
feeDisplay={feeDisplay}
|
||||
feeDisplayToggler={feeDisplayToggler}
|
||||
/>
|
||||
</SelectionContext.Provider>
|
||||
) : (
|
||||
<PendingResults />
|
||||
)}
|
||||
</ContentFrame>
|
||||
</Route>
|
||||
<Route path="/address/:addressOrName/contract" exact>
|
||||
<Contract checksummedAddress={checksummedAddress} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Route, Switch, useParams } from "react-router-dom";
|
|||
import StandardFrame from "./StandardFrame";
|
||||
import StandardSubtitle from "./StandardSubtitle";
|
||||
import ContentFrame from "./ContentFrame";
|
||||
import TabGroup from "./components/TabGroup";
|
||||
import Tab from "./components/Tab";
|
||||
import Details from "./transaction/Details";
|
||||
import Logs from "./transaction/Logs";
|
||||
|
@ -55,14 +56,14 @@ const Transaction: React.FC = () => {
|
|||
)}
|
||||
{txData && (
|
||||
<SelectionContext.Provider value={selectionCtx}>
|
||||
<div className="flex space-x-2 border-l border-r border-t rounded-t-lg bg-white">
|
||||
<TabGroup>
|
||||
<Tab href={`/tx/${txhash}`}>Overview</Tab>
|
||||
{txData.confirmedData?.blockNumber !== undefined && (
|
||||
<Tab href={`/tx/${txhash}/logs`}>
|
||||
Logs{txData && ` (${txData.confirmedData?.logs?.length ?? 0})`}
|
||||
</Tab>
|
||||
)}
|
||||
</div>
|
||||
</TabGroup>
|
||||
<Switch>
|
||||
<Route path="/tx/:txhash/" exact>
|
||||
<Details
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import ContentFrame from "../ContentFrame";
|
||||
import Highlight from "react-highlight";
|
||||
|
||||
import "highlight.js/styles/stackoverflow-light.css";
|
||||
import hljs from "highlight.js";
|
||||
import hljsDefineSolidity from "highlightjs-solidity";
|
||||
hljsDefineSolidity(hljs);
|
||||
hljs.initHighlightingOnLoad();
|
||||
|
||||
type ContractProps = {
|
||||
checksummedAddress: string;
|
||||
};
|
||||
|
||||
const Contract: React.FC<ContractProps> = ({ checksummedAddress }) => {
|
||||
const [sources, setSources] = useState<
|
||||
{ [fileName: string]: any } | undefined | null
|
||||
>(undefined);
|
||||
useEffect(() => {
|
||||
if (!checksummedAddress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchMetadata = async () => {
|
||||
try {
|
||||
const result = await fetch(
|
||||
`https://repo.sourcify.dev/contracts/full_match/1/${checksummedAddress}/metadata.json`
|
||||
);
|
||||
if (result.ok) {
|
||||
const json = await result.json();
|
||||
console.log(json);
|
||||
setSources(json.sources);
|
||||
setSelected(Object.keys(json.sources)[0]);
|
||||
} else {
|
||||
setSources(null);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setSources(null);
|
||||
}
|
||||
};
|
||||
fetchMetadata();
|
||||
}, [checksummedAddress]);
|
||||
|
||||
const [selected, setSelected] = useState<string>();
|
||||
|
||||
return (
|
||||
<ContentFrame tabs>
|
||||
<div className="py-5">
|
||||
{sources === null && (
|
||||
<span>Couldn't find contract metadata in Sourcify repository.</span>
|
||||
)}
|
||||
{sources !== undefined && sources !== null && (
|
||||
<>
|
||||
{Object.entries(sources).map(([k]) => (
|
||||
<button
|
||||
className={`border-b-2 border-transparent rounded-t text-sm px-2 py-1 bg-gray-200 text-gray-500 ${
|
||||
selected === k ? "border-orange-300 font-bold" : ""
|
||||
}`}
|
||||
>
|
||||
{k}
|
||||
</button>
|
||||
))}
|
||||
{selected && (
|
||||
<Highlight className="w-full h-full border focus:outline-none font-code text-base">
|
||||
{sources[selected].content}
|
||||
</Highlight>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</ContentFrame>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Contract);
|
|
@ -0,0 +1,7 @@
|
|||
const TabGroup: React.FC = ({ children }) => (
|
||||
<div className="flex space-x-2 border-l border-r border-t rounded-t-lg bg-white">
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
|
||||
export default TabGroup;
|
|
@ -1,2 +1,3 @@
|
|||
/// <reference types="react-scripts" />
|
||||
declare module "use-keyboard-shortcut";
|
||||
declare module "highlightjs-solidity";
|
||||
|
|
|
@ -27,6 +27,7 @@ module.exports = {
|
|||
data: ["Roboto Mono"],
|
||||
balance: ["Fira Code"],
|
||||
blocknum: ["Roboto"],
|
||||
code: ["Fira Code"],
|
||||
},
|
||||
borderColor: {
|
||||
skin: {
|
||||
|
|
Loading…
Reference in New Issue