Add third way to integrate with Sourcify

This commit is contained in:
Willian Mitsuda 2021-09-10 18:27:42 -03:00
parent 05c230ef9d
commit 21ed9ce431
6 changed files with 101 additions and 45 deletions

View File

@ -32,6 +32,7 @@ import { useFeeToggler } from "./search/useFeeToggler";
import { SelectionContext, useSelection } from "./useSelection";
import { useMultipleETHUSDOracle } from "./usePriceOracle";
import { useSourcify } from "./useSourcify";
import { SourcifySource } from "./url";
type BlockParams = {
addressOrName: string;
@ -179,11 +180,13 @@ const AddressTransactions: React.FC = () => {
const [feeDisplay, feeDisplayToggler] = useFeeToggler();
const selectionCtx = useSelection();
const [useIPFS, setUseIPFS] = useState<boolean>(true);
const [sourcifySource, setSourcifySource] = useState<SourcifySource>(
SourcifySource.IPFS_IPNS
);
const rawMetadata = useSourcify(
checksummedAddress,
provider?.network.chainId,
useIPFS
sourcifySource
);
return (
@ -313,8 +316,8 @@ const AddressTransactions: React.FC = () => {
<Contracts
checksummedAddress={checksummedAddress}
rawMetadata={rawMetadata}
useIPFS={useIPFS}
setUseIPFS={setUseIPFS}
sourcifySource={sourcifySource}
setSourcifySource={setSourcifySource}
/>
</Route>
</Switch>

View File

@ -3,6 +3,7 @@ import { Light as SyntaxHighlighter } from "react-syntax-highlighter";
import hljs from "highlight.js";
import docco from "react-syntax-highlighter/dist/esm/styles/hljs/docco";
import { useContract } from "../useSourcify";
import { SourcifySource } from "../url";
import hljsDefineSolidity from "highlightjs-solidity";
hljsDefineSolidity(hljs);
@ -12,7 +13,7 @@ type ContractProps = {
networkId: number;
filename: string;
source: any;
useIPFS: boolean;
sourcifySource: SourcifySource;
};
const Contract: React.FC<ContractProps> = ({
@ -20,14 +21,14 @@ const Contract: React.FC<ContractProps> = ({
networkId,
filename,
source,
useIPFS,
sourcifySource,
}) => {
const content = useContract(
checksummedAddress,
networkId,
filename,
source,
useIPFS
sourcifySource
);
return (

View File

@ -1,6 +1,6 @@
import React, { useState, useEffect, useContext, Fragment } from "react";
import { commify } from "@ethersproject/units";
import { Menu, Switch } from "@headlessui/react";
import { Menu, RadioGroup } from "@headlessui/react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
import ContentFrame from "../ContentFrame";
@ -10,20 +10,21 @@ import Contract from "./Contract";
import { RuntimeContext } from "../useRuntime";
import { Metadata } from "../useSourcify";
import ExternalLink from "../components/ExternalLink";
import { openInRemixURL } from "../url";
import { openInRemixURL, SourcifySource } from "../url";
import RadioButton from "./RadioButton";
type ContractsProps = {
checksummedAddress: string;
rawMetadata: Metadata | null | undefined;
useIPFS: boolean;
setUseIPFS: (useIPFS: boolean) => void;
sourcifySource: SourcifySource;
setSourcifySource: (sourcifySource: SourcifySource) => void;
};
const Contracts: React.FC<ContractsProps> = ({
checksummedAddress,
rawMetadata,
useIPFS,
setUseIPFS,
sourcifySource,
setSourcifySource,
}) => {
const { provider } = useContext(RuntimeContext);
@ -37,20 +38,20 @@ const Contracts: React.FC<ContractsProps> = ({
return (
<ContentFrame tabs>
<InfoRow title="Use IPFS">
<Switch
className={`flex items-center h-7 w-12 px-1 rounded-full transition duration-200 ${
useIPFS ? "bg-blue-500" : "bg-blue-900"
}`}
checked={useIPFS}
onChange={setUseIPFS}
>
<span
className={`inline-block border rounded-full w-5 h-5 bg-white transform duration-200 ${
useIPFS ? "" : "translate-x-5"
}`}
></span>
</Switch>
<InfoRow title="Sourcify integration">
<RadioGroup value={sourcifySource} onChange={setSourcifySource}>
<div className="flex space-x-2">
<RadioButton value={SourcifySource.IPFS_IPNS}>
Resolve IPNS
</RadioButton>
<RadioButton value={SourcifySource.CENTRAL_SERVER}>
Sourcify Servers
</RadioButton>
<RadioButton value={SourcifySource.CUSTOM_SNAPSHOT_SERVER}>
Local Snapshot
</RadioButton>
</div>
</RadioGroup>
</InfoRow>
{rawMetadata && (
<>
@ -76,6 +77,9 @@ const Contracts: React.FC<ContractsProps> = ({
</>
)}
<div className="py-5">
{rawMetadata === undefined && (
<span>Getting data from Sourcify repository...</span>
)}
{rawMetadata === null && (
<span>
Address is not a contract or couldn't find contract metadata in
@ -139,7 +143,7 @@ const Contracts: React.FC<ContractsProps> = ({
networkId={provider!.network.chainId}
filename={selected}
source={rawMetadata.sources[selected]}
useIPFS={useIPFS}
sourcifySource={sourcifySource}
/>
)}
</div>

View File

@ -0,0 +1,24 @@
import React from "react";
import { RadioGroup } from "@headlessui/react";
import { SourcifySource } from "../url";
type RadioButtonProps = {
value: SourcifySource;
};
const RadioButton: React.FC<RadioButtonProps> = ({ value, children }) => (
<RadioGroup.Option
className={({ checked }) =>
`border rounded px-2 py-1 cursor-pointer ${
checked
? "bg-blue-400 hover:bg-blue-500 text-white"
: "hover:bg-gray-200"
}`
}
value={value}
>
{children}
</RadioGroup.Option>
);
export default RadioButton;

View File

@ -14,29 +14,52 @@ export const blockURL = (blockNum: BlockTag) => `/block/${blockNum}`;
export const blockTxsURL = (blockNum: BlockTag) => `/block/${blockNum}/txs`;
const sourcifyRootHash =
export enum SourcifySource {
// Resolve trusted IPNS for root IPFS
IPFS_IPNS,
// Centralized Sourcify servers
CENTRAL_SERVER,
// Snapshot server
CUSTOM_SNAPSHOT_SERVER,
}
const sourcifyIPNS =
"k51qzi5uqu5dll0ocge71eudqnrgnogmbr37gsgl12uubsinphjoknl6bbi41p";
const ipfsGatewayPrefix = `https://ipfs.io/ipns/${sourcifyRootHash}`;
const ipfsGatewayPrefix = `https://ipfs.io/ipns/${sourcifyIPNS}`;
// const ipfsGatewayPrefix = "http://localhost:8080/ipfs/QmWQoGfrLcizHueg3YkgDCh1S7SkfSP9A7H8YeZmUDfbnn"
const sourcifyHttpRepoPrefix = `https://repo.sourcify.dev`;
const snapshotPrefix = "http://localhost:3006";
const resolveSourcifySource = (source: SourcifySource) => {
if (source === SourcifySource.IPFS_IPNS) {
return ipfsGatewayPrefix;
}
if (source === SourcifySource.CENTRAL_SERVER) {
return sourcifyHttpRepoPrefix;
}
return snapshotPrefix;
};
export const sourcifyMetadata = (
checksummedAddress: string,
networkId: number,
useIPFS: boolean
source: SourcifySource
) =>
`${
useIPFS ? ipfsGatewayPrefix : sourcifyHttpRepoPrefix
}/contracts/full_match/${networkId}/${checksummedAddress}/metadata.json`;
`${resolveSourcifySource(
source
)}/contracts/full_match/${networkId}/${checksummedAddress}/metadata.json`;
export const sourcifySourceFile = (
checksummedAddress: string,
networkId: number,
filepath: string,
useIPFS: boolean
source: SourcifySource
) =>
`${
useIPFS ? ipfsGatewayPrefix : sourcifyHttpRepoPrefix
}/contracts/full_match/${networkId}/${checksummedAddress}/sources/${filepath}`;
`${resolveSourcifySource(
source
)}/contracts/full_match/${networkId}/${checksummedAddress}/sources/${filepath}`;
export const openInRemixURL = (checksummedAddress: string, networkId: number) =>
`https://remix.ethereum.org/#call=source-verification//fetchAndSave//${checksummedAddress}//${networkId}`;

View File

@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
import { sourcifyMetadata, sourcifySourceFile } from "./url";
import { sourcifyMetadata, SourcifySource, sourcifySourceFile } from "./url";
export type Metadata = {
version: string;
@ -39,7 +39,7 @@ export type Metadata = {
export const useSourcify = (
checksummedAddress: string | undefined,
chainId: number | undefined,
useIPFS: boolean
source: SourcifySource
) => {
const [rawMetadata, setRawMetadata] = useState<Metadata | null | undefined>();
@ -48,12 +48,13 @@ export const useSourcify = (
return;
}
setRawMetadata(undefined);
const fetchMetadata = async () => {
try {
const contractMetadataURL = sourcifyMetadata(
checksummedAddress,
chainId,
useIPFS
source
);
const result = await fetch(contractMetadataURL);
if (result.ok) {
@ -68,7 +69,7 @@ export const useSourcify = (
}
};
fetchMetadata();
}, [checksummedAddress, chainId, useIPFS]);
}, [checksummedAddress, chainId, source]);
return rawMetadata;
};
@ -78,7 +79,7 @@ export const useContract = (
networkId: number,
filename: string,
source: any,
useIPFS: boolean = true
sourcifySource: SourcifySource
) => {
const [content, setContent] = useState<string>(source.content);
@ -93,7 +94,7 @@ export const useContract = (
checksummedAddress,
networkId,
normalizedFilename,
useIPFS
sourcifySource
);
const res = await fetch(url);
if (res.ok) {
@ -102,7 +103,7 @@ export const useContract = (
}
};
readContent();
}, [checksummedAddress, networkId, filename, source.content, useIPFS]);
}, [checksummedAddress, networkId, filename, source.content, sourcifySource]);
return content;
};