Merge branch 'feature/better-abi-ui' into develop

This commit is contained in:
Willian Mitsuda 2021-10-25 15:18:21 -03:00
commit c411900c67
8 changed files with 197 additions and 72 deletions

92
package-lock.json generated
View File

@ -30,7 +30,6 @@
"@types/react": "^17.0.31", "@types/react": "^17.0.31",
"@types/react-blockies": "^1.4.1", "@types/react-blockies": "^1.4.1",
"@types/react-dom": "^17.0.10", "@types/react-dom": "^17.0.10",
"@types/react-helmet": "^6.1.4",
"@types/react-highlight": "^0.12.5", "@types/react-highlight": "^0.12.5",
"@types/react-router-dom": "^5.3.1", "@types/react-router-dom": "^5.3.1",
"@types/react-syntax-highlighter": "^13.5.2", "@types/react-syntax-highlighter": "^13.5.2",
@ -43,7 +42,7 @@
"react-chartjs-2": "^3.2.0", "react-chartjs-2": "^3.2.0",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-error-boundary": "^3.1.3", "react-error-boundary": "^3.1.3",
"react-helmet": "^6.1.0", "react-helmet-async": "^1.1.2",
"react-image": "^4.0.3", "react-image": "^4.0.3",
"react-router-dom": "^5.3.0", "react-router-dom": "^5.3.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",
@ -3119,14 +3118,6 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"node_modules/@types/react-helmet": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.4.tgz",
"integrity": "sha512-jyx50RNZXVaTGHY3MsoRPNpeiVk8b0XTPgD/O6KHF6COTDnG/+lRjPYvTK5nfWtR3xDOux0w6bHLAsaHo2ZLTA==",
"dependencies": {
"@types/react": "*"
}
},
"node_modules/@types/react-highlight": { "node_modules/@types/react-highlight": {
"version": "0.12.5", "version": "0.12.5",
"resolved": "https://registry.npmjs.org/@types/react-highlight/-/react-highlight-0.12.5.tgz", "resolved": "https://registry.npmjs.org/@types/react-highlight/-/react-highlight-0.12.5.tgz",
@ -9839,6 +9830,14 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"dependencies": {
"loose-envify": "^1.0.0"
}
},
"node_modules/ip": { "node_modules/ip": {
"version": "1.1.5", "version": "1.1.5",
"license": "MIT" "license": "MIT"
@ -14588,18 +14587,20 @@
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz",
"integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
}, },
"node_modules/react-helmet": { "node_modules/react-helmet-async": {
"version": "6.1.0", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.1.2.tgz",
"integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", "integrity": "sha512-LTTzDDkyIleT/JJ6T/uqx7Y8qi1EuPPSiJawQY/nHHz0h7SPDT6HxP1YDDQx/fzcVxCqpWEEMS3QdrSrNkJYhg==",
"dependencies": { "dependencies": {
"object-assign": "^4.1.1", "@babel/runtime": "^7.12.5",
"invariant": "^2.2.4",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react-fast-compare": "^3.1.1", "react-fast-compare": "^3.2.0",
"react-side-effect": "^2.1.0" "shallowequal": "^1.1.0"
}, },
"peerDependencies": { "peerDependencies": {
"react": ">=16.3.0" "react": "^16.6.0 || ^17.0.0",
"react-dom": "^16.6.0 || ^17.0.0"
} }
}, },
"node_modules/react-image": { "node_modules/react-image": {
@ -14949,14 +14950,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-side-effect": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.1.tgz",
"integrity": "sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==",
"peerDependencies": {
"react": "^16.3.0 || ^17.0.0"
}
},
"node_modules/react-syntax-highlighter": { "node_modules/react-syntax-highlighter": {
"version": "15.4.4", "version": "15.4.4",
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.4.4.tgz", "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.4.4.tgz",
@ -16314,6 +16307,11 @@
"sha.js": "bin.js" "sha.js": "bin.js"
} }
}, },
"node_modules/shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
},
"node_modules/shebang-command": { "node_modules/shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"license": "MIT", "license": "MIT",
@ -21703,14 +21701,6 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"@types/react-helmet": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/@types/react-helmet/-/react-helmet-6.1.4.tgz",
"integrity": "sha512-jyx50RNZXVaTGHY3MsoRPNpeiVk8b0XTPgD/O6KHF6COTDnG/+lRjPYvTK5nfWtR3xDOux0w6bHLAsaHo2ZLTA==",
"requires": {
"@types/react": "*"
}
},
"@types/react-highlight": { "@types/react-highlight": {
"version": "0.12.5", "version": "0.12.5",
"resolved": "https://registry.npmjs.org/@types/react-highlight/-/react-highlight-0.12.5.tgz", "resolved": "https://registry.npmjs.org/@types/react-highlight/-/react-highlight-0.12.5.tgz",
@ -26271,6 +26261,14 @@
"side-channel": "^1.0.4" "side-channel": "^1.0.4"
} }
}, },
"invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"requires": {
"loose-envify": "^1.0.0"
}
},
"ip": { "ip": {
"version": "1.1.5" "version": "1.1.5"
}, },
@ -29420,15 +29418,16 @@
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz",
"integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
}, },
"react-helmet": { "react-helmet-async": {
"version": "6.1.0", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/react-helmet/-/react-helmet-6.1.0.tgz", "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-1.1.2.tgz",
"integrity": "sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==", "integrity": "sha512-LTTzDDkyIleT/JJ6T/uqx7Y8qi1EuPPSiJawQY/nHHz0h7SPDT6HxP1YDDQx/fzcVxCqpWEEMS3QdrSrNkJYhg==",
"requires": { "requires": {
"object-assign": "^4.1.1", "@babel/runtime": "^7.12.5",
"invariant": "^2.2.4",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"react-fast-compare": "^3.1.1", "react-fast-compare": "^3.2.0",
"react-side-effect": "^2.1.0" "shallowequal": "^1.1.0"
} }
}, },
"react-image": { "react-image": {
@ -29675,12 +29674,6 @@
} }
} }
}, },
"react-side-effect": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/react-side-effect/-/react-side-effect-2.1.1.tgz",
"integrity": "sha512-2FoTQzRNTncBVtnzxFOk2mCpcfxQpenBMbk5kSVBg5UcPqV9fRbgY2zhb7GTWWOlpFmAxhClBDlIq8Rsubz1yQ==",
"requires": {}
},
"react-syntax-highlighter": { "react-syntax-highlighter": {
"version": "15.4.4", "version": "15.4.4",
"resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.4.4.tgz", "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.4.4.tgz",
@ -30615,6 +30608,11 @@
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
}, },
"shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
},
"shebang-command": { "shebang-command": {
"version": "2.0.0", "version": "2.0.0",
"requires": { "requires": {

View File

@ -25,7 +25,6 @@
"@types/react": "^17.0.31", "@types/react": "^17.0.31",
"@types/react-blockies": "^1.4.1", "@types/react-blockies": "^1.4.1",
"@types/react-dom": "^17.0.10", "@types/react-dom": "^17.0.10",
"@types/react-helmet": "^6.1.4",
"@types/react-highlight": "^0.12.5", "@types/react-highlight": "^0.12.5",
"@types/react-router-dom": "^5.3.1", "@types/react-router-dom": "^5.3.1",
"@types/react-syntax-highlighter": "^13.5.2", "@types/react-syntax-highlighter": "^13.5.2",
@ -38,7 +37,7 @@
"react-chartjs-2": "^3.2.0", "react-chartjs-2": "^3.2.0",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-error-boundary": "^3.1.3", "react-error-boundary": "^3.1.3",
"react-helmet": "^6.1.0", "react-helmet-async": "^1.1.2",
"react-image": "^4.0.3", "react-image": "^4.0.3",
"react-router-dom": "^5.3.0", "react-router-dom": "^5.3.0",
"react-scripts": "4.0.3", "react-scripts": "4.0.3",

View File

@ -0,0 +1,35 @@
import React from "react";
import { Tab } from "@headlessui/react";
import ModeTab from "../components/ModeTab";
import Copy from "../components/Copy";
import DecodedABI from "./DecodedABI";
import RawABI from "./RawABI";
type ContractABIProps = {
abi: any[];
};
const ContractABI: React.FC<ContractABIProps> = ({ abi }) => (
<div className="mb-3">
<Tab.Group>
<Tab.List className="flex items-baseline space-x-1 mb-1">
<div className="flex items-baseline space-x-2 text-sm pr-2 py-1">
<span>ABI</span>
<Copy value={JSON.stringify(abi)} />
</div>
<ModeTab>Decoded</ModeTab>
<ModeTab>Raw</ModeTab>
</Tab.List>
<Tab.Panels>
<Tab.Panel>
<DecodedABI abi={abi} />
</Tab.Panel>
<Tab.Panel>
<RawABI abi={abi} />
</Tab.Panel>
</Tab.Panels>
</Tab.Group>
</div>
);
export default React.memo(ContractABI);

View File

@ -5,13 +5,12 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown"; import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
import ContentFrame from "../ContentFrame"; import ContentFrame from "../ContentFrame";
import InfoRow from "../components/InfoRow"; import InfoRow from "../components/InfoRow";
import Copy from "../components/Copy";
import ABI from "./ABI";
import Contract from "./Contract"; import Contract from "./Contract";
import { RuntimeContext } from "../useRuntime"; import { RuntimeContext } from "../useRuntime";
import { Metadata } from "../useSourcify"; import { Metadata } from "../useSourcify";
import ExternalLink from "../components/ExternalLink"; import ExternalLink from "../components/ExternalLink";
import { openInRemixURL } from "../url"; import { openInRemixURL } from "../url";
import ContractABI from "./ContractABI";
type ContractsProps = { type ContractsProps = {
checksummedAddress: string; checksummedAddress: string;
@ -70,13 +69,7 @@ const Contracts: React.FC<ContractsProps> = ({
{rawMetadata !== undefined && rawMetadata !== null && ( {rawMetadata !== undefined && rawMetadata !== null && (
<> <>
{rawMetadata.output.abi && ( {rawMetadata.output.abi && (
<div className="mb-3"> <ContractABI abi={rawMetadata.output.abi} />
<div className="flex space-x-2 text-sm border-l border-r border-t rounded-t px-2 py-1">
<span>ABI</span>
<Copy value={JSON.stringify(rawMetadata.output.abi)} />
</div>
<ABI abi={rawMetadata.output.abi} />
</div>
)} )}
<div> <div>
<Menu> <Menu>

View File

@ -0,0 +1,20 @@
import { Interface } from "@ethersproject/abi";
import React from "react";
import DecodedFragment from "./DecodedFragment";
type DecodedABIProps = {
abi: any[];
};
const DecodedABI: React.FC<DecodedABIProps> = ({ abi }) => {
const intf = new Interface(abi);
return (
<div className="border overflow-x-auto">
{intf.fragments.map((f, i) => (
<DecodedFragment key={i} intf={intf} fragment={f} />
))}
</div>
);
};
export default React.memo(DecodedABI);

View File

@ -0,0 +1,78 @@
import React from "react";
import {
ConstructorFragment,
EventFragment,
Fragment,
FunctionFragment,
Interface,
} from "@ethersproject/abi";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCaretRight } from "@fortawesome/free-solid-svg-icons/faCaretRight";
type DecodedFragmentProps = {
intf: Interface;
fragment: Fragment;
};
const DecodedFragment: React.FC<DecodedFragmentProps> = ({
intf,
fragment,
}) => {
let fragmentType: "constructor" | "event" | "function" | undefined;
let sig: string | undefined;
let letter: string | undefined;
let letterBg: string | undefined;
let hashBg: string | undefined;
if (FunctionFragment.isFunctionFragment(fragment)) {
fragmentType = "function";
sig = intf.getSighash(fragment);
letter = "F";
letterBg = "bg-purple-500";
hashBg = "bg-purple-50";
} else if (EventFragment.isEventFragment(fragment)) {
fragmentType = "event";
sig = intf.getEventTopic(fragment);
letter = "E";
letterBg = "bg-green-300";
hashBg = "bg-green-50";
} else if (ConstructorFragment.isConstructorFragment(fragment)) {
fragmentType = "constructor";
letter = "C";
letterBg = "bg-blue-500";
}
return (
<div className="flex flex-wrap items-baseline space-x-2 px-2 py-1 hover:bg-gray-100">
<span className="text-gray-500">
<FontAwesomeIcon icon={faCaretRight} size="1x" />
</span>
{letter && (
<span
className={`flex-shrink-0 text-xs font-code border border-gray-300 rounded-full w-5 h-5 self-center flex items-center justify-center text-white font-bold ${letterBg}`}
>
{letter}
</span>
)}
<span className="text-sm font-code whitespace-nowrap">
{fragment.format("full")}
</span>
{sig && (
<span
className={`text-xs border rounded-xl px-2 pt-1 font-code text-gray-600 ${hashBg}`}
title={
fragmentType === "function"
? "Method Selector"
: fragmentType === "event"
? "Topic Hash"
: ""
}
>
{sig}
</span>
)}
</div>
);
};
export default React.memo(DecodedFragment);

View File

@ -1,11 +1,11 @@
import React from "react"; import React from "react";
import { SyntaxHighlighter, docco } from "../highlight-init"; import { SyntaxHighlighter, docco } from "../highlight-init";
type ABIProps = { type RawABIProps = {
abi: any[]; abi: any[];
}; };
const ABI: React.FC<ABIProps> = ({ abi }) => ( const RawABI: React.FC<RawABIProps> = ({ abi }) => (
<SyntaxHighlighter <SyntaxHighlighter
className="w-full h-60 border font-code text-base" className="w-full h-60 border font-code text-base"
language="json" language="json"
@ -16,4 +16,4 @@ const ABI: React.FC<ABIProps> = ({ abi }) => (
</SyntaxHighlighter> </SyntaxHighlighter>
); );
export default React.memo(ABI); export default React.memo(RawABI);

View File

@ -1,6 +1,6 @@
import React from "react"; import React from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import { Helmet } from "react-helmet"; import { HelmetProvider, Helmet } from "react-helmet-async";
import "@fontsource/space-grotesk/index.css"; import "@fontsource/space-grotesk/index.css";
import "@fontsource/roboto/index.css"; import "@fontsource/roboto/index.css";
import "@fontsource/roboto-mono/index.css"; import "@fontsource/roboto-mono/index.css";
@ -11,6 +11,7 @@ import reportWebVitals from "./reportWebVitals";
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<HelmetProvider>
<Helmet> <Helmet>
<link <link
rel="preload" rel="preload"
@ -21,6 +22,7 @@ ReactDOM.render(
/> />
</Helmet> </Helmet>
<App /> <App />
</HelmetProvider>
</React.StrictMode>, </React.StrictMode>,
document.getElementById("root") document.getElementById("root")
); );