Add support for external files
This commit is contained in:
parent
0b328123d3
commit
f15c75bb8e
|
@ -16,7 +16,7 @@ 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 Contracts from "./address/Contracts";
|
||||
import UndefinedPageControl from "./search/UndefinedPageControl";
|
||||
import ResultHeader from "./search/ResultHeader";
|
||||
import PendingResults from "./search/PendingResults";
|
||||
|
@ -273,7 +273,7 @@ const AddressTransactions: React.FC = () => {
|
|||
</ContentFrame>
|
||||
</Route>
|
||||
<Route path="/address/:addressOrName/contract" exact>
|
||||
<Contract checksummedAddress={checksummedAddress} />
|
||||
<Contracts checksummedAddress={checksummedAddress} />
|
||||
</Route>
|
||||
</Switch>
|
||||
</>
|
||||
|
|
|
@ -1,100 +1,53 @@
|
|||
import React, { useState, useEffect, useContext } from "react";
|
||||
import { ethers } from "ethers";
|
||||
import ContentFrame from "../ContentFrame";
|
||||
import React, { useState } from "react";
|
||||
import Highlight from "react-highlight";
|
||||
import InfoRow from "../components/InfoRow";
|
||||
import { sourcifyMetadata } from "../url";
|
||||
import { RuntimeContext } from "../useRuntime";
|
||||
|
||||
import "highlight.js/styles/stackoverflow-light.css";
|
||||
import hljs from "highlight.js";
|
||||
import hljsDefineSolidity from "highlightjs-solidity";
|
||||
import { useEffect } from "react";
|
||||
import { sourcifySourceFile } from "../url";
|
||||
hljsDefineSolidity(hljs);
|
||||
hljs.initHighlightingOnLoad();
|
||||
|
||||
type ContractProps = {
|
||||
checksummedAddress: string;
|
||||
networkId: number;
|
||||
filename: string;
|
||||
source: any;
|
||||
};
|
||||
|
||||
const Contract: React.FC<ContractProps> = ({ checksummedAddress }) => {
|
||||
const { provider } = useContext(RuntimeContext);
|
||||
const [rawMetadata, setRawMetadata] = useState<any>();
|
||||
const Contract: React.FC<ContractProps> = ({
|
||||
checksummedAddress,
|
||||
networkId,
|
||||
filename,
|
||||
source,
|
||||
}) => {
|
||||
const [content, setContent] = useState<string>(source.content);
|
||||
useEffect(() => {
|
||||
if (!checksummedAddress) {
|
||||
if (source.content) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchMetadata = async () => {
|
||||
try {
|
||||
const result = await fetch(
|
||||
sourcifyMetadata(checksummedAddress, provider!.network.chainId)
|
||||
);
|
||||
if (result.ok) {
|
||||
const json = await result.json();
|
||||
console.log(json);
|
||||
setRawMetadata(json);
|
||||
setSelected(Object.keys(json.sources)[0]);
|
||||
} else {
|
||||
setRawMetadata(null);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setRawMetadata(null);
|
||||
const readContent = async () => {
|
||||
const normalizedFilename = filename.replaceAll("@", "_");
|
||||
const url = sourcifySourceFile(
|
||||
checksummedAddress,
|
||||
networkId,
|
||||
normalizedFilename
|
||||
);
|
||||
const res = await fetch(url);
|
||||
if (res.ok) {
|
||||
const _content = await res.text();
|
||||
setContent(_content);
|
||||
}
|
||||
};
|
||||
fetchMetadata();
|
||||
}, [provider, checksummedAddress]);
|
||||
|
||||
const [selected, setSelected] = useState<string>();
|
||||
|
||||
const optimizer = rawMetadata?.settings?.optimizer;
|
||||
readContent();
|
||||
}, [checksummedAddress, networkId, filename, source.content]);
|
||||
|
||||
return (
|
||||
<ContentFrame tabs>
|
||||
{rawMetadata && (
|
||||
<>
|
||||
<InfoRow title="Compiler">
|
||||
<span>{rawMetadata.compiler?.version}</span>
|
||||
</InfoRow>
|
||||
<InfoRow title="Optimizer Enabled">
|
||||
{optimizer?.enabled ? (
|
||||
<span>
|
||||
<span className="font-bold text-green-600">Yes</span> with{" "}
|
||||
<span className="font-bold text-green-600">
|
||||
{ethers.utils.commify(optimizer?.runs)}
|
||||
</span>{" "}
|
||||
runs
|
||||
</span>
|
||||
) : (
|
||||
<span className="font-bold text-red-600">No</span>
|
||||
)}
|
||||
</InfoRow>
|
||||
</>
|
||||
)}
|
||||
<div className="py-5">
|
||||
{rawMetadata === null && (
|
||||
<span>Couldn't find contract metadata in Sourcify repository.</span>
|
||||
)}
|
||||
{rawMetadata !== undefined && rawMetadata !== null && (
|
||||
<div>
|
||||
{Object.entries(rawMetadata.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">
|
||||
{rawMetadata.sources[selected].content}
|
||||
</Highlight>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ContentFrame>
|
||||
<Highlight className="w-full h-full border focus:outline-none font-code text-base">
|
||||
{content}
|
||||
</Highlight>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
import React, { useState, useEffect, useContext } from "react";
|
||||
import { ethers } from "ethers";
|
||||
import ContentFrame from "../ContentFrame";
|
||||
import InfoRow from "../components/InfoRow";
|
||||
import Contract from "./Contract";
|
||||
import { sourcifyMetadata } from "../url";
|
||||
import { RuntimeContext } from "../useRuntime";
|
||||
|
||||
type ContractsProps = {
|
||||
checksummedAddress: string;
|
||||
};
|
||||
|
||||
const Contracts: React.FC<ContractsProps> = ({ checksummedAddress }) => {
|
||||
const { provider } = useContext(RuntimeContext);
|
||||
const [rawMetadata, setRawMetadata] = useState<any>();
|
||||
useEffect(() => {
|
||||
if (!checksummedAddress) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fetchMetadata = async () => {
|
||||
try {
|
||||
const result = await fetch(
|
||||
sourcifyMetadata(checksummedAddress, provider!.network.chainId)
|
||||
);
|
||||
if (result.ok) {
|
||||
const json = await result.json();
|
||||
console.log(json);
|
||||
setRawMetadata(json);
|
||||
setSelected(Object.keys(json.sources)[0]);
|
||||
} else {
|
||||
setRawMetadata(null);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
setRawMetadata(null);
|
||||
}
|
||||
};
|
||||
fetchMetadata();
|
||||
}, [provider, checksummedAddress]);
|
||||
|
||||
const [selected, setSelected] = useState<string>();
|
||||
|
||||
const optimizer = rawMetadata?.settings?.optimizer;
|
||||
|
||||
return (
|
||||
<ContentFrame tabs>
|
||||
{rawMetadata && (
|
||||
<>
|
||||
<InfoRow title="Compiler">
|
||||
<span>{rawMetadata.compiler?.version}</span>
|
||||
</InfoRow>
|
||||
<InfoRow title="Optimizer Enabled">
|
||||
{optimizer?.enabled ? (
|
||||
<span>
|
||||
<span className="font-bold text-green-600">Yes</span> with{" "}
|
||||
<span className="font-bold text-green-600">
|
||||
{ethers.utils.commify(optimizer?.runs)}
|
||||
</span>{" "}
|
||||
runs
|
||||
</span>
|
||||
) : (
|
||||
<span className="font-bold text-red-600">No</span>
|
||||
)}
|
||||
</InfoRow>
|
||||
</>
|
||||
)}
|
||||
<div className="py-5">
|
||||
{rawMetadata === null && (
|
||||
<span>Couldn't find contract metadata in Sourcify repository.</span>
|
||||
)}
|
||||
{rawMetadata !== undefined && rawMetadata !== null && (
|
||||
<div>
|
||||
{Object.entries(rawMetadata.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 && (
|
||||
<Contract
|
||||
checksummedAddress={checksummedAddress}
|
||||
networkId={provider!.network.chainId}
|
||||
filename={selected}
|
||||
source={rawMetadata.sources[selected]}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ContentFrame>
|
||||
);
|
||||
};
|
||||
|
||||
export default React.memo(Contracts);
|
|
@ -19,3 +19,10 @@ export const sourcifyMetadata = (
|
|||
networkId: number
|
||||
) =>
|
||||
`http://localhost:7000/sourcify/contracts/full_match/${networkId}/${checksummedAddress}/metadata.json`;
|
||||
|
||||
export const sourcifySourceFile = (
|
||||
checksummedAddress: string,
|
||||
networkId: number,
|
||||
filepath: string
|
||||
) =>
|
||||
`http://localhost:7000/sourcify/contracts/full_match/${networkId}/${checksummedAddress}/sources/${filepath}`;
|
||||
|
|
Loading…
Reference in New Issue