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": "^17.0.19",
|
||||||
"@types/react-blockies": "^1.4.1",
|
"@types/react-blockies": "^1.4.1",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.9",
|
||||||
|
"@types/react-highlight": "^0.12.3",
|
||||||
"@types/react-router-dom": "^5.1.8",
|
"@types/react-router-dom": "^5.1.8",
|
||||||
"chart.js": "^3.5.1",
|
"chart.js": "^3.5.1",
|
||||||
"ethers": "^5.4.1",
|
"ethers": "^5.4.1",
|
||||||
|
"highlightjs-solidity": "^1.2.0",
|
||||||
"query-string": "^7.0.1",
|
"query-string": "^7.0.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-blockies": "^1.4.1",
|
"react-blockies": "^1.4.1",
|
||||||
"react-chartjs-2": "^3.0.4",
|
"react-chartjs-2": "^3.0.4",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-error-boundary": "^3.1.3",
|
"react-error-boundary": "^3.1.3",
|
||||||
|
"react-highlight": "^0.14.0",
|
||||||
"react-image": "^4.0.3",
|
"react-image": "^4.0.3",
|
||||||
"react-router-dom": "^5.2.1",
|
"react-router-dom": "^5.2.1",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
|
@ -3103,6 +3106,14 @@
|
||||||
"@types/react": "*"
|
"@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": {
|
"node_modules/@types/react-router": {
|
||||||
"version": "5.1.15",
|
"version": "5.1.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.15.tgz",
|
||||||
|
@ -9207,6 +9218,19 @@
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/history": {
|
||||||
"version": "4.10.1",
|
"version": "4.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
|
||||||
|
@ -14419,6 +14443,18 @@
|
||||||
"version": "6.0.9",
|
"version": "6.0.9",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/react-image": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-image/-/react-image-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-image/-/react-image-4.0.3.tgz",
|
||||||
|
@ -21465,6 +21501,14 @@
|
||||||
"@types/react": "*"
|
"@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": {
|
"@types/react-router": {
|
||||||
"version": "5.1.15",
|
"version": "5.1.15",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.15.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.15.tgz",
|
||||||
|
@ -25605,6 +25649,16 @@
|
||||||
"hex-color-regex": {
|
"hex-color-regex": {
|
||||||
"version": "1.1.0"
|
"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": {
|
"history": {
|
||||||
"version": "4.10.1",
|
"version": "4.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
|
||||||
|
@ -29065,6 +29119,14 @@
|
||||||
"react-error-overlay": {
|
"react-error-overlay": {
|
||||||
"version": "6.0.9"
|
"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": {
|
"react-image": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-image/-/react-image-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-image/-/react-image-4.0.3.tgz",
|
||||||
|
|
|
@ -25,15 +25,18 @@
|
||||||
"@types/react": "^17.0.19",
|
"@types/react": "^17.0.19",
|
||||||
"@types/react-blockies": "^1.4.1",
|
"@types/react-blockies": "^1.4.1",
|
||||||
"@types/react-dom": "^17.0.9",
|
"@types/react-dom": "^17.0.9",
|
||||||
|
"@types/react-highlight": "^0.12.3",
|
||||||
"@types/react-router-dom": "^5.1.8",
|
"@types/react-router-dom": "^5.1.8",
|
||||||
"chart.js": "^3.5.1",
|
"chart.js": "^3.5.1",
|
||||||
"ethers": "^5.4.1",
|
"ethers": "^5.4.1",
|
||||||
|
"highlightjs-solidity": "^1.2.0",
|
||||||
"query-string": "^7.0.1",
|
"query-string": "^7.0.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-blockies": "^1.4.1",
|
"react-blockies": "^1.4.1",
|
||||||
"react-chartjs-2": "^3.0.4",
|
"react-chartjs-2": "^3.0.4",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-error-boundary": "^3.1.3",
|
"react-error-boundary": "^3.1.3",
|
||||||
|
"react-highlight": "^0.14.0",
|
||||||
"react-image": "^4.0.3",
|
"react-image": "^4.0.3",
|
||||||
"react-router-dom": "^5.2.1",
|
"react-router-dom": "^5.2.1",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
import React, { useState, useEffect, useMemo, useContext } from "react";
|
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 { BlockTag } from "@ethersproject/abstract-provider";
|
||||||
import { getAddress, isAddress } from "@ethersproject/address";
|
import { getAddress, isAddress } from "@ethersproject/address";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
|
@ -8,6 +14,9 @@ import StandardFrame from "./StandardFrame";
|
||||||
import StandardSubtitle from "./StandardSubtitle";
|
import StandardSubtitle from "./StandardSubtitle";
|
||||||
import Copy from "./components/Copy";
|
import Copy from "./components/Copy";
|
||||||
import ContentFrame from "./ContentFrame";
|
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 UndefinedPageControl from "./search/UndefinedPageControl";
|
||||||
import ResultHeader from "./search/ResultHeader";
|
import ResultHeader from "./search/ResultHeader";
|
||||||
import PendingResults from "./search/PendingResults";
|
import PendingResults from "./search/PendingResults";
|
||||||
|
@ -194,7 +203,15 @@ const AddressTransactions: React.FC = () => {
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</StandardSubtitle>
|
</StandardSubtitle>
|
||||||
<ContentFrame>
|
<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="flex justify-between items-baseline py-3">
|
||||||
<div className="text-sm text-gray-500">
|
<div className="text-sm text-gray-500">
|
||||||
{page === undefined ? (
|
{page === undefined ? (
|
||||||
|
@ -230,23 +247,35 @@ const AddressTransactions: React.FC = () => {
|
||||||
))}
|
))}
|
||||||
<div className="flex justify-between items-baseline py-3">
|
<div className="flex justify-between items-baseline py-3">
|
||||||
<div className="text-sm text-gray-500">
|
<div className="text-sm text-gray-500">
|
||||||
{page !== undefined && (
|
{page === undefined ? (
|
||||||
|
<>Waiting for search results...</>
|
||||||
|
) : (
|
||||||
<>{page.length} transactions on this page</>
|
<>{page.length} transactions on this page</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<UndefinedPageControl
|
<UndefinedPageControl
|
||||||
address={params.addressOrName}
|
address={params.addressOrName}
|
||||||
isFirst={controller.isFirst}
|
isFirst={controller?.isFirst}
|
||||||
isLast={controller.isLast}
|
isLast={controller?.isLast}
|
||||||
prevHash={page ? page[0].hash : ""}
|
prevHash={page ? page[0].hash : ""}
|
||||||
nextHash={page ? page[page.length - 1].hash : ""}
|
nextHash={page ? page[page.length - 1].hash : ""}
|
||||||
|
disabled={controller === undefined}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<ResultHeader
|
||||||
|
feeDisplay={feeDisplay}
|
||||||
|
feeDisplayToggler={feeDisplayToggler}
|
||||||
|
/>
|
||||||
</SelectionContext.Provider>
|
</SelectionContext.Provider>
|
||||||
) : (
|
) : (
|
||||||
<PendingResults />
|
<PendingResults />
|
||||||
)}
|
)}
|
||||||
</ContentFrame>
|
</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 StandardFrame from "./StandardFrame";
|
||||||
import StandardSubtitle from "./StandardSubtitle";
|
import StandardSubtitle from "./StandardSubtitle";
|
||||||
import ContentFrame from "./ContentFrame";
|
import ContentFrame from "./ContentFrame";
|
||||||
|
import TabGroup from "./components/TabGroup";
|
||||||
import Tab from "./components/Tab";
|
import Tab from "./components/Tab";
|
||||||
import Details from "./transaction/Details";
|
import Details from "./transaction/Details";
|
||||||
import Logs from "./transaction/Logs";
|
import Logs from "./transaction/Logs";
|
||||||
|
@ -55,14 +56,14 @@ const Transaction: React.FC = () => {
|
||||||
)}
|
)}
|
||||||
{txData && (
|
{txData && (
|
||||||
<SelectionContext.Provider value={selectionCtx}>
|
<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>
|
<Tab href={`/tx/${txhash}`}>Overview</Tab>
|
||||||
{txData.confirmedData?.blockNumber !== undefined && (
|
{txData.confirmedData?.blockNumber !== undefined && (
|
||||||
<Tab href={`/tx/${txhash}/logs`}>
|
<Tab href={`/tx/${txhash}/logs`}>
|
||||||
Logs{txData && ` (${txData.confirmedData?.logs?.length ?? 0})`}
|
Logs{txData && ` (${txData.confirmedData?.logs?.length ?? 0})`}
|
||||||
</Tab>
|
</Tab>
|
||||||
)}
|
)}
|
||||||
</div>
|
</TabGroup>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/tx/:txhash/" exact>
|
<Route path="/tx/:txhash/" exact>
|
||||||
<Details
|
<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" />
|
/// <reference types="react-scripts" />
|
||||||
declare module "use-keyboard-shortcut";
|
declare module "use-keyboard-shortcut";
|
||||||
|
declare module "highlightjs-solidity";
|
||||||
|
|
|
@ -27,6 +27,7 @@ module.exports = {
|
||||||
data: ["Roboto Mono"],
|
data: ["Roboto Mono"],
|
||||||
balance: ["Fira Code"],
|
balance: ["Fira Code"],
|
||||||
blocknum: ["Roboto"],
|
blocknum: ["Roboto"],
|
||||||
|
code: ["Fira Code"],
|
||||||
},
|
},
|
||||||
borderColor: {
|
borderColor: {
|
||||||
skin: {
|
skin: {
|
||||||
|
|
Loading…
Reference in New Issue