From 9989c6bd717753d634ba3d86a50b08d53d76169f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Wed, 29 May 2024 17:44:22 +0200 Subject: [PATCH 001/100] Add nvmrc --- .nvmrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000000..9a2a0e219c9 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v20 From e15427b71b636ee97adfd5e8328ea2bc3c047f20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Wed, 5 Jun 2024 17:22:41 +0200 Subject: [PATCH 002/100] Init contract-verification plugin and add it inside plugins --- apps/contract-verification/.babelrc | 9 + apps/contract-verification/.browserslistrc | 16 + apps/contract-verification/.eslintrc | 3 + apps/contract-verification/.eslintrc.json | 34 + apps/contract-verification/project.json | 69 + apps/contract-verification/src/app/App.css | 7 + .../src/app/AppContext.tsx | 25 + .../src/app/EtherscanPluginClient.ts | 70 + apps/contract-verification/src/app/app.tsx | 136 ++ .../src/app/components/HeaderWithSettings.tsx | 81 ++ .../src/app/components/SubmitButton.tsx | 34 + .../src/app/components/index.ts | 2 + .../src/app/hooks/useLocalStorage.tsx | 36 + .../src/app/layouts/Default.tsx | 17 + .../src/app/layouts/index.ts | 1 + apps/contract-verification/src/app/routes.tsx | 37 + .../src/app/types/Receipt.ts | 9 + .../src/app/types/ThemeType.ts | 1 + .../src/app/types/index.ts | 2 + .../src/app/utils/index.ts | 1 + .../src/app/utils/networks.ts | 42 + .../src/app/utils/scripts.ts | 30 + .../src/app/utils/utilities.ts | 69 + .../src/app/utils/verify.ts | 206 +++ .../src/app/views/CaptureKeyView.tsx | 63 + .../src/app/views/ErrorView.tsx | 16 + .../src/app/views/HomeView.tsx | 31 + .../src/app/views/ReceiptsView.tsx | 170 +++ .../src/app/views/VerifyView.tsx | 235 ++++ .../src/app/views/index.ts | 4 + .../contract-verification/src/assets/.gitkeep | 0 .../src/environments/environment.prod.ts | 3 + .../src/environments/environment.ts | 6 + apps/contract-verification/src/favicon.ico | Bin 0 -> 15086 bytes apps/contract-verification/src/index.html | 17 + apps/contract-verification/src/main.tsx | 14 + apps/contract-verification/src/polyfills.ts | 7 + apps/contract-verification/src/profile.json | 16 + apps/contract-verification/src/styles.css | 1 + apps/contract-verification/tsconfig.app.json | 22 + apps/contract-verification/tsconfig.json | 16 + apps/contract-verification/webpack.config.js | 90 ++ apps/remix-ide/project.json | 2 +- apps/remix-ide/src/assets/list.json | 1123 +++++++++++++++++ apps/remix-ide/src/remixAppManager.js | 25 +- 45 files changed, 2785 insertions(+), 13 deletions(-) create mode 100644 apps/contract-verification/.babelrc create mode 100644 apps/contract-verification/.browserslistrc create mode 100644 apps/contract-verification/.eslintrc create mode 100644 apps/contract-verification/.eslintrc.json create mode 100644 apps/contract-verification/project.json create mode 100644 apps/contract-verification/src/app/App.css create mode 100644 apps/contract-verification/src/app/AppContext.tsx create mode 100644 apps/contract-verification/src/app/EtherscanPluginClient.ts create mode 100644 apps/contract-verification/src/app/app.tsx create mode 100644 apps/contract-verification/src/app/components/HeaderWithSettings.tsx create mode 100644 apps/contract-verification/src/app/components/SubmitButton.tsx create mode 100644 apps/contract-verification/src/app/components/index.ts create mode 100644 apps/contract-verification/src/app/hooks/useLocalStorage.tsx create mode 100644 apps/contract-verification/src/app/layouts/Default.tsx create mode 100644 apps/contract-verification/src/app/layouts/index.ts create mode 100644 apps/contract-verification/src/app/routes.tsx create mode 100644 apps/contract-verification/src/app/types/Receipt.ts create mode 100644 apps/contract-verification/src/app/types/ThemeType.ts create mode 100644 apps/contract-verification/src/app/types/index.ts create mode 100644 apps/contract-verification/src/app/utils/index.ts create mode 100644 apps/contract-verification/src/app/utils/networks.ts create mode 100644 apps/contract-verification/src/app/utils/scripts.ts create mode 100644 apps/contract-verification/src/app/utils/utilities.ts create mode 100644 apps/contract-verification/src/app/utils/verify.ts create mode 100644 apps/contract-verification/src/app/views/CaptureKeyView.tsx create mode 100644 apps/contract-verification/src/app/views/ErrorView.tsx create mode 100644 apps/contract-verification/src/app/views/HomeView.tsx create mode 100644 apps/contract-verification/src/app/views/ReceiptsView.tsx create mode 100644 apps/contract-verification/src/app/views/VerifyView.tsx create mode 100644 apps/contract-verification/src/app/views/index.ts create mode 100644 apps/contract-verification/src/assets/.gitkeep create mode 100644 apps/contract-verification/src/environments/environment.prod.ts create mode 100644 apps/contract-verification/src/environments/environment.ts create mode 100644 apps/contract-verification/src/favicon.ico create mode 100644 apps/contract-verification/src/index.html create mode 100644 apps/contract-verification/src/main.tsx create mode 100644 apps/contract-verification/src/polyfills.ts create mode 100644 apps/contract-verification/src/profile.json create mode 100644 apps/contract-verification/src/styles.css create mode 100644 apps/contract-verification/tsconfig.app.json create mode 100644 apps/contract-verification/tsconfig.json create mode 100644 apps/contract-verification/webpack.config.js create mode 100644 apps/remix-ide/src/assets/list.json diff --git a/apps/contract-verification/.babelrc b/apps/contract-verification/.babelrc new file mode 100644 index 00000000000..e37036ce668 --- /dev/null +++ b/apps/contract-verification/.babelrc @@ -0,0 +1,9 @@ +{ + "presets": ["@babel/preset-env", ["@babel/preset-react", + {"runtime": "automatic"} + ]], + "plugins": ["@babel/plugin-proposal-class-properties", "@babel/plugin-transform-runtime", "@babel/plugin-proposal-nullish-coalescing-operator"], + "ignore": [ + "**/node_modules/**" + ] +} \ No newline at end of file diff --git a/apps/contract-verification/.browserslistrc b/apps/contract-verification/.browserslistrc new file mode 100644 index 00000000000..f1d12df4faa --- /dev/null +++ b/apps/contract-verification/.browserslistrc @@ -0,0 +1,16 @@ +# This file is used by: +# 1. autoprefixer to adjust CSS to support the below specified browsers +# 2. babel preset-env to adjust included polyfills +# +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# If you need to support different browsers in production, you may tweak the list below. + +last 1 Chrome version +last 1 Firefox version +last 2 Edge major versions +last 2 Safari major version +last 2 iOS major versions +Firefox ESR +not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/apps/contract-verification/.eslintrc b/apps/contract-verification/.eslintrc new file mode 100644 index 00000000000..2d85f9fa667 --- /dev/null +++ b/apps/contract-verification/.eslintrc @@ -0,0 +1,3 @@ +{ + "extends": "../../.eslintrc.json", +} \ No newline at end of file diff --git a/apps/contract-verification/.eslintrc.json b/apps/contract-verification/.eslintrc.json new file mode 100644 index 00000000000..a92d0f887ac --- /dev/null +++ b/apps/contract-verification/.eslintrc.json @@ -0,0 +1,34 @@ +{ + "extends": [ + "plugin:@nrwl/nx/react", + "../../.eslintrc.json" + ], + "ignorePatterns": [ + "!**/*" + ], + "overrides": [ + { + "files": [ + "*.ts", + "*.tsx", + "*.js", + "*.jsx" + ], + "rules": {} + }, + { + "files": [ + "*.ts", + "*.tsx" + ], + "rules": {} + }, + { + "files": [ + "*.js", + "*.jsx" + ], + "rules": {} + } + ] +} \ No newline at end of file diff --git a/apps/contract-verification/project.json b/apps/contract-verification/project.json new file mode 100644 index 00000000000..dee28fe3260 --- /dev/null +++ b/apps/contract-verification/project.json @@ -0,0 +1,69 @@ +{ + "name": "contract-verification", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/contract-verification/src", + "projectType": "application", + "targets": { + "build": { + "executor": "@nrwl/webpack:webpack", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "development", + "options": { + "compiler": "babel", + "outputPath": "dist/apps/contract-verification", + "index": "apps/contract-verification/src/index.html", + "baseHref": "./", + "main": "apps/contract-verification/src/main.tsx", + "polyfills": "apps/contract-verification/src/polyfills.ts", + "tsConfig": "apps/contract-verification/tsconfig.app.json", + "assets": [ + "apps/contract-verification/src/favicon.ico", + "apps/contract-verification/src/assets", + "apps/contract-verification/src/profile.json" + ], + "styles": ["apps/contract-verification/src/styles.css"], + "scripts": [], + "webpackConfig": "apps/contract-verification/webpack.config.js" + }, + "configurations": { + "development": { + }, + "production": { + "fileReplacements": [ + { + "replace": "apps/contract-verification/src/environments/environment.ts", + "with": "apps/contract-verification/src/environments/environment.prod.ts" + } + ] + } + } + }, + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["apps/contract-verification/**/*.ts"], + "eslintConfig": "apps/contract-verification/.eslintrc" + } + }, + "serve": { + "executor": "@nrwl/webpack:dev-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "contract-verification:build", + "hmr": true, + "baseHref": "/" + }, + "configurations": { + "development": { + "buildTarget": "contract-verification:build:development", + "port": 5003 + }, + "production": { + "buildTarget": "contract-verification:build:production" + } + } + } + }, + "tags": [] +} diff --git a/apps/contract-verification/src/app/App.css b/apps/contract-verification/src/app/App.css new file mode 100644 index 00000000000..74a89ee342b --- /dev/null +++ b/apps/contract-verification/src/app/App.css @@ -0,0 +1,7 @@ +body { + margin: 0; +} + +#root { + padding: 8px 14px; +} \ No newline at end of file diff --git a/apps/contract-verification/src/app/AppContext.tsx b/apps/contract-verification/src/app/AppContext.tsx new file mode 100644 index 00000000000..69d967534d2 --- /dev/null +++ b/apps/contract-verification/src/app/AppContext.tsx @@ -0,0 +1,25 @@ +import React from 'react' +import {PluginClient} from '@remixproject/plugin' + +import {Receipt, ThemeType} from './types' + +export const AppContext = React.createContext({ + apiKey: '', + setAPIKey: (value: string) => { + console.log('Set API Key from Context') + }, + clientInstance: {} as PluginClient, + receipts: [] as Receipt[], + setReceipts: (receipts: Receipt[]) => { + console.log('Calling Set Receipts') + }, + contracts: [] as string[], + setContracts: (contracts: string[]) => { + console.log('Calling Set Contract Names') + }, + themeType: 'dark' as ThemeType, + setThemeType: (themeType: ThemeType) => { + console.log('Calling Set Theme Type') + }, + networkName: '' +}) diff --git a/apps/contract-verification/src/app/EtherscanPluginClient.ts b/apps/contract-verification/src/app/EtherscanPluginClient.ts new file mode 100644 index 00000000000..3d1bf22d943 --- /dev/null +++ b/apps/contract-verification/src/app/EtherscanPluginClient.ts @@ -0,0 +1,70 @@ +import { PluginClient } from '@remixproject/plugin' +import { createClient } from '@remixproject/plugin-webview' +import { verify, EtherScanReturn } from './utils/verify' +import { getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus } from './utils' +import EventManager from 'events' + +export class EtherscanPluginClient extends PluginClient { + public internalEvents: EventManager + + constructor() { + super() + this.internalEvents = new EventManager() + createClient(this) + this.onload() + } + + onActivation(): void { + this.internalEvents.emit('etherscan_activated') + } + + async verify( + apiKey: string, + contractAddress: string, + contractArguments: string, + contractName: string, + compilationResultParam: any, + chainRef?: number | string, + isProxyContract?: boolean, + expectedImplAddress?: string + ) { + const result = await verify( + apiKey, + contractAddress, + contractArguments, + contractName, + compilationResultParam, + chainRef, + isProxyContract, + expectedImplAddress, + this, + (value: EtherScanReturn) => {}, + (value: string) => {} + ) + return result + } + + async receiptStatus(receiptGuid: string, apiKey: string, isProxyContract: boolean) { + try { + const { network, networkId } = await getNetworkName(this) + if (network === 'vm') { + throw new Error('Cannot check the receipt status in the selected network') + } + const etherscanApi = getEtherScanApi(networkId) + let receiptStatus + + if (isProxyContract) receiptStatus = await getProxyContractReceiptStatus(receiptGuid, apiKey, etherscanApi) + else receiptStatus = await getReceiptStatus(receiptGuid, apiKey, etherscanApi) + return { + message: receiptStatus.result, + succeed: receiptStatus.status === '0' ? false : true + } + } catch (e: any) { + return { + status: 'error', + message: e.message, + succeed: false + } + } + } +} diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx new file mode 100644 index 00000000000..bf553d83197 --- /dev/null +++ b/apps/contract-verification/src/app/app.tsx @@ -0,0 +1,136 @@ +import React, {useState, useEffect, useRef} from 'react' + +import {CompilationFileSources, CompilationResult} from '@remixproject/plugin-api' + +import { EtherscanPluginClient } from './EtherscanPluginClient' + +import {AppContext} from './AppContext' +import {DisplayRoutes} from './routes' + +import {useLocalStorage} from './hooks/useLocalStorage' + +import {getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus} from './utils' +import {Receipt, ThemeType} from './types' + +import './App.css' + +export const getNewContractNames = (compilationResult: CompilationResult) => { + const compiledContracts = compilationResult.contracts + let result: string[] = [] + + for (const file of Object.keys(compiledContracts)) { + const newContractNames = Object.keys(compiledContracts[file]) + + result = [...result, ...newContractNames] + } + + return result +} + +const plugin = new EtherscanPluginClient() + +const App = () => { + const [apiKey, setAPIKey] = useLocalStorage('apiKey', '') + const [receipts, setReceipts] = useLocalStorage('receipts', []) + const [contracts, setContracts] = useState([]) + const [themeType, setThemeType] = useState('dark') + const [networkName, setNetworkName] = useState('Loading...') + const timer = useRef(null) + const contractsRef = useRef(contracts) + + contractsRef.current = contracts + + const setListeners = () => { + plugin.on('solidity', 'compilationFinished', (fileName: string, source: CompilationFileSources, languageVersion: string, data: CompilationResult) => { + const newContractsNames = getNewContractNames(data) + + const newContractsToSave: string[] = [...contractsRef.current, ...newContractsNames] + + const uniqueContracts: string[] = [...new Set(newContractsToSave)] + + setContracts(uniqueContracts) + }) + plugin.on('blockchain' as any, 'networkStatus', (result) => { + setNetworkName(`${result.network.name} ${result.network.id !== '-' ? `(Chain id: ${result.network.id})` : '(Not supported)'}`) + }) + // @ts-ignore + plugin.call('blockchain', 'getCurrentNetworkStatus').then((result: any) => setNetworkName(`${result.network.name} ${result.network.id !== '-' ? `(Chain id: ${result.network.id})` : '(Not supported)'}`)) + + } + + useEffect(() => { + plugin.onload(() => { + setListeners() + }) + }, []) + + useEffect(() => { + let receiptsNotVerified: Receipt[] = receipts.filter((item: Receipt) => item.status === 'Pending in queue' || item.status === 'Max rate limit reached') + + if (receiptsNotVerified.length > 0) { + if (timer.current) { + clearInterval(timer.current) + timer.current = null + } + timer.current = setInterval(async () => { + const {network, networkId} = await getNetworkName(plugin) + + if (!plugin) return + if (network === 'vm') return + let newReceipts = receipts + + for (const item of receiptsNotVerified) { + await new Promise((r) => setTimeout(r, 500)) // avoid api rate limit exceed. + let status + if (item.isProxyContract) { + status = await getProxyContractReceiptStatus(item.guid, apiKey, getEtherScanApi(networkId)) + if (status.status === '1') { + status.message = status.result + status.result = 'Successfully Updated' + } + } else status = await getReceiptStatus(item.guid, apiKey, getEtherScanApi(networkId)) + if (status.result === 'Pass - Verified' || status.result === 'Already Verified' || status.result === 'Successfully Updated') { + newReceipts = newReceipts.map((currentReceipt: Receipt) => { + if (currentReceipt.guid === item.guid) { + const res = { + ...currentReceipt, + status: status.result + } + if (currentReceipt.isProxyContract) res.message = status.message + return res + } + return currentReceipt + }) + } + } + receiptsNotVerified = newReceipts.filter((item: Receipt) => item.status === 'Pending in queue' || item.status === 'Max rate limit reached') + if (timer.current && receiptsNotVerified.length === 0) { + clearInterval(timer.current) + timer.current = null + } + setReceipts(newReceipts) + }, 10000) + } + }, [receipts]) + + return ( + + { plugin && } + + ) +} + +export default App diff --git a/apps/contract-verification/src/app/components/HeaderWithSettings.tsx b/apps/contract-verification/src/app/components/HeaderWithSettings.tsx new file mode 100644 index 00000000000..5818b2bc7e1 --- /dev/null +++ b/apps/contract-verification/src/app/components/HeaderWithSettings.tsx @@ -0,0 +1,81 @@ +import React from 'react' + +import {NavLink} from 'react-router-dom' +import {CustomTooltip} from '@remix-ui/helper' +import {AppContext} from '../AppContext' + +interface Props { + title?: string + from: string +} + +interface IconProps { + from: string +} + +const HomeIcon = ({from}: IconProps) => { + return ( + (isActive ? 'border border-secondary shadow-none btn p-1 m-0' : 'border-0 shadow-none btn p-1 m-0')} + style={({isActive}) => (!isActive ? {width: '1.8rem', filter: 'contrast(0.5)'} : {width: '1.8rem'})} + state={from} + > + + + + + ) +} + +const ReceiptsIcon = ({from}: IconProps) => { + return ( + (isActive ? 'border border-secondary shadow-none btn p-1 m-0' : 'border-0 shadow-none btn p-1 m-0')} + style={({isActive}) => (!isActive ? {width: '1.8rem', filter: 'contrast(0.5)'} : {width: '1.8rem'})} + state={from} + > + + + + + ) +} + +const SettingsIcon = ({from}: IconProps) => { + return ( + (isActive ? 'border border-secondary shadow-none btn p-1 m-0' : 'border-0 shadow-none btn p-1 m-0')} + style={({isActive}) => (!isActive ? {width: '1.8rem', filter: 'contrast(0.5)'} : {width: '1.8rem'})} + state={from} + > + + + + + ) +} + +export const HeaderWithSettings = ({title = '', from}) => { + return ( +
+
{title}
+
+ + + +
+
+ ) +} diff --git a/apps/contract-verification/src/app/components/SubmitButton.tsx b/apps/contract-verification/src/app/components/SubmitButton.tsx new file mode 100644 index 00000000000..9f4bed6200f --- /dev/null +++ b/apps/contract-verification/src/app/components/SubmitButton.tsx @@ -0,0 +1,34 @@ +import React from 'react' +import {CustomTooltip} from '@remix-ui/helper' + +interface Props { + text: string + isSubmitting?: boolean + dataId?: string + disable?: boolean +} + +export const SubmitButton = ({text, dataId, isSubmitting = false, disable = true}) => { + return ( +
+ +
+ ) +} diff --git a/apps/contract-verification/src/app/components/index.ts b/apps/contract-verification/src/app/components/index.ts new file mode 100644 index 00000000000..c52e3712f0c --- /dev/null +++ b/apps/contract-verification/src/app/components/index.ts @@ -0,0 +1,2 @@ +export { HeaderWithSettings } from "./HeaderWithSettings" +export { SubmitButton } from "./SubmitButton" diff --git a/apps/contract-verification/src/app/hooks/useLocalStorage.tsx b/apps/contract-verification/src/app/hooks/useLocalStorage.tsx new file mode 100644 index 00000000000..85d30c849de --- /dev/null +++ b/apps/contract-verification/src/app/hooks/useLocalStorage.tsx @@ -0,0 +1,36 @@ +import {useState} from 'react' + +export function useLocalStorage(key: string, initialValue: any) { + // State to store our value + // Pass initial state function to useState so logic is only executed once + const [storedValue, setStoredValue] = useState(() => { + try { + // Get from local storage by key + const item = window.localStorage.getItem(key) + // Parse stored json or if none return initialValue + return item ? JSON.parse(item) : initialValue + } catch (error) { + // If error also return initialValue + console.error(error) + return initialValue + } + }) + + // Return a wrapped version of useState's setter function that ... + // ... persists the new value to localStorage. + const setValue = (value: any) => { + try { + // Allow value to be a function so we have same API as useState + const valueToStore = value instanceof Function ? value(storedValue) : value + // Save state + setStoredValue(valueToStore) + // Save to local storage + window.localStorage.setItem(key, JSON.stringify(valueToStore)) + } catch (error) { + // A more advanced implementation would handle the error case + console.error(error) + } + } + + return [storedValue, setValue] +} diff --git a/apps/contract-verification/src/app/layouts/Default.tsx b/apps/contract-verification/src/app/layouts/Default.tsx new file mode 100644 index 00000000000..fa9a1111e57 --- /dev/null +++ b/apps/contract-verification/src/app/layouts/Default.tsx @@ -0,0 +1,17 @@ +import React, {PropsWithChildren} from 'react' + +import {HeaderWithSettings} from '../components' + +interface Props { + from: string + title?: string +} + +export const DefaultLayout = ({children, from, title}) => { + return ( +
+ + {children} +
+ ) +} diff --git a/apps/contract-verification/src/app/layouts/index.ts b/apps/contract-verification/src/app/layouts/index.ts new file mode 100644 index 00000000000..9b8e6166d59 --- /dev/null +++ b/apps/contract-verification/src/app/layouts/index.ts @@ -0,0 +1 @@ +export { DefaultLayout } from "./Default" diff --git a/apps/contract-verification/src/app/routes.tsx b/apps/contract-verification/src/app/routes.tsx new file mode 100644 index 00000000000..165b5ae5a71 --- /dev/null +++ b/apps/contract-verification/src/app/routes.tsx @@ -0,0 +1,37 @@ +import React from 'react' +import {HashRouter as Router, Route, Routes, RouteProps} from 'react-router-dom' + +import {ErrorView, HomeView, ReceiptsView, CaptureKeyView} from './views' +import {DefaultLayout} from './layouts' + +export const DisplayRoutes = () => ( + + + + + + } + /> + } /> + + + + } + /> + + + + } + /> + + +) diff --git a/apps/contract-verification/src/app/types/Receipt.ts b/apps/contract-verification/src/app/types/Receipt.ts new file mode 100644 index 00000000000..2dd501651dd --- /dev/null +++ b/apps/contract-verification/src/app/types/Receipt.ts @@ -0,0 +1,9 @@ +export type ReceiptStatus = "Pending in queue" | "Pass - Verified" | "Already Verified" | "Max rate limit reached" | "Successfully Updated" + +export interface Receipt { + guid: string + status: ReceiptStatus + isProxyContract: boolean + message?: string + succeed?: boolean +} diff --git a/apps/contract-verification/src/app/types/ThemeType.ts b/apps/contract-verification/src/app/types/ThemeType.ts new file mode 100644 index 00000000000..13b3710cd0d --- /dev/null +++ b/apps/contract-verification/src/app/types/ThemeType.ts @@ -0,0 +1 @@ +export type ThemeType = "dark" | "light" diff --git a/apps/contract-verification/src/app/types/index.ts b/apps/contract-verification/src/app/types/index.ts new file mode 100644 index 00000000000..1a8733d6ff0 --- /dev/null +++ b/apps/contract-verification/src/app/types/index.ts @@ -0,0 +1,2 @@ +export * from "./Receipt" +export * from "./ThemeType" diff --git a/apps/contract-verification/src/app/utils/index.ts b/apps/contract-verification/src/app/utils/index.ts new file mode 100644 index 00000000000..b23d52e6e05 --- /dev/null +++ b/apps/contract-verification/src/app/utils/index.ts @@ -0,0 +1 @@ +export * from "./utilities" diff --git a/apps/contract-verification/src/app/utils/networks.ts b/apps/contract-verification/src/app/utils/networks.ts new file mode 100644 index 00000000000..fdb28e50a8f --- /dev/null +++ b/apps/contract-verification/src/app/utils/networks.ts @@ -0,0 +1,42 @@ +export const scanAPIurls = { + // all mainnet + 1: 'https://api.etherscan.io/api', + 56: 'https://api.bscscan.com/api', + 137: 'https://api.polygonscan.com/api', + 250: 'https://api.ftmscan.com/api', + 42161: 'https://api.arbiscan.io/api', + 43114: 'https://api.snowtrace.io/api', + 1285: 'https://api-moonriver.moonscan.io/api', + 1284: 'https://api-moonbeam.moonscan.io/api', + 25: 'https://api.cronoscan.com/api', + 199: 'https://api.bttcscan.com/api', + 10: 'https://api-optimistic.etherscan.io/api', + 42220: 'https://api.celoscan.io/api', + 288: 'https://api.bobascan.com/api', + 100: 'https://api.gnosisscan.io/api', + 1101: 'https://api-zkevm.polygonscan.com/api', + 59144: 'https://api.lineascan.build/api', + 8453: 'https://api.basescan.org/api', + 534352: 'https://api.scrollscan.com/api', + + // all testnet + 17000: 'https://api-holesky.etherscan.io/api', + 11155111: 'https://api-sepolia.etherscan.io/api', + 97: 'https://api-testnet.bscscan.com/api', + 80001: 'https://api-testnet.polygonscan.com/api', + 4002: 'https://api-testnet.ftmscan.com/api', + 421611: 'https://api-testnet.arbiscan.io/api', + 42170: 'https://api-nova.arbiscan.io/api', + 43113: 'https://api-testnet.snowtrace.io/api', + 1287: 'https://api-moonbase.moonscan.io/api', + 338: 'https://api-testnet.cronoscan.com/api', + 1028: 'https://api-testnet.bttcscan.com/api', + 420: 'https://api-goerli-optimistic.etherscan.io/api', + 44787: 'https://api-alfajores.celoscan.io/api', + 2888: 'https://api-testnet.bobascan.com/api', + 84531: 'https://api-goerli.basescan.org/api', + 84532: "https://api-sepolia.basescan.org/api", + 1442: 'https://api-testnet-zkevm.polygonscan.com/api', + 59140: 'https://api-testnet.lineascan.build/api', + 534351: 'https://api-sepolia.scrollscan.com/api', +} diff --git a/apps/contract-verification/src/app/utils/scripts.ts b/apps/contract-verification/src/app/utils/scripts.ts new file mode 100644 index 00000000000..0d204d8d557 --- /dev/null +++ b/apps/contract-verification/src/app/utils/scripts.ts @@ -0,0 +1,30 @@ +export const verifyScript = ` +/** + * @param {string} apikey - etherscan api key + * @param {string} contractAddress - Address of the contract to verify + * @param {string} contractArguments - Parameters used in the contract constructor during the initial deployment. It should be the hex encoded value + * @param {string} contractName - Name of the contract + * @param {string} contractFile - File where the contract is located + * @param {number | string} chainRef - Network chain id or API URL (optional) + * @param {boolean} isProxyContract - true, if contract is a proxy contract (optional) + * @param {string} expectedImplAddress - Implementation contract address, in case of proxy contract verification (optional) + * @returns {{ guid, status, message, succeed }} verification result + */ +export const verify = async (apikey: string, contractAddress: string, contractArguments: string, contractName: string, contractFile: string, chainRef?: number | string, isProxyContract?: boolean, expectedImplAddress?: string) => { + const compilationResultParam = await remix.call('compilerArtefacts' as any, 'getCompilerAbstract', contractFile) + console.log('verifying.. ' + contractName) + // update apiKey and chainRef to verify contract on multiple networks + return await remix.call('etherscan' as any, 'verify', apikey, contractAddress, contractArguments, contractName, compilationResultParam, chainRef, isProxyContract, expectedImplAddress) +}` + +export const receiptGuidScript = ` +/** + * @param {string} apikey - etherscan api key + * @param {string} guid - receipt id + * @param {boolean} isProxyContract - true, if contract is a proxy contract (optional) + * @returns {{ status, message, succeed }} receiptStatus + */ +export const receiptStatus = async (apikey: string, guid: string, isProxyContract?: boolean) => { + return await remix.call('etherscan' as any, 'receiptStatus', guid, apikey, isProxyContract) +} +` \ No newline at end of file diff --git a/apps/contract-verification/src/app/utils/utilities.ts b/apps/contract-verification/src/app/utils/utilities.ts new file mode 100644 index 00000000000..048b6e2335b --- /dev/null +++ b/apps/contract-verification/src/app/utils/utilities.ts @@ -0,0 +1,69 @@ +import { PluginClient } from "@remixproject/plugin" +import axios from 'axios' +import { scanAPIurls } from "./networks" +type RemixClient = PluginClient + +/* + status: 0=Error, 1=Pass + message: OK, NOTOK + result: explanation +*/ +export type receiptStatus = { + result: string + message: string + status: string +} + +export const getEtherScanApi = (networkId: any) => { + if (!(networkId in scanAPIurls)) { + throw new Error("no known network to verify against") + } + const apiUrl = (scanAPIurls as any)[networkId] + return apiUrl +} + +export const getNetworkName = async (client: RemixClient) => { + const network = await client.call("network", "detectNetwork") + if (!network) { + throw new Error("no known network to verify against") + } + return { network: network.name!.toLowerCase(), networkId: network.id } +} + +export const getReceiptStatus = async ( + receiptGuid: string, + apiKey: string, + etherscanApi: string +): Promise => { + const params = `guid=${receiptGuid}&module=contract&action=checkverifystatus&apiKey=${apiKey}` + try { + const response = await axios.get(`${etherscanApi}?${params}`) + const { result, message, status } = response.data + return { + result, + message, + status, + } + } catch (error) { + console.error(error) + } +} + +export const getProxyContractReceiptStatus = async ( + receiptGuid: string, + apiKey: string, + etherscanApi: string +): Promise => { + const params = `guid=${receiptGuid}&module=contract&action=checkproxyverification&apiKey=${apiKey}` + try { + const response = await axios.get(`${etherscanApi}?${params}`) + const { result, message, status } = response.data + return { + result, + message, + status, + } + } catch (error) { + console.error(error) + } +} diff --git a/apps/contract-verification/src/app/utils/verify.ts b/apps/contract-verification/src/app/utils/verify.ts new file mode 100644 index 00000000000..a459fb5499e --- /dev/null +++ b/apps/contract-verification/src/app/utils/verify.ts @@ -0,0 +1,206 @@ +import { getNetworkName, getEtherScanApi, getReceiptStatus, getProxyContractReceiptStatus } from "." +import { CompilationResult } from "@remixproject/plugin-api" +import { CompilerAbstract } from '@remix-project/remix-solidity' +import axios from 'axios' +import { PluginClient } from "@remixproject/plugin" + +const resetAfter10Seconds = (client: PluginClient, setResults: (value: string) => void) => { + setTimeout(() => { + client.emit("statusChanged", { key: "none" }) + setResults("") + }, 10000) +} + +export type EtherScanReturn = { + guid: any, + status: any, +} +export const verify = async ( + apiKeyParam: string, + contractAddress: string, + contractArgumentsParam: string, + contractName: string, + compilationResultParam: CompilerAbstract, + chainRef: number | string, + isProxyContract: boolean, + expectedImplAddress: string, + client: PluginClient, + onVerifiedContract: (value: EtherScanReturn) => void, + setResults: (value: string) => void +) => { + let networkChainId + let etherscanApi + if (chainRef) { + if (typeof chainRef === 'number') { + networkChainId = chainRef + etherscanApi = getEtherScanApi(networkChainId) + } else if (typeof chainRef === 'string') etherscanApi = chainRef + } else { + const { network, networkId } = await getNetworkName(client) + if (network === "vm") { + return { + succeed: false, + message: "Cannot verify in the selected network" + } + } else { + networkChainId = networkId + etherscanApi = getEtherScanApi(networkChainId) + } + } + + try { + const contractMetadata = getContractMetadata( + // cast from the remix-plugin interface to the solidity one. Should be fixed when remix-plugin move to the remix-project repository + compilationResultParam.data as unknown as CompilationResult, + contractName + ) + + if (!contractMetadata) { + return { + succeed: false, + message: "Please recompile contract" + } + } + + const contractMetadataParsed = JSON.parse(contractMetadata) + + const fileName = getContractFileName( + // cast from the remix-plugin interface to the solidity one. Should be fixed when remix-plugin move to the remix-project repository + compilationResultParam.data as unknown as CompilationResult, + contractName + ) + + const jsonInput = { + language: 'Solidity', + sources: compilationResultParam.source.sources, + settings: { + optimizer: { + enabled: contractMetadataParsed.settings.optimizer.enabled, + runs: contractMetadataParsed.settings.optimizer.runs + } + } + } + + const data: { [key: string]: string | any } = { + apikey: apiKeyParam, // A valid API-Key is required + module: "contract", // Do not change + action: "verifysourcecode", // Do not change + codeformat: "solidity-standard-json-input", + sourceCode: JSON.stringify(jsonInput), + contractname: fileName + ':' + contractName, + compilerversion: `v${contractMetadataParsed.compiler.version}`, // see http://etherscan.io/solcversions for list of support versions + constructorArguements: contractArgumentsParam ? contractArgumentsParam.replace('0x', '') : '', // if applicable + } + + if (isProxyContract) { + data.action = "verifyproxycontract" + data.expectedimplementation = expectedImplAddress + data.address = contractAddress + } else { + data.contractaddress = contractAddress + } + + const body = new FormData() + Object.keys(data).forEach((key) => body.append(key, data[key])) + + client.emit("statusChanged", { + key: "loading", + type: "info", + title: "Verifying ...", + }) + const response = await axios.post(etherscanApi, body) + const { message, result, status } = await response.data + + if (message === "OK" && status === "1") { + resetAfter10Seconds(client, setResults) + let receiptStatus + if (isProxyContract) { + receiptStatus = await getProxyContractReceiptStatus( + result, + apiKeyParam, + etherscanApi + ) + if (receiptStatus.status === '1') { + receiptStatus.message = receiptStatus.result + receiptStatus.result = 'Successfully Updated' + } + } else receiptStatus = await getReceiptStatus( + result, + apiKeyParam, + etherscanApi + ) + + const returnValue = { + guid: result, + status: receiptStatus.result, + message: `Verification request submitted successfully. Use this receipt GUID ${result} to track the status of your submission`, + succeed: true, + isProxyContract + } + onVerifiedContract(returnValue) + return returnValue + } else if (message === "NOTOK") { + client.emit("statusChanged", { + key: "failed", + type: "error", + title: result, + }) + const returnValue = { + message: result, + succeed: false, + isProxyContract + } + resetAfter10Seconds(client, setResults) + return returnValue + } + return { + message: 'unknown reason ' + result, + succeed: false + } + } catch (error: any) { + console.error(error) + setResults("Something wrong happened, try again") + return { + message: error.message, + succeed: false + } + } +} + +export const getContractFileName = ( + compilationResult: CompilationResult, + contractName: string +) => { + const compiledContracts = compilationResult.contracts + let fileName = "" + + for (const file of Object.keys(compiledContracts)) { + for (const contract of Object.keys(compiledContracts[file])) { + if (contract === contractName) { + fileName = file + break + } + } + } + return fileName +} + +export const getContractMetadata = ( + compilationResult: CompilationResult, + contractName: string +) => { + const compiledContracts = compilationResult.contracts + let contractMetadata = "" + + for (const file of Object.keys(compiledContracts)) { + for (const contract of Object.keys(compiledContracts[file])) { + if (contract === contractName) { + contractMetadata = compiledContracts[file][contract].metadata + if (contractMetadata) { + break + } + } + } + } + return contractMetadata +} diff --git a/apps/contract-verification/src/app/views/CaptureKeyView.tsx b/apps/contract-verification/src/app/views/CaptureKeyView.tsx new file mode 100644 index 00000000000..e63ec4278de --- /dev/null +++ b/apps/contract-verification/src/app/views/CaptureKeyView.tsx @@ -0,0 +1,63 @@ +import React, {useState, useEffect} from 'react' + +import {Formik, ErrorMessage, Field} from 'formik' +import {useNavigate, useLocation} from 'react-router-dom' + +import {AppContext} from '../AppContext' +import {SubmitButton} from '../components' + +export const CaptureKeyView = () => { + const location = useLocation() + const navigate = useNavigate() + const [msg, setMsg] = useState('') + const context = React.useContext(AppContext) + + useEffect(() => { + if (!context.apiKey) setMsg('Please provide a 34-character API key to continue') + }, [context.apiKey]) + + return ( +
+ { + const errors = {} as any + if (!values.apiKey) { + errors.apiKey = 'Required' + } else if (values.apiKey.length !== 34) { + errors.apiKey = 'API key should be 34 characters long' + } + return errors + }} + onSubmit={(values) => { + const apiKey = values.apiKey + if (apiKey.length === 34) { + context.setAPIKey(values.apiKey) + navigate(location && location.state ? location.state : '/') + } + }} + > + {({errors, touched, handleSubmit}) => ( +
+
+ + + +
+ +
+ +
+
+ )} +
+ +
+
+ ) +} diff --git a/apps/contract-verification/src/app/views/ErrorView.tsx b/apps/contract-verification/src/app/views/ErrorView.tsx new file mode 100644 index 00000000000..90ee41e62a8 --- /dev/null +++ b/apps/contract-verification/src/app/views/ErrorView.tsx @@ -0,0 +1,16 @@ +import React from 'react' + +export const ErrorView = () => { + return ( +
+ Error page +
Sorry, something unexpected happened.
+
+ Please raise an issue:{' '} + + Here + +
+
+ ) +} diff --git a/apps/contract-verification/src/app/views/HomeView.tsx b/apps/contract-verification/src/app/views/HomeView.tsx new file mode 100644 index 00000000000..d0cda503d61 --- /dev/null +++ b/apps/contract-verification/src/app/views/HomeView.tsx @@ -0,0 +1,31 @@ +import React from 'react' + +import {Navigate} from 'react-router-dom' + +import {AppContext} from '../AppContext' +import {Receipt} from '../types' + +import {VerifyView} from './VerifyView' + +export const HomeView = () => { + const context = React.useContext(AppContext) + + return !context.apiKey ? ( + + ) : ( + { + const newReceipts = [...context.receipts, receipt] + context.setReceipts(newReceipts) + }} + networkName={context.networkName} + /> + ) +} diff --git a/apps/contract-verification/src/app/views/ReceiptsView.tsx b/apps/contract-verification/src/app/views/ReceiptsView.tsx new file mode 100644 index 00000000000..9a2c3454627 --- /dev/null +++ b/apps/contract-verification/src/app/views/ReceiptsView.tsx @@ -0,0 +1,170 @@ +import React, {useState} from 'react' + +import {Formik, ErrorMessage, Field} from 'formik' +import {getEtherScanApi, getNetworkName, getReceiptStatus, getProxyContractReceiptStatus} from '../utils' +import {Receipt} from '../types' +import {AppContext} from '../AppContext' +import {SubmitButton} from '../components' +import {Navigate} from 'react-router-dom' +import {Button} from 'react-bootstrap' +import {CustomTooltip} from '@remix-ui/helper' + +interface FormValues { + receiptGuid: string +} + +export const ReceiptsView = () => { + const [results, setResults] = useState({succeed: false, message: ''}) + const [isProxyContractReceipt, setIsProxyContractReceipt] = useState(false) + const context = React.useContext(AppContext) + + const onGetReceiptStatus = async (values: FormValues, clientInstance: any, apiKey: string) => { + try { + const {network, networkId} = await getNetworkName(clientInstance) + if (network === 'vm') { + setResults({ + succeed: false, + message: 'Cannot verify in the selected network' + }) + return + } + const etherscanApi = getEtherScanApi(networkId) + let result + if (isProxyContractReceipt) { + result = await getProxyContractReceiptStatus(values.receiptGuid, apiKey, etherscanApi) + if (result.status === '1') { + result.message = result.result + result.result = 'Successfully Updated' + } + } else result = await getReceiptStatus(values.receiptGuid, apiKey, etherscanApi) + setResults({ + succeed: result.status === '1' ? true : false, + message: result.result || (result.status === '0' ? 'Verification failed' : result.message) + }) + } catch (error: any) { + setResults({ + succeed: false, + message: error.message + }) + } + } + + return !context.apiKey ? ( + + ) : ( +
+ { + const errors = {} as any + if (!values.receiptGuid) { + errors.receiptGuid = 'Required' + } + return errors + }} + onSubmit={(values) => onGetReceiptStatus(values, context.clientInstance, context.apiKey)} + > + {({errors, touched, handleSubmit, handleChange}) => ( +
+
+ + + +
+ +
+ { + handleChange(e) + if (e.target.checked) setIsProxyContractReceipt(true) + else setIsProxyContractReceipt(false) + }} + /> + +
+ + + )} +
+ +
+ + +
+ + + +
+ ) +} + +const ReceiptsTable = ({receipts}) => { + return ( +
+
Receipts
+ + + + + + + + + {receipts && + receipts.length > 0 && + receipts.map((item: Receipt, index) => { + return ( + + + + + ) + })} + +
StatusGUID
+ {item.status} + {item.status === 'Successfully Updated' && ( + + + + )} + {item.guid}
+
+ ) +} diff --git a/apps/contract-verification/src/app/views/VerifyView.tsx b/apps/contract-verification/src/app/views/VerifyView.tsx new file mode 100644 index 00000000000..ca70dba74cd --- /dev/null +++ b/apps/contract-verification/src/app/views/VerifyView.tsx @@ -0,0 +1,235 @@ +import React, {useEffect, useRef, useState} from 'react' +import Web3 from 'web3' + +import {PluginClient} from '@remixproject/plugin' +import {CustomTooltip} from '@remix-ui/helper' +import {Formik, ErrorMessage, Field} from 'formik' + +import {SubmitButton} from '../components' +import {Receipt} from '../types' +import {verify} from '../utils/verify' +import {etherscanScripts} from '@remix-project/remix-ws-templates' + +interface Props { + client: PluginClient + apiKey: string + onVerifiedContract: (receipt: Receipt) => void + contracts: string[], + networkName: string +} + +interface FormValues { + contractName: string + contractAddress: string + expectedImplAddress?: string +} + +export const VerifyView = ({apiKey, client, contracts, onVerifiedContract, networkName}) => { + const [results, setResults] = useState('') + const [selectedContract, setSelectedContract] = useState('') + const [showConstructorArgs, setShowConstructorArgs] = useState(false) + const [isProxyContract, setIsProxyContract] = useState(false) + const [constructorInputs, setConstructorInputs] = useState([]) + const verificationResult = useRef({}) + + useEffect(() => { + if (contracts.includes(selectedContract)) updateConsFields(selectedContract) + }, [contracts]) + + const updateConsFields = (contractName) => { + client.call('compilerArtefacts' as any, 'getArtefactsByContractName', contractName).then((result) => { + const {artefact} = result + if (artefact && artefact.abi && artefact.abi[0] && artefact.abi[0].type && artefact.abi[0].type === 'constructor' && artefact.abi[0].inputs.length > 0) { + setConstructorInputs(artefact.abi[0].inputs) + setShowConstructorArgs(true) + } else { + setConstructorInputs([]) + setShowConstructorArgs(false) + } + }) + } + + const onVerifyContract = async (values: FormValues) => { + const compilationResult = (await client.call('solidity', 'getCompilationResult')) as any + + if (!compilationResult) { + throw new Error('no compilation result available') + } + + const constructorValues = [] + for (const key in values) { + if (key.startsWith('contractArgValue')) constructorValues.push(values[key]) + } + const web3 = new Web3() + const constructorTypes = constructorInputs.map((e) => e.type) + let contractArguments = web3.eth.abi.encodeParameters(constructorTypes, constructorValues) + contractArguments = contractArguments.replace('0x', '') + + verificationResult.current = await verify( + apiKey, + values.contractAddress, + contractArguments, + values.contractName, + compilationResult, + null, + isProxyContract, + values.expectedImplAddress, + client, + onVerifiedContract, + setResults + ) + setResults(verificationResult.current['message']) + } + + return ( +
+ { + const errors = {} as any + if (!values.contractName) { + errors.contractName = 'Required' + } + if (!values.contractAddress) { + errors.contractAddress = 'Required' + } + if (values.contractAddress.trim() === '' || !values.contractAddress.startsWith('0x') || values.contractAddress.length !== 42) { + errors.contractAddress = 'Please enter a valid contract address' + } + return errors + }} + onSubmit={(values) => onVerifyContract(values)} + > + {({errors, touched, handleSubmit, handleChange, isSubmitting}) => { + return ( +
+
+ + + + +
+
+ + { + handleChange(e) + setSelectedContract(e.target.value) + updateConsFields(e.target.value) + }} + > + + {contracts.map((item) => ( + + ))} + + +
+
+ + {constructorInputs.map((item, index) => { + return ( +
+ + + + +
+ ) + })} +
+
+ + + +
+ { + handleChange(e) + if (e.target.checked) setIsProxyContract(true) + else setIsProxyContract(false) + }} + /> + +
+
+
+ + + + + + +
+ +
+ + + + + ) + }} +
+
+ {/*
+ View Receipts +
*/} +
+ ) +} diff --git a/apps/contract-verification/src/app/views/index.ts b/apps/contract-verification/src/app/views/index.ts new file mode 100644 index 00000000000..c483228ece4 --- /dev/null +++ b/apps/contract-verification/src/app/views/index.ts @@ -0,0 +1,4 @@ +export { HomeView } from "./HomeView" +export { ErrorView } from "./ErrorView" +export { ReceiptsView } from "./ReceiptsView" +export { CaptureKeyView } from "./CaptureKeyView" diff --git a/apps/contract-verification/src/assets/.gitkeep b/apps/contract-verification/src/assets/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/contract-verification/src/environments/environment.prod.ts b/apps/contract-verification/src/environments/environment.prod.ts new file mode 100644 index 00000000000..3612073bc31 --- /dev/null +++ b/apps/contract-verification/src/environments/environment.prod.ts @@ -0,0 +1,3 @@ +export const environment = { + production: true +}; diff --git a/apps/contract-verification/src/environments/environment.ts b/apps/contract-verification/src/environments/environment.ts new file mode 100644 index 00000000000..d9370e924b5 --- /dev/null +++ b/apps/contract-verification/src/environments/environment.ts @@ -0,0 +1,6 @@ +// This file can be replaced during build by using the `fileReplacements` array. +// When building for production, this file is replaced with `environment.prod.ts`. + +export const environment = { + production: false +}; diff --git a/apps/contract-verification/src/favicon.ico b/apps/contract-verification/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57 GIT binary patch literal 15086 zcmeI332;U^%p|z7g|#(P)qFEA@4f!_@qOK2 z_lJl}!lhL!VT_U|uN7%8B2iKH??xhDa;*`g{yjTFWHvXn;2s{4R7kH|pKGdy(7z!K zgftM+Ku7~24TLlh(!g)gz|foI94G^t2^IO$uvX$3(OR0<_5L2sB)lMAMy|+`xodJ{ z_Uh_1m)~h?a;2W{dmhM;u!YGo=)OdmId_B<%^V^{ovI@y`7^g1_V9G}*f# zNzAtvou}I!W1#{M^@ROc(BZ! z+F!!_aR&Px3_reO(EW+TwlW~tv*2zr?iP7(d~a~yA|@*a89IUke+c472NXM0wiX{- zl`UrZC^1XYyf%1u)-Y)jj9;MZ!SLfd2Hl?o|80Su%Z?To_=^g_Jt0oa#CT*tjx>BI z16wec&AOWNK<#i0Qd=1O$fymLRoUR*%;h@*@v7}wApDl^w*h}!sYq%kw+DKDY)@&A z@9$ULEB3qkR#85`lb8#WZw=@})#kQig9oqy^I$dj&k4jU&^2(M3q{n1AKeGUKPFbr z1^<)aH;VsG@J|B&l>UtU#Ejv3GIqERzYgL@UOAWtW<{p#zy`WyJgpCy8$c_e%wYJL zyGHRRx38)HyjU3y{-4z6)pzb>&Q1pR)B&u01F-|&Gx4EZWK$nkUkOI|(D4UHOXg_- zw{OBf!oWQUn)Pe(=f=nt=zkmdjpO^o8ZZ9o_|4tW1ni+Un9iCW47*-ut$KQOww!;u z`0q)$s6IZO!~9$e_P9X!hqLxu`fpcL|2f^I5d4*a@Dq28;@2271v_N+5HqYZ>x;&O z05*7JT)mUe&%S0@UD)@&8SmQrMtsDfZT;fkdA!r(S=}Oz>iP)w=W508=Rc#nNn7ym z1;42c|8($ALY8#a({%1#IXbWn9-Y|0eDY$_L&j{63?{?AH{);EzcqfydD$@-B`Y3<%IIj7S7rK_N}je^=dEk%JQ4c z!tBdTPE3Tse;oYF>cnrapWq*o)m47X1`~6@(!Y29#>-#8zm&LXrXa(3=7Z)ElaQqj z-#0JJy3Fi(C#Rx(`=VXtJ63E2_bZGCz+QRa{W0e2(m3sI?LOcUBx)~^YCqZ{XEPX)C>G>U4tfqeH8L(3|pQR*zbL1 zT9e~4Tb5p9_G}$y4t`i*4t_Mr9QYvL9C&Ah*}t`q*}S+VYh0M6GxTTSXI)hMpMpIq zD1ImYqJLzbj0}~EpE-aH#VCH_udYEW#`P2zYmi&xSPs_{n6tBj=MY|-XrA;SGA_>y zGtU$?HXm$gYj*!N)_nQ59%lQdXtQZS3*#PC-{iB_sm+ytD*7j`D*k(P&IH2GHT}Eh z5697eQECVIGQAUe#eU2I!yI&%0CP#>%6MWV z@zS!p@+Y1i1b^QuuEF*13CuB zu69dve5k7&Wgb+^s|UB08Dr3u`h@yM0NTj4h7MnHo-4@xmyr7(*4$rpPwsCDZ@2be zRz9V^GnV;;?^Lk%ynzq&K(Aix`mWmW`^152Hoy$CTYVehpD-S1-W^#k#{0^L`V6CN+E z!w+xte;2vu4AmVNEFUOBmrBL>6MK@!O2*N|2=d|Y;oN&A&qv=qKn73lDD zI(+oJAdgv>Yr}8(&@ZuAZE%XUXmX(U!N+Z_sjL<1vjy1R+1IeHt`79fnYdOL{$ci7 z%3f0A*;Zt@ED&Gjm|OFTYBDe%bbo*xXAQsFz+Q`fVBH!N2)kaxN8P$c>sp~QXnv>b zwq=W3&Mtmih7xkR$YA)1Yi?avHNR6C99!u6fh=cL|KQ&PwF!n@ud^n(HNIImHD!h87!i*t?G|p0o+eelJ?B@A64_9%SBhNaJ64EvKgD&%LjLCYnNfc; znj?%*p@*?dq#NqcQFmmX($wms@CSAr9#>hUR^=I+=0B)vvGX%T&#h$kmX*s=^M2E!@N9#m?LhMvz}YB+kd zG~mbP|D(;{s_#;hsKK9lbVK&Lo734x7SIFJ9V_}2$@q?zm^7?*XH94w5Qae{7zOMUF z^?%F%)c1Y)Q?Iy?I>knw*8gYW#ok|2gdS=YYZLiD=CW|Nj;n^x!=S#iJ#`~Ld79+xXpVmUK^B(xO_vO!btA9y7w3L3-0j-y4 z?M-V{%z;JI`bk7yFDcP}OcCd*{Q9S5$iGA7*E1@tfkyjAi!;wP^O71cZ^Ep)qrQ)N z#wqw0_HS;T7x3y|`P==i3hEwK%|>fZ)c&@kgKO1~5<5xBSk?iZV?KI6&i72H6S9A* z=U(*e)EqEs?Oc04)V-~K5AUmh|62H4*`UAtItO$O(q5?6jj+K^oD!04r=6#dsxp?~}{`?&sXn#q2 zGuY~7>O2=!u@@Kfu7q=W*4egu@qPMRM>(eyYyaIE<|j%d=iWNdGsx%c!902v#ngNg z@#U-O_4xN$s_9?(`{>{>7~-6FgWpBpqXb`Ydc3OFL#&I}Irse9F_8R@4zSS*Y*o*B zXL?6*Aw!AfkNCgcr#*yj&p3ZDe2y>v$>FUdKIy_2N~}6AbHc7gA3`6$g@1o|dE>vz z4pl(j9;kyMsjaw}lO?(?Xg%4k!5%^t#@5n=WVc&JRa+XT$~#@rldvN3S1rEpU$;XgxVny7mki3 z-Hh|jUCHrUXuLr!)`w>wgO0N%KTB-1di>cj(x3Bav`7v z3G7EIbU$z>`Nad7Rk_&OT-W{;qg)-GXV-aJT#(ozdmnA~Rq3GQ_3mby(>q6Ocb-RgTUhTN)))x>m&eD;$J5Bg zo&DhY36Yg=J=$Z>t}RJ>o|@hAcwWzN#r(WJ52^g$lh^!63@hh+dR$&_dEGu&^CR*< z!oFqSqO@>xZ*nC2oiOd0eS*F^IL~W-rsrO`J`ej{=ou_q^_(<$&-3f^J z&L^MSYWIe{&pYq&9eGaArA~*kA + + + + Etherscan + + + + + + + +
+ + + diff --git a/apps/contract-verification/src/main.tsx b/apps/contract-verification/src/main.tsx new file mode 100644 index 00000000000..077b7ac8f4a --- /dev/null +++ b/apps/contract-verification/src/main.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import * as ReactDOM from 'react-dom' +import { createRoot } from 'react-dom/client'; +import App from './app/app' + + +const container = document.getElementById('root'); + +if (container) { + createRoot(container).render( + + ); +} + diff --git a/apps/contract-verification/src/polyfills.ts b/apps/contract-verification/src/polyfills.ts new file mode 100644 index 00000000000..2adf3d05b6f --- /dev/null +++ b/apps/contract-verification/src/polyfills.ts @@ -0,0 +1,7 @@ +/** + * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. + * + * See: https://github.com/zloirock/core-js#babel + */ +import 'core-js/stable'; +import 'regenerator-runtime/runtime'; diff --git a/apps/contract-verification/src/profile.json b/apps/contract-verification/src/profile.json new file mode 100644 index 00000000000..f2feb39afa7 --- /dev/null +++ b/apps/contract-verification/src/profile.json @@ -0,0 +1,16 @@ +{ + "name": "contreact-verification", + "displayName": "[NEW] Contract verification", + "description": "VERIFY CODE", + "version": "0.1.0", + "events": [], + "methods": ["verify", "receiptStatus"], + "kind": "none", + "icon": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAADWCAQAAACUa5RrAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAB3RJTUUH5QUODTESn149ewAAAAJiS0dEAACqjSMyAAAQqUlEQVR42u2d+X/W1ZXH75M9lEBIIAmE5Ps+CBQILtSlIyiDG+BQdZAX2hlaKuM24lhrlbpWJYR9E6JQW0bEcRBlmHamIsqIwlhBEaVSEJRNkD2QhC1AIHn6QyJQBSHhec73fp9c7h9Anvv53Ps9933PPccY9y/w/zDEk0gy2VzCTdxLIb+kDz1pTxpJJBDCTVJMGyBEd55iLitlg2yW7VIiO2SzbJL1LOJZbqWlM0CsrvwQ6fyE2fIX2SlHJPytUSllskEW8Gu6EOdsEGvyp3MLr8hnUnkK6U8eR2WbvMswWjkTxI74hnYMk+VSfQbxvx5VUsI0rifNWSAW5E/iEqZI6VmK//U4Jv/P7WQ5CwT/y38Vc2R/HeWvGZ8zmObOAsHe/C/gD/US/4QFmjkLBNcAwgw5cA4GCMsX3OXFOwsEc/NPY0Y9N/+Tx3wuxzgLBG/zT6VQtp2z/GGpZDrfcwYImvwpDJQNZ33w++6xlnvcHhAsA6TQW1bJ0YjIH5ZqmU8mITezQZE/gUt494zMry5jPf9MgpvboGz/bXklovKH5SCzSXazGwwDwASpiKj8YQmzmrZudoMgfyZDZG+k5ZewbGWgm1/r5fdS+Rf5PAryh6WUqW6G7Q/+bpT3oiJ/WCr4wM2x3fKH6CpvRkn+sFTylZtlmyN/Q1tmnTLTJ1Kjys20zQZozG+lPIryhyXsZtrmr/9Y2RFd+Z0B7JU/hbtkY5TlPyYlbq5tlb+XLI8Y9z/dOMRyN9s2yp/ED2V+VIO/mrGf191823j068j0CHP/U4/djHMzbl/sn8cIjijIH5bN3Ojm3DYDNON+ylXkD8tymrs5t0p+L55BbFOSv5yp7jrYtu2/ryxVkj8sn3Et8W7ebZK/m/wxQhl/Z3EPIHNIxk28RQboKLPksNr6/5SbnPw2rf4snpM9avLvoMilhdskfyJPsVVN/mqZRQcnvz0GSOZuNqjJH5ZFcr24NwEWyX8dq6VKL/qXgfku/LNG/kR+wAI5ovj1f5hsJ78t4CeODjJNUf5yRuE5+e0J/vIpkmNq8h9mBue5F4H2yJ/Bz9W4f1gqWczFuLoA1hggngFsVpO/Sr7kUhLd+rfHAP1YoQZ+w7JB+pHqDn/2yN+DeYryb+dhmnghJ78t8neSl+Sgmvy7mEQuTn5r5M+VSbJLTf69zHDg1x7xQzThUflKL/hjHlc6+e05+iUxkPWK3H8p/TwX+lljgCR6sFKR+38pg85z8lsjfxydWBb15x4nBX9yn9fEyW+J/G0M5/GKHFKT/4iMAQd+7Pn6t2a4HFQ7+x9lOp3aOPmtMUBzeUDKFLn/G1zk2kPYI38jBrJOTf5jrOE6Upz89mz/P2Kp4tFvB/1p5L7+9hjgKt5U5P7b5BFJcdc+9sjfkZmKR7/dMplMQk5+W+TP4RnZrSb/AXmVzq4EtC3ih2jKr+RLxZP/XLq7tW9P6NeIn4hmvv9i/tHJb4/8SfTgL3rcn43cQ6IzgC0GiKM9ixUTvivkAS/VHf3sWf+tmRv5Au+nr/clT9PKHf3sMUBrJsgBtbN/tUyn4HwnvzXyt+B+2al37SNv0NVzX39r5E+TgbJG79pHltKTVCe/LfIncAPvqclfJZv4mSv1YFPw15X/VTz5l/AkTVzsb48B2jNDkfuXy7+7Wz+b5E9n6jm2da5T2zeZRT4hJ78tm38qv1bM96+WBXT3jFv/tsifxE8VY/+wLKGvW/02yX+drFDM91/JbY7723T0u4CFikUeS3mUDCe/Peu/Na8pcv+wjCDXffvtMUAuk2S/Gvg9Ji/I9921jz3yN+cXUqYo/5tcmufy/W2R32vMgCj19T31tc+fuYFGTn5bVn8SfWSh3nMPWcttNHby2yJ/iMvl94qh33Yed6vfpti/HdPRK/JYzos0d+jHHgM04RnZp/j1n0sL4tzhz5bVbxgR/b6+J3H/eXQh5OS3xQBx3K0Y+4flQ/p6rsSrNfIn0ks+Urz1X8VdLufHJvkvlv9TLPSymYdo7uS3Z/Nvi2aNzwrGIU5+e4K/bEaiJ3+YlznfhX72GCCDf6NUkfu/J11cmSd75E/mx2p9fcNyTFbQw0ty8lsivxfHP/CB4sl/K4NIc9u/JfKL4e9kjmqZp8dId7f+9gR/HeRFxeZOe5hMBiEnvy0GyGKCYpHHQ/yRtq7Ioz3yx/MEWzQbu9LFXfvYY4AQ96py/yVyo/v227P6E7helqv29b0z3x39LJK/i8xX5P5beYIcJ7893/628oLiY88yxnKeVfLnmHbGSyKTfAoo4AIupDMdEbJj/XqSmnz/QsXnHpW8RGesmoJUMmkrvXiIaSzhQ1byGctYxEyG0k+EbNJi86xa29f3X9HL96/iT3SzZDapufVOow+TZaVUyhE5KlXHxzE5KpVyRLYzkzvJJin2TIAhib58pXjts1mu8OItOPpRk+6cwnX8j+yQiu+gX9VySPbwOv1qalMTW+u/N6vUYv8q2SI38z0r5hBDiFyel7Vy6Cz8Xy0VspW5XBVLuwCGbryuWN+/jEfIyLVE/iQuZ34d37odZhH/RBqxIn9H+Z3i0a+UYlpbAX4xNGOALK7H1lfJCn5FLrEgf66MU6zvv5eZtLdEfi9F+sun9U9elJFBz17DkMYjivX9j/EuV1jR3gHzoOFa3j7HXjVjIKjRQG34exurFbn/J/SzYr4wGC5i1jn/oJ0yEi+YF5kY4unJx4rB3zoZbEnGH4YsJkUEepZSRD6Be8WCIZ5OvC+Vejk/8rCXhjWb389kZaTaFlFIvheoXQBDHB4zFbl/hUyyhvtjaMorEdz6KigkPzg96zEdDDkUar715SUusAaeYRggqyJbxJQivGDQQQyGTAZLuSL3n8dlYpH8htci/u3bKyODYIHa3l792ago/xdcT7I1M0McHeTjaGS2yhj7uQAGwzWqsX8Z/Whs0dIggdujhD52yljaYLsBruQtxZSv3fKgNLEq549kZsj+qLUxtvptK4YCpiu+9C+TYrK9kGfVJKTyUVQ7WVtLBzG0YrQi998vc+hsHSORVFkdZeBhJR3E0JSHZL2a/IdlPt0tpKS0iHrW+x7b6CAGQwo/jfDh97vHR/S38mNIN9kY/c2PofbQQWrA79VR/fR9c2zgARLsNMC1skml1MlQ8j0rYgEM8bRjoSL33ydP5idaSkXoKOt0WhwxjHz/JwHjGVowV7HOzyEZSUtroZikqXW62Scj/KaD1BR4nyDlitv/f3CRxYVeon4K+Fs6OMpfLoChGffKDkXy9wbdvQRr5TeGZF5T3A53+gmIMaTxY1mrmPC9lN6kWE1DSWSIbFPcELfJWH8sgCGRnryv19eXbdxGE8vvQ4jnCtXzcFi2+kEHMRgu4w+Kv3Mfj5Bh/Y0oIZrI26oGCMt2fTqIoSPTFLn/Xpkm6YGo8ofhSdWPQFjCUiJF5OtZAEMLxinGOgfkvwOTHouhjcxVNkBY9jKUPJ0pwtCIh1WA19ftHd7j7wOTHY3BMESx7fEJNPQ0edGmg7WNXQfICmXuHwrQg1kM35f/UjdAWA4ylPxopkdQU+jlWlmm+KtWc3fA3kZg2hlulU98sMA+KYoeIK699ilggRxRLPI4jKaBkr92qlK5W/F2/KSnJDISomaAEC2YHbWMp1ONCWQHsloChiweVayHeWLsktHRQUMYMpii+Juq5QUpCGiVPwyGPIZKqSInPzlxLOIWwJDB/VKi+HvmcUWuXRl/dbZALkWyxwcL1NDByP6axvSXzxW5/yf09YJdPa22KcoY1VVzYheIIB3EkExPWaj33EPWMYj0QMt/3AKZTJSdPlhgV6ToIIYQP2S24rd/N4+TEXj5j09eOsWqd+Zfj/JI0EEMhvZMRe+5x35eJEf7eiuae0CIphTLTl/Q0FPnSgcxZDAcvafeh+VtsgJF/s7KAulMlBJfLPA0efW/RcMQ4gnZpcj9F3Ih8S1jq8R7bSwwWvb4YIH99U8fxWC4QzW/4VP6kRCD7R0wGHIoklIfLFBWkz5aj786RE95X/Gx5xoG0yjmxD/JAq0Z6hMdHFVXLoAhni4yXw6r/ZWbeYxmMSr/N+hg2AcuUCdAXFvn52XFQi8VFMd8X9/aXcAvOjj6bHcBDIZ0xqCZ7/8yFzaA1k4YDC0Z7Qsd3Coj8c7mfI0hnZ+j9zdWyzvSrYE0d6p9TeMPHdwpRWdGQxgacTNb1IK/avmz9PYSG4T8x8/WzXyig6VnooMYL4GrWaLI/bdwZ0wHf6elg8/6QgcP8BR5p3tcjvFCXCqvKnL/Eh4ns4E1djxOByf5RAefIu9UrI2afMapqvcVz9GiQfb1xBAik7E+0cFC8r457dTkMQ1H7+h3iPm0DV4t5EjuA9mM8IkODiefb6OfIWxV/CuW0TkmwW+dLJBLoS90sOSb6aMY7mGN4l/wsfRp8G2dj9NBPyyw/WQ0hKGPfKB4LvmcwV5ygxb/byxQ5Ev66JYaC2CIo4vMVezsuYWhZDv5T1igFaNkt090MJ8E2sh0xUIvpTxjWV9fCyyQxQTZ5YMFtstwLmGE4kfoKDP5gZP/2xbIoNgXQFzGbPbq/b8s4poGHvqdlgs05Tlf6KDeqJIN0qvAyf8ddLDYFzqoBX63ya1W1fe30AIZjPeFDurcQzwa0MeeynRwlC90MPryF9tS4NZ+OljkCxqKrvyvNWDuX2cL5PsEiKN39PuAriQ4+etiAX/oYHTGKm5q0Nc+9fwQjPIlfTTyY53c19k4+esTDk7wJX000inpT1vS1zeAFsj0iQ5GMPlEptLOyV9/OpjOlADTwSPyn1zs5D9XOvis4vvciJI/5nOl+/ZHgg5OVOzIFzn5v+BmEp38kTBBFmMCRgerZZ/c6jVy6z9yh8LhAUJD1bJXfkGmOPkjioaGBcYCB6WYvDzH/aNAB8sCcCg8KHM434HfaFigdQDo4CF5hytd8BctC+Qw3mo6WC2fcou79YuaBTxDc4p9SR89u7GRB0lysX906WAzplgKiEtllOdWvwodnGIhHTwok8hxq1+LDk6yjg6+ysVOfk06OM4qOvgWV7uMP10LtGKkNWjoI27wkpz8fqChcguufXZyRwCbO8WEBTwLMogPM4Qs9/X3ywJ5jPQ1ffSATJEcd+3jbyww3pfH5WEJS4X8nrZenJPfXwu08IkOHpHF9MAFf1bQwanqFjgmy7nF3frZQwenKtPBtdxHyAV/9ligGcWKdHA342nixLfrQ9CC8Up0sEqeJ8OtfhtPBKMUuEC1vESBO/rZygWGR50OvsU1uSEnv710MLoZxMvo7zVy8ttsgfyo0cFqWcftDaq+f0AtkMu4KKSPVks5T5Dj5A+CBbKYHPH00cP8Ds/F/kE5FGZEmA4ekgXS+nInf6DQ0G8iRgcrZQkXuUIvwbPAcxGig2voT1K+kz9wFmjOxAjQwfXcR6pb/cE0QUvGnCMX2MJQx/2DbIE8RpwDHSxnIllO/mBbAAplR73k38RYOjn5g2+BVjwoa+rcEHYdj7mTf6yYIJM7ZJ7sP2sycFjeYTCtnfixY4EkLpPx8icpP4MJquWgLJPf0s1LcfLHmgni6CqT5UP5UspP8UGolgOySZbJi/TGiR/DNihgkDwvH8o62SSbZYeUyFeySTbIJ/Iyd1FAyIkf6/tAgiRJGu3oRR9+SSH96cX50lSSSGjwHT3r+e+vCfeoMkIkTX0AAAAldEVYdGRhdGU6Y3JlYXRlADIwMjEtMDUtMTRUMTM6NDk6MTgrMDA6MDDl5ZNFAAAAJXRFWHRkYXRlOm1vZGlmeQAyMDIxLTA1LTE0VDEzOjQ5OjE4KzAwOjAwlLgr+QAAAABJRU5ErkJggg==", + "location": "sidePanel", + "url": "https://ipfs-cluster.ethdevops.io/ipfs/QmQsZbBSYCVBVpz2mVRbPRVTrcz59oJEpuuoxiT9otu3mh", + "repo": "https://github.com/ethereum/remix-project/tree/master/apps/etherscan", + "documentation": "https://remix-ide.readthedocs.io/en/latest/contract_verification.html#etherscan", + "maintainedBy": "Remix", + "authorContact": "remix@ethereum.org" +} \ No newline at end of file diff --git a/apps/contract-verification/src/styles.css b/apps/contract-verification/src/styles.css new file mode 100644 index 00000000000..90d4ee0072c --- /dev/null +++ b/apps/contract-verification/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/contract-verification/tsconfig.app.json b/apps/contract-verification/tsconfig.app.json new file mode 100644 index 00000000000..252904bb738 --- /dev/null +++ b/apps/contract-verification/tsconfig.app.json @@ -0,0 +1,22 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "exclude": [ + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] +} diff --git a/apps/contract-verification/tsconfig.json b/apps/contract-verification/tsconfig.json new file mode 100644 index 00000000000..5aab5e79111 --- /dev/null +++ b/apps/contract-verification/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/apps/contract-verification/webpack.config.js b/apps/contract-verification/webpack.config.js new file mode 100644 index 00000000000..5564f25b943 --- /dev/null +++ b/apps/contract-verification/webpack.config.js @@ -0,0 +1,90 @@ +const {composePlugins, withNx} = require('@nrwl/webpack') +const webpack = require('webpack') +const TerserPlugin = require('terser-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') + +const versionData = { + timestamp: Date.now(), + mode: process.env.NODE_ENV === 'production' ? 'production' : 'development' +} +// Nx plugins for webpack. +module.exports = composePlugins(withNx(), (config) => { + // Update the webpack config as needed here. + // e.g. `config.plugins.push(new MyPlugin())` + + // add fallback for node modules + config.resolve.fallback = { + ...config.resolve.fallback, + crypto: require.resolve('crypto-browserify'), + stream: require.resolve('stream-browserify'), + path: require.resolve('path-browserify'), + http: require.resolve('stream-http'), + https: require.resolve('https-browserify'), + constants: require.resolve('constants-browserify'), + os: false, //require.resolve("os-browserify/browser"), + timers: false, // require.resolve("timers-browserify"), + zlib: require.resolve('browserify-zlib'), + fs: false, + module: false, + tls: false, + net: false, + readline: false, + child_process: false, + buffer: require.resolve('buffer/'), + vm: require.resolve('vm-browserify') + } + + // add externals + config.externals = { + ...config.externals, + solc: 'solc' + } + + // add public path + config.output.publicPath = '/' + + // set filename + config.output.filename = `[name].plugin-etherscan.${versionData.timestamp}.js` + config.output.chunkFilename = `[name].plugin-etherscan.${versionData.timestamp}.js` + + // add copy & provide plugin + config.plugins.push( + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + url: ['url', 'URL'], + process: 'process/browser' + }) + ) + + // souce-map loader + config.module.rules.push({ + test: /\.js$/, + use: ['source-map-loader'], + enforce: 'pre' + }) + + config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings + + // set minimizer + config.optimization.minimizer = [ + new TerserPlugin({ + parallel: true, + terserOptions: { + ecma: 2015, + compress: false, + mangle: false, + format: { + comments: false + } + }, + extractComments: false + }), + new CssMinimizerPlugin() + ] + + config.watchOptions = { + ignored: /node_modules/ + } + + return config +}) diff --git a/apps/remix-ide/project.json b/apps/remix-ide/project.json index 563c6d29107..d53fdd6e335 100644 --- a/apps/remix-ide/project.json +++ b/apps/remix-ide/project.json @@ -3,7 +3,7 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "apps/remix-ide/src", "projectType": "application", - "implicitDependencies": ["doc-gen", "doc-viewer", "etherscan", "vyper", "solhint", "walletconnect", "circuit-compiler", "learneth", "quick-dapp", "remix-dapp"], + "implicitDependencies": ["doc-gen", "doc-viewer", "etherscan", "contract-verification", "vyper", "solhint", "walletconnect", "circuit-compiler", "learneth", "quick-dapp", "remix-dapp"], "targets": { "build": { "executor": "@nrwl/webpack:webpack", diff --git a/apps/remix-ide/src/assets/list.json b/apps/remix-ide/src/assets/list.json new file mode 100644 index 00000000000..6a55fff4f71 --- /dev/null +++ b/apps/remix-ide/src/assets/list.json @@ -0,0 +1,1123 @@ +{ + "builds": [ + { + "path": "soljson-v0.3.6+commit.3fc68da5.js", + "version": "0.3.6", + "build": "commit.3fc68da5", + "longVersion": "0.3.6+commit.3fc68da5", + "keccak256": "0x4a1c2a6a4896edefd3a4178a6c3ed8f1de625bd7c00dd7cc5781a9f36236e7db", + "sha256": "0xee7ba01680ed3a1c1cda236189a51c1e6ff99f6dca602a580e5b16441772b50b", + "urls": [ + "dweb:/ipfs/Qme9brfZS3XhbiRbbNDKhBpgFknyD92omMmYa7XSf56bJP" + ] + }, + { + "path": "soljson-v0.4.0+commit.acd334c9.js", + "version": "0.4.0", + "build": "commit.acd334c9", + "longVersion": "0.4.0+commit.acd334c9", + "keccak256": "0x07994ad8c59c498bf44ca8e84914e27b79be964d98a9556226db377819d67387", + "sha256": "0xb83d2025e0bbc7f7f0dc9e47f5aa22eacb548b42c55add8f5f6822c105163500", + "urls": [ + "dweb:/ipfs/QmcBZ6Q2iHmrf9omvD7Jyy8kgrqyPmZFwvKWqvVDaxo1Ta" + ] + }, + { + "path": "soljson-v0.4.1+commit.4fc6fc2c.js", + "version": "0.4.1", + "build": "commit.4fc6fc2c", + "longVersion": "0.4.1+commit.4fc6fc2c", + "keccak256": "0x4c358c2e90447ad9e7c1816b5be8edde1172f67dedf16755a6c7373ede46b245", + "sha256": "0x9825565e1f199dbed6de01d27e10f83a9180300acab80f8469bf427e3cf92e96", + "urls": [ + "dweb:/ipfs/QmcEK5gvWNeHUtjsF3B6j5AXb9uNoG3aHbPrCMJDx7C8TM" + ] + }, + { + "path": "soljson-v0.4.2+commit.af6afb04.js", + "version": "0.4.2", + "build": "commit.af6afb04", + "longVersion": "0.4.2+commit.af6afb04", + "keccak256": "0xb67df5c37e8255e0de7918b6d3261f0f29e277d121bf5f414b66157a5b1070cd", + "sha256": "0x67f8a94b60278cfb80d505c47a1a5e67ec2caf20167ef85f2bdf2a80a692bd1b", + "urls": [ + "dweb:/ipfs/QmVumPvgQVFLZvDvQddcDGcdxjbVWTTzxoQvJAECBBZ6Ju" + ] + }, + { + "path": "soljson-v0.4.3+commit.2353da71.js", + "version": "0.4.3", + "build": "commit.2353da71", + "longVersion": "0.4.3+commit.2353da71", + "keccak256": "0x62a65d0a951617f022524fc844ca11d90266f64e693343a2f41107183bf364c1", + "sha256": "0x66da311056ec26c9c3fb501350ee22187c30e79c41bf2713eeff7d84479948c5", + "urls": [ + "dweb:/ipfs/QmXf2cKYJ26tXAU6A6tmUk2dn4tuX3CWNaXJVnGLuoe15y" + ] + }, + { + "path": "soljson-v0.4.4+commit.4633f3de.js", + "version": "0.4.4", + "build": "commit.4633f3de", + "longVersion": "0.4.4+commit.4633f3de", + "keccak256": "0x06afcb6dc23efb1482545b63c5e3983dded0c383ecc46c3ae319f7b868201e47", + "sha256": "0x9e386edb2ee759ad65792f7d62c10ae7edf65c5b874a5451f1e695e586b69eea", + "urls": [ + "dweb:/ipfs/QmSJFaZhpXQ2EPF2koyiTNAiiuJRykv1Q8yubhkmBhvYyu" + ] + }, + { + "path": "soljson-v0.4.5+commit.b318366e.js", + "version": "0.4.5", + "build": "commit.b318366e", + "longVersion": "0.4.5+commit.b318366e", + "keccak256": "0xcdf7c4d4c6b9331b755170fa927692019c94088f87f100d2c3c920bcc3740d0b", + "sha256": "0x7184dae0b761485a5dce66b50075e17857c5b55fe3fa71fe22d4d5acc0839741", + "urls": [ + "dweb:/ipfs/QmYJuZgMbeMiotHAFNWEXdxjTa5yi7GaV4UkgBYABomFpj" + ] + }, + { + "path": "soljson-v0.4.6+commit.2dabbdf0.js", + "version": "0.4.6", + "build": "commit.2dabbdf0", + "longVersion": "0.4.6+commit.2dabbdf0", + "keccak256": "0x52ca702b8ed4b1e6d43d8a006b3d27f6dba611bac118c523711bfd209fb1cc9d", + "sha256": "0x8db9466df3b91c52e3412cebd13176ea9fe16d3239d000828a081c34ce899337", + "urls": [ + "dweb:/ipfs/QmZZ9hNntBxJw3G7LGW3e8nXtnGxLnaSMM44K4BbLrkELs" + ] + }, + { + "path": "soljson-v0.4.7+commit.822622cf.js", + "version": "0.4.7", + "build": "commit.822622cf", + "longVersion": "0.4.7+commit.822622cf", + "keccak256": "0xcd8a6a8b2626de75ef6ff73fb724f3ad5693a8902f86e88290f048b56182e7cc", + "sha256": "0xd28a58fbc3ce56ff650d4daf3a1d8092e25cadf2a5b2769fd333b321dfc6a22d", + "urls": [ + "dweb:/ipfs/QmfHjv4nYKuv3yFpWZqBYyiYEYmkQGydQmFT5b6mJkFpWp" + ] + }, + { + "path": "soljson-v0.4.8+commit.60cc1668.js", + "version": "0.4.8", + "build": "commit.60cc1668", + "longVersion": "0.4.8+commit.60cc1668", + "keccak256": "0x43c96fc79cf288cecda12b23a17f30b1cf0427a19dc7c1c094bb461eabefe0df", + "sha256": "0x9af176f42b63eaec838999a07e80484f92f41a0fc497adefa65baf88d8fbecaf", + "urls": [ + "dweb:/ipfs/Qmf7WYJJ8y6oHr4RQ7HC4tXgFPGvsnp3Qf6TrMBdK52Y5Z" + ] + }, + { + "path": "soljson-v0.4.9+commit.364da425.js", + "version": "0.4.9", + "build": "commit.364da425", + "longVersion": "0.4.9+commit.364da425", + "keccak256": "0xbe94ff397be2a951cbeb6c9c1a60ddf531d0ce76f45d51755386b6fa42cc2e2c", + "sha256": "0x6ff1683eb76dc58c31043fea474be6da8535ec625d1cd8331a3daead84fd5564", + "urls": [ + "dweb:/ipfs/QmeBWFbK1aAxnB6muXWStZJWndrFvMJt4xfAzEJD7AqaY3" + ] + }, + { + "path": "soljson-v0.4.10+commit.f0d539ae.js", + "version": "0.4.10", + "build": "commit.f0d539ae", + "longVersion": "0.4.10+commit.f0d539ae", + "keccak256": "0x178e51ad0c6a350ec4ed6fd07675dfd4d2581ee07b14b4954dd0b0f6d8633ca5", + "sha256": "0xd70ca2f656a88a9be7a3f7d602f03b30149b3bda0d1057cfa3a3c5e3d6e07453", + "urls": [ + "dweb:/ipfs/QmarthW41sfbrdkMmCK6jicXFZDGgvALzdgzygtUqEauae" + ] + }, + { + "path": "soljson-v0.4.11+commit.68ef5810.js", + "version": "0.4.11", + "build": "commit.68ef5810", + "longVersion": "0.4.11+commit.68ef5810", + "keccak256": "0xb8c3f5654b323cea016c0cc1a4584069714cdf796489efe2496a13f8f83a0e63", + "sha256": "0xdeb3c274f8b840d657e2f9b1dba602e89f58b1bf3fd7178c48c9033310a1f006", + "urls": [ + "dweb:/ipfs/QmNUf8dTW9xANAvJmV1ho279AyWSCCvDp6bXet1QTcS2z5" + ] + }, + { + "path": "soljson-v0.4.12+commit.194ff033.js", + "version": "0.4.12", + "build": "commit.194ff033", + "longVersion": "0.4.12+commit.194ff033", + "keccak256": "0x598af6fec02a6783d6a438a6bb0f7d3012716d003f7bf6c9ac5a4d2bc911941b", + "sha256": "0xd522b307a014a32ed5815b05045c4396abc047e70c8a53c1e3ef92e14daa61c6", + "urls": [ + "dweb:/ipfs/QmWGK9FbQiNWNeqysvCNCBw3q7cR1dzpnD1EKtNija2zyK" + ] + }, + { + "path": "soljson-v0.4.13+commit.0fb4cb1a.js", + "version": "0.4.13", + "build": "commit.0fb4cb1a", + "longVersion": "0.4.13+commit.0fb4cb1a", + "keccak256": "0x93f7046d6e0ea2492ec5229936821b3b020dbe9eb2e1193953389293d64a190b", + "sha256": "0x68ace74ca809ff47b09449d4054c77907d9412f14f6003d5475b60f4fec13709", + "urls": [ + "dweb:/ipfs/Qmco9fGHM6mdaPVYqeDQ11GB3BrCbwRcEzM5XzHpAdAVWc" + ] + }, + { + "path": "soljson-v0.4.14+commit.c2215d46.js", + "version": "0.4.14", + "build": "commit.c2215d46", + "longVersion": "0.4.14+commit.c2215d46", + "keccak256": "0x7def3c264883cbe6ffbfc54894e48f9a0d2984ddbd1145eb898758d2a41d1559", + "sha256": "0x54f3dc64f2ff5a5350410f6157a537d96fb4aeec90476e90a951ddfbd1fe4bca", + "urls": [ + "dweb:/ipfs/QmXyyuEWhexuez2rzAeFjunpiAhncD1AfcXitGNHxpRWha" + ] + }, + { + "path": "soljson-v0.4.15+commit.bbb8e64f.js", + "version": "0.4.15", + "build": "commit.bbb8e64f", + "longVersion": "0.4.15+commit.bbb8e64f", + "keccak256": "0x9ffa9ee890ec483580c0b4ed72270b16e92eb0b7a8a97fb00c257f8809aa4023", + "sha256": "0x3e64525797e0b2d9abaeb022688cc02d63fc5820327e382fc6574a7de650dc97", + "urls": [ + "dweb:/ipfs/QmW2rPbEtiVAbWJxtizzDqTjwpRpXCxkpSR696g9GxAYKT" + ] + }, + { + "path": "soljson-v0.4.16+commit.d7661dd9.js", + "version": "0.4.16", + "build": "commit.d7661dd9", + "longVersion": "0.4.16+commit.d7661dd9", + "keccak256": "0xf0a6c32af3eaa2f8c6d9e6c8b90f3bac5e775c7f1c90a61c1e72b593fbb1528d", + "sha256": "0x0e6d842e941cd8b76280c59f28f6d020af1afdea8e4be9d9da677ac5dbe860c6", + "urls": [ + "dweb:/ipfs/QmSwumWbYwYe4xLcqpi38VNtw7xCgbNaUkRhiZro9EnqLt" + ] + }, + { + "path": "soljson-v0.4.17+commit.bdeb9e52.js", + "version": "0.4.17", + "build": "commit.bdeb9e52", + "longVersion": "0.4.17+commit.bdeb9e52", + "keccak256": "0xeb8c3c474b5fa792f9b1b2ac6be945c32f835ccdc059deb562da4e99a031eab9", + "sha256": "0x7fe677e8214d0486fa7164f797862fae0a0fefb7b72cf6ad8e728faa54f12b60", + "urls": [ + "dweb:/ipfs/QmbgEAtdmSoxH4cfRJXj7mVpKv9rT5Cq2YmXmAnjgsyqBC" + ] + }, + { + "path": "soljson-v0.4.18+commit.9cf6e910.js", + "version": "0.4.18", + "build": "commit.9cf6e910", + "longVersion": "0.4.18+commit.9cf6e910", + "keccak256": "0xf824e695e8e66079b4b6063622c7dd80ed056d29969c8c3babac4fb572f3dfec", + "sha256": "0x5bb50839ba5116bf31669f3de8dad72eaec298ba32a643be7d0dc2d1392c54d6", + "urls": [ + "dweb:/ipfs/Qmf5RrLbWeMykvWJbCyyThCLQ9YVmU8uWagMdSp9nNzZMc" + ] + }, + { + "path": "soljson-v0.4.19+commit.c4cbbb05.js", + "version": "0.4.19", + "build": "commit.c4cbbb05", + "longVersion": "0.4.19+commit.c4cbbb05", + "keccak256": "0xa60eadfddbfda0daebb8a1b883b89d33b800cff7ce7e12458170ea17cd5ede58", + "sha256": "0x8c2a69fbab9bdf503538028c697e09e51a7e699323ae7100c375cb35c415a819", + "urls": [ + "dweb:/ipfs/QmSZEQEGuVJ7hudg8FzfDMXKVtn5AVGKaxbhSSDXwpX73K" + ] + }, + { + "path": "soljson-v0.4.20+commit.3155dd80.js", + "version": "0.4.20", + "build": "commit.3155dd80", + "longVersion": "0.4.20+commit.3155dd80", + "keccak256": "0x6c6dfa967526b7060634474ef730761711e5be662abf5ee02dc05985abfadec9", + "sha256": "0x9852ad94048600cc5a1458b4a7ab625996844c809b314422693bdc81d953fcc0", + "urls": [ + "dweb:/ipfs/QmcsCpg6kfp7Vea4y9qPtfDXcaQJbDidb65n3t9f2MFDpR" + ] + }, + { + "path": "soljson-v0.4.21+commit.dfe3193c.js", + "version": "0.4.21", + "build": "commit.dfe3193c", + "longVersion": "0.4.21+commit.dfe3193c", + "keccak256": "0xd0f9a689670184ad874ca6a2cb40dfe57e9cf539d9330ca3f2501951478eace8", + "sha256": "0x4197bb1cb0ea7e637ed8a0e7810f1bfe32c90d0151d6f423bb3dfeef9f6777c4", + "urls": [ + "dweb:/ipfs/QmY7UN95hdfFSD1jwFANegze5eLX8PgP5BfWFH1usTB8Sw" + ] + }, + { + "path": "soljson-v0.4.22+commit.4cb486ee.js", + "version": "0.4.22", + "build": "commit.4cb486ee", + "longVersion": "0.4.22+commit.4cb486ee", + "keccak256": "0x50972c5b966188341d133aa58fbf895c54655d7bd733fb5ad58852e85f9f9444", + "sha256": "0x73458d16a3e34fc7b489d2399b3680cccfc968d01abc9f1b61e438b6fb0c24a1", + "urls": [ + "dweb:/ipfs/QmPUJNa1LYaThwLQsw6fF5DMYyDfEg57gmD5wCsazkLS8c" + ] + }, + { + "path": "soljson-v0.4.23+commit.124ca40d.js", + "version": "0.4.23", + "build": "commit.124ca40d", + "longVersion": "0.4.23+commit.124ca40d", + "keccak256": "0x74f927b4f520d8d31863996a100ebc7827f919c77f777f6d4d416c6e613a03c7", + "sha256": "0x98c350cc41f873af84a78d1e24cbc8449045ee54923af0a39440e4d84600dc50", + "urls": [ + "dweb:/ipfs/QmZbo5YkSbcenWrUDjiCvUZdQe4UrNBw9vtx9nbgcMdRAs" + ] + }, + { + "path": "soljson-v0.4.24+commit.e67f0147.js", + "version": "0.4.24", + "build": "commit.e67f0147", + "longVersion": "0.4.24+commit.e67f0147", + "keccak256": "0x4cc2bb4c8894ad4349a88f330ba74d7ea643030d3f68037d1c94c370b6a25dd7", + "sha256": "0xf83e8f7014ad6b8bc801dc3684c644e372673ed678425c35aea5d4b4fe37e922", + "urls": [ + "dweb:/ipfs/QmauztXLDUdwJitA4Uc9MQYCTttUcivR5foTZYgwt4aAeC" + ] + }, + { + "path": "soljson-v0.4.25+commit.59dbf8f1.js", + "version": "0.4.25", + "build": "commit.59dbf8f1", + "longVersion": "0.4.25+commit.59dbf8f1", + "keccak256": "0x92b9c5de10bd908527e9cfba3f04bbe637163b4a5313c5a69179ccddd5fa6685", + "sha256": "0x782a999d3e1227c86854e7e29954ee856c6ae684124b9facf09f4f1724dc4e85", + "urls": [ + "dweb:/ipfs/QmUtwmzqqCftcubfyGwAefLBQ8ffp8EFhW7HCEQfhaviFs" + ] + }, + { + "path": "soljson-v0.4.26+commit.4563c3fc.js", + "version": "0.4.26", + "build": "commit.4563c3fc", + "longVersion": "0.4.26+commit.4563c3fc", + "keccak256": "0xc9c60203789ef778b9104ae7a39e9090b3d1256b24983d49e40e7d1e3c3ed65d", + "sha256": "0x264d0d25e31cb32f4369f82ba3ad0b6a84a8a1975b10bd738123ddf947618840", + "urls": [ + "dweb:/ipfs/QmRd1uRbHRvpybQk5TQ11zyqmG4wQqHnefgvYdJ14V5D8x" + ] + }, + { + "path": "soljson-v0.5.0+commit.1d4f565a.js", + "version": "0.5.0", + "build": "commit.1d4f565a", + "longVersion": "0.5.0+commit.1d4f565a", + "keccak256": "0x2921f518cf5a0627d96e07e8c3d2b5482dbbf14d7dc6bbb055481c46d98903f3", + "sha256": "0xaf811843add541705ff65f0c20fd864bd0387116544524fa1830cf67a14af6c4", + "urls": [ + "dweb:/ipfs/QmYLhaeGbq3tFdCUC2pvtA8QdGnCbA8kn24z3C741k5TUE" + ] + }, + { + "path": "soljson-v0.5.1+commit.c8a2cb62.js", + "version": "0.5.1", + "build": "commit.c8a2cb62", + "longVersion": "0.5.1+commit.c8a2cb62", + "keccak256": "0x1980cf8a81c6bd2b371bf7d9145c819a7fb2d72e9aa462aaff0c10b4eccd595c", + "sha256": "0x69cb1300b5f72eb128604507991d9ada97180d31afde7c59aa3fa3ae9ad5200d", + "urls": [ + "dweb:/ipfs/QmPfxPYsYysRR8HFkWr47FMQ8ardmfmtrmdYc2ogT9Gfp9" + ] + }, + { + "path": "soljson-v0.5.2+commit.1df8f40c.js", + "version": "0.5.2", + "build": "commit.1df8f40c", + "longVersion": "0.5.2+commit.1df8f40c", + "keccak256": "0x3efd0585a3c00a1a2c62e590e22a69aa981d1b5148af2ebdbe1610dff93cea78", + "sha256": "0xaff4ca62ac0b03cb4b9c50f8250e2e7307b5c75fefc9847f269bd05c20367148", + "urls": [ + "dweb:/ipfs/QmaZrQSg8njYzFXH2PzwxHDLKxkBhKmYmLm43DJWnurPeJ" + ] + }, + { + "path": "soljson-v0.5.3+commit.10d17f24.js", + "version": "0.5.3", + "build": "commit.10d17f24", + "longVersion": "0.5.3+commit.10d17f24", + "keccak256": "0x9b7a39606c3c27a8619b3eb493efca512cbd26c5ab7fc95489564239aab32a50", + "sha256": "0x24b4cbc28d68bde8455c14a46b55e4f292c3c295271e09991b2176a487cb4487", + "urls": [ + "dweb:/ipfs/QmQmkd5FGiKKg8eRmo3L7Cn62nuV1M6GRDUGiq5bAx4AWx" + ] + }, + { + "path": "soljson-v0.5.4+commit.9549d8ff.js", + "version": "0.5.4", + "build": "commit.9549d8ff", + "longVersion": "0.5.4+commit.9549d8ff", + "keccak256": "0x4a6244b03de1968f0a48800e75640921d62b7602d0301093e1c5c318d1effb36", + "sha256": "0x91ed0cf4390f33174a4aaf49d1ce7cd9c72e28b95d2f9422314a29b2144b2042", + "urls": [ + "dweb:/ipfs/QmRPchg1b5ofkLnLTPuunfSMKnxbXcZyzSR4NkyJAYUTrR" + ] + }, + { + "path": "soljson-v0.5.5+commit.47a71e8f.js", + "version": "0.5.5", + "build": "commit.47a71e8f", + "longVersion": "0.5.5+commit.47a71e8f", + "keccak256": "0xf46cb35b3aefb9b3d59a1fb4c151eb23a0f0a05387b379b3e7fbed1c01c861df", + "sha256": "0xaf812445476c101ae5ef92941c79eaebf57b39d455bdfb54a6a86b4ab6ca498c", + "urls": [ + "dweb:/ipfs/QmPYEmgLWDjk7kPGovojurz7fzdGv8Ti3H66nEzRzdiGwh" + ] + }, + { + "path": "soljson-v0.5.6+commit.b259423e.js", + "version": "0.5.6", + "build": "commit.b259423e", + "longVersion": "0.5.6+commit.b259423e", + "keccak256": "0x66669372d2d958bfeb5129a387dbc3882a96e260fc12e2910a7eb148b8ea5dd6", + "sha256": "0x9ffc04d0aee2c817ae6a897b1ba5aaca2bcd860416aaddfaa4de553fc1ad6e8e", + "urls": [ + "dweb:/ipfs/QmYWL8Z3yXfCuhrprimdLhYFkjR74TjFHULxcABbUipetv" + ] + }, + { + "path": "soljson-v0.5.7+commit.6da8b019.js", + "version": "0.5.7", + "build": "commit.6da8b019", + "longVersion": "0.5.7+commit.6da8b019", + "keccak256": "0x27e324f75dd52eb180569e7a8865048253e5fcdaacc52e7c998ecaeb78dcdabd", + "sha256": "0xfd7c4e652d5891c84d93b28c90b8ac58c9253d2a3677935883a337ee96087b8f", + "urls": [ + "dweb:/ipfs/QmdEr1zJrD2UYawZzeE6zPuYiYaSHdpLtKeHYixHgRp9ko" + ] + }, + { + "path": "soljson-v0.5.8+commit.23d335f2.js", + "version": "0.5.8", + "build": "commit.23d335f2", + "longVersion": "0.5.8+commit.23d335f2", + "keccak256": "0x05c00863784c63220704197d8446ac1e277fe53c42b5264093960b7bb70b9792", + "sha256": "0x25cfdd733e9c780ab85373268fde7bfa2e4b22093af57422ca3b586c7af7cd60", + "urls": [ + "dweb:/ipfs/QmSUakgiWEffZ82RrN7hgLaemdqtLSCD7pfGAKxGhDUJxB" + ] + }, + { + "path": "soljson-v0.5.9+commit.e560f70d.js", + "version": "0.5.9", + "build": "commit.e560f70d", + "longVersion": "0.5.9+commit.e560f70d", + "keccak256": "0x7c967d9dc0fdca0db88a7cee22cf5886f65e8fa8b4a145eccd910fc81a1c949d", + "sha256": "0x7d40c6325c0aa4635babdb8913626b7c4bac6a4f41e1c383de5f398e1fc98e1b", + "urls": [ + "dweb:/ipfs/QmZcHLPfa2Dz8M3justKYyDmDnaNo4pseTgAeQbtJNYywe" + ] + }, + { + "path": "soljson-v0.5.10+commit.5a6ea5b1.js", + "version": "0.5.10", + "build": "commit.5a6ea5b1", + "longVersion": "0.5.10+commit.5a6ea5b1", + "keccak256": "0x012ae146ebdd510b31c1e44a8d60071a66cdebc77f0e743a6ebc2fe68e67d297", + "sha256": "0x566601442deff058d393359df59ed72b41e1f6a65b0aa371fab7f903c189b59d", + "urls": [ + "dweb:/ipfs/Qmej9jEnSsD2LqGnL4jgbUvHTxTwiFiHqeMpqyuPLaX1uw" + ] + }, + { + "path": "soljson-v0.5.11+commit.c082d0b4.js", + "version": "0.5.11", + "build": "commit.c082d0b4", + "longVersion": "0.5.11+commit.c082d0b4", + "keccak256": "0x4ba5500559a9ad03e4c1d3866ba9d915cdb5d7f2e326b4cb1fa0fe7bdf90dc27", + "sha256": "0x89978dcef86244b8e7af95298abe26aaf4825df819d6c556e4323dc152c988ad", + "urls": [ + "dweb:/ipfs/QmdgDj3bPSKU1xKMY8FRHj8E6z9BQefeuaVuF27RpvZMXJ" + ] + }, + { + "path": "soljson-v0.5.12+commit.7709ece9.js", + "version": "0.5.12", + "build": "commit.7709ece9", + "longVersion": "0.5.12+commit.7709ece9", + "keccak256": "0xcda83fe69ce2a319d0caa20c98b53ff36ea1886054ab3dab23fa80ede3dcdea0", + "sha256": "0x1784f89fcfffccddaa94273a58e452682f61dea05d142406775f099c6ef5d61f", + "urls": [ + "dweb:/ipfs/QmPA1Uf4iwkr2ouguzxxFepVxaRg36XFXxiwqYUuwafQzQ" + ] + }, + { + "path": "soljson-v0.5.13+commit.5b0b510c.js", + "version": "0.5.13", + "build": "commit.5b0b510c", + "longVersion": "0.5.13+commit.5b0b510c", + "keccak256": "0x432dd5d662d88c2316b4df503f693ae9e6e8ed4216726db2fdb3e7f628523fe5", + "sha256": "0x6e095eefc48dfc21fec18d0b63f229e929f881b5d6e8a999e1622c6b707a7f54", + "urls": [ + "dweb:/ipfs/QmSgJ8Ru6vraz9CyCDPMifVxpckkoooVSBj9vYcQqG4wG4" + ] + }, + { + "path": "soljson-v0.5.14+commit.01f1aaa4.js", + "version": "0.5.14", + "build": "commit.01f1aaa4", + "longVersion": "0.5.14+commit.01f1aaa4", + "keccak256": "0x98e1027fbf3acb279f740c3b38df69d79ad3f2e6171414508d50604dc2dfc13e", + "sha256": "0x43b85bc9941814b018065da5c6c8d40e2af49264d0d1f06bdefbfbe628e65ff8", + "urls": [ + "dweb:/ipfs/QmeXatGB9MdWA2NBLSNQbcKvuZpa4Sxem51vCrqyQGfXnU" + ] + }, + { + "path": "soljson-v0.5.15+commit.6a57276f.js", + "version": "0.5.15", + "build": "commit.6a57276f", + "longVersion": "0.5.15+commit.6a57276f", + "keccak256": "0x6f9251f86fd798a3ae25688307ffc7a9984dcf0d809a1aef54f5c68b6cf9fb6a", + "sha256": "0x0d34e4ed048bbf67daacdf36cd5ce0f553a32962967b52edab6afccaa071878b", + "urls": [ + "dweb:/ipfs/Qmdx3AHUB8bN6ZZs1XsTV3Gz9FV3gAB7x7JbYeUsn43Azu" + ] + }, + { + "path": "soljson-v0.5.16+commit.9c3226ce.js", + "version": "0.5.16", + "build": "commit.9c3226ce", + "longVersion": "0.5.16+commit.9c3226ce", + "keccak256": "0x6abf17bdb1b934d072739e0e083ecfd579c523d200d45184b8d3987924ca0454", + "sha256": "0xa09c9cc2672678d461dc71100600bb58802db87be4de9424769241712ccbec03", + "urls": [ + "dweb:/ipfs/QmQjodGav6KhMDjuoyJ1ag8osgKLBsFC1E9LmaGP7qCRZ2" + ] + }, + { + "path": "soljson-v0.5.17+commit.d19bba13.js", + "version": "0.5.17", + "build": "commit.d19bba13", + "longVersion": "0.5.17+commit.d19bba13", + "keccak256": "0x936e6bfbf4ea9ac32997adb893b0aeecd050cfef8b475f297dca1add0a1ff934", + "sha256": "0x7fd1d3f1fddc615e117f7fb7586acabd60c649c390cf110c8fdc5ce159fa5734", + "urls": [ + "dweb:/ipfs/QmNrRJwVHaJSZ3aAQZWZKjV9o8BqWKFP3RPYL6hKU65PAE" + ] + }, + { + "path": "soljson-v0.6.0+commit.26b70077.js", + "version": "0.6.0", + "build": "commit.26b70077", + "longVersion": "0.6.0+commit.26b70077", + "keccak256": "0xea559c55bf7046cb48378fe9b43eaab6e345700aa22d701fcf946a42ec6b1008", + "sha256": "0xf22c63511a85230f7640ff5a77433db643d8d32be8b7c7f1dc24c1301a5158e9", + "urls": [ + "dweb:/ipfs/QmTQPQb6br2VEzKTiXBEE6z69xRXEk24xi2R2gn8EsvGD9" + ] + }, + { + "path": "soljson-v0.6.1+commit.e6f7d5a4.js", + "version": "0.6.1", + "build": "commit.e6f7d5a4", + "longVersion": "0.6.1+commit.e6f7d5a4", + "keccak256": "0xb2657b5ce7a9b405a65e4a88845a51216cd7371e8f84861eef9cb0cb20d78081", + "sha256": "0x3628fdefd6971ea9cc16acbf91e5f6d6cfb2079181784b47e4d24f4c5d92e4e4", + "urls": [ + "dweb:/ipfs/QmYWAkYAJo59kc5dHWaLuQqEm7xusESdu5meDzjpxnyXKt" + ] + }, + { + "path": "soljson-v0.6.2+commit.bacdbe57.js", + "version": "0.6.2", + "build": "commit.bacdbe57", + "longVersion": "0.6.2+commit.bacdbe57", + "keccak256": "0x7dc96455c864b49abc7dd5f38ba6a47904709ad132ea36babbfce98d42e962e6", + "sha256": "0x25f564cbecc5bfe95d6d358e0e7543c31ece0ab1332c555ff323ca163711bd2b", + "urls": [ + "dweb:/ipfs/QmaLUM18c7ecA911ig5u2HY6fAu4AiUbhJpnZwwCMc9cWi" + ] + }, + { + "path": "soljson-v0.6.3+commit.8dda9521.js", + "version": "0.6.3", + "build": "commit.8dda9521", + "longVersion": "0.6.3+commit.8dda9521", + "keccak256": "0x39ae8b2f3ba05ed7d4a7c16f0a9f4f5118180a209379cfc9bdd2d4fb5d015dff", + "sha256": "0xf89514dedd8cfb3c4d351580ff80b8444acde702f8be0e5fad710fe6e906c687", + "urls": [ + "dweb:/ipfs/Qmd9JfFpUXsUQrJad1u2QDuMxBMeVrcG8mrpfJVV9jiBXB" + ] + }, + { + "path": "soljson-v0.6.4+commit.1dca32f3.js", + "version": "0.6.4", + "build": "commit.1dca32f3", + "longVersion": "0.6.4+commit.1dca32f3", + "keccak256": "0x435820544c2598d4ffbfb6f11003364c883a0766c8ac2a03215dd73022b34679", + "sha256": "0xa4fd5bb021259cdde001b03dac0e66353a3b066b47eb2476acb58b2610a224ca", + "urls": [ + "dweb:/ipfs/QmTxzbPN4HwcK5YX7n3PNkb1BzKFiRwStsmBfgC9VwrtFt" + ] + }, + { + "path": "soljson-v0.6.5+commit.f956cc89.js", + "version": "0.6.5", + "build": "commit.f956cc89", + "longVersion": "0.6.5+commit.f956cc89", + "keccak256": "0x6262768243c1ceaf91418e52dc6f52d2ce94d19c6e1065d54499b7bc4d6e14dc", + "sha256": "0xf8f83757e73f33f44389d1fa72d013fb266454a8dd9bb6897c7776f8fc3b0231", + "urls": [ + "dweb:/ipfs/QmRUoBQeA5zpun1NK7BvBhQk6pTT4uZw7Jn2wZnWQETH9W" + ] + }, + { + "path": "soljson-v0.6.6+commit.6c089d02.js", + "version": "0.6.6", + "build": "commit.6c089d02", + "longVersion": "0.6.6+commit.6c089d02", + "keccak256": "0x3c9cfccc78bf352f4c7901d7af76757bd228f93af2634af4cd16b4916c13e44e", + "sha256": "0x09f6098026622c5c334c7798c3ad2b8f7c0ebc62f87846c7d5e7e725c3d1cbc2", + "urls": [ + "dweb:/ipfs/QmRj2pxXxvmJ96i57maVjLMfs4DUtCuptM8vSVvvDweJ74" + ] + }, + { + "path": "soljson-v0.6.7+commit.b8d736ae.js", + "version": "0.6.7", + "build": "commit.b8d736ae", + "longVersion": "0.6.7+commit.b8d736ae", + "keccak256": "0xb463b6a61fc027247655a32cbfd50bf543eafa3a6b42ceacdda7293e3ada8866", + "sha256": "0xb795f1b20f065a0aee492c24071fc1efa1633c3caab77cff20278a9ae822f04e", + "urls": [ + "dweb:/ipfs/QmShUrNZf1dZFjziorJYE8fMGNUSMFsbaR3ipSvsCMvExM" + ] + }, + { + "path": "soljson-v0.6.8+commit.0bbfe453.js", + "version": "0.6.8", + "build": "commit.0bbfe453", + "longVersion": "0.6.8+commit.0bbfe453", + "keccak256": "0x537cefc0579dd9631ec952cae951b3df0a50a3e557b5638107a67275f7aacc07", + "sha256": "0x3e8b01cbd194e40971b41017ada7c8b2fa941b0458cb701bdfb6a82257ca971b", + "urls": [ + "dweb:/ipfs/Qmdq9AfwdmKfEGP8u7H9E4VYrKLVinRZPZD1EWRnXSn1oe" + ] + }, + { + "path": "soljson-v0.6.9+commit.3e3065ac.js", + "version": "0.6.9", + "build": "commit.3e3065ac", + "longVersion": "0.6.9+commit.3e3065ac", + "keccak256": "0xa2d4d3ebe5d52bfa7ddf1a1fcd9bfed81eaa8678e6a1dd5a1c84954dd064422c", + "sha256": "0xf1724fd46b7a353561b3f8d473b0dc8c855b6d84b5af559d7e3326ac79b9d758", + "urls": [ + "dweb:/ipfs/Qmad6iesaR5FQ45RRtMrt2Fa1EYDuq1oGoMJJB6beMHESn" + ] + }, + { + "path": "soljson-v0.6.10+commit.00c0fcaf.js", + "version": "0.6.10", + "build": "commit.00c0fcaf", + "longVersion": "0.6.10+commit.00c0fcaf", + "keccak256": "0x620163da7ee7b2622c9ee48b06110a52739f633189555148a3b5ecf767e60cfb", + "sha256": "0xfa27ce9d23bddaa76a4aefbafa48e48affde9a1ee7c8a5e8784cf8d4c390f655", + "urls": [ + "dweb:/ipfs/QmUinsRZvs2zFNG6FMWy7ngTYUnZccXq7MRtgpj1dPfxu4" + ] + }, + { + "path": "soljson-v0.6.11+commit.5ef660b1.js", + "version": "0.6.11", + "build": "commit.5ef660b1", + "longVersion": "0.6.11+commit.5ef660b1", + "keccak256": "0xf0abd02c495a0b4c5c9a7ff20de8b932e11fc3066d0b754422035ecd96fcdbbc", + "sha256": "0x9778e4a7667d5fd7632caf3ef3791d390a7cc217f94f96e919a31e3be332386a", + "urls": [ + "dweb:/ipfs/QmXyjgFNMyFD4fdf8wt9uvUU92MGdDVGmcPdMZhNEo1g8N" + ] + }, + { + "path": "soljson-v0.6.12+commit.27d51765.js", + "version": "0.6.12", + "build": "commit.27d51765", + "longVersion": "0.6.12+commit.27d51765", + "keccak256": "0xe1412d909a0dae79b13c0066b9bf08831c522daec00b273bbc19a799af213d6a", + "sha256": "0x3e1956c550ca48e289044c7c0bd892403081b4b5e17e77ce707c815ce6c4228f", + "urls": [ + "dweb:/ipfs/QmTs8PnAGr1ijXtWvMjoWraefAtVv2Y5ZnwkArz6NqJ93w" + ] + }, + { + "path": "soljson-v0.7.0+commit.9e61f92b.js", + "version": "0.7.0", + "build": "commit.9e61f92b", + "longVersion": "0.7.0+commit.9e61f92b", + "keccak256": "0x0c7a4386781683c327fde95363535f377941e14feffad5bb1134c7aa7eba726f", + "sha256": "0xe7e1be3d0a67469f6a37cd676a22314c4faa8a22ff9d5ebde11302db754453eb", + "urls": [ + "dweb:/ipfs/QmQFhTptWdDzhemjGpa7Q65HKWGphs4nKKS13nzkcVE8pM" + ] + }, + { + "path": "soljson-v0.7.1+commit.f4a555be.js", + "version": "0.7.1", + "build": "commit.f4a555be", + "longVersion": "0.7.1+commit.f4a555be", + "keccak256": "0x3502cf7933fbce9f1fe1d87a83d5b9df12eee36c03997c3b9821493ce03fcf3e", + "sha256": "0x7fcc983c5149840a47b946fc51fc14f1c21cda07c01d650e4a1f814319cb1423", + "urls": [ + "dweb:/ipfs/Qmdw9c3usmqgdV2w4JoNWJqscHzscKNVWsWtos1engJa1o" + ] + }, + { + "path": "soljson-v0.7.2+commit.51b20bc0.js", + "version": "0.7.2", + "build": "commit.51b20bc0", + "longVersion": "0.7.2+commit.51b20bc0", + "keccak256": "0x0c80a0bf9e17700249a04a80d7729ccb012a55a82cb0f9e412fa32cc14b09c2b", + "sha256": "0xdfa3f2bb4589bdc9c054292173c82ee70e65af8d1971598f6e13b9b79ba94185", + "urls": [ + "dweb:/ipfs/QmTNWY4vkVLgtNdfGXyH6CY8URmzr33VzMJNN37z5dsAgu" + ] + }, + { + "path": "soljson-v0.7.3+commit.9bfce1f6.js", + "version": "0.7.3", + "build": "commit.9bfce1f6", + "longVersion": "0.7.3+commit.9bfce1f6", + "keccak256": "0xcf099e7057d6c3d5acac1f4e349798ad5a581b6cb7ffcebdf5b37b86eac4872d", + "sha256": "0xcaf4b1f3e01fcf946aad2d22bbe046b9dc4fd50049a05c3458ff239e2c93a785", + "urls": [ + "dweb:/ipfs/QmQMH2o7Nz3DaQ31hNYyHVAgejqTyZouvA35Zzzwe2UBPt" + ] + }, + { + "path": "soljson-v0.7.4+commit.3f05b770.js", + "version": "0.7.4", + "build": "commit.3f05b770", + "longVersion": "0.7.4+commit.3f05b770", + "keccak256": "0x300330ecd127756b824aa13e843cb1f43c473cb22eaf3750d5fb9c99279af8c3", + "sha256": "0x2b55ed5fec4d9625b6c7b3ab1abd2b7fb7dd2a9c68543bf0323db2c7e2d55af2", + "urls": [ + "dweb:/ipfs/QmTLs5MuLEWXQkths41HiACoXDiH8zxyqBHGFDRSzVE5CS" + ] + }, + { + "path": "soljson-v0.7.5+commit.eb77ed08.js", + "version": "0.7.5", + "build": "commit.eb77ed08", + "longVersion": "0.7.5+commit.eb77ed08", + "keccak256": "0xfe223dd264421f9b96c3dd3c835a3d0d4d9cfa4c61f75ca0761860c9ae8906ca", + "sha256": "0x2ee1c6434a32a40b137ac28be12ceeba64701bfad5e80239690803d9c139908e", + "urls": [ + "dweb:/ipfs/Qmf5fpJmeHdwgmSjQPqdu25XtA9akTotakkNmrh4axgo8N" + ] + }, + { + "path": "soljson-v0.7.6+commit.7338295f.js", + "version": "0.7.6", + "build": "commit.7338295f", + "longVersion": "0.7.6+commit.7338295f", + "keccak256": "0xc68517effed7163db0c7f4559931a4c5530fe6f2a8a20596361640d9d7eff655", + "sha256": "0xb94e69dfb056b3e26080f805ab43b668afbc0ac70bf124bfb7391ecfc0172ad2", + "urls": [ + "dweb:/ipfs/QmWjG6PLzF5M6kxkHujhEMg5znQCgf2m1cM1UptKA719Hy" + ] + }, + { + "path": "soljson-v0.8.0+commit.c7dfd78e.js", + "version": "0.8.0", + "build": "commit.c7dfd78e", + "longVersion": "0.8.0+commit.c7dfd78e", + "keccak256": "0x08dd57a5cf5fd59accbd5b601909ffa22d28da756b5367c29b523ff17bbc2f99", + "sha256": "0xc596765f9b3dce486cf596ea35676f37124d54f3ada0fcbc02f094c392066a59", + "urls": [ + "dweb:/ipfs/QmYh5C2rgDAx452f7HyHA8soLhnoL1GeeNNEWEuw9jKY8w" + ] + }, + { + "path": "soljson-v0.8.1+commit.df193b15.js", + "version": "0.8.1", + "build": "commit.df193b15", + "longVersion": "0.8.1+commit.df193b15", + "keccak256": "0x84a0e9282047512eeec499d55c83dbb6981430b08692d81d6c09730bb18e6cd8", + "sha256": "0xf77f141e5fed9594b28342e2c630ac6d48f2a724e4383a457881acd7fa62b1cf", + "urls": [ + "dweb:/ipfs/QmQ6W5VedQpZAwuGTtp1BhmNkvVheLnJq4xwN9Qmt9bAbH" + ] + }, + { + "path": "soljson-v0.8.2+commit.661d1103.js", + "version": "0.8.2", + "build": "commit.661d1103", + "longVersion": "0.8.2+commit.661d1103", + "keccak256": "0xd0c15275c5b0d03871332719def9b0f17e8860c7db60e0e71f18b971458a7391", + "sha256": "0x015e83fb0b72ccdafb0c217961b21a0321adb2d3f2ad992f5e79635c2086e6dd", + "urls": [ + "dweb:/ipfs/QmdfVfa2mhyosaJVeV7rbfnvQ95GTHPeRPzmvxcds7RYej" + ] + }, + { + "path": "soljson-v0.8.3+commit.8d00100c.js", + "version": "0.8.3", + "build": "commit.8d00100c", + "longVersion": "0.8.3+commit.8d00100c", + "keccak256": "0x51777116af58223a41aa3016d0bf733bbb0f78ad9ba4bcc36487eba175f65015", + "sha256": "0xb5cedfa8de5f9421fbdaccf9fd5038652c2632344b3b68e5278de81e9aeac210", + "urls": [ + "dweb:/ipfs/QmWbNMzJryhiZmyifLDQteGPwN4aTgXQB6barBvXYVw975" + ] + }, + { + "path": "soljson-v0.8.4+commit.c7e474f2.js", + "version": "0.8.4", + "build": "commit.c7e474f2", + "longVersion": "0.8.4+commit.c7e474f2", + "keccak256": "0x7e0bca960d11fb095798ff65d029436f23358ac060b25a0938acfcb4652da2ec", + "sha256": "0x4a14c7bcaf0d988a829db2174b8f7731898aa8633216490603ad74bff64eca3c", + "urls": [ + "dweb:/ipfs/QmPYDf4qYtZLNEAicW7hcvpUJ69FoHiXmUypipDpTKo9hU" + ] + }, + { + "path": "soljson-v0.8.5+commit.a4f2e591.js", + "version": "0.8.5", + "build": "commit.a4f2e591", + "longVersion": "0.8.5+commit.a4f2e591", + "keccak256": "0x6d6d75b033717aae0a728e527005d8d2cc7dbd0a835c8873c630a2a9689a2976", + "sha256": "0x4af595f976235d33a22ffe223e9e3210b4ca510f6a93f153b3daed60f2b11fbc", + "urls": [ + "dweb:/ipfs/QmNWkyirqXy3gDHNXpPuVUbExMGWjMqPR82Xzs64RzgQzy" + ] + }, + { + "path": "soljson-v0.8.6+commit.11564f7e.js", + "version": "0.8.6", + "build": "commit.11564f7e", + "longVersion": "0.8.6+commit.11564f7e", + "keccak256": "0x070e41c7f761ff1a8383a2c0d54c22aab0f115ca8c3790ecea27d6dde11611ca", + "sha256": "0x06a671efd8865a6ecc0ad648076177b35abcd06a7059888ea65111272e33a57f", + "urls": [ + "dweb:/ipfs/QmQre11ZPgWSx79Jzca1tkTYFyMbXz8H4kcrhfpWSj4qs8" + ] + }, + { + "path": "soljson-v0.8.7+commit.e28d00a7.js", + "version": "0.8.7", + "build": "commit.e28d00a7", + "longVersion": "0.8.7+commit.e28d00a7", + "keccak256": "0x8d6be9e58c33d265b5a8b1132a27fce126067419f3f4f15d3ef6b7147593b61d", + "sha256": "0x663ba99f7c7ee907f0f03227502d48a78256c3c292ace3b79a5d3eb510665306", + "urls": [ + "dweb:/ipfs/QmYv3Rsi9pL6PZAtc4XLHezPqti8yCRGEdDBqzEsQv57GV" + ] + }, + { + "path": "soljson-v0.8.8+commit.dddeac2f.js", + "version": "0.8.8", + "build": "commit.dddeac2f", + "longVersion": "0.8.8+commit.dddeac2f", + "keccak256": "0x56cb2f6978bf1213982ef217ee76b39dc97b6e66c92a7be7a1b44079c0236e5c", + "sha256": "0x534b7d4079d13bb4cd10b7559dc105c2adec625df4105f20ebce47e6da60bfda", + "urls": [ + "dweb:/ipfs/QmZaSrn3TPvPVoShtjSonQLFd3BV6RdgRMqw8GTzhnKYpm" + ] + }, + { + "path": "soljson-v0.8.9+commit.e5eed63a.js", + "version": "0.8.9", + "build": "commit.e5eed63a", + "longVersion": "0.8.9+commit.e5eed63a", + "keccak256": "0xbc470ab3442e78bb4d3f16c01c39b2f160f4f34eb4373efed11c234e1c7f6ca0", + "sha256": "0x5b25f987aae32a0275fdc6c1be36cc47cf126024a04dafd8e4be39a1d1d1422c", + "urls": [ + "dweb:/ipfs/QmfFq3MvisCSUJy8N8EVsBribgPbdpTZb7tQ2eHYw7dwag" + ] + }, + { + "path": "soljson-v0.8.10+commit.fc410830.js", + "version": "0.8.10", + "build": "commit.fc410830", + "longVersion": "0.8.10+commit.fc410830", + "keccak256": "0x3820aae0de50f10f62819d65f0b5a236ccffed11ab465a3295a5408fa47e24f5", + "sha256": "0x5eaee3240a06891abf5ac70c75caf9a0c33ebe9a2736abdaa22a337f86c22933", + "urls": [ + "dweb:/ipfs/QmcsfYpEWbPXfVptzi1YvGokxi2FYCUzUr8rQYJCc5fEiB" + ] + }, + { + "path": "soljson-v0.8.11+commit.d7f03943.js", + "version": "0.8.11", + "build": "commit.d7f03943", + "longVersion": "0.8.11+commit.d7f03943", + "keccak256": "0x798b23086ce1339e3d47b3648a1f3ae40561e2c9f66ffcc98e71fc14a7f77584", + "sha256": "0x64117d4b13bfc5bc6e5f80823519b140e753a0c09e99edd756772dc3029bc1f8", + "urls": [ + "dweb:/ipfs/QmNQTFQmfnjxnDmbguVSnZ5DiHGFQHCsffccW5c2DMcSsT" + ] + }, + { + "path": "soljson-v0.8.12+commit.f00d7308.js", + "version": "0.8.12", + "build": "commit.f00d7308", + "longVersion": "0.8.12+commit.f00d7308", + "keccak256": "0xdd4ae95607655404b769fab5f949ac95c6a1a506330f512aef0d92974c390431", + "sha256": "0xc2c4738c96ad329cbb9baea615ed50ffb5a53d93fed8e00785e47242581d3c60", + "urls": [ + "dweb:/ipfs/QmVdW2ygaT2vecoSUog3HUn8hZqXU4XXQZvuRSdpV6DJPL" + ] + }, + { + "path": "soljson-v0.8.13+commit.abaa5c0e.js", + "version": "0.8.13", + "build": "commit.abaa5c0e", + "longVersion": "0.8.13+commit.abaa5c0e", + "keccak256": "0x9afa714859d1c8f8ed2fded497b83a7a420474282494d25d4c9f592667729f21", + "sha256": "0x387343bcf8f2b77fe4cdcddcaa84361fabf8e1c3508f874fbbcbb9c313542f56", + "urls": [ + "dweb:/ipfs/Qma9V9dJwmkim98H6DQX4f7RH395vsUuqHCDxbKetcbj18" + ] + }, + { + "path": "soljson-v0.8.14+commit.80d49f37.js", + "version": "0.8.14", + "build": "commit.80d49f37", + "longVersion": "0.8.14+commit.80d49f37", + "keccak256": "0xb0f7f19a8590e5c0aaf779019c1deaafed170d8c26bec9bfd782d212e097619e", + "sha256": "0x7c3b3d0066fd381283b1d8d9a86153b2ddb5c01da14a1ae015c05cfa484e81b6", + "urls": [ + "dweb:/ipfs/QmcM1TcDB4ta8ttNLWZ4d24M4Qs35rc91sQkdNmJMNbuvV" + ] + }, + { + "path": "soljson-v0.8.15+commit.e14f2714.js", + "version": "0.8.15", + "build": "commit.e14f2714", + "longVersion": "0.8.15+commit.e14f2714", + "keccak256": "0x4f6cdc0f25e734bcb977bb6a3e22fa41d8a82cbd5f220a2e4238c2d233526d1a", + "sha256": "0x71135e459d691767ce3453bab4564ef4a640dd50182da36517cbc1f96c1d4c7c", + "urls": [ + "dweb:/ipfs/QmPiBrYZxxpNZPQ98GNyL7Xa1F9Dq7uHtdt9ESwhPNkHhc" + ] + }, + { + "path": "soljson-v0.8.16+commit.07a7930e.js", + "version": "0.8.16", + "build": "commit.07a7930e", + "longVersion": "0.8.16+commit.07a7930e", + "keccak256": "0x331f4bc6de3d44d87b68629e83f711105325b482da7e9ca9bdbdd01371fee438", + "sha256": "0x27b2820ef93805a65c76b7945a49432582d306fd17a28985709a51e6403677c2", + "urls": [ + "dweb:/ipfs/QmWzBJ8gdccvRSSB5YsMKiF2qt3RFmAP2X25QEWqqQnR4y" + ] + }, + { + "path": "soljson-v0.8.17+commit.8df45f5f.js", + "version": "0.8.17", + "build": "commit.8df45f5f", + "longVersion": "0.8.17+commit.8df45f5f", + "keccak256": "0x3f2be218cf4545b4d2e380417c6da1e008fdc4255ab38c9ee12f64c0e3f55ea9", + "sha256": "0x617828e63be485c7cc2dbcbdd5a22b582b40fafaa41016ad595637b83c90656c", + "urls": [ + "dweb:/ipfs/QmTedx1wBKSUaLatuqXYngjfKQLD2cGqPKjdLYCnbMYwiz" + ] + }, + { + "path": "soljson-v0.8.18+commit.87f61d96.js", + "version": "0.8.18", + "build": "commit.87f61d96", + "longVersion": "0.8.18+commit.87f61d96", + "keccak256": "0x9a8fa4183ef95496045189b80dfb39f745db89a903b398e40131f500953e5d57", + "sha256": "0xd82bdcba2c386d60b33aca148a9cfdf097551f68c5e45d8ec01aebbafacf5075", + "urls": [ + "dweb:/ipfs/QmcKzrqRBy7PeFQxzJDs1AZZzNHKaKbJces6zUDysXZofJ" + ] + }, + { + "path": "soljson-v0.8.19+commit.7dd6d404.js", + "version": "0.8.19", + "build": "commit.7dd6d404", + "longVersion": "0.8.19+commit.7dd6d404", + "keccak256": "0x6be35b86f5656c06ae897ef311c28da375bdcbded68c4a81e124f2cb36adf830", + "sha256": "0xe0b74e0a16e783a35169f74d1a615ecb48d07c30f97346b83cd587949268681e", + "urls": [ + "dweb:/ipfs/QmPnhNtzrEBeWWQMXdAByQTDPoKXXV9NFXLk3YL4QbghMP" + ] + }, + { + "path": "soljson-v0.8.20+commit.a1b79de6.js", + "version": "0.8.20", + "build": "commit.a1b79de6", + "longVersion": "0.8.20+commit.a1b79de6", + "keccak256": "0x3a420fa9963772eee5b9221ebb8cf9548eea8f88b09537390960ea9b440f333c", + "sha256": "0x5c509f760dc110a695c8b39bbc21e08c17dee431aa14d606f59e623d7c3cc657", + "urls": [ + "dweb:/ipfs/QmciAxUX2kfuoxitmMdkKSfWn2SfxQdieLRa3S5S2munot" + ] + }, + { + "path": "soljson-v0.8.21+commit.d9974bed.js", + "version": "0.8.21", + "build": "commit.d9974bed", + "longVersion": "0.8.21+commit.d9974bed", + "keccak256": "0x370efd28e2d28b6d0ba55e20d8994f3d286c3772552ed63586b5fe157c0d3c57", + "sha256": "0x45bea352b41d04039e19439962ddef1d3e10cf2bc9526feba39f2cc79e3c5a17", + "urls": [ + "dweb:/ipfs/QmXLgy6oexvCBWYS5pTpJWohsDNGqgdNFLRKX7JrE3NxYt" + ] + }, + { + "path": "soljson-v0.8.22+commit.4fc1097e.js", + "version": "0.8.22", + "build": "commit.4fc1097e", + "longVersion": "0.8.22+commit.4fc1097e", + "keccak256": "0x907eeba6e6e0d6977ac5a8f50e4dd2762539ca827ceab1afb1f5a4f0f3ce3e0c", + "sha256": "0x92d283c545395b91a656fa1ec94d567a464bca55aebcdbb99debf42b43026845", + "urls": [ + "dweb:/ipfs/Qma6o4e57YtWj8cQLQs12r2Enx9qmRA7VHtupCauXjYTAk" + ] + }, + { + "path": "soljson-v0.8.23+commit.f704f362.js", + "version": "0.8.23", + "build": "commit.f704f362", + "longVersion": "0.8.23+commit.f704f362", + "keccak256": "0x743aaafac24d9740a0b71215f55a132f89336a662487944767ca4bfd66400769", + "sha256": "0x9c681b165c8647867589c0a5ecdc8692637a935928a2b1bbea2ff4a1f4976985", + "urls": [ + "dweb:/ipfs/QmZy5ho8W943FMGwppXZFS1WFrVwV3UXhUUwcD7oH5vrYe" + ] + }, + { + "path": "soljson-v0.8.24+commit.e11b9ed9.js", + "version": "0.8.24", + "build": "commit.e11b9ed9", + "longVersion": "0.8.24+commit.e11b9ed9", + "keccak256": "0x1b6ceeabad21bbb2011ba13373160f7c4d46c11371a354243ee1be07159345f3", + "sha256": "0x11b054b55273ec55f6ab3f445eb0eb2c83a23fed43d10079d34ac3eabe6ed8b1", + "urls": [ + "dweb:/ipfs/QmW2SQbEhiz3n2qV5iL8WBgzapv6cXjkLStvTMpCZhvr2x" + ] + }, + { + "path": "soljson-v0.8.25+commit.b61c2a91.js", + "version": "0.8.25", + "build": "commit.b61c2a91", + "longVersion": "0.8.25+commit.b61c2a91", + "keccak256": "0x4639103a26b2f669bd3ecc22b1a1665819f2a2956f917ab91380bd9565dbcd01", + "sha256": "0xf8c9554471ff2db3843167dffb7a503293b5dc728c8305b044ef9fd37d626ca7", + "urls": [ + "dweb:/ipfs/QmdduJxmPXungjJk2FBDw1bdDQ6ucHxYGLXRMBJqMFW7h9" + ] + }, + { + "path": "soljson-v0.8.26+commit.8a97fa7a.js", + "version": "0.8.26", + "build": "commit.8a97fa7a", + "longVersion": "0.8.26+commit.8a97fa7a", + "keccak256": "0x34ffb570dd3b2041e3df86cb1f9190256cd28ee5a6f3d4200fe4b9747d33f901", + "sha256": "0xdb85e5396f523cc1a53c4c4d742e204f6dcba1a05842623d73be946809e11cd6", + "urls": [ + "dweb:/ipfs/QmS5JdeXtYhGBvdgNTLWuBNHupyP623X4sf43fRbrgiTaA" + ] + } + ], + "releases": { + "0.8.26": "soljson-v0.8.26+commit.8a97fa7a.js", + "0.8.25": "soljson-v0.8.25+commit.b61c2a91.js", + "0.8.24": "soljson-v0.8.24+commit.e11b9ed9.js", + "0.8.23": "soljson-v0.8.23+commit.f704f362.js", + "0.8.22": "soljson-v0.8.22+commit.4fc1097e.js", + "0.8.21": "soljson-v0.8.21+commit.d9974bed.js", + "0.8.20": "soljson-v0.8.20+commit.a1b79de6.js", + "0.8.19": "soljson-v0.8.19+commit.7dd6d404.js", + "0.8.18": "soljson-v0.8.18+commit.87f61d96.js", + "0.8.17": "soljson-v0.8.17+commit.8df45f5f.js", + "0.8.16": "soljson-v0.8.16+commit.07a7930e.js", + "0.8.15": "soljson-v0.8.15+commit.e14f2714.js", + "0.8.14": "soljson-v0.8.14+commit.80d49f37.js", + "0.8.13": "soljson-v0.8.13+commit.abaa5c0e.js", + "0.8.12": "soljson-v0.8.12+commit.f00d7308.js", + "0.8.11": "soljson-v0.8.11+commit.d7f03943.js", + "0.8.10": "soljson-v0.8.10+commit.fc410830.js", + "0.8.9": "soljson-v0.8.9+commit.e5eed63a.js", + "0.8.8": "soljson-v0.8.8+commit.dddeac2f.js", + "0.8.7": "soljson-v0.8.7+commit.e28d00a7.js", + "0.8.6": "soljson-v0.8.6+commit.11564f7e.js", + "0.8.5": "soljson-v0.8.5+commit.a4f2e591.js", + "0.8.4": "soljson-v0.8.4+commit.c7e474f2.js", + "0.8.3": "soljson-v0.8.3+commit.8d00100c.js", + "0.8.2": "soljson-v0.8.2+commit.661d1103.js", + "0.8.1": "soljson-v0.8.1+commit.df193b15.js", + "0.8.0": "soljson-v0.8.0+commit.c7dfd78e.js", + "0.7.6": "soljson-v0.7.6+commit.7338295f.js", + "0.7.5": "soljson-v0.7.5+commit.eb77ed08.js", + "0.7.4": "soljson-v0.7.4+commit.3f05b770.js", + "0.7.3": "soljson-v0.7.3+commit.9bfce1f6.js", + "0.7.2": "soljson-v0.7.2+commit.51b20bc0.js", + "0.7.1": "soljson-v0.7.1+commit.f4a555be.js", + "0.7.0": "soljson-v0.7.0+commit.9e61f92b.js", + "0.6.12": "soljson-v0.6.12+commit.27d51765.js", + "0.6.11": "soljson-v0.6.11+commit.5ef660b1.js", + "0.6.10": "soljson-v0.6.10+commit.00c0fcaf.js", + "0.6.9": "soljson-v0.6.9+commit.3e3065ac.js", + "0.6.8": "soljson-v0.6.8+commit.0bbfe453.js", + "0.6.7": "soljson-v0.6.7+commit.b8d736ae.js", + "0.6.6": "soljson-v0.6.6+commit.6c089d02.js", + "0.6.5": "soljson-v0.6.5+commit.f956cc89.js", + "0.6.4": "soljson-v0.6.4+commit.1dca32f3.js", + "0.6.3": "soljson-v0.6.3+commit.8dda9521.js", + "0.6.2": "soljson-v0.6.2+commit.bacdbe57.js", + "0.6.1": "soljson-v0.6.1+commit.e6f7d5a4.js", + "0.6.0": "soljson-v0.6.0+commit.26b70077.js", + "0.5.17": "soljson-v0.5.17+commit.d19bba13.js", + "0.5.16": "soljson-v0.5.16+commit.9c3226ce.js", + "0.5.15": "soljson-v0.5.15+commit.6a57276f.js", + "0.5.14": "soljson-v0.5.14+commit.01f1aaa4.js", + "0.5.13": "soljson-v0.5.13+commit.5b0b510c.js", + "0.5.12": "soljson-v0.5.12+commit.7709ece9.js", + "0.5.11": "soljson-v0.5.11+commit.c082d0b4.js", + "0.5.10": "soljson-v0.5.10+commit.5a6ea5b1.js", + "0.5.9": "soljson-v0.5.9+commit.e560f70d.js", + "0.5.8": "soljson-v0.5.8+commit.23d335f2.js", + "0.5.7": "soljson-v0.5.7+commit.6da8b019.js", + "0.5.6": "soljson-v0.5.6+commit.b259423e.js", + "0.5.5": "soljson-v0.5.5+commit.47a71e8f.js", + "0.5.4": "soljson-v0.5.4+commit.9549d8ff.js", + "0.5.3": "soljson-v0.5.3+commit.10d17f24.js", + "0.5.2": "soljson-v0.5.2+commit.1df8f40c.js", + "0.5.1": "soljson-v0.5.1+commit.c8a2cb62.js", + "0.5.0": "soljson-v0.5.0+commit.1d4f565a.js", + "0.4.26": "soljson-v0.4.26+commit.4563c3fc.js", + "0.4.25": "soljson-v0.4.25+commit.59dbf8f1.js", + "0.4.24": "soljson-v0.4.24+commit.e67f0147.js", + "0.4.23": "soljson-v0.4.23+commit.124ca40d.js", + "0.4.22": "soljson-v0.4.22+commit.4cb486ee.js", + "0.4.21": "soljson-v0.4.21+commit.dfe3193c.js", + "0.4.20": "soljson-v0.4.20+commit.3155dd80.js", + "0.4.19": "soljson-v0.4.19+commit.c4cbbb05.js", + "0.4.18": "soljson-v0.4.18+commit.9cf6e910.js", + "0.4.17": "soljson-v0.4.17+commit.bdeb9e52.js", + "0.4.16": "soljson-v0.4.16+commit.d7661dd9.js", + "0.4.15": "soljson-v0.4.15+commit.bbb8e64f.js", + "0.4.14": "soljson-v0.4.14+commit.c2215d46.js", + "0.4.13": "soljson-v0.4.13+commit.0fb4cb1a.js", + "0.4.12": "soljson-v0.4.12+commit.194ff033.js", + "0.4.11": "soljson-v0.4.11+commit.68ef5810.js", + "0.4.10": "soljson-v0.4.10+commit.f0d539ae.js", + "0.4.9": "soljson-v0.4.9+commit.364da425.js", + "0.4.8": "soljson-v0.4.8+commit.60cc1668.js", + "0.4.7": "soljson-v0.4.7+commit.822622cf.js", + "0.4.6": "soljson-v0.4.6+commit.2dabbdf0.js", + "0.4.5": "soljson-v0.4.5+commit.b318366e.js", + "0.4.4": "soljson-v0.4.4+commit.4633f3de.js", + "0.4.3": "soljson-v0.4.3+commit.2353da71.js", + "0.4.2": "soljson-v0.4.2+commit.af6afb04.js", + "0.4.1": "soljson-v0.4.1+commit.4fc6fc2c.js", + "0.4.0": "soljson-v0.4.0+commit.acd334c9.js", + "0.3.6": "soljson-v0.3.6+commit.3fc68da5.js" + }, + "latestRelease": "0.8.26" +} \ No newline at end of file diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index 9dab012bd55..7c333fd0cc1 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -7,7 +7,8 @@ import {Registry} from '@remix-project/remix-lib' const _paq = (window._paq = window._paq || []) // requiredModule removes the plugin from the plugin manager list on UI -let requiredModules = [ // services + layout views + system views +let requiredModules = [ + // services + layout views + system views 'manager', 'config', 'compilerArtefacts', @@ -92,14 +93,14 @@ let requiredModules = [ // services + layout views + system views // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither'] -const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'etherscan', 'vyper', 'solhint', 'walletconnect', 'circuit-compiler', 'learneth', 'quick-dapp'] +const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'etherscan', 'contract-verification', 'vyper', 'solhint', 'walletconnect', 'circuit-compiler', 'learneth', 'quick-dapp'] const partnerPlugins = ['cookbookdev'] const sensitiveCalls = { fileManager: ['writeFile', 'copyFile', 'rename', 'copyDir'], contentImport: ['resolveAndSave'], - web3Provider: ['sendAsync'] + web3Provider: ['sendAsync'], } const isInjectedProvider = (name) => { @@ -316,7 +317,7 @@ export class RemixAppManager extends PluginManager { path: [], pattern: [], sticky: true, - group: 5 + group: 5, }) await this.call('filePanel', 'registerContextMenuItem', { id: 'nahmii-compiler', @@ -327,7 +328,7 @@ export class RemixAppManager extends PluginManager { path: [], pattern: [], sticky: true, - group: 6 + group: 6, }) await this.call('filePanel', 'registerContextMenuItem', { id: 'solidityumlgen', @@ -338,7 +339,7 @@ export class RemixAppManager extends PluginManager { path: [], pattern: [], sticky: true, - group: 7 + group: 7, }) await this.call('filePanel', 'registerContextMenuItem', { id: 'doc-gen', @@ -349,7 +350,7 @@ export class RemixAppManager extends PluginManager { path: [], pattern: [], sticky: true, - group: 7 + group: 7, }) await this.call('filePanel', 'registerContextMenuItem', { id: 'vyper', @@ -360,7 +361,7 @@ export class RemixAppManager extends PluginManager { path: [], pattern: [], sticky: true, - group: 7 + group: 7, }) if (Registry.getInstance().get('platform').api.isDesktop()) { await this.call('filePanel', 'registerContextMenuItem', { @@ -372,7 +373,7 @@ export class RemixAppManager extends PluginManager { path: [], pattern: [], sticky: true, - group: 8 + group: 8, }) await this.call('filePanel', 'registerContextMenuItem', { id: 'fs', @@ -383,7 +384,7 @@ export class RemixAppManager extends PluginManager { path: [], pattern: [], sticky: true, - group: 8 + group: 8, }) } } @@ -418,7 +419,7 @@ class PluginLoader { }, get: () => { return JSON.parse(localStorage.getItem('workspace')) - } + }, } this.loaders.queryParams = { @@ -429,7 +430,7 @@ class PluginLoader { const {activate} = queryParams.get() if (!activate) return [] return activate.split(',') - } + }, } this.current = queryParams.get().activate ? 'queryParams' : 'localStorage' From f9e90e724ab2a36ecec00de8d25f5d416f6788fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Wed, 12 Jun 2024 13:30:08 +0200 Subject: [PATCH 003/100] Clean legacy Etherscan code --- .../src/app/AppContext.tsx | 24 +- .../src/app/EtherscanPluginClient.ts | 70 ------ apps/contract-verification/src/app/app.tsx | 128 +--------- .../src/app/components/HeaderWithSettings.tsx | 81 ------ .../src/app/components/NavMenu.tsx | 39 +++ .../src/app/components/SubmitButton.tsx | 34 --- .../src/app/components/index.ts | 3 +- .../src/app/layouts/Default.tsx | 4 +- apps/contract-verification/src/app/routes.tsx | 23 +- .../src/app/types/Receipt.ts | 9 - .../src/app/types/index.ts | 3 +- .../src/app/utils/index.ts | 1 - .../src/app/utils/networks.ts | 42 ---- .../src/app/utils/scripts.ts | 30 --- .../src/app/utils/utilities.ts | 69 ----- .../src/app/utils/verify.ts | 206 --------------- .../src/app/views/CaptureKeyView.tsx | 63 ----- .../src/app/views/ErrorView.tsx | 16 -- .../src/app/views/HomeView.tsx | 26 +- .../src/app/views/ReceiptsView.tsx | 170 ------------- .../src/app/views/VerifyView.tsx | 235 ------------------ .../src/app/views/index.ts | 5 +- 22 files changed, 53 insertions(+), 1228 deletions(-) delete mode 100644 apps/contract-verification/src/app/EtherscanPluginClient.ts delete mode 100644 apps/contract-verification/src/app/components/HeaderWithSettings.tsx create mode 100644 apps/contract-verification/src/app/components/NavMenu.tsx delete mode 100644 apps/contract-verification/src/app/components/SubmitButton.tsx delete mode 100644 apps/contract-verification/src/app/types/Receipt.ts delete mode 100644 apps/contract-verification/src/app/utils/index.ts delete mode 100644 apps/contract-verification/src/app/utils/networks.ts delete mode 100644 apps/contract-verification/src/app/utils/scripts.ts delete mode 100644 apps/contract-verification/src/app/utils/utilities.ts delete mode 100644 apps/contract-verification/src/app/utils/verify.ts delete mode 100644 apps/contract-verification/src/app/views/CaptureKeyView.tsx delete mode 100644 apps/contract-verification/src/app/views/ErrorView.tsx delete mode 100644 apps/contract-verification/src/app/views/ReceiptsView.tsx delete mode 100644 apps/contract-verification/src/app/views/VerifyView.tsx diff --git a/apps/contract-verification/src/app/AppContext.tsx b/apps/contract-verification/src/app/AppContext.tsx index 69d967534d2..b2f2e0f0643 100644 --- a/apps/contract-verification/src/app/AppContext.tsx +++ b/apps/contract-verification/src/app/AppContext.tsx @@ -1,25 +1,3 @@ import React from 'react' -import {PluginClient} from '@remixproject/plugin' -import {Receipt, ThemeType} from './types' - -export const AppContext = React.createContext({ - apiKey: '', - setAPIKey: (value: string) => { - console.log('Set API Key from Context') - }, - clientInstance: {} as PluginClient, - receipts: [] as Receipt[], - setReceipts: (receipts: Receipt[]) => { - console.log('Calling Set Receipts') - }, - contracts: [] as string[], - setContracts: (contracts: string[]) => { - console.log('Calling Set Contract Names') - }, - themeType: 'dark' as ThemeType, - setThemeType: (themeType: ThemeType) => { - console.log('Calling Set Theme Type') - }, - networkName: '' -}) +export const AppContext = React.createContext({}) diff --git a/apps/contract-verification/src/app/EtherscanPluginClient.ts b/apps/contract-verification/src/app/EtherscanPluginClient.ts deleted file mode 100644 index 3d1bf22d943..00000000000 --- a/apps/contract-verification/src/app/EtherscanPluginClient.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { PluginClient } from '@remixproject/plugin' -import { createClient } from '@remixproject/plugin-webview' -import { verify, EtherScanReturn } from './utils/verify' -import { getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus } from './utils' -import EventManager from 'events' - -export class EtherscanPluginClient extends PluginClient { - public internalEvents: EventManager - - constructor() { - super() - this.internalEvents = new EventManager() - createClient(this) - this.onload() - } - - onActivation(): void { - this.internalEvents.emit('etherscan_activated') - } - - async verify( - apiKey: string, - contractAddress: string, - contractArguments: string, - contractName: string, - compilationResultParam: any, - chainRef?: number | string, - isProxyContract?: boolean, - expectedImplAddress?: string - ) { - const result = await verify( - apiKey, - contractAddress, - contractArguments, - contractName, - compilationResultParam, - chainRef, - isProxyContract, - expectedImplAddress, - this, - (value: EtherScanReturn) => {}, - (value: string) => {} - ) - return result - } - - async receiptStatus(receiptGuid: string, apiKey: string, isProxyContract: boolean) { - try { - const { network, networkId } = await getNetworkName(this) - if (network === 'vm') { - throw new Error('Cannot check the receipt status in the selected network') - } - const etherscanApi = getEtherScanApi(networkId) - let receiptStatus - - if (isProxyContract) receiptStatus = await getProxyContractReceiptStatus(receiptGuid, apiKey, etherscanApi) - else receiptStatus = await getReceiptStatus(receiptGuid, apiKey, etherscanApi) - return { - message: receiptStatus.result, - succeed: receiptStatus.status === '0' ? false : true - } - } catch (e: any) { - return { - status: 'error', - message: e.message, - succeed: false - } - } - } -} diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index bf553d83197..41ca186b3c4 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -1,136 +1,12 @@ import React, {useState, useEffect, useRef} from 'react' -import {CompilationFileSources, CompilationResult} from '@remixproject/plugin-api' - -import { EtherscanPluginClient } from './EtherscanPluginClient' - import {AppContext} from './AppContext' -import {DisplayRoutes} from './routes' - -import {useLocalStorage} from './hooks/useLocalStorage' - -import {getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus} from './utils' -import {Receipt, ThemeType} from './types' +import DisplayRoutes from './routes' import './App.css' -export const getNewContractNames = (compilationResult: CompilationResult) => { - const compiledContracts = compilationResult.contracts - let result: string[] = [] - - for (const file of Object.keys(compiledContracts)) { - const newContractNames = Object.keys(compiledContracts[file]) - - result = [...result, ...newContractNames] - } - - return result -} - -const plugin = new EtherscanPluginClient() - const App = () => { - const [apiKey, setAPIKey] = useLocalStorage('apiKey', '') - const [receipts, setReceipts] = useLocalStorage('receipts', []) - const [contracts, setContracts] = useState([]) - const [themeType, setThemeType] = useState('dark') - const [networkName, setNetworkName] = useState('Loading...') - const timer = useRef(null) - const contractsRef = useRef(contracts) - - contractsRef.current = contracts - - const setListeners = () => { - plugin.on('solidity', 'compilationFinished', (fileName: string, source: CompilationFileSources, languageVersion: string, data: CompilationResult) => { - const newContractsNames = getNewContractNames(data) - - const newContractsToSave: string[] = [...contractsRef.current, ...newContractsNames] - - const uniqueContracts: string[] = [...new Set(newContractsToSave)] - - setContracts(uniqueContracts) - }) - plugin.on('blockchain' as any, 'networkStatus', (result) => { - setNetworkName(`${result.network.name} ${result.network.id !== '-' ? `(Chain id: ${result.network.id})` : '(Not supported)'}`) - }) - // @ts-ignore - plugin.call('blockchain', 'getCurrentNetworkStatus').then((result: any) => setNetworkName(`${result.network.name} ${result.network.id !== '-' ? `(Chain id: ${result.network.id})` : '(Not supported)'}`)) - - } - - useEffect(() => { - plugin.onload(() => { - setListeners() - }) - }, []) - - useEffect(() => { - let receiptsNotVerified: Receipt[] = receipts.filter((item: Receipt) => item.status === 'Pending in queue' || item.status === 'Max rate limit reached') - - if (receiptsNotVerified.length > 0) { - if (timer.current) { - clearInterval(timer.current) - timer.current = null - } - timer.current = setInterval(async () => { - const {network, networkId} = await getNetworkName(plugin) - - if (!plugin) return - if (network === 'vm') return - let newReceipts = receipts - - for (const item of receiptsNotVerified) { - await new Promise((r) => setTimeout(r, 500)) // avoid api rate limit exceed. - let status - if (item.isProxyContract) { - status = await getProxyContractReceiptStatus(item.guid, apiKey, getEtherScanApi(networkId)) - if (status.status === '1') { - status.message = status.result - status.result = 'Successfully Updated' - } - } else status = await getReceiptStatus(item.guid, apiKey, getEtherScanApi(networkId)) - if (status.result === 'Pass - Verified' || status.result === 'Already Verified' || status.result === 'Successfully Updated') { - newReceipts = newReceipts.map((currentReceipt: Receipt) => { - if (currentReceipt.guid === item.guid) { - const res = { - ...currentReceipt, - status: status.result - } - if (currentReceipt.isProxyContract) res.message = status.message - return res - } - return currentReceipt - }) - } - } - receiptsNotVerified = newReceipts.filter((item: Receipt) => item.status === 'Pending in queue' || item.status === 'Max rate limit reached') - if (timer.current && receiptsNotVerified.length === 0) { - clearInterval(timer.current) - timer.current = null - } - setReceipts(newReceipts) - }, 10000) - } - }, [receipts]) - - return ( - - { plugin && } - - ) + return } export default App diff --git a/apps/contract-verification/src/app/components/HeaderWithSettings.tsx b/apps/contract-verification/src/app/components/HeaderWithSettings.tsx deleted file mode 100644 index 5818b2bc7e1..00000000000 --- a/apps/contract-verification/src/app/components/HeaderWithSettings.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import React from 'react' - -import {NavLink} from 'react-router-dom' -import {CustomTooltip} from '@remix-ui/helper' -import {AppContext} from '../AppContext' - -interface Props { - title?: string - from: string -} - -interface IconProps { - from: string -} - -const HomeIcon = ({from}: IconProps) => { - return ( - (isActive ? 'border border-secondary shadow-none btn p-1 m-0' : 'border-0 shadow-none btn p-1 m-0')} - style={({isActive}) => (!isActive ? {width: '1.8rem', filter: 'contrast(0.5)'} : {width: '1.8rem'})} - state={from} - > - - - - - ) -} - -const ReceiptsIcon = ({from}: IconProps) => { - return ( - (isActive ? 'border border-secondary shadow-none btn p-1 m-0' : 'border-0 shadow-none btn p-1 m-0')} - style={({isActive}) => (!isActive ? {width: '1.8rem', filter: 'contrast(0.5)'} : {width: '1.8rem'})} - state={from} - > - - - - - ) -} - -const SettingsIcon = ({from}: IconProps) => { - return ( - (isActive ? 'border border-secondary shadow-none btn p-1 m-0' : 'border-0 shadow-none btn p-1 m-0')} - style={({isActive}) => (!isActive ? {width: '1.8rem', filter: 'contrast(0.5)'} : {width: '1.8rem'})} - state={from} - > - - - - - ) -} - -export const HeaderWithSettings = ({title = '', from}) => { - return ( -
-
{title}
-
- - - -
-
- ) -} diff --git a/apps/contract-verification/src/app/components/NavMenu.tsx b/apps/contract-verification/src/app/components/NavMenu.tsx new file mode 100644 index 00000000000..8a179857d4b --- /dev/null +++ b/apps/contract-verification/src/app/components/NavMenu.tsx @@ -0,0 +1,39 @@ +import React from 'react' + +import {NavLink} from 'react-router-dom' + +interface NavItemProps { + to: string + icon: JSX.Element + title: string +} + +const NavItem = ({to, icon, title}: NavItemProps) => { + return ( + (isActive ? 'border border-secondary shadow-none btn p-1 m-0' : 'border-0 shadow-none btn p-1 m-0')} + style={({isActive}) => (!isActive ? {width: '1.8rem', filter: 'contrast(0.5)'} : {width: '1.8rem'})} + // state={from} + > +
+
{icon}
+
{title}
+
+
+ ) +} + +export const NavMenu = () => { + return ( +
+
+ } title="Verify" /> + } title="Receipts" /> + } title="Lookup" /> + } title="Settings" /> +
+
+ ) +} diff --git a/apps/contract-verification/src/app/components/SubmitButton.tsx b/apps/contract-verification/src/app/components/SubmitButton.tsx deleted file mode 100644 index 9f4bed6200f..00000000000 --- a/apps/contract-verification/src/app/components/SubmitButton.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react' -import {CustomTooltip} from '@remix-ui/helper' - -interface Props { - text: string - isSubmitting?: boolean - dataId?: string - disable?: boolean -} - -export const SubmitButton = ({text, dataId, isSubmitting = false, disable = true}) => { - return ( -
- -
- ) -} diff --git a/apps/contract-verification/src/app/components/index.ts b/apps/contract-verification/src/app/components/index.ts index c52e3712f0c..e97ffb6670d 100644 --- a/apps/contract-verification/src/app/components/index.ts +++ b/apps/contract-verification/src/app/components/index.ts @@ -1,2 +1 @@ -export { HeaderWithSettings } from "./HeaderWithSettings" -export { SubmitButton } from "./SubmitButton" +export {NavMenu} from './NavMenu' diff --git a/apps/contract-verification/src/app/layouts/Default.tsx b/apps/contract-verification/src/app/layouts/Default.tsx index fa9a1111e57..333fec39951 100644 --- a/apps/contract-verification/src/app/layouts/Default.tsx +++ b/apps/contract-verification/src/app/layouts/Default.tsx @@ -1,6 +1,6 @@ import React, {PropsWithChildren} from 'react' -import {HeaderWithSettings} from '../components' +import {NavMenu} from '../components/NavMenu' interface Props { from: string @@ -10,7 +10,7 @@ interface Props { export const DefaultLayout = ({children, from, title}) => { return (
- + {children}
) diff --git a/apps/contract-verification/src/app/routes.tsx b/apps/contract-verification/src/app/routes.tsx index 165b5ae5a71..8a5f006b643 100644 --- a/apps/contract-verification/src/app/routes.tsx +++ b/apps/contract-verification/src/app/routes.tsx @@ -1,10 +1,10 @@ import React from 'react' import {HashRouter as Router, Route, Routes, RouteProps} from 'react-router-dom' -import {ErrorView, HomeView, ReceiptsView, CaptureKeyView} from './views' +import {HomeView} from './views' import {DefaultLayout} from './layouts' -export const DisplayRoutes = () => ( +const DisplayRoutes = () => ( ( } /> - } /> - - - - } - /> - - - - } - /> ) + +export default DisplayRoutes diff --git a/apps/contract-verification/src/app/types/Receipt.ts b/apps/contract-verification/src/app/types/Receipt.ts deleted file mode 100644 index 2dd501651dd..00000000000 --- a/apps/contract-verification/src/app/types/Receipt.ts +++ /dev/null @@ -1,9 +0,0 @@ -export type ReceiptStatus = "Pending in queue" | "Pass - Verified" | "Already Verified" | "Max rate limit reached" | "Successfully Updated" - -export interface Receipt { - guid: string - status: ReceiptStatus - isProxyContract: boolean - message?: string - succeed?: boolean -} diff --git a/apps/contract-verification/src/app/types/index.ts b/apps/contract-verification/src/app/types/index.ts index 1a8733d6ff0..0143b906b4a 100644 --- a/apps/contract-verification/src/app/types/index.ts +++ b/apps/contract-verification/src/app/types/index.ts @@ -1,2 +1 @@ -export * from "./Receipt" -export * from "./ThemeType" +export * from './ThemeType' diff --git a/apps/contract-verification/src/app/utils/index.ts b/apps/contract-verification/src/app/utils/index.ts deleted file mode 100644 index b23d52e6e05..00000000000 --- a/apps/contract-verification/src/app/utils/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./utilities" diff --git a/apps/contract-verification/src/app/utils/networks.ts b/apps/contract-verification/src/app/utils/networks.ts deleted file mode 100644 index fdb28e50a8f..00000000000 --- a/apps/contract-verification/src/app/utils/networks.ts +++ /dev/null @@ -1,42 +0,0 @@ -export const scanAPIurls = { - // all mainnet - 1: 'https://api.etherscan.io/api', - 56: 'https://api.bscscan.com/api', - 137: 'https://api.polygonscan.com/api', - 250: 'https://api.ftmscan.com/api', - 42161: 'https://api.arbiscan.io/api', - 43114: 'https://api.snowtrace.io/api', - 1285: 'https://api-moonriver.moonscan.io/api', - 1284: 'https://api-moonbeam.moonscan.io/api', - 25: 'https://api.cronoscan.com/api', - 199: 'https://api.bttcscan.com/api', - 10: 'https://api-optimistic.etherscan.io/api', - 42220: 'https://api.celoscan.io/api', - 288: 'https://api.bobascan.com/api', - 100: 'https://api.gnosisscan.io/api', - 1101: 'https://api-zkevm.polygonscan.com/api', - 59144: 'https://api.lineascan.build/api', - 8453: 'https://api.basescan.org/api', - 534352: 'https://api.scrollscan.com/api', - - // all testnet - 17000: 'https://api-holesky.etherscan.io/api', - 11155111: 'https://api-sepolia.etherscan.io/api', - 97: 'https://api-testnet.bscscan.com/api', - 80001: 'https://api-testnet.polygonscan.com/api', - 4002: 'https://api-testnet.ftmscan.com/api', - 421611: 'https://api-testnet.arbiscan.io/api', - 42170: 'https://api-nova.arbiscan.io/api', - 43113: 'https://api-testnet.snowtrace.io/api', - 1287: 'https://api-moonbase.moonscan.io/api', - 338: 'https://api-testnet.cronoscan.com/api', - 1028: 'https://api-testnet.bttcscan.com/api', - 420: 'https://api-goerli-optimistic.etherscan.io/api', - 44787: 'https://api-alfajores.celoscan.io/api', - 2888: 'https://api-testnet.bobascan.com/api', - 84531: 'https://api-goerli.basescan.org/api', - 84532: "https://api-sepolia.basescan.org/api", - 1442: 'https://api-testnet-zkevm.polygonscan.com/api', - 59140: 'https://api-testnet.lineascan.build/api', - 534351: 'https://api-sepolia.scrollscan.com/api', -} diff --git a/apps/contract-verification/src/app/utils/scripts.ts b/apps/contract-verification/src/app/utils/scripts.ts deleted file mode 100644 index 0d204d8d557..00000000000 --- a/apps/contract-verification/src/app/utils/scripts.ts +++ /dev/null @@ -1,30 +0,0 @@ -export const verifyScript = ` -/** - * @param {string} apikey - etherscan api key - * @param {string} contractAddress - Address of the contract to verify - * @param {string} contractArguments - Parameters used in the contract constructor during the initial deployment. It should be the hex encoded value - * @param {string} contractName - Name of the contract - * @param {string} contractFile - File where the contract is located - * @param {number | string} chainRef - Network chain id or API URL (optional) - * @param {boolean} isProxyContract - true, if contract is a proxy contract (optional) - * @param {string} expectedImplAddress - Implementation contract address, in case of proxy contract verification (optional) - * @returns {{ guid, status, message, succeed }} verification result - */ -export const verify = async (apikey: string, contractAddress: string, contractArguments: string, contractName: string, contractFile: string, chainRef?: number | string, isProxyContract?: boolean, expectedImplAddress?: string) => { - const compilationResultParam = await remix.call('compilerArtefacts' as any, 'getCompilerAbstract', contractFile) - console.log('verifying.. ' + contractName) - // update apiKey and chainRef to verify contract on multiple networks - return await remix.call('etherscan' as any, 'verify', apikey, contractAddress, contractArguments, contractName, compilationResultParam, chainRef, isProxyContract, expectedImplAddress) -}` - -export const receiptGuidScript = ` -/** - * @param {string} apikey - etherscan api key - * @param {string} guid - receipt id - * @param {boolean} isProxyContract - true, if contract is a proxy contract (optional) - * @returns {{ status, message, succeed }} receiptStatus - */ -export const receiptStatus = async (apikey: string, guid: string, isProxyContract?: boolean) => { - return await remix.call('etherscan' as any, 'receiptStatus', guid, apikey, isProxyContract) -} -` \ No newline at end of file diff --git a/apps/contract-verification/src/app/utils/utilities.ts b/apps/contract-verification/src/app/utils/utilities.ts deleted file mode 100644 index 048b6e2335b..00000000000 --- a/apps/contract-verification/src/app/utils/utilities.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { PluginClient } from "@remixproject/plugin" -import axios from 'axios' -import { scanAPIurls } from "./networks" -type RemixClient = PluginClient - -/* - status: 0=Error, 1=Pass - message: OK, NOTOK - result: explanation -*/ -export type receiptStatus = { - result: string - message: string - status: string -} - -export const getEtherScanApi = (networkId: any) => { - if (!(networkId in scanAPIurls)) { - throw new Error("no known network to verify against") - } - const apiUrl = (scanAPIurls as any)[networkId] - return apiUrl -} - -export const getNetworkName = async (client: RemixClient) => { - const network = await client.call("network", "detectNetwork") - if (!network) { - throw new Error("no known network to verify against") - } - return { network: network.name!.toLowerCase(), networkId: network.id } -} - -export const getReceiptStatus = async ( - receiptGuid: string, - apiKey: string, - etherscanApi: string -): Promise => { - const params = `guid=${receiptGuid}&module=contract&action=checkverifystatus&apiKey=${apiKey}` - try { - const response = await axios.get(`${etherscanApi}?${params}`) - const { result, message, status } = response.data - return { - result, - message, - status, - } - } catch (error) { - console.error(error) - } -} - -export const getProxyContractReceiptStatus = async ( - receiptGuid: string, - apiKey: string, - etherscanApi: string -): Promise => { - const params = `guid=${receiptGuid}&module=contract&action=checkproxyverification&apiKey=${apiKey}` - try { - const response = await axios.get(`${etherscanApi}?${params}`) - const { result, message, status } = response.data - return { - result, - message, - status, - } - } catch (error) { - console.error(error) - } -} diff --git a/apps/contract-verification/src/app/utils/verify.ts b/apps/contract-verification/src/app/utils/verify.ts deleted file mode 100644 index a459fb5499e..00000000000 --- a/apps/contract-verification/src/app/utils/verify.ts +++ /dev/null @@ -1,206 +0,0 @@ -import { getNetworkName, getEtherScanApi, getReceiptStatus, getProxyContractReceiptStatus } from "." -import { CompilationResult } from "@remixproject/plugin-api" -import { CompilerAbstract } from '@remix-project/remix-solidity' -import axios from 'axios' -import { PluginClient } from "@remixproject/plugin" - -const resetAfter10Seconds = (client: PluginClient, setResults: (value: string) => void) => { - setTimeout(() => { - client.emit("statusChanged", { key: "none" }) - setResults("") - }, 10000) -} - -export type EtherScanReturn = { - guid: any, - status: any, -} -export const verify = async ( - apiKeyParam: string, - contractAddress: string, - contractArgumentsParam: string, - contractName: string, - compilationResultParam: CompilerAbstract, - chainRef: number | string, - isProxyContract: boolean, - expectedImplAddress: string, - client: PluginClient, - onVerifiedContract: (value: EtherScanReturn) => void, - setResults: (value: string) => void -) => { - let networkChainId - let etherscanApi - if (chainRef) { - if (typeof chainRef === 'number') { - networkChainId = chainRef - etherscanApi = getEtherScanApi(networkChainId) - } else if (typeof chainRef === 'string') etherscanApi = chainRef - } else { - const { network, networkId } = await getNetworkName(client) - if (network === "vm") { - return { - succeed: false, - message: "Cannot verify in the selected network" - } - } else { - networkChainId = networkId - etherscanApi = getEtherScanApi(networkChainId) - } - } - - try { - const contractMetadata = getContractMetadata( - // cast from the remix-plugin interface to the solidity one. Should be fixed when remix-plugin move to the remix-project repository - compilationResultParam.data as unknown as CompilationResult, - contractName - ) - - if (!contractMetadata) { - return { - succeed: false, - message: "Please recompile contract" - } - } - - const contractMetadataParsed = JSON.parse(contractMetadata) - - const fileName = getContractFileName( - // cast from the remix-plugin interface to the solidity one. Should be fixed when remix-plugin move to the remix-project repository - compilationResultParam.data as unknown as CompilationResult, - contractName - ) - - const jsonInput = { - language: 'Solidity', - sources: compilationResultParam.source.sources, - settings: { - optimizer: { - enabled: contractMetadataParsed.settings.optimizer.enabled, - runs: contractMetadataParsed.settings.optimizer.runs - } - } - } - - const data: { [key: string]: string | any } = { - apikey: apiKeyParam, // A valid API-Key is required - module: "contract", // Do not change - action: "verifysourcecode", // Do not change - codeformat: "solidity-standard-json-input", - sourceCode: JSON.stringify(jsonInput), - contractname: fileName + ':' + contractName, - compilerversion: `v${contractMetadataParsed.compiler.version}`, // see http://etherscan.io/solcversions for list of support versions - constructorArguements: contractArgumentsParam ? contractArgumentsParam.replace('0x', '') : '', // if applicable - } - - if (isProxyContract) { - data.action = "verifyproxycontract" - data.expectedimplementation = expectedImplAddress - data.address = contractAddress - } else { - data.contractaddress = contractAddress - } - - const body = new FormData() - Object.keys(data).forEach((key) => body.append(key, data[key])) - - client.emit("statusChanged", { - key: "loading", - type: "info", - title: "Verifying ...", - }) - const response = await axios.post(etherscanApi, body) - const { message, result, status } = await response.data - - if (message === "OK" && status === "1") { - resetAfter10Seconds(client, setResults) - let receiptStatus - if (isProxyContract) { - receiptStatus = await getProxyContractReceiptStatus( - result, - apiKeyParam, - etherscanApi - ) - if (receiptStatus.status === '1') { - receiptStatus.message = receiptStatus.result - receiptStatus.result = 'Successfully Updated' - } - } else receiptStatus = await getReceiptStatus( - result, - apiKeyParam, - etherscanApi - ) - - const returnValue = { - guid: result, - status: receiptStatus.result, - message: `Verification request submitted successfully. Use this receipt GUID ${result} to track the status of your submission`, - succeed: true, - isProxyContract - } - onVerifiedContract(returnValue) - return returnValue - } else if (message === "NOTOK") { - client.emit("statusChanged", { - key: "failed", - type: "error", - title: result, - }) - const returnValue = { - message: result, - succeed: false, - isProxyContract - } - resetAfter10Seconds(client, setResults) - return returnValue - } - return { - message: 'unknown reason ' + result, - succeed: false - } - } catch (error: any) { - console.error(error) - setResults("Something wrong happened, try again") - return { - message: error.message, - succeed: false - } - } -} - -export const getContractFileName = ( - compilationResult: CompilationResult, - contractName: string -) => { - const compiledContracts = compilationResult.contracts - let fileName = "" - - for (const file of Object.keys(compiledContracts)) { - for (const contract of Object.keys(compiledContracts[file])) { - if (contract === contractName) { - fileName = file - break - } - } - } - return fileName -} - -export const getContractMetadata = ( - compilationResult: CompilationResult, - contractName: string -) => { - const compiledContracts = compilationResult.contracts - let contractMetadata = "" - - for (const file of Object.keys(compiledContracts)) { - for (const contract of Object.keys(compiledContracts[file])) { - if (contract === contractName) { - contractMetadata = compiledContracts[file][contract].metadata - if (contractMetadata) { - break - } - } - } - } - return contractMetadata -} diff --git a/apps/contract-verification/src/app/views/CaptureKeyView.tsx b/apps/contract-verification/src/app/views/CaptureKeyView.tsx deleted file mode 100644 index e63ec4278de..00000000000 --- a/apps/contract-verification/src/app/views/CaptureKeyView.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import React, {useState, useEffect} from 'react' - -import {Formik, ErrorMessage, Field} from 'formik' -import {useNavigate, useLocation} from 'react-router-dom' - -import {AppContext} from '../AppContext' -import {SubmitButton} from '../components' - -export const CaptureKeyView = () => { - const location = useLocation() - const navigate = useNavigate() - const [msg, setMsg] = useState('') - const context = React.useContext(AppContext) - - useEffect(() => { - if (!context.apiKey) setMsg('Please provide a 34-character API key to continue') - }, [context.apiKey]) - - return ( -
- { - const errors = {} as any - if (!values.apiKey) { - errors.apiKey = 'Required' - } else if (values.apiKey.length !== 34) { - errors.apiKey = 'API key should be 34 characters long' - } - return errors - }} - onSubmit={(values) => { - const apiKey = values.apiKey - if (apiKey.length === 34) { - context.setAPIKey(values.apiKey) - navigate(location && location.state ? location.state : '/') - } - }} - > - {({errors, touched, handleSubmit}) => ( -
-
- - - -
- -
- -
-
- )} -
- -
-
- ) -} diff --git a/apps/contract-verification/src/app/views/ErrorView.tsx b/apps/contract-verification/src/app/views/ErrorView.tsx deleted file mode 100644 index 90ee41e62a8..00000000000 --- a/apps/contract-verification/src/app/views/ErrorView.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react' - -export const ErrorView = () => { - return ( -
- Error page -
Sorry, something unexpected happened.
-
- Please raise an issue:{' '} - - Here - -
-
- ) -} diff --git a/apps/contract-verification/src/app/views/HomeView.tsx b/apps/contract-verification/src/app/views/HomeView.tsx index d0cda503d61..1590cf15322 100644 --- a/apps/contract-verification/src/app/views/HomeView.tsx +++ b/apps/contract-verification/src/app/views/HomeView.tsx @@ -1,31 +1,9 @@ import React from 'react' -import {Navigate} from 'react-router-dom' - import {AppContext} from '../AppContext' -import {Receipt} from '../types' - -import {VerifyView} from './VerifyView' export const HomeView = () => { const context = React.useContext(AppContext) - - return !context.apiKey ? ( - - ) : ( - { - const newReceipts = [...context.receipts, receipt] - context.setReceipts(newReceipts) - }} - networkName={context.networkName} - /> - ) + + return
HOME
} diff --git a/apps/contract-verification/src/app/views/ReceiptsView.tsx b/apps/contract-verification/src/app/views/ReceiptsView.tsx deleted file mode 100644 index 9a2c3454627..00000000000 --- a/apps/contract-verification/src/app/views/ReceiptsView.tsx +++ /dev/null @@ -1,170 +0,0 @@ -import React, {useState} from 'react' - -import {Formik, ErrorMessage, Field} from 'formik' -import {getEtherScanApi, getNetworkName, getReceiptStatus, getProxyContractReceiptStatus} from '../utils' -import {Receipt} from '../types' -import {AppContext} from '../AppContext' -import {SubmitButton} from '../components' -import {Navigate} from 'react-router-dom' -import {Button} from 'react-bootstrap' -import {CustomTooltip} from '@remix-ui/helper' - -interface FormValues { - receiptGuid: string -} - -export const ReceiptsView = () => { - const [results, setResults] = useState({succeed: false, message: ''}) - const [isProxyContractReceipt, setIsProxyContractReceipt] = useState(false) - const context = React.useContext(AppContext) - - const onGetReceiptStatus = async (values: FormValues, clientInstance: any, apiKey: string) => { - try { - const {network, networkId} = await getNetworkName(clientInstance) - if (network === 'vm') { - setResults({ - succeed: false, - message: 'Cannot verify in the selected network' - }) - return - } - const etherscanApi = getEtherScanApi(networkId) - let result - if (isProxyContractReceipt) { - result = await getProxyContractReceiptStatus(values.receiptGuid, apiKey, etherscanApi) - if (result.status === '1') { - result.message = result.result - result.result = 'Successfully Updated' - } - } else result = await getReceiptStatus(values.receiptGuid, apiKey, etherscanApi) - setResults({ - succeed: result.status === '1' ? true : false, - message: result.result || (result.status === '0' ? 'Verification failed' : result.message) - }) - } catch (error: any) { - setResults({ - succeed: false, - message: error.message - }) - } - } - - return !context.apiKey ? ( - - ) : ( -
- { - const errors = {} as any - if (!values.receiptGuid) { - errors.receiptGuid = 'Required' - } - return errors - }} - onSubmit={(values) => onGetReceiptStatus(values, context.clientInstance, context.apiKey)} - > - {({errors, touched, handleSubmit, handleChange}) => ( -
-
- - - -
- -
- { - handleChange(e) - if (e.target.checked) setIsProxyContractReceipt(true) - else setIsProxyContractReceipt(false) - }} - /> - -
- - - )} -
- -
- - -
- - - -
- ) -} - -const ReceiptsTable = ({receipts}) => { - return ( -
-
Receipts
- - - - - - - - - {receipts && - receipts.length > 0 && - receipts.map((item: Receipt, index) => { - return ( - - - - - ) - })} - -
StatusGUID
- {item.status} - {item.status === 'Successfully Updated' && ( - - - - )} - {item.guid}
-
- ) -} diff --git a/apps/contract-verification/src/app/views/VerifyView.tsx b/apps/contract-verification/src/app/views/VerifyView.tsx deleted file mode 100644 index ca70dba74cd..00000000000 --- a/apps/contract-verification/src/app/views/VerifyView.tsx +++ /dev/null @@ -1,235 +0,0 @@ -import React, {useEffect, useRef, useState} from 'react' -import Web3 from 'web3' - -import {PluginClient} from '@remixproject/plugin' -import {CustomTooltip} from '@remix-ui/helper' -import {Formik, ErrorMessage, Field} from 'formik' - -import {SubmitButton} from '../components' -import {Receipt} from '../types' -import {verify} from '../utils/verify' -import {etherscanScripts} from '@remix-project/remix-ws-templates' - -interface Props { - client: PluginClient - apiKey: string - onVerifiedContract: (receipt: Receipt) => void - contracts: string[], - networkName: string -} - -interface FormValues { - contractName: string - contractAddress: string - expectedImplAddress?: string -} - -export const VerifyView = ({apiKey, client, contracts, onVerifiedContract, networkName}) => { - const [results, setResults] = useState('') - const [selectedContract, setSelectedContract] = useState('') - const [showConstructorArgs, setShowConstructorArgs] = useState(false) - const [isProxyContract, setIsProxyContract] = useState(false) - const [constructorInputs, setConstructorInputs] = useState([]) - const verificationResult = useRef({}) - - useEffect(() => { - if (contracts.includes(selectedContract)) updateConsFields(selectedContract) - }, [contracts]) - - const updateConsFields = (contractName) => { - client.call('compilerArtefacts' as any, 'getArtefactsByContractName', contractName).then((result) => { - const {artefact} = result - if (artefact && artefact.abi && artefact.abi[0] && artefact.abi[0].type && artefact.abi[0].type === 'constructor' && artefact.abi[0].inputs.length > 0) { - setConstructorInputs(artefact.abi[0].inputs) - setShowConstructorArgs(true) - } else { - setConstructorInputs([]) - setShowConstructorArgs(false) - } - }) - } - - const onVerifyContract = async (values: FormValues) => { - const compilationResult = (await client.call('solidity', 'getCompilationResult')) as any - - if (!compilationResult) { - throw new Error('no compilation result available') - } - - const constructorValues = [] - for (const key in values) { - if (key.startsWith('contractArgValue')) constructorValues.push(values[key]) - } - const web3 = new Web3() - const constructorTypes = constructorInputs.map((e) => e.type) - let contractArguments = web3.eth.abi.encodeParameters(constructorTypes, constructorValues) - contractArguments = contractArguments.replace('0x', '') - - verificationResult.current = await verify( - apiKey, - values.contractAddress, - contractArguments, - values.contractName, - compilationResult, - null, - isProxyContract, - values.expectedImplAddress, - client, - onVerifiedContract, - setResults - ) - setResults(verificationResult.current['message']) - } - - return ( -
- { - const errors = {} as any - if (!values.contractName) { - errors.contractName = 'Required' - } - if (!values.contractAddress) { - errors.contractAddress = 'Required' - } - if (values.contractAddress.trim() === '' || !values.contractAddress.startsWith('0x') || values.contractAddress.length !== 42) { - errors.contractAddress = 'Please enter a valid contract address' - } - return errors - }} - onSubmit={(values) => onVerifyContract(values)} - > - {({errors, touched, handleSubmit, handleChange, isSubmitting}) => { - return ( -
-
- - - - -
-
- - { - handleChange(e) - setSelectedContract(e.target.value) - updateConsFields(e.target.value) - }} - > - - {contracts.map((item) => ( - - ))} - - -
-
- - {constructorInputs.map((item, index) => { - return ( -
- - - - -
- ) - })} -
-
- - - -
- { - handleChange(e) - if (e.target.checked) setIsProxyContract(true) - else setIsProxyContract(false) - }} - /> - -
-
-
- - - - - - -
- -
- - - - - ) - }} -
-
- {/*
- View Receipts -
*/} -
- ) -} diff --git a/apps/contract-verification/src/app/views/index.ts b/apps/contract-verification/src/app/views/index.ts index c483228ece4..aad7f1311cf 100644 --- a/apps/contract-verification/src/app/views/index.ts +++ b/apps/contract-verification/src/app/views/index.ts @@ -1,4 +1 @@ -export { HomeView } from "./HomeView" -export { ErrorView } from "./ErrorView" -export { ReceiptsView } from "./ReceiptsView" -export { CaptureKeyView } from "./CaptureKeyView" +export {HomeView} from './HomeView' From 10770e84262cc193a79bdcd15dbd8145088fee36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Wed, 12 Jun 2024 13:52:15 +0200 Subject: [PATCH 004/100] Add ThemeType --- apps/contract-verification/src/app/AppContext.tsx | 8 +++++++- apps/contract-verification/src/app/app.tsx | 10 +++++++++- .../src/app/components/NavMenu.tsx | 14 ++++++-------- 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/apps/contract-verification/src/app/AppContext.tsx b/apps/contract-verification/src/app/AppContext.tsx index b2f2e0f0643..abe76da5d11 100644 --- a/apps/contract-verification/src/app/AppContext.tsx +++ b/apps/contract-verification/src/app/AppContext.tsx @@ -1,3 +1,9 @@ import React from 'react' +import {ThemeType} from './types' -export const AppContext = React.createContext({}) +export const AppContext = React.createContext({ + themeType: 'dark' as ThemeType, + setThemeType: (themeType: ThemeType) => { + console.log('Calling Set Theme Type') + }, +}) diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index 41ca186b3c4..7e6c2af5ca0 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -3,10 +3,18 @@ import React, {useState, useEffect, useRef} from 'react' import {AppContext} from './AppContext' import DisplayRoutes from './routes' +import {ThemeType} from './types' + import './App.css' const App = () => { - return + const [themeType, setThemeType] = useState('dark') + + return ( + + + + ) } export default App diff --git a/apps/contract-verification/src/app/components/NavMenu.tsx b/apps/contract-verification/src/app/components/NavMenu.tsx index 8a179857d4b..da85e3d9073 100644 --- a/apps/contract-verification/src/app/components/NavMenu.tsx +++ b/apps/contract-verification/src/app/components/NavMenu.tsx @@ -27,13 +27,11 @@ const NavItem = ({to, icon, title}: NavItemProps) => { export const NavMenu = () => { return ( -
-
- } title="Verify" /> - } title="Receipts" /> - } title="Lookup" /> - } title="Settings" /> -
-
+ ) } From 97ac7f5ab08e6266ad0aefa924c1a8fa1865222c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Wed, 12 Jun 2024 14:02:08 +0200 Subject: [PATCH 005/100] Add pluginClient to fix unstyled Plugin Only after adding the PluginClient (that imports @remixproject/plugin-webview) the contract-verification-plugin started to inherit Remix styles --- .../src/app/ContractVerificationPluginClient.ts | 14 ++++++++++++++ apps/contract-verification/src/app/app.tsx | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 apps/contract-verification/src/app/ContractVerificationPluginClient.ts diff --git a/apps/contract-verification/src/app/ContractVerificationPluginClient.ts b/apps/contract-verification/src/app/ContractVerificationPluginClient.ts new file mode 100644 index 00000000000..a72b7b764e3 --- /dev/null +++ b/apps/contract-verification/src/app/ContractVerificationPluginClient.ts @@ -0,0 +1,14 @@ +import {PluginClient} from '@remixproject/plugin' +import {createClient} from '@remixproject/plugin-webview' +import EventManager from 'events' + +export class ContractVerificationPluginClient extends PluginClient { + public internalEvents: EventManager + + constructor() { + super() + this.internalEvents = new EventManager() + createClient(this) + this.onload() + } +} diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index 7e6c2af5ca0..215b2269bab 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -1,12 +1,16 @@ import React, {useState, useEffect, useRef} from 'react' +import {ContractVerificationPluginClient} from './ContractVerificationPluginClient' + import {AppContext} from './AppContext' import DisplayRoutes from './routes' - +import {CustomTooltip} from '@remix-ui/helper' import {ThemeType} from './types' import './App.css' +const plugin = new ContractVerificationPluginClient() + const App = () => { const [themeType, setThemeType] = useState('dark') From c769c8b920f417426c6ce9467b993919205a2c6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Thu, 13 Jun 2024 08:55:00 +0200 Subject: [PATCH 006/100] Add Verify form items. Fetch and format chains form chainid.network/chains.json --- .../src/app/AppContext.tsx | 1 + apps/contract-verification/src/app/app.tsx | 11 +++- .../app/components/Input/Dropdown/index.tsx | 27 ++++++++++ .../src/app/components/NavMenu.tsx | 7 ++- .../src/app/views/HomeView.tsx | 50 ++++++++++++++++++- 5 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 apps/contract-verification/src/app/components/Input/Dropdown/index.tsx diff --git a/apps/contract-verification/src/app/AppContext.tsx b/apps/contract-verification/src/app/AppContext.tsx index abe76da5d11..c2cb1ae795f 100644 --- a/apps/contract-verification/src/app/AppContext.tsx +++ b/apps/contract-verification/src/app/AppContext.tsx @@ -6,4 +6,5 @@ export const AppContext = React.createContext({ setThemeType: (themeType: ThemeType) => { console.log('Calling Set Theme Type') }, + chains: [], }) diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index 215b2269bab..4feb954663e 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -13,9 +13,18 @@ const plugin = new ContractVerificationPluginClient() const App = () => { const [themeType, setThemeType] = useState('dark') + const [chains, setChains] = useState([]) // State to hold the chains data + + useEffect(() => { + // Fetch chains.json and update state + fetch('https://chainid.network/chains.json') + .then((response) => response.json()) + .then((data) => setChains(data)) + .catch((error) => console.error('Failed to fetch chains.json:', error)) + }, []) return ( - + ) diff --git a/apps/contract-verification/src/app/components/Input/Dropdown/index.tsx b/apps/contract-verification/src/app/components/Input/Dropdown/index.tsx new file mode 100644 index 00000000000..c92d1c0d4a7 --- /dev/null +++ b/apps/contract-verification/src/app/components/Input/Dropdown/index.tsx @@ -0,0 +1,27 @@ +import React from 'react' + +interface DropdownItem { + value: string + text: string +} + +interface DropdownProps { + label: string + items: DropdownItem[] + id: string +} + +export const Dropdown: React.FC = ({label, items, id}) => { + return ( +
+ + +
+ ) +} diff --git a/apps/contract-verification/src/app/components/NavMenu.tsx b/apps/contract-verification/src/app/components/NavMenu.tsx index da85e3d9073..08508efd10a 100644 --- a/apps/contract-verification/src/app/components/NavMenu.tsx +++ b/apps/contract-verification/src/app/components/NavMenu.tsx @@ -13,11 +13,10 @@ const NavItem = ({to, icon, title}: NavItemProps) => { (isActive ? 'border border-secondary shadow-none btn p-1 m-0' : 'border-0 shadow-none btn p-1 m-0')} - style={({isActive}) => (!isActive ? {width: '1.8rem', filter: 'contrast(0.5)'} : {width: '1.8rem'})} + className={({isActive}) => 'p-2 ' + (isActive ? 'bg-primary text-white' : 'bg-secondary')} // state={from} > -
+
{icon}
{title}
@@ -27,7 +26,7 @@ const NavItem = ({to, icon, title}: NavItemProps) => { export const NavMenu = () => { return ( -
- + +
+ diff --git a/package.json b/package.json index bc80e3aaf5d..26794bb36be 100644 --- a/package.json +++ b/package.json @@ -153,6 +153,7 @@ "formik": "^2.4.5", "from-exponential": "1.1.1", "fs-extra": "^3.0.1", + "fuse.js": "^7.0.0", "ganache": "^7.9.1", "graphql": "^16.8.1", "html-react-parser": "^3.0.4", diff --git a/yarn.lock b/yarn.lock index 8b3f23b7e41..6aac3209ea0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16531,6 +16531,11 @@ functions-have-names@^1.2.2, functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +fuse.js@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-7.0.0.tgz#6573c9fcd4c8268e403b4fc7d7131ffcf99a9eb2" + integrity sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q== + galactus@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/galactus/-/galactus-0.2.1.tgz#cbed2d20a40c1f5679a35908e2b9415733e78db9" From 7505c4099f697fd59387c4ee64e92f9b9b4b24a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Thu, 13 Jun 2024 11:21:25 +0200 Subject: [PATCH 008/100] Basic select compiled contract name --- .../src/app/AppContext.tsx | 1 + apps/contract-verification/src/app/app.tsx | 27 ++++++++++++++++++- .../src/app/views/HomeView.tsx | 12 ++------- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/apps/contract-verification/src/app/AppContext.tsx b/apps/contract-verification/src/app/AppContext.tsx index fe59dbcc8ec..a887ae1c839 100644 --- a/apps/contract-verification/src/app/AppContext.tsx +++ b/apps/contract-verification/src/app/AppContext.tsx @@ -9,4 +9,5 @@ export const AppContext = React.createContext({ chains: [], selectedChain: null, setSelectedChain: (chain: string) => {}, + contractNames: [], }) diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index 861cd8eb7c0..acfd73790d6 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -8,6 +8,7 @@ import {CustomTooltip} from '@remix-ui/helper' import {ThemeType} from './types' import './App.css' +import {CompilationFileSources, CompilationResult} from '@remixproject/plugin-api' const plugin = new ContractVerificationPluginClient() @@ -15,17 +16,41 @@ const App = () => { const [themeType, setThemeType] = useState('dark') const [chains, setChains] = useState([]) // State to hold the chains data const [selectedChain, setSelectedChain] = useState(null) + const [targetFileName, setTargetFileName] = useState('') + const [contractNames, setContractNames] = useState([]) useEffect(() => { + // TODO: Fix 'compilationFinished' event types. The interface is outdated at https://github.com/ethereum/remix-plugin/blob/master/packages/api/src/lib/compiler/api.ts. It does not include data, input, or version. See the current parameters: https://github.com/ethereum/remix-project/blob/9f6c5be882453a555055f07171701459e4ae88a4/libs/remix-solidity/src/compiler/compiler.ts#L189 + // Because of this reason we use @ts-expect-error for the next line + // @ts-expect-error:next-line + plugin.on('solidity', 'compilationFinished', (fileName: string, source: CompilationFileSources, languageVersion: string, data: CompilationResult, input: string, version: string) => { + console.log('Compilation output') + console.log(data) + console.log('File Name:', fileName) + console.log('Source:', source) + console.log('Language Version:', languageVersion) + console.log('Compilation Result:', data) + // console.log('Input:', input) + console.log('Compiler Version:', version) + console.log('contractNames') + console.log(Object.keys(data.contracts[fileName])) + + setTargetFileName(fileName) + setContractNames(Object.keys(data.contracts[fileName])) + }) // Fetch chains.json and update state fetch('https://chainid.network/chains.json') .then((response) => response.json()) .then((data) => setChains(data)) .catch((error) => console.error('Failed to fetch chains.json:', error)) + + return () => { + plugin.off('solidity', 'compilationFinished') // Clean up on unmount + } }, []) return ( - + ) diff --git a/apps/contract-verification/src/app/views/HomeView.tsx b/apps/contract-verification/src/app/views/HomeView.tsx index 9185957832a..baea8776673 100644 --- a/apps/contract-verification/src/app/views/HomeView.tsx +++ b/apps/contract-verification/src/app/views/HomeView.tsx @@ -5,7 +5,7 @@ import {Dropdown} from '../components' import {SearchableDropdown} from '../components' export const HomeView = () => { - const {chains, selectedChain, setSelectedChain} = React.useContext(AppContext) + const {chains, selectedChain, setSelectedChain, contractNames} = React.useContext(AppContext) const ethereumChainIds = [1, 3, 4, 5, 11155111, 17000] @@ -39,15 +39,7 @@ export const HomeView = () => {
- + {contractNames.length > 0 ? ({value: item, name: item}))} id="contract-name-dropdown" /> :
No compiled contracts
}
Constructor Arguments
{/* TODO: Add input fields for constructor arguments */} From f8b3b023a7b34dccd7ea9d5e7d15acfd5fa924ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Thu, 13 Jun 2024 11:48:12 +0200 Subject: [PATCH 009/100] Turn on strict Typescript in the contract-verification-plugin --- apps/contract-verification/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/contract-verification/tsconfig.json b/apps/contract-verification/tsconfig.json index 5aab5e79111..c366a45f2ba 100644 --- a/apps/contract-verification/tsconfig.json +++ b/apps/contract-verification/tsconfig.json @@ -4,7 +4,8 @@ "jsx": "react-jsx", "allowJs": true, "esModuleInterop": true, - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "strict": true }, "files": [], "include": [], From baa5c01e251943b365b790f06824f76025984735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Thu, 13 Jun 2024 14:34:23 +0200 Subject: [PATCH 010/100] Fix types for contract-verification-plugin --- .../src/app/AppContext.tsx | 25 +++++++++++++++---- apps/contract-verification/src/app/app.tsx | 11 ++++---- .../src/app/layouts/Default.tsx | 2 +- .../src/app/views/HomeView.tsx | 6 +++-- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/apps/contract-verification/src/app/AppContext.tsx b/apps/contract-verification/src/app/AppContext.tsx index a887ae1c839..4106ffbb5c2 100644 --- a/apps/contract-verification/src/app/AppContext.tsx +++ b/apps/contract-verification/src/app/AppContext.tsx @@ -1,13 +1,28 @@ import React from 'react' import {ThemeType} from './types' +import {CompilationResult} from '@remixproject/plugin-api' -export const AppContext = React.createContext({ - themeType: 'dark' as ThemeType, +// Define the type for the context +type AppContextType = { + themeType: ThemeType + setThemeType: (themeType: ThemeType) => void + chains: any[] + selectedChain: any | undefined + setSelectedChain: (chain: string) => void + compilationOutput: CompilationResult | undefined +} + +// Provide a default value with the appropriate types +const defaultContextValue: AppContextType = { + themeType: 'dark', setThemeType: (themeType: ThemeType) => { console.log('Calling Set Theme Type') }, chains: [], - selectedChain: null, + selectedChain: undefined, setSelectedChain: (chain: string) => {}, - contractNames: [], -}) + compilationOutput: undefined, +} + +// Create the context with the type +export const AppContext = React.createContext(defaultContextValue) diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index acfd73790d6..cbae61b49d8 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -14,10 +14,11 @@ const plugin = new ContractVerificationPluginClient() const App = () => { const [themeType, setThemeType] = useState('dark') - const [chains, setChains] = useState([]) // State to hold the chains data - const [selectedChain, setSelectedChain] = useState(null) + // TODO: Types for chains + const [chains, setChains] = useState([]) // State to hold the chains data + const [selectedChain, setSelectedChain] = useState() const [targetFileName, setTargetFileName] = useState('') - const [contractNames, setContractNames] = useState([]) + const [compilationOutput, setCompilationOutput] = useState() useEffect(() => { // TODO: Fix 'compilationFinished' event types. The interface is outdated at https://github.com/ethereum/remix-plugin/blob/master/packages/api/src/lib/compiler/api.ts. It does not include data, input, or version. See the current parameters: https://github.com/ethereum/remix-project/blob/9f6c5be882453a555055f07171701459e4ae88a4/libs/remix-solidity/src/compiler/compiler.ts#L189 @@ -36,7 +37,7 @@ const App = () => { console.log(Object.keys(data.contracts[fileName])) setTargetFileName(fileName) - setContractNames(Object.keys(data.contracts[fileName])) + setCompilationOutput(undefined) }) // Fetch chains.json and update state fetch('https://chainid.network/chains.json') @@ -50,7 +51,7 @@ const App = () => { }, []) return ( - + ) diff --git a/apps/contract-verification/src/app/layouts/Default.tsx b/apps/contract-verification/src/app/layouts/Default.tsx index 333fec39951..a564f50dc6c 100644 --- a/apps/contract-verification/src/app/layouts/Default.tsx +++ b/apps/contract-verification/src/app/layouts/Default.tsx @@ -7,7 +7,7 @@ interface Props { title?: string } -export const DefaultLayout = ({children, from, title}) => { +export const DefaultLayout = ({children}: PropsWithChildren) => { return (
diff --git a/apps/contract-verification/src/app/views/HomeView.tsx b/apps/contract-verification/src/app/views/HomeView.tsx index baea8776673..3f6bb885905 100644 --- a/apps/contract-verification/src/app/views/HomeView.tsx +++ b/apps/contract-verification/src/app/views/HomeView.tsx @@ -5,10 +5,12 @@ import {Dropdown} from '../components' import {SearchableDropdown} from '../components' export const HomeView = () => { - const {chains, selectedChain, setSelectedChain, contractNames} = React.useContext(AppContext) + const {chains, selectedChain, setSelectedChain, compilationOutput} = React.useContext(AppContext) const ethereumChainIds = [1, 3, 4, 5, 11155111, 17000] + const contractNames = compilationOutput?.contracts && Object.keys(compilationOutput?.contracts) + // Add Ethereum chains to the head of the chains list. Sort the rest alphabetically const dropdownChains = chains .map((chain) => ({value: chain.chainId, name: `${chain.title || chain.name} (${chain.chainId})`})) @@ -39,7 +41,7 @@ export const HomeView = () => {
- {contractNames.length > 0 ? ({value: item, name: item}))} id="contract-name-dropdown" /> :
No compiled contracts
} + {contractNames && contractNames.length > 0 ? ({value: item, name: item}))} id="contract-name-dropdown" /> :
No compiled contracts
}
Constructor Arguments
{/* TODO: Add input fields for constructor arguments */} From a1484322c9f1c552b9e9b0a232c91133182162c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Thu, 13 Jun 2024 15:46:05 +0200 Subject: [PATCH 011/100] Turn off temp. strict. Dropdown to ContractDropdown. Style ContractDropdown --- .../src/app/components/ContractDropdown.css | 3 ++ .../src/app/components/ContractDropdown.tsx | 33 +++++++++++++++++++ .../src/app/components/Dropdown.tsx | 27 --------------- .../src/app/components/index.tsx | 2 +- .../src/app/views/HomeView.tsx | 4 +-- apps/contract-verification/tsconfig.json | 2 +- 6 files changed, 40 insertions(+), 31 deletions(-) create mode 100644 apps/contract-verification/src/app/components/ContractDropdown.css create mode 100644 apps/contract-verification/src/app/components/ContractDropdown.tsx delete mode 100644 apps/contract-verification/src/app/components/Dropdown.tsx diff --git a/apps/contract-verification/src/app/components/ContractDropdown.css b/apps/contract-verification/src/app/components/ContractDropdown.css new file mode 100644 index 00000000000..2a51d709867 --- /dev/null +++ b/apps/contract-verification/src/app/components/ContractDropdown.css @@ -0,0 +1,3 @@ +.disabled-cursor { + cursor: not-allowed; +} diff --git a/apps/contract-verification/src/app/components/ContractDropdown.tsx b/apps/contract-verification/src/app/components/ContractDropdown.tsx new file mode 100644 index 00000000000..2dea4a32ccf --- /dev/null +++ b/apps/contract-verification/src/app/components/ContractDropdown.tsx @@ -0,0 +1,33 @@ +import React from 'react' +import './ContractDropdown.css' +interface ContractDropdownItem { + value: string + name: string +} + +interface ContractDropdownProps { + label: string + contractNames: ContractDropdownItem[] + id: string +} + +export const ContractDropdown: React.FC = ({label, contractNames, id}) => { + const hasContracts = contractNames && contractNames.length > 0 + return ( +
+ + + +
+ ) +} diff --git a/apps/contract-verification/src/app/components/Dropdown.tsx b/apps/contract-verification/src/app/components/Dropdown.tsx deleted file mode 100644 index 59c54c1ce9a..00000000000 --- a/apps/contract-verification/src/app/components/Dropdown.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import React from 'react' - -interface DropdownItem { - value: string - name: string -} - -interface DropdownProps { - label: string - items: DropdownItem[] - id: string -} - -export const Dropdown: React.FC = ({label, items, id}) => { - return ( -
- - -
- ) -} diff --git a/apps/contract-verification/src/app/components/index.tsx b/apps/contract-verification/src/app/components/index.tsx index 30926f8f8b3..f2978cea34d 100644 --- a/apps/contract-verification/src/app/components/index.tsx +++ b/apps/contract-verification/src/app/components/index.tsx @@ -1,3 +1,3 @@ export {NavMenu} from './NavMenu' -export {Dropdown} from './Dropdown' +export {ContractDropdown} from './ContractDropdown' export {SearchableDropdown} from './SearchableDropdown' diff --git a/apps/contract-verification/src/app/views/HomeView.tsx b/apps/contract-verification/src/app/views/HomeView.tsx index 3f6bb885905..94013b21a83 100644 --- a/apps/contract-verification/src/app/views/HomeView.tsx +++ b/apps/contract-verification/src/app/views/HomeView.tsx @@ -1,8 +1,8 @@ import React from 'react' import {AppContext} from '../AppContext' -import {Dropdown} from '../components' import {SearchableDropdown} from '../components' +import {ContractDropdown} from '../components/ContractDropdown' export const HomeView = () => { const {chains, selectedChain, setSelectedChain, compilationOutput} = React.useContext(AppContext) @@ -41,7 +41,7 @@ export const HomeView = () => {
- {contractNames && contractNames.length > 0 ? ({value: item, name: item}))} id="contract-name-dropdown" /> :
No compiled contracts
} + ({value: item, name: item}))} id="contract-name-dropdown" />
Constructor Arguments
{/* TODO: Add input fields for constructor arguments */} diff --git a/apps/contract-verification/tsconfig.json b/apps/contract-verification/tsconfig.json index c366a45f2ba..bfdc10e8590 100644 --- a/apps/contract-verification/tsconfig.json +++ b/apps/contract-verification/tsconfig.json @@ -5,7 +5,7 @@ "allowJs": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, - "strict": true + // "strict": true }, "files": [], "include": [], From 9da31b7ded01e7c69e4992e44831cda0d3d8292a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Fri, 14 Jun 2024 10:35:12 +0200 Subject: [PATCH 012/100] Add getAllCompilerAbstracts method to `compiler-artefacts.ts` The current compilerArtefacts plugin's existing methods had two flaws: 1. It wasn't possible to get all Compiler Abstracts available in one go. 2. It was possible to first get all files with `getAllContractsData` and then call each CompilerAbstract one by one with `getCompilerAbstract`, however, in that case the CompilerAbstract was missing the `input` because it wasn't passed to the contructor and saveCompilationPerFileResult. It was only done so for the `solidityUnitTesting` plugin listener. The compiler input is needed for consistent contract verification. While it's possible to generate a compiler input from the contract artefact, via the metadata, it is not always possible to get a match due to known bugs in compiler's AST generation in prev. versions. This results in different bytecode from the original compiler input's output vs the compilation output from the metadata file. --- .../src/lib/compiler-artefacts.ts | 111 +++++++----------- 1 file changed, 44 insertions(+), 67 deletions(-) diff --git a/libs/remix-core-plugin/src/lib/compiler-artefacts.ts b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts index d008795aec4..90e8af79819 100644 --- a/libs/remix-core-plugin/src/lib/compiler-artefacts.ts +++ b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts @@ -1,89 +1,67 @@ 'use strict' -import { Plugin } from '@remixproject/engine' -import { util } from '@remix-project/remix-lib' -import { CompilerAbstract } from '@remix-project/remix-solidity' +import {Plugin} from '@remixproject/engine' +import {util} from '@remix-project/remix-lib' +import {CompilerAbstract} from '@remix-project/remix-solidity' const profile = { name: 'compilerArtefacts', - methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas', 'getLastCompilationResult', 'getArtefactsByContractName', 'getContractDataFromAddress', 'getContractDataFromByteCode', 'saveCompilerAbstract'], + methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas', 'getLastCompilationResult', 'getArtefactsByContractName', 'getContractDataFromAddress', 'getContractDataFromByteCode', 'saveCompilerAbstract', 'getAllCompilerAbstracts'], events: [], - version: '0.0.1' + version: '0.0.1', } export class CompilerArtefacts extends Plugin { compilersArtefactsPerFile: any compilersArtefacts: any - constructor () { + constructor() { super(profile) this.compilersArtefacts = {} this.compilersArtefactsPerFile = {} } - clear () { + clear() { this.compilersArtefacts = {} this.compilersArtefactsPerFile = {} } - saveCompilerAbstract (file: string, compilerAbstract: CompilerAbstract) { + saveCompilerAbstract(file: string, compilerAbstract: CompilerAbstract) { this.compilersArtefactsPerFile[file] = compilerAbstract } - onActivation () { - const saveCompilationPerFileResult = (file, source, languageVersion, data, input?) => { + getAllCompilerAbstracts() { + return this.compilersArtefactsPerFile + } + + onActivation() { + const saveCompilationResult = (file, source, languageVersion, data, input?) => { + this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source, input) this.compilersArtefactsPerFile[file] = new CompilerAbstract(languageVersion, data, source, input) } - this.on('solidity', 'compilationFinished', (file, source, languageVersion, data, input, version) => { - this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source, input) - saveCompilationPerFileResult(file, source, languageVersion, data) - }) + this.on('solidity', 'compilationFinished', saveCompilationResult) - this.on('vyper', 'compilationFinished', (file, source, languageVersion, data) => { - this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) - saveCompilationPerFileResult(file, source, languageVersion, data) - }) + this.on('vyper', 'compilationFinished', saveCompilationResult) - this.on('lexon', 'compilationFinished', (file, source, languageVersion, data) => { - this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) - saveCompilationPerFileResult(file, source, languageVersion, data) - }) + this.on('lexon', 'compilationFinished', saveCompilationResult) - this.on('yulp', 'compilationFinished', (file, source, languageVersion, data) => { - this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) - saveCompilationPerFileResult(file, source, languageVersion, data) - }) + this.on('yulp', 'compilationFinished', saveCompilationResult) - this.on('solidityUnitTesting', 'compilationFinished', (file, source, languageVersion, data, input, version) => { - this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source, input) - saveCompilationPerFileResult(file, source, languageVersion, data, input) - }) + this.on('solidityUnitTesting', 'compilationFinished', saveCompilationResult) - this.on('nahmii-compiler', 'compilationFinished', (file, source, languageVersion, data) => { - this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) - saveCompilationPerFileResult(file, source, languageVersion, data) - }) + this.on('nahmii-compiler', 'compilationFinished', saveCompilationResult) - this.on('hardhat', 'compilationFinished', (file, source, languageVersion, data) => { - this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) - saveCompilationPerFileResult(file, source, languageVersion, data) - }) + this.on('hardhat', 'compilationFinished', saveCompilationResult) - this.on('truffle', 'compilationFinished', (file, source, languageVersion, data) => { - this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) - saveCompilationPerFileResult(file, source, languageVersion, data) - }) + this.on('truffle', 'compilationFinished', saveCompilationResult) - this.on('foundry', 'compilationFinished', (file, source, languageVersion, data) => { - this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source) - saveCompilationPerFileResult(file, source, languageVersion, data) - }) + this.on('foundry', 'compilationFinished', saveCompilationResult) } /** * Get artefacts for last compiled contract * * @returns last compiled contract compiler abstract */ - getLastCompilationResult () { + getLastCompilationResult() { return this.compilersArtefacts.__last } @@ -91,7 +69,7 @@ export class CompilerArtefacts extends Plugin { * Get compilation output for contracts compiled during a session of Remix IDE * @returns compilatin output */ - getAllContractDatas () { + getAllContractDatas() { return this.filterAllContractDatas(() => true) } @@ -99,7 +77,7 @@ export class CompilerArtefacts extends Plugin { * filter compilation output for contracts compiled during a session of Remix IDE * @returns compilatin output */ - filterAllContractDatas (filter) { + filterAllContractDatas(filter) { const contractsData = {} Object.keys(this.compilersArtefactsPerFile).map((targetFile) => { const artefact = this.compilersArtefactsPerFile[targetFile] @@ -124,7 +102,7 @@ export class CompilerArtefacts extends Plugin { * @param contractName contract name * @returns arefacts object, with fully qualified name (e.g; contracts/1_Storage.sol:Storage) as key */ - _getAllContractArtefactsfromOutput (compilerOutput, contractName) { + _getAllContractArtefactsfromOutput(compilerOutput, contractName) { const contractArtefacts = {} for (const filename in compilerOutput) { if (Object.keys(compilerOutput[filename]).includes(contractName)) contractArtefacts[filename + ':' + contractName] = compilerOutput[filename][contractName] @@ -139,12 +117,12 @@ export class CompilerArtefacts extends Plugin { * @param contractArtefacts populated resultant artefacts object, with fully qualified name (e.g: contracts/1_Storage.sol:Storage) as key * Once method execution completes, contractArtefacts object will hold all possible artefacts for contract */ - async _populateAllContractArtefactsFromFE (path, contractName, contractArtefacts) { + async _populateAllContractArtefactsFromFE(path, contractName, contractArtefacts) { const dirList = await this.call('fileManager', 'dirList', path) if (dirList && dirList.length) { for (const dirPath of dirList) { // check if directory contains an 'artifacts' folder and a 'build-info' folder inside 'artifacts' - if (dirPath === path + '/artifacts' && await this.call('fileManager', 'exists', dirPath + '/build-info')) { + if (dirPath === path + '/artifacts' && (await this.call('fileManager', 'exists', dirPath + '/build-info'))) { const buildFileList = await this.call('fileManager', 'fileList', dirPath + '/build-info') // process each build-info file to populate the artefacts for contractName for (const buildFile of buildFileList) { @@ -155,7 +133,7 @@ export class CompilerArtefacts extends Plugin { // populate the resultant object with artefacts Object.assign(contractArtefacts, artefacts) } - } else await this._populateAllContractArtefactsFromFE (dirPath, contractName, contractArtefacts) + } else await this._populateAllContractArtefactsFromFE(dirPath, contractName, contractArtefacts) } } else return } @@ -165,7 +143,7 @@ export class CompilerArtefacts extends Plugin { * @param name contract name or fully qualified name i.e. : e.g: contracts/1_Storage.sol:Storage * @returns artefacts for the contract */ - async getArtefactsByContractName (name) { + async getArtefactsByContractName(name) { const contractsDataByFilename = this.getAllContractDatas() // check if name is a fully qualified name if (name.includes(':')) { @@ -173,12 +151,11 @@ export class CompilerArtefacts extends Plugin { const nameArr = fullyQualifiedName.split(':') const filename = nameArr[0] const contract = nameArr[1] - if (Object.keys(contractsDataByFilename).includes(filename) && contractsDataByFilename[filename][contract]) - return contractsDataByFilename[filename][contract] + if (Object.keys(contractsDataByFilename).includes(filename) && contractsDataByFilename[filename][contract]) return contractsDataByFilename[filename][contract] else { const allContractsData = {} - await this._populateAllContractArtefactsFromFE ('contracts', contract, allContractsData) - if (allContractsData[fullyQualifiedName]) return { fullyQualifiedName, artefact: allContractsData[fullyQualifiedName] } + await this._populateAllContractArtefactsFromFE('contracts', contract, allContractsData) + if (allContractsData[fullyQualifiedName]) return {fullyQualifiedName, artefact: allContractsData[fullyQualifiedName]} else throw new Error(`Could not find artifacts for ${fullyQualifiedName}. Compile contract to generate artifacts.`) } } else { @@ -186,10 +163,10 @@ export class CompilerArtefacts extends Plugin { const contractArtefacts = this._getAllContractArtefactsfromOutput(contractsDataByFilename, contractName) let keys = Object.keys(contractArtefacts) if (!keys.length) { - await this._populateAllContractArtefactsFromFE ('contracts', contractName, contractArtefacts) + await this._populateAllContractArtefactsFromFE('contracts', contractName, contractArtefacts) keys = Object.keys(contractArtefacts) } - if (keys.length === 1) return { fullyQualifiedName: keys[0], artefact: contractArtefacts[keys[0]] } + if (keys.length === 1) return {fullyQualifiedName: keys[0], artefact: contractArtefacts[keys[0]]} else if (keys.length > 1) { throw new Error(`There are multiple artifacts for contract "${contractName}", please use a fully qualified name.\n Please replace ${contractName} for one of these options wherever you are trying to read its artifact: \n @@ -199,7 +176,7 @@ export class CompilerArtefacts extends Plugin { } } - async getCompilerAbstract (file) { + async getCompilerAbstract(file) { if (!file) return null if (this.compilersArtefactsPerFile[file]) return this.compilersArtefactsPerFile[file] const path = await this.call('fileManager', 'getPathFromUrl', file) @@ -215,30 +192,30 @@ export class CompilerArtefacts extends Plugin { return artefact } - addResolvedContract (address: string, compilerData: CompilerAbstract) { + addResolvedContract(address: string, compilerData: CompilerAbstract) { this.compilersArtefacts[address] = compilerData } - isResolved (address) { + isResolved(address) { return this.compilersArtefacts[address] !== undefined } - get (key) { + get(key) { return this.compilersArtefacts[key] } - async getContractDataFromAddress (address) { + async getContractDataFromAddress(address) { const code = await this.call('blockchain', 'getCode', address) return this.getContractDataFromByteCode(code) } - async getContractDataFromByteCode (code) { + async getContractDataFromByteCode(code) { let found this.filterAllContractDatas((file, contractsData) => { for (const name of Object.keys(contractsData)) { const contract = contractsData[name] if (util.compareByteCode(code, '0x' + contract.evm.deployedBytecode.object)) { - found = { name, contract, file } + found = {name, contract, file} return true } } From 12702c5ae798779eaf214947b9f680ea75032d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Fri, 14 Jun 2024 10:44:28 +0200 Subject: [PATCH 013/100] Don't create two separate new CompilerAbstracts --- libs/remix-core-plugin/src/lib/compiler-artefacts.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-core-plugin/src/lib/compiler-artefacts.ts b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts index 90e8af79819..428bc7bf751 100644 --- a/libs/remix-core-plugin/src/lib/compiler-artefacts.ts +++ b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts @@ -34,8 +34,8 @@ export class CompilerArtefacts extends Plugin { onActivation() { const saveCompilationResult = (file, source, languageVersion, data, input?) => { - this.compilersArtefacts.__last = new CompilerAbstract(languageVersion, data, source, input) this.compilersArtefactsPerFile[file] = new CompilerAbstract(languageVersion, data, source, input) + this.compilersArtefacts.__last = this.compilersArtefactsPerFile[file] } this.on('solidity', 'compilationFinished', saveCompilationResult) From f4a3fa55304c4c8372e3f8e28d0da287bc6d9e63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Fri, 14 Jun 2024 11:53:55 +0200 Subject: [PATCH 014/100] Fetch compilation outputs from `compilerArtefacts` module --- .../src/app/AppContext.tsx | 8 ++- apps/contract-verification/src/app/app.tsx | 60 +++++++++++++------ .../app/components/ConstructorArguments.tsx | 0 .../src/app/components/ContractDropdown.tsx | 38 +++++++++--- 4 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 apps/contract-verification/src/app/components/ConstructorArguments.tsx diff --git a/apps/contract-verification/src/app/AppContext.tsx b/apps/contract-verification/src/app/AppContext.tsx index 4106ffbb5c2..70d1056dbc3 100644 --- a/apps/contract-verification/src/app/AppContext.tsx +++ b/apps/contract-verification/src/app/AppContext.tsx @@ -1,6 +1,6 @@ import React from 'react' import {ThemeType} from './types' -import {CompilationResult} from '@remixproject/plugin-api' +import {CompilationResult, CompiledContract} from '@remixproject/plugin-api' // Define the type for the context type AppContextType = { @@ -10,6 +10,9 @@ type AppContextType = { selectedChain: any | undefined setSelectedChain: (chain: string) => void compilationOutput: CompilationResult | undefined + selectedContract: CompiledContract | undefined + setSelectedContract: (contract: CompiledContract) => void + targetFileName: string | undefined } // Provide a default value with the appropriate types @@ -22,6 +25,9 @@ const defaultContextValue: AppContextType = { selectedChain: undefined, setSelectedChain: (chain: string) => {}, compilationOutput: undefined, + selectedContract: undefined, + setSelectedContract: (contract: CompiledContract) => {}, + targetFileName: undefined, } // Create the context with the type diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index cbae61b49d8..b54815eb9f8 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -8,7 +8,7 @@ import {CustomTooltip} from '@remix-ui/helper' import {ThemeType} from './types' import './App.css' -import {CompilationFileSources, CompilationResult} from '@remixproject/plugin-api' +import {CompilationFileSources, CompilationResult, CompiledContract} from '@remixproject/plugin-api' const plugin = new ContractVerificationPluginClient() @@ -19,39 +19,65 @@ const App = () => { const [selectedChain, setSelectedChain] = useState() const [targetFileName, setTargetFileName] = useState('') const [compilationOutput, setCompilationOutput] = useState() + const [selectedContract, setSelectedContract] = useState() useEffect(() => { // TODO: Fix 'compilationFinished' event types. The interface is outdated at https://github.com/ethereum/remix-plugin/blob/master/packages/api/src/lib/compiler/api.ts. It does not include data, input, or version. See the current parameters: https://github.com/ethereum/remix-project/blob/9f6c5be882453a555055f07171701459e4ae88a4/libs/remix-solidity/src/compiler/compiler.ts#L189 // Because of this reason we use @ts-expect-error for the next line - // @ts-expect-error:next-line - plugin.on('solidity', 'compilationFinished', (fileName: string, source: CompilationFileSources, languageVersion: string, data: CompilationResult, input: string, version: string) => { - console.log('Compilation output') + // // @ts-expect-error:next-line + // plugin.on('solidity', 'compilationFinished', (fileName: string, source: CompilationFileSources, languageVersion: string, data: CompilationResult, input: string, version: string) => { + // console.log('Compilation output') + // console.log(data) + // console.log('File Name:', fileName) + // console.log('Source:', source) + // console.log('Language Version:', languageVersion) + // console.log('Compilation Result:', data) + // // console.log('Input:', input) + // console.log('Compiler Version:', version) + // console.log('contractNames') + // console.log(Object.keys(data.contracts[fileName])) + + // setTargetFileName(fileName) + // setCompilationOutput(data) + // }) + + // plugin.call('compilerArtefacts', 'getAllContractDatas').then((allContractDatas: any) => { + // console.log('compilerArtefacts.getAllContractDatas') + // console.log(allContractDatas) + // const files = Object.keys(allContractDatas) + // files.forEach((file) => { + // // + // plugin.call('compilerArtefacts' as any, 'getCompilerAbstract', file).then((data: any) => { + // console.log('compilerArtefacts.getCompilerAbstract ' + file) + // console.log(data) + // }) + // }) + // }) + + // // TODO: why "as any" needed here + // plugin.call('compilerArtefacts' as any, 'getLastCompilationResult').then((data: any) => { + // console.log('compilerArtefacts.getLastCompilationResult') + // console.log(data) + // }) + + plugin.call('compilerArtefacts' as any, 'getAllCompilerAbstracts').then((data: any) => { + console.log('compilerArtefacts.getAllCompilerAbstracts') console.log(data) - console.log('File Name:', fileName) - console.log('Source:', source) - console.log('Language Version:', languageVersion) - console.log('Compilation Result:', data) - // console.log('Input:', input) - console.log('Compiler Version:', version) - console.log('contractNames') - console.log(Object.keys(data.contracts[fileName])) - - setTargetFileName(fileName) - setCompilationOutput(undefined) + setCompilationOutput(data) }) + // Fetch chains.json and update state fetch('https://chainid.network/chains.json') .then((response) => response.json()) .then((data) => setChains(data)) .catch((error) => console.error('Failed to fetch chains.json:', error)) - return () => { plugin.off('solidity', 'compilationFinished') // Clean up on unmount } }, []) return ( - + ) diff --git a/apps/contract-verification/src/app/components/ConstructorArguments.tsx b/apps/contract-verification/src/app/components/ConstructorArguments.tsx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/apps/contract-verification/src/app/components/ContractDropdown.tsx b/apps/contract-verification/src/app/components/ContractDropdown.tsx index 2dea4a32ccf..f54d28cd8dd 100644 --- a/apps/contract-verification/src/app/components/ContractDropdown.tsx +++ b/apps/contract-verification/src/app/components/ContractDropdown.tsx @@ -1,5 +1,6 @@ -import React from 'react' +import React, {useEffect, useState, useContext} from 'react' import './ContractDropdown.css' +import {AppContext} from '../AppContext' interface ContractDropdownItem { value: string name: string @@ -11,19 +12,38 @@ interface ContractDropdownProps { id: string } -export const ContractDropdown: React.FC = ({label, contractNames, id}) => { - const hasContracts = contractNames && contractNames.length > 0 +// Chooses one contract from the compilation output. +export const ContractDropdown: React.FC = ({label, id}) => { + const {setSelectedContract, compilationOutput} = useContext(AppContext) + const [chosenContractFileAndName, setChosenContractFileAndName] = useState('') + + useEffect(() => { + console.log('CompiilationOutput chainged', compilationOutput) + }, [compilationOutput]) + + const handleSelectContract = (event: React.ChangeEvent) => { + console.log('contractName', event.target.value) + } + + const hasContracts = compilationOutput && Object.keys(compilationOutput).length > 0 + return (
- {hasContracts ? ( - contractNames.map((item, index) => ( - - )) + Object.keys(compilationOutput).map((fileName) => + Object.keys(compilationOutput[fileName].data.contracts).map((fileName2) => ( + + {Object.keys(compilationOutput[fileName].data.contracts[fileName2]).map((contractName) => ( + + ))} + + )) + ) ) : ( )} From 93d4af37881677c804db9289cf87e7ff17168d63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Fri, 14 Jun 2024 19:05:05 +0200 Subject: [PATCH 015/100] Add SourcifyVerifier and submit a verification. Proper e2e chain and contract selection. --- .../src/app/AppContext.tsx | 26 +++--- .../src/app/Verifiers/SourcifyVerifier.ts | 57 +++++++++++++ apps/contract-verification/src/app/app.tsx | 31 ++++--- .../src/app/components/ContractDropdown.tsx | 17 +++- .../src/app/components/SearchableDropdown.tsx | 36 ++++---- .../src/app/types/VerificationTypes.ts | 30 +++++++ .../src/app/views/HomeView.tsx | 82 ++++++++++++++----- 7 files changed, 210 insertions(+), 69 deletions(-) create mode 100644 apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts create mode 100644 apps/contract-verification/src/app/types/VerificationTypes.ts diff --git a/apps/contract-verification/src/app/AppContext.tsx b/apps/contract-verification/src/app/AppContext.tsx index 70d1056dbc3..77180cb3aa4 100644 --- a/apps/contract-verification/src/app/AppContext.tsx +++ b/apps/contract-verification/src/app/AppContext.tsx @@ -1,18 +1,21 @@ import React from 'react' import {ThemeType} from './types' -import {CompilationResult, CompiledContract} from '@remixproject/plugin-api' +import {Chain, VerifiedContract} from './types/VerificationTypes' +import {SourcifyVerifier} from './Verifiers/SourcifyVerifier' +import {CompilerAbstract} from '@remix-project/remix-solidity' // Define the type for the context type AppContextType = { themeType: ThemeType setThemeType: (themeType: ThemeType) => void - chains: any[] - selectedChain: any | undefined - setSelectedChain: (chain: string) => void - compilationOutput: CompilationResult | undefined - selectedContract: CompiledContract | undefined - setSelectedContract: (contract: CompiledContract) => void + chains: Chain[] + compilationOutput: {[key: string]: CompilerAbstract} | undefined + selectedContractFileAndName: string | undefined + setSelectedContractFileAndName: (contract: string) => void targetFileName: string | undefined + verifiedContracts: VerifiedContract[] + setVerifiedContracts: (verifiedContracts: VerifiedContract[]) => void + sourcifyVerifiers: SourcifyVerifier[] } // Provide a default value with the appropriate types @@ -22,12 +25,13 @@ const defaultContextValue: AppContextType = { console.log('Calling Set Theme Type') }, chains: [], - selectedChain: undefined, - setSelectedChain: (chain: string) => {}, compilationOutput: undefined, - selectedContract: undefined, - setSelectedContract: (contract: CompiledContract) => {}, + selectedContractFileAndName: undefined, + setSelectedContractFileAndName: (contract: string) => {}, targetFileName: undefined, + verifiedContracts: [], + setVerifiedContracts: (verifiedContracts: VerifiedContract[]) => {}, + sourcifyVerifiers: [], } // Create the context with the type diff --git a/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts new file mode 100644 index 00000000000..f3de4695aa8 --- /dev/null +++ b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts @@ -0,0 +1,57 @@ +import {SourcesCode} from '@remix-project/remix-solidity' +import {AbstractVerifier} from './AbstractVerifier' + +export class SourcifyVerifier { + name: string + apiUrl: string + + constructor(apiUrl: string, name: string = 'Sourcify') { + this.apiUrl = apiUrl + this.name = name + } + + async verify(chainId: string, address: string, sources: SourcesCode, metadataStr: string): Promise { + // from { "filename.sol": {content: "contract MyContract { ... }"} } + // to { "filename.sol": "contract MyContract { ... }" } + const formattedSources = Object.entries(sources).reduce((acc, [fileName, {content}]) => { + acc[fileName] = content + return acc + }, {}) + const body = { + chainId, + address, + files: { + 'metadata.json': metadataStr, + ...formattedSources, + }, + } + + console.log(body) + + const response = await fetch(new URL('verify', this.apiUrl).href, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }) + + if (!response.ok) { + throw new Error(`Error on Sourcify verification at ${this.apiUrl}: Status:${response.status} Response: ${await response.text()}`) + } + + const data = await response.json() + console.log(data) + + return data.result + } + + async lookup(): Promise { + // Implement the lookup logic here + console.log('Sourcify lookup started') + // Placeholder logic for lookup + const lookupResult = {} // Replace with actual lookup logic + console.log('Sourcify lookup completed') + return lookupResult + } +} diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index b54815eb9f8..a914214f78b 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -4,24 +4,34 @@ import {ContractVerificationPluginClient} from './ContractVerificationPluginClie import {AppContext} from './AppContext' import DisplayRoutes from './routes' -import {CustomTooltip} from '@remix-ui/helper' import {ThemeType} from './types' import './App.css' -import {CompilationFileSources, CompilationResult, CompiledContract} from '@remixproject/plugin-api' +import {Chain, VerifiedContract} from './types/VerificationTypes' +import {SourcifyVerifier} from './Verifiers/SourcifyVerifier' +import {CompilerAbstract} from '@remix-project/remix-solidity' const plugin = new ContractVerificationPluginClient() const App = () => { const [themeType, setThemeType] = useState('dark') // TODO: Types for chains - const [chains, setChains] = useState([]) // State to hold the chains data - const [selectedChain, setSelectedChain] = useState() + const [chains, setChains] = useState([]) // State to hold the chains data const [targetFileName, setTargetFileName] = useState('') - const [compilationOutput, setCompilationOutput] = useState() - const [selectedContract, setSelectedContract] = useState() + const [compilationOutput, setCompilationOutput] = useState<{[key: string]: CompilerAbstract} | undefined>() + // Contract file and name in format contracts/Storage.sol:Storage + const [selectedContractFileAndName, setSelectedContractFileAndName] = useState() + const [verifiedContracts, setVerifiedContracts] = useState([]) + const [sourcifyVerifiers, setSourcifyVerifiers] = useState([]) useEffect(() => { + console.log('Selected Contract File And Name Changed', selectedContractFileAndName) + }, [selectedContractFileAndName]) + + useEffect(() => { + // const sourcifyVerifier = new SourcifyVerifier('http://sourcify.dev/server/', 'Sourcify') + const sourcifyVerifier = new SourcifyVerifier('http://localhost:5555/', 'Sourcify Localhost') + setSourcifyVerifiers([sourcifyVerifier]) // TODO: Fix 'compilationFinished' event types. The interface is outdated at https://github.com/ethereum/remix-plugin/blob/master/packages/api/src/lib/compiler/api.ts. It does not include data, input, or version. See the current parameters: https://github.com/ethereum/remix-project/blob/9f6c5be882453a555055f07171701459e4ae88a4/libs/remix-solidity/src/compiler/compiler.ts#L189 // Because of this reason we use @ts-expect-error for the next line // // @ts-expect-error:next-line @@ -60,12 +70,11 @@ const App = () => { // console.log(data) // }) - plugin.call('compilerArtefacts' as any, 'getAllCompilerAbstracts').then((data: any) => { + plugin.call('compilerArtefacts' as any, 'getAllCompilerAbstracts').then((obj: any) => { console.log('compilerArtefacts.getAllCompilerAbstracts') - console.log(data) - setCompilationOutput(data) + console.log(obj) + setCompilationOutput(obj) }) - // Fetch chains.json and update state fetch('https://chainid.network/chains.json') .then((response) => response.json()) @@ -77,7 +86,7 @@ const App = () => { }, []) return ( - + ) diff --git a/apps/contract-verification/src/app/components/ContractDropdown.tsx b/apps/contract-verification/src/app/components/ContractDropdown.tsx index f54d28cd8dd..39fc47869fb 100644 --- a/apps/contract-verification/src/app/components/ContractDropdown.tsx +++ b/apps/contract-verification/src/app/components/ContractDropdown.tsx @@ -8,21 +8,30 @@ interface ContractDropdownItem { interface ContractDropdownProps { label: string - contractNames: ContractDropdownItem[] id: string } // Chooses one contract from the compilation output. export const ContractDropdown: React.FC = ({label, id}) => { - const {setSelectedContract, compilationOutput} = useContext(AppContext) - const [chosenContractFileAndName, setChosenContractFileAndName] = useState('') + const {setSelectedContractFileAndName, compilationOutput} = useContext(AppContext) useEffect(() => { console.log('CompiilationOutput chainged', compilationOutput) + if (!compilationOutput) return + const isOnlyOneFileCompiled = Object.keys(compilationOutput).length === 1 + if (isOnlyOneFileCompiled) { + const onlyFileName = Object.keys(compilationOutput)[0] + const isOnlyOneContractCompiled = Object.keys(compilationOutput[onlyFileName].data.contracts[onlyFileName]).length === 1 + if (isOnlyOneContractCompiled) { + const onlyContractName = Object.keys(compilationOutput[onlyFileName].data.contracts[onlyFileName])[0] + setSelectedContractFileAndName(onlyFileName + ':' + onlyContractName) + } + } }, [compilationOutput]) const handleSelectContract = (event: React.ChangeEvent) => { - console.log('contractName', event.target.value) + console.log('selecting ', event.target.value) + setSelectedContractFileAndName(event.target.value) } const hasContracts = compilationOutput && Object.keys(compilationOutput).length > 0 diff --git a/apps/contract-verification/src/app/components/SearchableDropdown.tsx b/apps/contract-verification/src/app/components/SearchableDropdown.tsx index bae40e0aa6e..7af3f40c4d5 100644 --- a/apps/contract-verification/src/app/components/SearchableDropdown.tsx +++ b/apps/contract-verification/src/app/components/SearchableDropdown.tsx @@ -1,39 +1,34 @@ import React, {useState, useEffect, useRef} from 'react' import Fuse from 'fuse.js' - -interface DropdownItem { - value: string - name: string -} +import {Chain} from '../types/VerificationTypes' interface DropdownProps { label: string - options: DropdownItem[] + chains: Chain[] id: string - value: string - onChange: (value: string) => void + setSelectedChain: (chain: Chain) => void + selectedChain: Chain } -export const SearchableDropdown: React.FC = ({options, label, id, value, onChange}) => { +export const SearchableDropdown: React.FC = ({chains, label, id, setSelectedChain, selectedChain}) => { const [searchTerm, setSearchTerm] = useState('') - const [selectedOption, setSelectedOption] = useState(null) const [isOpen, setIsOpen] = useState(false) - const [filteredOptions, setFilteredOptions] = useState(options) + const [filteredOptions, setFilteredOptions] = useState(chains) const dropdownRef = useRef(null) - const fuse = new Fuse(options, { + const fuse = new Fuse(chains, { keys: ['name'], threshold: 0.3, }) useEffect(() => { if (searchTerm === '') { - setFilteredOptions(options) + setFilteredOptions(chains) } else { const result = fuse.search(searchTerm) setFilteredOptions(result.map(({item}) => item)) } - }, [searchTerm, options]) + }, [searchTerm, chains]) // Close dropdown when user clicks outside useEffect(() => { @@ -50,12 +45,11 @@ export const SearchableDropdown: React.FC = ({options, label, id, const handleInputChange = (e: React.ChangeEvent) => { setSearchTerm(e.target.value) - onChange(e.target.value) setIsOpen(true) } - const handleOptionClick = (option: DropdownItem) => { - setSelectedOption(option) + const handleOptionClick = (option: Chain) => { + setSelectedChain(option) setSearchTerm(option.name) setIsOpen(false) } @@ -65,7 +59,7 @@ export const SearchableDropdown: React.FC = ({options, label, id, setSearchTerm('') } - if (!options || options.length === 0) { + if (!chains || chains.length === 0) { return (
@@ -82,9 +76,9 @@ export const SearchableDropdown: React.FC = ({options, label, id, {isOpen && (
    - {filteredOptions.map((option) => ( -
  • handleOptionClick(option)} className={`dropdown-item ${selectedOption === option ? 'active' : ''}`} style={{cursor: 'pointer', whiteSpace: 'normal'}}> - {option.name} + {filteredOptions.map((chain) => ( +
  • handleOptionClick(chain)} className={`dropdown-item ${selectedChain?.chainId === chain.chainId ? 'active' : ''}`} style={{cursor: 'pointer', whiteSpace: 'normal'}}> + {chain.title || chain.name} ({chain.chainId})
  • ))}
diff --git a/apps/contract-verification/src/app/types/VerificationTypes.ts b/apps/contract-verification/src/app/types/VerificationTypes.ts new file mode 100644 index 00000000000..108c48074f4 --- /dev/null +++ b/apps/contract-verification/src/app/types/VerificationTypes.ts @@ -0,0 +1,30 @@ +import {SourcifyVerifier} from '../Verifiers/SourcifyVerifier' + +export interface VerifiedContract { + name: string + address: string + chainId: string + date: Date + verifier: SourcifyVerifier + status: string + receipt?: string +} + +interface Currency { + name: string + symbol: string + decimals: number +} +// types for https://chainid.network/chains.json (i.e. https://github.com/ethereum-lists/chains) +export interface Chain { + name: string + title?: string + chainId: number + shortName?: string + network?: string + networkId?: number + nativeCurrency?: Currency + rpc: Array + faucets?: string[] + infoURL?: string +} diff --git a/apps/contract-verification/src/app/views/HomeView.tsx b/apps/contract-verification/src/app/views/HomeView.tsx index 94013b21a83..75c6880ff43 100644 --- a/apps/contract-verification/src/app/views/HomeView.tsx +++ b/apps/contract-verification/src/app/views/HomeView.tsx @@ -1,30 +1,66 @@ -import React from 'react' +import React, {useEffect, useState} from 'react' import {AppContext} from '../AppContext' import {SearchableDropdown} from '../components' import {ContractDropdown} from '../components/ContractDropdown' +// INSERT_YOUR_CODE +import {ethers} from 'ethers/' +import {Chain} from '../types/VerificationTypes' export const HomeView = () => { - const {chains, selectedChain, setSelectedChain, compilationOutput} = React.useContext(AppContext) + const {chains, compilationOutput, sourcifyVerifiers, selectedContractFileAndName} = React.useContext(AppContext) + const [contractAddress, setContractAddress] = useState('') + const [contractAddressError, setContractAddressError] = useState('') + const [selectedChain, setSelectedChain] = useState() - const ethereumChainIds = [1, 3, 4, 5, 11155111, 17000] + useEffect(() => { + console.log('Selected chain changed', selectedChain) + }, [selectedChain]) - const contractNames = compilationOutput?.contracts && Object.keys(compilationOutput?.contracts) + const ethereumChainIds = [1, 3, 4, 5, 11155111, 17000] // Add Ethereum chains to the head of the chains list. Sort the rest alphabetically - const dropdownChains = chains - .map((chain) => ({value: chain.chainId, name: `${chain.title || chain.name} (${chain.chainId})`})) - .sort((a, b) => { - const isAInEthereum = ethereumChainIds.includes(a.value) - const isBInEthereum = ethereumChainIds.includes(b.value) + const dropdownChains = chains.sort((a, b) => { + const isAInEthereum = ethereumChainIds.includes(a.chainId) + const isBInEthereum = ethereumChainIds.includes(b.chainId) - if (isAInEthereum && !isBInEthereum) return -1 - if (!isAInEthereum && isBInEthereum) return 1 - if (isAInEthereum && isBInEthereum) return ethereumChainIds.indexOf(a.value) - ethereumChainIds.indexOf(b.value) + if (isAInEthereum && !isBInEthereum) return -1 + if (!isAInEthereum && isBInEthereum) return 1 + if (isAInEthereum && isBInEthereum) return ethereumChainIds.indexOf(a.chainId) - ethereumChainIds.indexOf(b.chainId) - return a.name.localeCompare(b.name) + return (a.title || a.name).localeCompare(b.title || b.name) + }) + + const handleVerify = async (e) => { + e.preventDefault() // Don't change the page + const [selectedFileName, selectedContractName] = selectedContractFileAndName.split(':') + const selectedContractAbstract = compilationOutput?.[selectedFileName || ''] + const selectedContractMetadataStr = selectedContractAbstract.data.contracts[selectedFileName][selectedContractName].metadata + console.log('selectedFileName:', selectedFileName) + console.log('selectedContractName:', selectedContractName) + console.log('selectedContractAbstract:', selectedContractAbstract) + console.log('selectedContractMetadataStr:', selectedContractMetadataStr) + console.log('sourcifyVerifiers:', sourcifyVerifiers) + console.log('selectedChain:', selectedChain) + console.log('contractAddress:', contractAddress) + const sourcifyPromises = sourcifyVerifiers.map((sourcifyVerifier) => { + return sourcifyVerifier.verify(selectedChain.chainId.toString(), contractAddress, selectedContractAbstract.source.sources, selectedContractMetadataStr) }) + const results = await Promise.all(sourcifyPromises) + console.log('results', results) + } + + const handleAddressChange = (event: React.ChangeEvent) => { + const isValidAddress = ethers.utils.isAddress(event.target.value) + setContractAddress(event.target.value) + if (!isValidAddress) { + setContractAddressError('Invalid contract address') + console.error('Invalid contract address') + return + } + setContractAddressError('') + } return (
@@ -33,20 +69,22 @@ export const HomeView = () => { Verify compiled contracts on different verification services

-
- +
+
- +
{contractAddressError &&
{contractAddressError}
}
+
- ({value: item, name: item}))} id="contract-name-dropdown" /> -
-
Constructor Arguments
- {/* TODO: Add input fields for constructor arguments */} -
-
+ + + +
) } From 0299f530da65d471ce2068a7273a2b33b03136ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Mon, 17 Jun 2024 15:48:12 +0200 Subject: [PATCH 016/100] Add compilationSaved event --- libs/remix-core-plugin/src/lib/compiler-artefacts.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/remix-core-plugin/src/lib/compiler-artefacts.ts b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts index 428bc7bf751..ded062af888 100644 --- a/libs/remix-core-plugin/src/lib/compiler-artefacts.ts +++ b/libs/remix-core-plugin/src/lib/compiler-artefacts.ts @@ -6,7 +6,7 @@ import {CompilerAbstract} from '@remix-project/remix-solidity' const profile = { name: 'compilerArtefacts', methods: ['get', 'addResolvedContract', 'getCompilerAbstract', 'getAllContractDatas', 'getLastCompilationResult', 'getArtefactsByContractName', 'getContractDataFromAddress', 'getContractDataFromByteCode', 'saveCompilerAbstract', 'getAllCompilerAbstracts'], - events: [], + events: ['compilationSaved'], version: '0.0.1', } @@ -36,6 +36,7 @@ export class CompilerArtefacts extends Plugin { const saveCompilationResult = (file, source, languageVersion, data, input?) => { this.compilersArtefactsPerFile[file] = new CompilerAbstract(languageVersion, data, source, input) this.compilersArtefacts.__last = this.compilersArtefactsPerFile[file] + this.emit('compilationSaved', {[file]: this.compilersArtefactsPerFile[file]}) } this.on('solidity', 'compilationFinished', saveCompilationResult) From 9363f745fa591f77579cdd8895e4b5df28f52c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Mon, 17 Jun 2024 15:57:59 +0200 Subject: [PATCH 017/100] Fetch all compilations on load and subscribe to compilations --- apps/contract-verification/src/app/app.tsx | 51 ++++++---------------- 1 file changed, 14 insertions(+), 37 deletions(-) diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index a914214f78b..924a2ea02f3 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -33,55 +33,32 @@ const App = () => { const sourcifyVerifier = new SourcifyVerifier('http://localhost:5555/', 'Sourcify Localhost') setSourcifyVerifiers([sourcifyVerifier]) // TODO: Fix 'compilationFinished' event types. The interface is outdated at https://github.com/ethereum/remix-plugin/blob/master/packages/api/src/lib/compiler/api.ts. It does not include data, input, or version. See the current parameters: https://github.com/ethereum/remix-project/blob/9f6c5be882453a555055f07171701459e4ae88a4/libs/remix-solidity/src/compiler/compiler.ts#L189 - // Because of this reason we use @ts-expect-error for the next line - // // @ts-expect-error:next-line - // plugin.on('solidity', 'compilationFinished', (fileName: string, source: CompilationFileSources, languageVersion: string, data: CompilationResult, input: string, version: string) => { - // console.log('Compilation output') - // console.log(data) - // console.log('File Name:', fileName) - // console.log('Source:', source) - // console.log('Language Version:', languageVersion) - // console.log('Compilation Result:', data) - // // console.log('Input:', input) - // console.log('Compiler Version:', version) - // console.log('contractNames') - // console.log(Object.keys(data.contracts[fileName])) - - // setTargetFileName(fileName) - // setCompilationOutput(data) - // }) - - // plugin.call('compilerArtefacts', 'getAllContractDatas').then((allContractDatas: any) => { - // console.log('compilerArtefacts.getAllContractDatas') - // console.log(allContractDatas) - // const files = Object.keys(allContractDatas) - // files.forEach((file) => { - // // - // plugin.call('compilerArtefacts' as any, 'getCompilerAbstract', file).then((data: any) => { - // console.log('compilerArtefacts.getCompilerAbstract ' + file) - // console.log(data) - // }) - // }) - // }) - - // // TODO: why "as any" needed here - // plugin.call('compilerArtefacts' as any, 'getLastCompilationResult').then((data: any) => { - // console.log('compilerArtefacts.getLastCompilationResult') - // console.log(data) - // }) + // Fetch compiler artefacts initially plugin.call('compilerArtefacts' as any, 'getAllCompilerAbstracts').then((obj: any) => { console.log('compilerArtefacts.getAllCompilerAbstracts') console.log(obj) setCompilationOutput(obj) }) + + // Subscribe to compilations + plugin.on('compilerArtefacts' as any, 'compilationSaved', (compilerAbstract: {[key: string]: CompilerAbstract}) => { + console.log('compilerArtefacts.compilationSaved') + console.log(compilerAbstract) + setCompilationOutput((prev) => ({...(prev || {}), ...compilerAbstract})) + }) + + // TODO: Is there a way to get all compilations from the `build-info` files without having to compile again? + // Fetch chains.json and update state fetch('https://chainid.network/chains.json') .then((response) => response.json()) .then((data) => setChains(data)) .catch((error) => console.error('Failed to fetch chains.json:', error)) + + // Clean up on unmount return () => { - plugin.off('solidity', 'compilationFinished') // Clean up on unmount + plugin.off('compilerArtefacts' as any, 'compilationSaved') } }, []) From f5de0e53debf1b716ba10d3f966e47bf503a31d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Mon, 17 Jun 2024 16:03:57 +0200 Subject: [PATCH 018/100] Rename HomeView to VerifyView --- apps/contract-verification/src/app/routes.tsx | 4 ++-- .../src/app/views/{HomeView.tsx => VerifyView.tsx} | 2 +- apps/contract-verification/src/app/views/index.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename apps/contract-verification/src/app/views/{HomeView.tsx => VerifyView.tsx} (99%) diff --git a/apps/contract-verification/src/app/routes.tsx b/apps/contract-verification/src/app/routes.tsx index 8a5f006b643..f7f72a57933 100644 --- a/apps/contract-verification/src/app/routes.tsx +++ b/apps/contract-verification/src/app/routes.tsx @@ -1,7 +1,7 @@ import React from 'react' import {HashRouter as Router, Route, Routes, RouteProps} from 'react-router-dom' -import {HomeView} from './views' +import {VerifyView} from './views' import {DefaultLayout} from './layouts' const DisplayRoutes = () => ( @@ -11,7 +11,7 @@ const DisplayRoutes = () => ( path="/" element={ - + } /> diff --git a/apps/contract-verification/src/app/views/HomeView.tsx b/apps/contract-verification/src/app/views/VerifyView.tsx similarity index 99% rename from apps/contract-verification/src/app/views/HomeView.tsx rename to apps/contract-verification/src/app/views/VerifyView.tsx index 75c6880ff43..521d3aa92c7 100644 --- a/apps/contract-verification/src/app/views/HomeView.tsx +++ b/apps/contract-verification/src/app/views/VerifyView.tsx @@ -7,7 +7,7 @@ import {ContractDropdown} from '../components/ContractDropdown' import {ethers} from 'ethers/' import {Chain} from '../types/VerificationTypes' -export const HomeView = () => { +export const VerifyView = () => { const {chains, compilationOutput, sourcifyVerifiers, selectedContractFileAndName} = React.useContext(AppContext) const [contractAddress, setContractAddress] = useState('') const [contractAddressError, setContractAddressError] = useState('') diff --git a/apps/contract-verification/src/app/views/index.ts b/apps/contract-verification/src/app/views/index.ts index aad7f1311cf..629111037bd 100644 --- a/apps/contract-verification/src/app/views/index.ts +++ b/apps/contract-verification/src/app/views/index.ts @@ -1 +1 @@ -export {HomeView} from './HomeView' +export {VerifyView} from './VerifyView' From 5bd16286e1d4cac02ff6a315090a90120ae324e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Mon, 17 Jun 2024 16:16:59 +0200 Subject: [PATCH 019/100] Add AbstractVerifier and enable/disable verifiers --- .../src/app/AppContext.tsx | 6 ++-- .../src/app/Verifiers/AbstractVerifier.ts | 11 ++++++ .../src/app/Verifiers/SourcifyVerifier.ts | 8 ++--- apps/contract-verification/src/app/app.tsx | 5 +-- .../src/app/views/VerifyView.tsx | 34 ++++++++++++++++--- 5 files changed, 50 insertions(+), 14 deletions(-) create mode 100644 apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts diff --git a/apps/contract-verification/src/app/AppContext.tsx b/apps/contract-verification/src/app/AppContext.tsx index 77180cb3aa4..550bc02ec58 100644 --- a/apps/contract-verification/src/app/AppContext.tsx +++ b/apps/contract-verification/src/app/AppContext.tsx @@ -15,7 +15,8 @@ type AppContextType = { targetFileName: string | undefined verifiedContracts: VerifiedContract[] setVerifiedContracts: (verifiedContracts: VerifiedContract[]) => void - sourcifyVerifiers: SourcifyVerifier[] + verifiers: SourcifyVerifier[] + setVerifiers: (verifiers: SourcifyVerifier[]) => void } // Provide a default value with the appropriate types @@ -31,7 +32,8 @@ const defaultContextValue: AppContextType = { targetFileName: undefined, verifiedContracts: [], setVerifiedContracts: (verifiedContracts: VerifiedContract[]) => {}, - sourcifyVerifiers: [], + verifiers: [], + setVerifiers: (verifiers: SourcifyVerifier[]) => {}, } // Create the context with the type diff --git a/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts b/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts new file mode 100644 index 00000000000..5ccd20a42ba --- /dev/null +++ b/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts @@ -0,0 +1,11 @@ +export abstract class AbstractVerifier { + name: string + apiUrl: string + enabled: boolean + + constructor(apiUrl: string, name: string) { + this.apiUrl = apiUrl + this.name = name + this.enabled = true + } +} diff --git a/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts index f3de4695aa8..f693a0866d3 100644 --- a/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts +++ b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts @@ -1,13 +1,9 @@ import {SourcesCode} from '@remix-project/remix-solidity' import {AbstractVerifier} from './AbstractVerifier' -export class SourcifyVerifier { - name: string - apiUrl: string - +export class SourcifyVerifier extends AbstractVerifier { constructor(apiUrl: string, name: string = 'Sourcify') { - this.apiUrl = apiUrl - this.name = name + super(apiUrl, name) } async verify(chainId: string, address: string, sources: SourcesCode, metadataStr: string): Promise { diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index 924a2ea02f3..5099d7e87ad 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -23,6 +23,7 @@ const App = () => { const [selectedContractFileAndName, setSelectedContractFileAndName] = useState() const [verifiedContracts, setVerifiedContracts] = useState([]) const [sourcifyVerifiers, setSourcifyVerifiers] = useState([]) + const [verifiers, setVerifiers] = useState([]) useEffect(() => { console.log('Selected Contract File And Name Changed', selectedContractFileAndName) @@ -31,7 +32,7 @@ const App = () => { useEffect(() => { // const sourcifyVerifier = new SourcifyVerifier('http://sourcify.dev/server/', 'Sourcify') const sourcifyVerifier = new SourcifyVerifier('http://localhost:5555/', 'Sourcify Localhost') - setSourcifyVerifiers([sourcifyVerifier]) + setVerifiers([sourcifyVerifier]) // TODO: Fix 'compilationFinished' event types. The interface is outdated at https://github.com/ethereum/remix-plugin/blob/master/packages/api/src/lib/compiler/api.ts. It does not include data, input, or version. See the current parameters: https://github.com/ethereum/remix-project/blob/9f6c5be882453a555055f07171701459e4ae88a4/libs/remix-solidity/src/compiler/compiler.ts#L189 // Fetch compiler artefacts initially @@ -63,7 +64,7 @@ const App = () => { }, []) return ( - + ) diff --git a/apps/contract-verification/src/app/views/VerifyView.tsx b/apps/contract-verification/src/app/views/VerifyView.tsx index 521d3aa92c7..4c34faffdc1 100644 --- a/apps/contract-verification/src/app/views/VerifyView.tsx +++ b/apps/contract-verification/src/app/views/VerifyView.tsx @@ -8,7 +8,7 @@ import {ethers} from 'ethers/' import {Chain} from '../types/VerificationTypes' export const VerifyView = () => { - const {chains, compilationOutput, sourcifyVerifiers, selectedContractFileAndName} = React.useContext(AppContext) + const {chains, compilationOutput, verifiers, setVerifiers, selectedContractFileAndName} = React.useContext(AppContext) const [contractAddress, setContractAddress] = useState('') const [contractAddressError, setContractAddressError] = useState('') const [selectedChain, setSelectedChain] = useState() @@ -40,11 +40,11 @@ export const VerifyView = () => { console.log('selectedContractName:', selectedContractName) console.log('selectedContractAbstract:', selectedContractAbstract) console.log('selectedContractMetadataStr:', selectedContractMetadataStr) - console.log('sourcifyVerifiers:', sourcifyVerifiers) + console.log('sourcifyVerifiers:', verifiers) console.log('selectedChain:', selectedChain) console.log('contractAddress:', contractAddress) - const sourcifyPromises = sourcifyVerifiers.map((sourcifyVerifier) => { - return sourcifyVerifier.verify(selectedChain.chainId.toString(), contractAddress, selectedContractAbstract.source.sources, selectedContractMetadataStr) + const sourcifyPromises = verifiers.map((verifier) => { + return verifier.verify(selectedChain.chainId.toString(), contractAddress, selectedContractAbstract.source.sources, selectedContractMetadataStr) }) const results = await Promise.all(sourcifyPromises) @@ -61,6 +61,9 @@ export const VerifyView = () => { } setContractAddressError('') } + + console.log('sourcifyVerifiers:', verifiers) + return (
@@ -84,6 +87,29 @@ export const VerifyView = () => { {' '} Verify{' '} + +
+ {verifiers?.length > 0 && + verifiers.map((verifier) => ( +
+ { + verifier.enabled = e.target.checked + // Trigger a re-render or state update if necessary + // For example, you might need to update the state that holds the verifiers + setVerifiers([...verifiers]) + }} + /> + +
+ ))} +
) From c11023ea90647025c7a764bef11284a712b64a97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Mon, 17 Jun 2024 17:41:57 +0200 Subject: [PATCH 020/100] Add EtherscanVerifier and extend from AbstractVerifier --- .../src/app/AppContext.tsx | 8 +-- .../src/app/Verifiers/AbstractVerifier.ts | 4 ++ .../src/app/Verifiers/EtherscanVerifier.ts | 52 +++++++++++++++++++ .../src/app/Verifiers/SourcifyVerifier.ts | 15 +++++- apps/contract-verification/src/app/app.tsx | 10 ++-- .../src/app/types/VerificationTypes.ts | 4 +- .../src/app/views/VerifyView.tsx | 12 +---- 7 files changed, 82 insertions(+), 23 deletions(-) create mode 100644 apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts diff --git a/apps/contract-verification/src/app/AppContext.tsx b/apps/contract-verification/src/app/AppContext.tsx index 550bc02ec58..b44b743f237 100644 --- a/apps/contract-verification/src/app/AppContext.tsx +++ b/apps/contract-verification/src/app/AppContext.tsx @@ -1,8 +1,8 @@ import React from 'react' import {ThemeType} from './types' import {Chain, VerifiedContract} from './types/VerificationTypes' -import {SourcifyVerifier} from './Verifiers/SourcifyVerifier' import {CompilerAbstract} from '@remix-project/remix-solidity' +import {AbstractVerifier} from './Verifiers/AbstractVerifier' // Define the type for the context type AppContextType = { @@ -15,8 +15,8 @@ type AppContextType = { targetFileName: string | undefined verifiedContracts: VerifiedContract[] setVerifiedContracts: (verifiedContracts: VerifiedContract[]) => void - verifiers: SourcifyVerifier[] - setVerifiers: (verifiers: SourcifyVerifier[]) => void + verifiers: AbstractVerifier[] + setVerifiers: (verifiers: AbstractVerifier[]) => void } // Provide a default value with the appropriate types @@ -33,7 +33,7 @@ const defaultContextValue: AppContextType = { verifiedContracts: [], setVerifiedContracts: (verifiedContracts: VerifiedContract[]) => {}, verifiers: [], - setVerifiers: (verifiers: SourcifyVerifier[]) => {}, + setVerifiers: (verifiers: AbstractVerifier[]) => {}, } // Create the context with the type diff --git a/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts b/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts index 5ccd20a42ba..3608ff475a3 100644 --- a/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts +++ b/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts @@ -1,3 +1,5 @@ +import {CompilerAbstract} from '@remix-project/remix-solidity' + export abstract class AbstractVerifier { name: string apiUrl: string @@ -8,4 +10,6 @@ export abstract class AbstractVerifier { this.name = name this.enabled = true } + + abstract verify(chainId: string, address: string, compilationOutput: {[fileName: string]: CompilerAbstract}, selectedContractFileAndName: string): Promise } diff --git a/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts b/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts new file mode 100644 index 00000000000..cb43f989180 --- /dev/null +++ b/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts @@ -0,0 +1,52 @@ +import {CompilerAbstract} from '@remix-project/remix-solidity' +import {AbstractVerifier} from './AbstractVerifier' + +export class EtherscanVerifier extends AbstractVerifier { + apiKey: string + + constructor(apiUrl: string, name: string = 'Etherscan', apiKey: string) { + super(apiUrl, name) + this.apiKey = apiKey + } + + async verify(chainId: string, address: string, compilationOutput: {[fileName: string]: CompilerAbstract}, selectedContractFileAndName: string) { + const CODE_FORMAT = 'solidity-standard-json-input' + + const [selectedFileName, selectedContractName] = selectedContractFileAndName.split(':') + const compilerAbstract = compilationOutput?.[selectedFileName || ''] + // TODO: Handle version Vyper contracts. This relies on Solidity metadata. + const metadata = JSON.parse(compilerAbstract.data.contracts[selectedFileName][selectedContractName].metadata) + const body = { + chainId, + codeformat: CODE_FORMAT, + sourceCode: compilerAbstract.input, + contractaddress: address, + contractname: selectedContractFileAndName, + compilerversion: metadata.compiler.version, + } + + const url = new URL('api', this.apiUrl) + url.searchParams.append('module', 'contract') + url.searchParams.append('action', 'verifysourcecode') + url.searchParams.append('apikey', this.apiKey) + + const response = await fetch(url.href, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(body), + }) + + if (!response.ok) { + throw new Error(`Error on Etherscan verification at ${this.apiUrl}: Status:${response.status} Response: ${await response.text()}`) + } + const data = await response.json() + + if (data.status !== '1' || data.message !== 'OK') { + throw new Error(`Error on Etherscan verification at ${this.apiUrl}: ${data.message}`) + } + + return data.result + } +} diff --git a/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts index f693a0866d3..16897e9b567 100644 --- a/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts +++ b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts @@ -1,4 +1,4 @@ -import {SourcesCode} from '@remix-project/remix-solidity' +import {CompilerAbstract, SourcesCode} from '@remix-project/remix-solidity' import {AbstractVerifier} from './AbstractVerifier' export class SourcifyVerifier extends AbstractVerifier { @@ -6,7 +6,18 @@ export class SourcifyVerifier extends AbstractVerifier { super(apiUrl, name) } - async verify(chainId: string, address: string, sources: SourcesCode, metadataStr: string): Promise { + async verify(chainId: string, address: string, compilationOutput: {[fileName: string]: CompilerAbstract}, selectedContractFileAndName: string): Promise { + const [selectedFileName, selectedContractName] = selectedContractFileAndName.split(':') + const compilerAbstract = compilationOutput?.[selectedFileName || ''] + const metadataStr = compilerAbstract.data.contracts[selectedFileName][selectedContractName].metadata + const sources = compilerAbstract.source.sources + console.log('selectedFileName:', selectedFileName) + console.log('selectedContractName:', selectedContractName) + console.log('compilerAbstract:', compilerAbstract) + console.log('selectedContractMetadataStr:', metadataStr) + console.log('chainId:', chainId) + console.log('address:', address) + // from { "filename.sol": {content: "contract MyContract { ... }"} } // to { "filename.sol": "contract MyContract { ... }" } const formattedSources = Object.entries(sources).reduce((acc, [fileName, {content}]) => { diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index 5099d7e87ad..eba30b67ff2 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -8,8 +8,10 @@ import {ThemeType} from './types' import './App.css' import {Chain, VerifiedContract} from './types/VerificationTypes' -import {SourcifyVerifier} from './Verifiers/SourcifyVerifier' import {CompilerAbstract} from '@remix-project/remix-solidity' +import {AbstractVerifier} from './Verifiers/AbstractVerifier' +import {SourcifyVerifier} from './Verifiers/SourcifyVerifier' +import {EtherscanVerifier} from './Verifiers/EtherscanVerifier' const plugin = new ContractVerificationPluginClient() @@ -22,8 +24,7 @@ const App = () => { // Contract file and name in format contracts/Storage.sol:Storage const [selectedContractFileAndName, setSelectedContractFileAndName] = useState() const [verifiedContracts, setVerifiedContracts] = useState([]) - const [sourcifyVerifiers, setSourcifyVerifiers] = useState([]) - const [verifiers, setVerifiers] = useState([]) + const [verifiers, setVerifiers] = useState([]) useEffect(() => { console.log('Selected Contract File And Name Changed', selectedContractFileAndName) @@ -32,7 +33,8 @@ const App = () => { useEffect(() => { // const sourcifyVerifier = new SourcifyVerifier('http://sourcify.dev/server/', 'Sourcify') const sourcifyVerifier = new SourcifyVerifier('http://localhost:5555/', 'Sourcify Localhost') - setVerifiers([sourcifyVerifier]) + const etherscanVerifier = new EtherscanVerifier('https://api.etherscan.io', 'Etherscan', 'API_KEY') + setVerifiers([sourcifyVerifier, etherscanVerifier]) // TODO: Fix 'compilationFinished' event types. The interface is outdated at https://github.com/ethereum/remix-plugin/blob/master/packages/api/src/lib/compiler/api.ts. It does not include data, input, or version. See the current parameters: https://github.com/ethereum/remix-project/blob/9f6c5be882453a555055f07171701459e4ae88a4/libs/remix-solidity/src/compiler/compiler.ts#L189 // Fetch compiler artefacts initially diff --git a/apps/contract-verification/src/app/types/VerificationTypes.ts b/apps/contract-verification/src/app/types/VerificationTypes.ts index 108c48074f4..c007d71b063 100644 --- a/apps/contract-verification/src/app/types/VerificationTypes.ts +++ b/apps/contract-verification/src/app/types/VerificationTypes.ts @@ -1,11 +1,11 @@ -import {SourcifyVerifier} from '../Verifiers/SourcifyVerifier' +import {AbstractVerifier} from '../Verifiers/AbstractVerifier' export interface VerifiedContract { name: string address: string chainId: string date: Date - verifier: SourcifyVerifier + verifier: AbstractVerifier status: string receipt?: string } diff --git a/apps/contract-verification/src/app/views/VerifyView.tsx b/apps/contract-verification/src/app/views/VerifyView.tsx index 4c34faffdc1..d57066e9456 100644 --- a/apps/contract-verification/src/app/views/VerifyView.tsx +++ b/apps/contract-verification/src/app/views/VerifyView.tsx @@ -33,18 +33,8 @@ export const VerifyView = () => { const handleVerify = async (e) => { e.preventDefault() // Don't change the page - const [selectedFileName, selectedContractName] = selectedContractFileAndName.split(':') - const selectedContractAbstract = compilationOutput?.[selectedFileName || ''] - const selectedContractMetadataStr = selectedContractAbstract.data.contracts[selectedFileName][selectedContractName].metadata - console.log('selectedFileName:', selectedFileName) - console.log('selectedContractName:', selectedContractName) - console.log('selectedContractAbstract:', selectedContractAbstract) - console.log('selectedContractMetadataStr:', selectedContractMetadataStr) - console.log('sourcifyVerifiers:', verifiers) - console.log('selectedChain:', selectedChain) - console.log('contractAddress:', contractAddress) const sourcifyPromises = verifiers.map((verifier) => { - return verifier.verify(selectedChain.chainId.toString(), contractAddress, selectedContractAbstract.source.sources, selectedContractMetadataStr) + return verifier.verify(selectedChain.chainId.toString(), contractAddress, compilationOutput, selectedContractFileAndName) }) const results = await Promise.all(sourcifyPromises) From b32e44a1dbf7e141fc46af51adbb1f878d170425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Tue, 18 Jun 2024 14:59:44 +0200 Subject: [PATCH 021/100] Send contracts for verification for each verifier --- .../src/app/AppContext.tsx | 14 ++-- .../src/app/Receipts/EtherscanReceipt.tsx | 34 +++++++++ .../src/app/Receipts/SourcifyReceipt.tsx | 36 ++++++++++ .../src/app/Receipts/props.ts | 9 +++ .../src/app/Verifiers/AbstractVerifier.ts | 5 +- ...rscanVerifier.ts => EtherscanVerifier.tsx} | 24 +++++-- .../src/app/Verifiers/SourcifyVerifier.ts | 15 ++-- apps/contract-verification/src/app/app.tsx | 8 +-- apps/contract-verification/src/app/routes.tsx | 12 +++- .../src/app/types/VerificationTypes.ts | 58 ++++++++++++--- .../src/app/views/ReceiptsView.tsx | 37 ++++++++++ .../src/app/views/VerifyView.tsx | 70 ++++++++++++++++--- 12 files changed, 277 insertions(+), 45 deletions(-) create mode 100644 apps/contract-verification/src/app/Receipts/EtherscanReceipt.tsx create mode 100644 apps/contract-verification/src/app/Receipts/SourcifyReceipt.tsx create mode 100644 apps/contract-verification/src/app/Receipts/props.ts rename apps/contract-verification/src/app/Verifiers/{EtherscanVerifier.ts => EtherscanVerifier.tsx} (61%) create mode 100644 apps/contract-verification/src/app/views/ReceiptsView.tsx diff --git a/apps/contract-verification/src/app/AppContext.tsx b/apps/contract-verification/src/app/AppContext.tsx index b44b743f237..2de02cb07ef 100644 --- a/apps/contract-verification/src/app/AppContext.tsx +++ b/apps/contract-verification/src/app/AppContext.tsx @@ -1,6 +1,6 @@ import React from 'react' import {ThemeType} from './types' -import {Chain, VerifiedContract} from './types/VerificationTypes' +import {Chain, SubmittedContracts} from './types/VerificationTypes' import {CompilerAbstract} from '@remix-project/remix-solidity' import {AbstractVerifier} from './Verifiers/AbstractVerifier' @@ -11,12 +11,12 @@ type AppContextType = { chains: Chain[] compilationOutput: {[key: string]: CompilerAbstract} | undefined selectedContractFileAndName: string | undefined - setSelectedContractFileAndName: (contract: string) => void + setSelectedContractFileAndName: React.Dispatch> targetFileName: string | undefined - verifiedContracts: VerifiedContract[] - setVerifiedContracts: (verifiedContracts: VerifiedContract[]) => void verifiers: AbstractVerifier[] - setVerifiers: (verifiers: AbstractVerifier[]) => void + setVerifiers: React.Dispatch> + submittedContracts: SubmittedContracts + setSubmittedContracts: React.Dispatch> } // Provide a default value with the appropriate types @@ -30,10 +30,10 @@ const defaultContextValue: AppContextType = { selectedContractFileAndName: undefined, setSelectedContractFileAndName: (contract: string) => {}, targetFileName: undefined, - verifiedContracts: [], - setVerifiedContracts: (verifiedContracts: VerifiedContract[]) => {}, verifiers: [], setVerifiers: (verifiers: AbstractVerifier[]) => {}, + submittedContracts: {}, + setSubmittedContracts: (submittedContracts: SubmittedContracts) => {}, } // Create the context with the type diff --git a/apps/contract-verification/src/app/Receipts/EtherscanReceipt.tsx b/apps/contract-verification/src/app/Receipts/EtherscanReceipt.tsx new file mode 100644 index 00000000000..613d99a991a --- /dev/null +++ b/apps/contract-verification/src/app/Receipts/EtherscanReceipt.tsx @@ -0,0 +1,34 @@ +import React, {useState, useEffect} from 'react' +import {EtherscanVerifier} from '../Verifiers/EtherscanVerifier' +import {ReceiptProps} from './props' + +export const EtherscanReceipt: React.FC = ({verifyPromise, address, chainId, verifier}) => { + const [status, setStatus] = useState(null) + const [submissionDate] = useState(new Date()) + + useEffect(() => { + // Handle the promise here or perform other side effects + verifyPromise + .then(() => { + // Handle promise resolution + // Update status based on the result + }) + .catch(() => { + // Handle promise rejection + }) + + // This effect should only run once on mount, hence the empty dependency array + }, [verifyPromise]) + + return ( +
+

Verification Receipt

+

Address: {address}

+

Chain ID: {chainId}

+

Submission Date: {submissionDate.toLocaleString()}

+

Status: {status ? status : 'Pending'}

+
+ ) +} + +export default EtherscanReceipt diff --git a/apps/contract-verification/src/app/Receipts/SourcifyReceipt.tsx b/apps/contract-verification/src/app/Receipts/SourcifyReceipt.tsx new file mode 100644 index 00000000000..5d757a7a4bc --- /dev/null +++ b/apps/contract-verification/src/app/Receipts/SourcifyReceipt.tsx @@ -0,0 +1,36 @@ +import React, {useState, useEffect} from 'react' +import {SourcifyVerifier} from '../Verifiers/SourcifyVerifier' +import {SourcifyVerificationStatus} from '../types/VerificationTypes' +import {ReceiptProps} from './props' + +// A receipt is something to be rendered +export const SourcifyReceipt: React.FC = ({verifyPromise, address, chainId, verifier}) => { + const [status, setStatus] = useState(null) + const [submissionDate] = useState(new Date()) // This will be set once and not change + + useEffect(() => { + // You might want to handle the promise here or perform other side effects + verifyPromise + .then(() => { + // Handle promise resolution + // Update status based on the result + }) + .catch(() => { + // Handle promise rejection + }) + + // This effect should only run once on mount, hence the empty dependency array + }, [verifyPromise]) + + return ( +
+

Verification Receipt

+

Address: {address}

+

Chain ID: {chainId}

+

Submission Date: {submissionDate.toLocaleString()}

+

Status: {status ? status : 'Pending'}

+
+ ) +} + +export default SourcifyReceipt diff --git a/apps/contract-verification/src/app/Receipts/props.ts b/apps/contract-verification/src/app/Receipts/props.ts new file mode 100644 index 00000000000..00c0119b8d0 --- /dev/null +++ b/apps/contract-verification/src/app/Receipts/props.ts @@ -0,0 +1,9 @@ +import {EtherscanVerifier} from '../Verifiers/EtherscanVerifier' +import {SourcifyVerifier} from '../Verifiers/SourcifyVerifier' + +export interface ReceiptProps { + verifyPromise: Promise + address: string + chainId: string + verifier: EtherscanVerifier | SourcifyVerifier +} diff --git a/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts b/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts index 3608ff475a3..ce6cc643a85 100644 --- a/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts +++ b/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts @@ -1,4 +1,6 @@ import {CompilerAbstract} from '@remix-project/remix-solidity' +import {SourcifyReceipt} from '../Receipts/SourcifyReceipt' +import {EtherscanReceipt} from '../Receipts/EtherscanReceipt' export abstract class AbstractVerifier { name: string @@ -11,5 +13,6 @@ export abstract class AbstractVerifier { this.enabled = true } - abstract verify(chainId: string, address: string, compilationOutput: {[fileName: string]: CompilerAbstract}, selectedContractFileAndName: string): Promise + abstract verify(chainId: string, address: string, compilerAbstract: CompilerAbstract, selectedContractFileAndName: string): Promise + abstract lookup(): Promise } diff --git a/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts b/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.tsx similarity index 61% rename from apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts rename to apps/contract-verification/src/app/Verifiers/EtherscanVerifier.tsx index cb43f989180..d41a048ef50 100644 --- a/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts +++ b/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.tsx @@ -1,5 +1,7 @@ import {CompilerAbstract} from '@remix-project/remix-solidity' import {AbstractVerifier} from './AbstractVerifier' +import {EtherscanReceipt} from '../Receipts/EtherscanReceipt' +import {EtherscanResponse} from '../types/VerificationTypes' export class EtherscanVerifier extends AbstractVerifier { apiKey: string @@ -9,11 +11,10 @@ export class EtherscanVerifier extends AbstractVerifier { this.apiKey = apiKey } - async verify(chainId: string, address: string, compilationOutput: {[fileName: string]: CompilerAbstract}, selectedContractFileAndName: string) { + async verify(chainId: string, address: string, compilerAbstract: CompilerAbstract, selectedContractFileAndName: string) { const CODE_FORMAT = 'solidity-standard-json-input' const [selectedFileName, selectedContractName] = selectedContractFileAndName.split(':') - const compilerAbstract = compilationOutput?.[selectedFileName || ''] // TODO: Handle version Vyper contracts. This relies on Solidity metadata. const metadata = JSON.parse(compilerAbstract.data.contracts[selectedFileName][selectedContractName].metadata) const body = { @@ -39,14 +40,25 @@ export class EtherscanVerifier extends AbstractVerifier { }) if (!response.ok) { - throw new Error(`Error on Etherscan verification at ${this.apiUrl}: Status:${response.status} Response: ${await response.text()}`) + throw new Error(`Request error Status:${response.status} Response: ${await response.text()}`) } - const data = await response.json() + const data: EtherscanResponse = await response.json() + console.log(data) if (data.status !== '1' || data.message !== 'OK') { - throw new Error(`Error on Etherscan verification at ${this.apiUrl}: ${data.message}`) + console.error(`Error on Etherscan verification at ${this.apiUrl}: ${data.result}`) + throw new Error(data.result) } - return data.result + return data + } + + async lookup(): Promise { + // Implement the lookup logic here + console.log('Etherscan lookup started') + // Placeholder logic for lookup + const lookupResult = {} // Replace with actual lookup logic + console.log('Etherscan lookup completed') + return lookupResult } } diff --git a/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts index 16897e9b567..a2f6ab3e4ba 100644 --- a/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts +++ b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts @@ -1,14 +1,15 @@ import {CompilerAbstract, SourcesCode} from '@remix-project/remix-solidity' import {AbstractVerifier} from './AbstractVerifier' +import {SourcifyReceipt} from '../Receipts/SourcifyReceipt' +import {SourcifyVerificationError, SourcifyVerificationResponse} from '../types/VerificationTypes' export class SourcifyVerifier extends AbstractVerifier { constructor(apiUrl: string, name: string = 'Sourcify') { super(apiUrl, name) } - async verify(chainId: string, address: string, compilationOutput: {[fileName: string]: CompilerAbstract}, selectedContractFileAndName: string): Promise { + async verify(chainId: string, address: string, compilerAbstract: CompilerAbstract, selectedContractFileAndName: string) { const [selectedFileName, selectedContractName] = selectedContractFileAndName.split(':') - const compilerAbstract = compilationOutput?.[selectedFileName || ''] const metadataStr = compilerAbstract.data.contracts[selectedFileName][selectedContractName].metadata const sources = compilerAbstract.source.sources console.log('selectedFileName:', selectedFileName) @@ -44,13 +45,13 @@ export class SourcifyVerifier extends AbstractVerifier { }) if (!response.ok) { - throw new Error(`Error on Sourcify verification at ${this.apiUrl}: Status:${response.status} Response: ${await response.text()}`) + const errorResponse: SourcifyVerificationError = await response.json() + console.error('Error on Sourcify verification at', this.apiUrl, 'Status:', response.status, 'Response:', JSON.stringify(errorResponse)) + throw new Error(errorResponse.error) } - const data = await response.json() - console.log(data) - - return data.result + const jsonResponse: SourcifyVerificationResponse = await response.json() + return jsonResponse } async lookup(): Promise { diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index eba30b67ff2..6fa3e00faf9 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -7,11 +7,11 @@ import DisplayRoutes from './routes' import {ThemeType} from './types' import './App.css' -import {Chain, VerifiedContract} from './types/VerificationTypes' +import {Chain, SubmittedContracts} from './types/VerificationTypes' import {CompilerAbstract} from '@remix-project/remix-solidity' -import {AbstractVerifier} from './Verifiers/AbstractVerifier' import {SourcifyVerifier} from './Verifiers/SourcifyVerifier' import {EtherscanVerifier} from './Verifiers/EtherscanVerifier' +import {AbstractVerifier} from './Verifiers/AbstractVerifier' const plugin = new ContractVerificationPluginClient() @@ -23,8 +23,8 @@ const App = () => { const [compilationOutput, setCompilationOutput] = useState<{[key: string]: CompilerAbstract} | undefined>() // Contract file and name in format contracts/Storage.sol:Storage const [selectedContractFileAndName, setSelectedContractFileAndName] = useState() - const [verifiedContracts, setVerifiedContracts] = useState([]) const [verifiers, setVerifiers] = useState([]) + const [submittedContracts, setSubmittedContracts] = useState({}) useEffect(() => { console.log('Selected Contract File And Name Changed', selectedContractFileAndName) @@ -66,7 +66,7 @@ const App = () => { }, []) return ( - + ) diff --git a/apps/contract-verification/src/app/routes.tsx b/apps/contract-verification/src/app/routes.tsx index f7f72a57933..6e9b39dccd8 100644 --- a/apps/contract-verification/src/app/routes.tsx +++ b/apps/contract-verification/src/app/routes.tsx @@ -1,8 +1,9 @@ import React from 'react' -import {HashRouter as Router, Route, Routes, RouteProps} from 'react-router-dom' +import {HashRouter as Router, Route, Routes} from 'react-router-dom' import {VerifyView} from './views' import {DefaultLayout} from './layouts' +import {ReceiptsView} from './views/ReceiptsView' const DisplayRoutes = () => ( @@ -15,6 +16,15 @@ const DisplayRoutes = () => ( } /> + + + + + } + /> ) diff --git a/apps/contract-verification/src/app/types/VerificationTypes.ts b/apps/contract-verification/src/app/types/VerificationTypes.ts index c007d71b063..8428fb1869d 100644 --- a/apps/contract-verification/src/app/types/VerificationTypes.ts +++ b/apps/contract-verification/src/app/types/VerificationTypes.ts @@ -1,14 +1,9 @@ +import {CompilerAbstract} from '@remix-project/remix-solidity' import {AbstractVerifier} from '../Verifiers/AbstractVerifier' +import {SourcifyVerifier} from '../Verifiers/SourcifyVerifier' +import {EtherscanVerifier} from '../Verifiers/EtherscanVerifier' -export interface VerifiedContract { - name: string - address: string - chainId: string - date: Date - verifier: AbstractVerifier - status: string - receipt?: string -} +export type SourcifyVerificationStatus = 'perfect' | 'partial' | null interface Currency { name: string @@ -28,3 +23,48 @@ export interface Chain { faucets?: string[] infoURL?: string } + +export interface VerificationReceipt { + receiptId?: string + verifier: AbstractVerifier + status: SourcifyVerificationStatus | 'error' | null + message?: string +} + +export interface SubmittedContract { + id: string + filePath: string + contractName: string + chainId: string + address: string + compilerAbstract: CompilerAbstract + date: Date + receipts: VerificationReceipt[] +} + +export interface SubmittedContracts { + [id: string]: SubmittedContract +} + +export interface SourcifyVerificationResponse { + result: [ + { + address: string + chainId: string + status: SourcifyVerificationStatus + libraryMap: { + [key: string]: string + } + } + ] +} + +export interface SourcifyVerificationError { + error: 'string' +} + +export interface EtherscanResponse { + status: '0' | '1' + message: string + result: string +} diff --git a/apps/contract-verification/src/app/views/ReceiptsView.tsx b/apps/contract-verification/src/app/views/ReceiptsView.tsx new file mode 100644 index 00000000000..b2aac0192c1 --- /dev/null +++ b/apps/contract-verification/src/app/views/ReceiptsView.tsx @@ -0,0 +1,37 @@ +import React from 'react' +import {AppContext} from '../AppContext' + +export const ReceiptsView = () => { + const {submittedContracts} = React.useContext(AppContext) + + return ( +
+ {Object.values(submittedContracts).map((contract) => ( +
+
Contract Address: {contract.address}
+
Chain ID: {contract.chainId}
+
+ filePath: {contract.filePath} contractName: {contract.contractName} +
+
Submission Date: {contract.date.toLocaleString()}
+
+ Receipts:{' '} +
    + {contract.receipts.map((receipt) => ( +
  • +
      +
    • Verifier: {receipt.verifier.name}
    • +
    • API URL: {receipt.verifier.apiUrl}
    • +
    • Status: {receipt.status}
    • +
    • Receipt ID: {receipt.receiptId}
    • +
    • Message: {receipt.message}
    • +
    +
  • + ))} +
+
+
+ ))} +
+ ) +} diff --git a/apps/contract-verification/src/app/views/VerifyView.tsx b/apps/contract-verification/src/app/views/VerifyView.tsx index d57066e9456..7b800efc4de 100644 --- a/apps/contract-verification/src/app/views/VerifyView.tsx +++ b/apps/contract-verification/src/app/views/VerifyView.tsx @@ -3,15 +3,18 @@ import React, {useEffect, useState} from 'react' import {AppContext} from '../AppContext' import {SearchableDropdown} from '../components' import {ContractDropdown} from '../components/ContractDropdown' -// INSERT_YOUR_CODE import {ethers} from 'ethers/' -import {Chain} from '../types/VerificationTypes' +import {Chain, SubmittedContract, VerificationReceipt} from '../types/VerificationTypes' +import {SourcifyVerifier} from '../Verifiers/SourcifyVerifier' +import {EtherscanVerifier} from '../Verifiers/EtherscanVerifier' +import {useNavigate} from 'react-router-dom' export const VerifyView = () => { - const {chains, compilationOutput, verifiers, setVerifiers, selectedContractFileAndName} = React.useContext(AppContext) + const {chains, compilationOutput, verifiers, setVerifiers, selectedContractFileAndName, setSubmittedContracts} = React.useContext(AppContext) const [contractAddress, setContractAddress] = useState('') const [contractAddressError, setContractAddressError] = useState('') const [selectedChain, setSelectedChain] = useState() + const navigate = useNavigate() useEffect(() => { console.log('Selected chain changed', selectedChain) @@ -33,12 +36,60 @@ export const VerifyView = () => { const handleVerify = async (e) => { e.preventDefault() // Don't change the page - const sourcifyPromises = verifiers.map((verifier) => { - return verifier.verify(selectedChain.chainId.toString(), contractAddress, compilationOutput, selectedContractFileAndName) - }) - const results = await Promise.all(sourcifyPromises) - console.log('results', results) + const [filePath, contractName] = selectedContractFileAndName.split(':') + const enabledVerifiers = verifiers.filter((verifier) => verifier.enabled) + const compilerAbstract = compilationOutput[filePath] + if (!compilerAbstract) { + throw new Error(`Error: Compilation output not found for ${selectedContractFileAndName}`) + } + + const date = new Date() + // A receipt for each verifier + const receipts: VerificationReceipt[] = enabledVerifiers.map((verifier) => ({verifier, status: null, receiptId: null, message: null})) + const newSubmittedContract: SubmittedContract = { + id: selectedChain?.chainId + '-' + contractAddress + '-' + date.toString(), + address: contractAddress, + chainId: selectedChain?.chainId.toString(), + filePath, + contractName, + compilerAbstract, + date, + receipts, + } + setSubmittedContracts((prev) => ({...prev, [newSubmittedContract.id]: newSubmittedContract})) + + console.log('newSubmittedContract:', newSubmittedContract) + + // Take user to receipt view + navigate('/receipts') + + // Verify for each verifier. forEach does not wait for await and each promise will execute in parallel + receipts.forEach(async (receipt) => { + const {verifier} = receipt + if (verifier instanceof SourcifyVerifier) { + try { + const response = await verifier.verify(selectedChain?.chainId.toString(), contractAddress, compilerAbstract, selectedContractFileAndName) + receipt.status = response.result[0].status + } catch (e) { + const err = e as Error + receipt.status = 'error' + receipt.message = err.message + } + } else if (verifier instanceof EtherscanVerifier) { + try { + const response = await verifier.verify(selectedChain?.chainId.toString(), contractAddress, compilerAbstract, selectedContractFileAndName) + receipt.status = 'perfect' + } catch (e) { + const err = e as Error + receipt.status = 'error' + receipt.message = err.message + } + } + + // Update the UI + setSubmittedContracts((prev) => ({...prev, [newSubmittedContract.id]: newSubmittedContract})) + }) } const handleAddressChange = (event: React.ChangeEvent) => { @@ -89,8 +140,7 @@ export const VerifyView = () => { checked={verifier.enabled} onChange={(e) => { verifier.enabled = e.target.checked - // Trigger a re-render or state update if necessary - // For example, you might need to update the state that holds the verifiers + // Trigger a re-render setVerifiers([...verifiers]) }} /> From 0dcf7f75dd14a839711f34d304e998ea409cec5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20Uzdo=C4=9Fan?= Date: Thu, 20 Jun 2024 10:51:33 +0200 Subject: [PATCH 022/100] Fix missing upper level triggerFilePath in contract selections --- .../src/app/Verifiers/EtherscanVerifier.tsx | 4 +-- .../src/app/Verifiers/SourcifyVerifier.ts | 6 ++--- apps/contract-verification/src/app/app.tsx | 3 ++- .../src/app/components/ContractDropdown.tsx | 26 +++++++++++-------- .../src/app/views/VerifyView.tsx | 4 +-- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.tsx b/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.tsx index d41a048ef50..ccb3c8ac9a9 100644 --- a/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.tsx +++ b/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.tsx @@ -14,9 +14,9 @@ export class EtherscanVerifier extends AbstractVerifier { async verify(chainId: string, address: string, compilerAbstract: CompilerAbstract, selectedContractFileAndName: string) { const CODE_FORMAT = 'solidity-standard-json-input' - const [selectedFileName, selectedContractName] = selectedContractFileAndName.split(':') + const [_triggerFilePath, selectedFilePath, selectedContractName] = selectedContractFileAndName.split(':') // TODO: Handle version Vyper contracts. This relies on Solidity metadata. - const metadata = JSON.parse(compilerAbstract.data.contracts[selectedFileName][selectedContractName].metadata) + const metadata = JSON.parse(compilerAbstract.data.contracts[selectedFilePath][selectedContractName].metadata) const body = { chainId, codeformat: CODE_FORMAT, diff --git a/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts index a2f6ab3e4ba..7e3865f198f 100644 --- a/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts +++ b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts @@ -9,10 +9,10 @@ export class SourcifyVerifier extends AbstractVerifier { } async verify(chainId: string, address: string, compilerAbstract: CompilerAbstract, selectedContractFileAndName: string) { - const [selectedFileName, selectedContractName] = selectedContractFileAndName.split(':') - const metadataStr = compilerAbstract.data.contracts[selectedFileName][selectedContractName].metadata + const [_triggerFileName, selectedFilePath, selectedContractName] = selectedContractFileAndName.split(':') + const metadataStr = compilerAbstract.data.contracts[selectedFilePath][selectedContractName].metadata const sources = compilerAbstract.source.sources - console.log('selectedFileName:', selectedFileName) + console.log('selectedFilePath:', selectedFilePath) console.log('selectedContractName:', selectedContractName) console.log('compilerAbstract:', compilerAbstract) console.log('selectedContractMetadataStr:', metadataStr) diff --git a/apps/contract-verification/src/app/app.tsx b/apps/contract-verification/src/app/app.tsx index 6fa3e00faf9..50394ecf5da 100644 --- a/apps/contract-verification/src/app/app.tsx +++ b/apps/contract-verification/src/app/app.tsx @@ -21,7 +21,8 @@ const App = () => { const [chains, setChains] = useState([]) // State to hold the chains data const [targetFileName, setTargetFileName] = useState('') const [compilationOutput, setCompilationOutput] = useState<{[key: string]: CompilerAbstract} | undefined>() - // Contract file and name in format contracts/Storage.sol:Storage + // Contract file and name in format contracts/Storage.sol:contracts/Owner.sol:Owner + // TODO: What happens if contract or filepath contains ":"" ? const [selectedContractFileAndName, setSelectedContractFileAndName] = useState() const [verifiers, setVerifiers] = useState([]) const [submittedContracts, setSubmittedContracts] = useState({}) diff --git a/apps/contract-verification/src/app/components/ContractDropdown.tsx b/apps/contract-verification/src/app/components/ContractDropdown.tsx index 39fc47869fb..c7ad090ac97 100644 --- a/apps/contract-verification/src/app/components/ContractDropdown.tsx +++ b/apps/contract-verification/src/app/components/ContractDropdown.tsx @@ -39,20 +39,24 @@ export const ContractDropdown: React.FC = ({label, id}) = return (
- setToggleRawInput(!toggleRawInput)} /> + +
+ {toggleRawInput ? ( +
+ {' '} +