From 07a7a8ea3928692a04000b022eb7c0847237c833 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/138] Add nvmrc --- .nvmrc | 1 + 1 file changed, 1 insertion(+) create mode 100644 .nvmrc diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000..9a2a0e219c --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v20 From 6ed602bb7ceb49b62e0ec9546de9e20a896142f3 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/138] 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 0000000000..e37036ce66 --- /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 0000000000..f1d12df4fa --- /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 0000000000..2d85f9fa66 --- /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 0000000000..a92d0f887a --- /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 0000000000..dee28fe326 --- /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 0000000000..74a89ee342 --- /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 0000000000..69d967534d --- /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 0000000000..3d1bf22d94 --- /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 0000000000..bf553d8319 --- /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 0000000000..5818b2bc7e --- /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 0000000000..9f4bed6200 --- /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 0000000000..c52e3712f0 --- /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 0000000000..85d30c849d --- /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 0000000000..fa9a1111e5 --- /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 0000000000..9b8e6166d5 --- /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 0000000000..165b5ae5a7 --- /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 0000000000..2dd501651d --- /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 0000000000..13b3710cd0 --- /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 0000000000..1a8733d6ff --- /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 0000000000..b23d52e6e0 --- /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 0000000000..fdb28e50a8 --- /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 0000000000..0d204d8d55 --- /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 0000000000..048b6e2335 --- /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 0000000000..a459fb5499 --- /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 0000000000..e63ec4278d --- /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 0000000000..90ee41e62a --- /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 0000000000..d0cda503d6 --- /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 0000000000..9a2c345462 --- /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 0000000000..ca70dba74c --- /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 0000000000..c483228ece --- /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 0000000000..e69de29bb2 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 0000000000..3612073bc3 --- /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 0000000000..d9370e924b --- /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 0000000000..077b7ac8f4 --- /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 0000000000..2adf3d05b6 --- /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 0000000000..f2feb39afa --- /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 0000000000..90d4ee0072 --- /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 0000000000..252904bb73 --- /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 0000000000..5aab5e7911 --- /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 0000000000..5564f25b94 --- /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 563c6d2910..d53fdd6e33 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 0000000000..6a55fff4f7 --- /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 9dab012bd5..7c333fd0cc 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 91ebeca78d237e8e9c3f37fe596d8ff5b5374f10 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/138] 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 69d967534d..b2f2e0f064 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 3d1bf22d94..0000000000 --- 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 bf553d8319..41ca186b3c 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 5818b2bc7e..0000000000 --- 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 0000000000..8a179857d4 --- /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 9f4bed6200..0000000000 --- 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 c52e3712f0..e97ffb6670 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 fa9a1111e5..333fec3995 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 165b5ae5a7..8a5f006b64 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 2dd501651d..0000000000 --- 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 1a8733d6ff..0143b906b4 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 b23d52e6e0..0000000000 --- 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 fdb28e50a8..0000000000 --- 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 0d204d8d55..0000000000 --- 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 048b6e2335..0000000000 --- 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 a459fb5499..0000000000 --- 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 e63ec4278d..0000000000 --- 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 90ee41e62a..0000000000 --- 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 d0cda503d6..1590cf1532 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 9a2c345462..0000000000 --- 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 ca70dba74c..0000000000 --- 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 c483228ece..aad7f1311c 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 19cec7dbb3926abf5c18f30f122de8ddeccfeb11 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/138] 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 b2f2e0f064..abe76da5d1 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 41ca186b3c..7e6c2af5ca 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 8a179857d4..da85e3d907 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 52198823219d9c6038917fa2f059e2ba9f1b2304 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/138] 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 0000000000..a72b7b764e --- /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 7e6c2af5ca..215b2269ba 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 09e3670f705dfdbf5e82f7d740fe71b3e775f399 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/138] 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 abe76da5d1..c2cb1ae795 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 215b2269ba..4feb954663 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 0000000000..c92d1c0d4a --- /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 da85e3d907..08508efd10 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 bc80e3aaf5..26794bb36b 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 8b3f23b7e4..6aac3209ea 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 e7995f422101f3184da5eb5beb57960b7796d5ea 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/138] 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 fe59dbcc8e..a887ae1c83 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 861cd8eb7c..acfd73790d 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 9185957832..baea877667 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 fa178148e6c8985d4f9321bf4746299325f696e2 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/138] 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 5aab5e7911..c366a45f2b 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 cba2296e4a15bd3f863ce43005fb31b082b8a55d 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/138] 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 a887ae1c83..4106ffbb5c 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 acfd73790d..cbae61b49d 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 333fec3995..a564f50dc6 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 baea877667..3f6bb88590 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 a4d6eb3c4862c00e905013684ae86e1c1f8656dd 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/138] 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 0000000000..2a51d70986 --- /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 0000000000..2dea4a32cc --- /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 59c54c1ce9..0000000000 --- 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 30926f8f8b..f2978cea34 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 3f6bb88590..94013b21a8 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 c366a45f2b..bfdc10e859 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 eadfe0d4f1b8529cd2000e13d3bab7428088cebf 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/138] 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 d008795aec..90e8af7981 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 cb65ac81b1b22c25246afac25e89eadadfa609f0 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/138] 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 90e8af7981..428bc7bf75 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 c2b185dc0258a4accd1bcebee86e9404244f196a 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/138] 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 4106ffbb5c..70d1056dbc 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 cbae61b49d..b54815eb9f 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 0000000000..e69de29bb2 diff --git a/apps/contract-verification/src/app/components/ContractDropdown.tsx b/apps/contract-verification/src/app/components/ContractDropdown.tsx index 2dea4a32cc..f54d28cd8d 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 7ad629c4c4232f41b64ede63f28f3c0a1db3c5e0 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/138] 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 70d1056dbc..77180cb3aa 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 0000000000..f3de4695aa --- /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 b54815eb9f..a914214f78 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 f54d28cd8d..39fc47869f 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 bae40e0aa6..7af3f40c4d 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 0000000000..108c48074f --- /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 94013b21a8..75c6880ff4 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 2c2fdb4139e2a5a15c85ddc9eff41d8d1876c3c1 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/138] 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 428bc7bf75..ded062af88 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 1f191c47c441f5dc3ae7e4546dae577293c3b7c5 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/138] 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 a914214f78..924a2ea02f 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 747b98d077d5fe5a9106735643fbf4e00fca9435 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/138] 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 8a5f006b64..f7f72a5793 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 75c6880ff4..521d3aa92c 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 aad7f1311c..629111037b 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 bf3b7b0901ba53971e53a0645f9e731afda7922b 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/138] 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 77180cb3aa..550bc02ec5 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 0000000000..5ccd20a42b --- /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 f3de4695aa..f693a0866d 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 924a2ea02f..5099d7e87a 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 521d3aa92c..4c34faffdc 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 52c656f59bb49fa1ec3776ec863b192bb6322f5a 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/138] 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 550bc02ec5..b44b743f23 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 5ccd20a42b..3608ff475a 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 0000000000..cb43f98918 --- /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 f693a0866d..16897e9b56 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 5099d7e87a..eba30b67ff 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 108c48074f..c007d71b06 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 4c34faffdc..d57066e945 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 7fa4c5fb5ec66a54d2bc407ce10c3d2232809d11 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/138] 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 b44b743f23..2de02cb07e 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 0000000000..613d99a991 --- /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 0000000000..5d757a7a4b --- /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 0000000000..00c0119b8d --- /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 3608ff475a..ce6cc643a8 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 cb43f98918..d41a048ef5 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 16897e9b56..a2f6ab3e4b 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 eba30b67ff..6fa3e00faf 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 f7f72a5793..6e9b39dccd 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 c007d71b06..8428fb1869 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 0000000000..b2aac0192c --- /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 d57066e945..7b800efc4d 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 9e3b41037a123e8908ec69523075b3e6d268ab1c 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/138] 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 d41a048ef5..ccb3c8ac9a 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 a2f6ab3e4b..7e3865f198 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 6fa3e00faf..50394ecf5d 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 39fc47869f..c7ad090ac9 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 ? ( +
+ {' '} + +
+ otherwise +
) } @@ -236,3 +255,29 @@ export function AccountUI(props: AccountProps) {
) } + +const EIP712_Example = { + domain: { + chainId: 1, + name: "Example App", + verifyingContract: "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC", + version: "1", + }, + message: { + prompt: "Welcome! In order to authenticate to this website, sign this request and your public address will be sent to the server in a verifiable way.", + createdAt: 1718570375196, + }, + primaryType: 'AuthRequest', + types: { + EIP712Domain: [ + { name: 'name', type: 'string' }, + { name: 'version', type: 'string' }, + { name: 'chainId', type: 'uint256' }, + { name: 'verifyingContract', type: 'address' }, + ], + AuthRequest: [ + { name: 'prompt', type: 'string' }, + { name: 'createdAt', type: 'uint256' }, + ], + }, +} \ No newline at end of file diff --git a/libs/remix-ui/run-tab/src/lib/components/settingsUI.tsx b/libs/remix-ui/run-tab/src/lib/components/settingsUI.tsx index d3d8ed5957..f9e09246f9 100644 --- a/libs/remix-ui/run-tab/src/lib/components/settingsUI.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/settingsUI.tsx @@ -15,6 +15,7 @@ export function SettingsUI(props: SettingsProps) {
void, setExecutionContext: (executionContext: { context: string, fork: string }) => void, createNewBlockchainAccount: (cbMessage: JSX.Element) => void, setPassphrase: (passphrase: string) => void, @@ -180,6 +181,7 @@ export interface AccountProps { isSuccessful: boolean, error: string }, + addFile: (path: string, content: string) => void, setAccount: (account: string) => void, personalMode: boolean, createNewBlockchainAccount: (cbMessage: JSX.Element) => void, diff --git a/libs/remix-ui/workspace/src/lib/actions/index.ts b/libs/remix-ui/workspace/src/lib/actions/index.tsx similarity index 96% rename from libs/remix-ui/workspace/src/lib/actions/index.ts rename to libs/remix-ui/workspace/src/lib/actions/index.tsx index e10fa20d43..bec7039e6a 100644 --- a/libs/remix-ui/workspace/src/lib/actions/index.ts +++ b/libs/remix-ui/workspace/src/lib/actions/index.tsx @@ -10,8 +10,7 @@ import { fetchContractFromEtherscan, fetchContractFromBlockscout } from '@remix- import JSZip from 'jszip' import { Actions, FileTree } from '../types' import IpfsHttpClient from 'ipfs-http-client' -import { AppModal } from '@remix-ui/app' -import { MessageWrapper } from '../components/file-explorer' +import { AppModal, ModalTypes } from '@remix-ui/app' export * from './events' export * from './workspace' @@ -510,6 +509,32 @@ export const runScript = async (path: string) => { }) } +export const signTypedData = async (path: string) => { + const typedData = await plugin.call('fileManager', 'readFile', path) + const web3 = await plugin.call('blockchain', 'web3') + const settings = await plugin.call('udapp', 'getSettings') + let parsed + try { + parsed = JSON.parse(typedData) + } catch (err) { + dispatch(displayPopUp(`${path} isn't a valid JSON.`)) + return + } + + try { + const result = await web3.currentProvider.request({ + method: 'eth_signTypedData', + params: [settings.selectedAccount, parsed] + }) + + plugin.call('terminal', 'log', { type: 'log', value: `${path} signature using ${settings.selectedAccount} : ${result}` }) + } catch (e) { + console.error(e) + plugin.call('terminal', 'log', { type: 'error', value: `error while signing ${path}: ${e}` }) + dispatch(displayPopUp(e.message)) + } +} + export const emitContextMenuEvent = async (cmd: customAction) => { await plugin.call(cmd.id, cmd.name, cmd) } diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx index b3a39f974c..0f408066aa 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx @@ -41,6 +41,7 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => downloadPath, uploadFile, publishManyFilesToGist, + signTypedData, ...otherProps } = props const contextMenuRef = useRef(null) @@ -233,7 +234,11 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => case 'Publish Workspace to Gist': _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', 'publishWorkspace']) publishFolderToGist(path) - break + break + case 'Sign Typed Data': + _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', 'signTypedData']) + signTypedData(path) + break default: _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', `${item.id}/${item.name}`]) emit && emit({ ...item, path: [path]} as customAction) diff --git a/libs/remix-ui/workspace/src/lib/contexts/index.ts b/libs/remix-ui/workspace/src/lib/contexts/index.ts index 04e1b7f8a3..dbbae11c20 100644 --- a/libs/remix-ui/workspace/src/lib/contexts/index.ts +++ b/libs/remix-ui/workspace/src/lib/contexts/index.ts @@ -34,6 +34,7 @@ export const FileSystemContext = createContext<{ dispatchCopyShareURL: (path: string) => Promise, dispatchCopyFolder: (src: string, dest: string) => Promise, dispatchRunScript: (path: string) => Promise, + dispatchSignTypedData: (path: string) => Promise, dispatchEmitContextMenuEvent: (cmd: customAction) => Promise, dispatchHandleClickFile: (path: string, type: 'file' | 'folder' ) => Promise dispatchHandleExpandPath: (paths: string[]) => Promise, diff --git a/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx b/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx index 12c5dc516f..3e923c7b76 100644 --- a/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx +++ b/libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx @@ -25,6 +25,7 @@ import { copyShareURL, copyFolder, runScript, + signTypedData, emitContextMenuEvent, handleClickFile, handleExpandPath, @@ -171,6 +172,10 @@ export const FileSystemProvider = (props: WorkspaceProps) => { await runScript(path) } + const dispatchSignTypedData = async (path: string) => { + await signTypedData(path) + } + const dispatchEmitContextMenuEvent = async (cmd: customAction) => { await emitContextMenuEvent(cmd) } @@ -358,6 +363,7 @@ export const FileSystemProvider = (props: WorkspaceProps) => { dispatchCopyShareURL, dispatchCopyFolder, dispatchRunScript, + dispatchSignTypedData, dispatchEmitContextMenuEvent, dispatchHandleClickFile, dispatchHandleExpandPath, diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index 5a4c19fc43..f7f79dbf72 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -706,6 +706,14 @@ export function Workspace() { } } + const signTypedData = async (path: string) => { + try { + global.dispatchSignTypedData(path) + } catch (error) { + global.toast(intl.formatMessage({ id: 'filePanel.signTypedDataError' })) + } + } + const emitContextMenuEvent = (cmd: customAction) => { try { global.dispatchEmitContextMenuEvent(cmd) @@ -1186,6 +1194,7 @@ export function Workspace() { dispatchCopyFolder={global.dispatchCopyFolder} dispatchPublishToGist={global.dispatchPublishToGist} dispatchRunScript={global.dispatchRunScript} + dispatchSignTypedData={global.dispatchSignTypedData} dispatchEmitContextMenuEvent={global.dispatchEmitContextMenuEvent} dispatchHandleClickFile={global.dispatchHandleClickFile} dispatchSetFocusElement={global.dispatchSetFocusElement} @@ -1262,6 +1271,7 @@ export function Workspace() { dispatchCopyFolder={global.dispatchCopyFolder} dispatchPublishToGist={global.dispatchPublishToGist} dispatchRunScript={global.dispatchRunScript} + dispatchSignTypedData={global.dispatchSignTypedData} // dispatchEmitContextMenuEvent={global.dispatchEmitContextMenuEvent} dispatchHandleClickFile={global.dispatchHandleClickFile} dispatchSetFocusElement={global.dispatchSetFocusElement} @@ -1436,6 +1446,7 @@ export function Workspace() { deletePath={deletePath} renamePath={editModeOn} runScript={runScript} + signTypedData={signTypedData} copy={handleCopyClick} paste={handlePasteClick} copyFileName={handleCopyFileNameClick} diff --git a/libs/remix-ui/workspace/src/lib/types/index.ts b/libs/remix-ui/workspace/src/lib/types/index.ts index 125cf29aeb..ba23f4cdc2 100644 --- a/libs/remix-ui/workspace/src/lib/types/index.ts +++ b/libs/remix-ui/workspace/src/lib/types/index.ts @@ -128,6 +128,7 @@ export interface FileExplorerProps { dispatchCopyShareURL: (path:string) => Promise, dispatchCopyFolder: (src: string, dest: string) => Promise, dispatchRunScript: (path: string) => Promise, + dispatchSignTypedData: (path: string) => Promise, dispatchPublishToGist: (path?: string, type?: string) => Promise, dispatchEmitContextMenuEvent: (cmd: customAction) => Promise, dispatchHandleClickFile: (path: string, type: WorkspaceElement) => Promise, @@ -197,6 +198,7 @@ export interface FileExplorerContextMenuProps { pushChangesToGist?: (path?: string) => void publishFolderToGist?: (path?: string) => void publishFileToGist?: (path?: string) => void + signTypedData?: (path?: string) => void runScript?: (path: string) => void emit?: (cmd: customAction) => void pageX: number diff --git a/libs/remix-ui/workspace/src/lib/utils/index.ts b/libs/remix-ui/workspace/src/lib/utils/index.ts index a0dfc8df6a..033c50bb55 100644 --- a/libs/remix-ui/workspace/src/lib/utils/index.ts +++ b/libs/remix-ui/workspace/src/lib/utils/index.ts @@ -80,6 +80,13 @@ export const contextMenuActions: MenuItems = [{ multiselect: false, label: '', group: 3 +}, { + id: 'signTypedData', + name: 'Sign Typed Data', + extension: ['.json'], + multiselect: false, + label: '', + group: 3 }, { id: 'publishFolderToGist', name: 'Publish folder to gist', From f89f6f4dbe858072c2ed2971e912112a6f4f055a Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 1 Oct 2024 15:27:44 +0200 Subject: [PATCH 118/138] use basic sign in the case of injected --- apps/remix-ide/src/blockchain/providers/injected.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide/src/blockchain/providers/injected.ts b/apps/remix-ide/src/blockchain/providers/injected.ts index 9e10ebc68d..81ac25a5e1 100644 --- a/apps/remix-ide/src/blockchain/providers/injected.ts +++ b/apps/remix-ide/src/blockchain/providers/injected.ts @@ -41,7 +41,7 @@ export class InjectedProvider { const messageHash = hashPersonalMessage(Buffer.from(message)) try { message = isHexString(message) ? message : Web3.utils.utf8ToHex(message) - this.executionContext.web3().eth.personal.sign(message, account).then((error, signedData) => { + this.executionContext.web3().eth.sign(message, account).then((error, signedData) => { cb(error, bytesToHex(messageHash), signedData) }).catch((error => cb(error))) } catch (e) { From f7bd13b9f8f5697a06675df0ec95672c95246b8a Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 1 Oct 2024 15:43:31 +0200 Subject: [PATCH 119/138] linting --- apps/remix-ide/src/blockchain/providers/vm.ts | 4 ++-- .../run-tab/src/lib/components/account.tsx | 16 ++++++++-------- .../remix-ui/workspace/src/lib/actions/index.tsx | 6 +++--- .../components/file-explorer-context-menu.tsx | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/remix-ide/src/blockchain/providers/vm.ts b/apps/remix-ide/src/blockchain/providers/vm.ts index 21d087cb96..a6614682c7 100644 --- a/apps/remix-ide/src/blockchain/providers/vm.ts +++ b/apps/remix-ide/src/blockchain/providers/vm.ts @@ -39,8 +39,8 @@ export class VMProvider { return new Promise((resolve, reject) => { this.worker.addEventListener('message', (msg) => { if (msg.data.cmd === 'sendAsyncResult' && stamps[msg.data.stamp]) { - let result = msg.data.result - if (stamps[msg.data.stamp].request && msg.data.result) result = msg.data.result.result + const result = msg.data.result + // if (stamps[msg.data.stamp].request && msg.data.result) result = msg.data.result.result if (stamps[msg.data.stamp].callback) { stamps[msg.data.stamp].callback(msg.data.error, result) diff --git a/libs/remix-ui/run-tab/src/lib/components/account.tsx b/libs/remix-ui/run-tab/src/lib/components/account.tsx index 087bd132b1..27b3b7264d 100644 --- a/libs/remix-ui/run-tab/src/lib/components/account.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/account.tsx @@ -178,19 +178,19 @@ export function AccountUI(props: AccountProps) {
otherwise
, intl.formatMessage({ id: 'udapp.EIP712-create-template' }), () => { props.addFile('EIP-712-data.json', JSON.stringify(EIP712_Example, null, '\t')) }, - intl.formatMessage({ id: 'udapp.EIP712-close' }), + intl.formatMessage({ id: 'udapp.EIP712-close' }), () => {}) }}>Sign with EIP 712
diff --git a/libs/remix-ui/workspace/src/lib/actions/index.tsx b/libs/remix-ui/workspace/src/lib/actions/index.tsx index bec7039e6a..9781a77e76 100644 --- a/libs/remix-ui/workspace/src/lib/actions/index.tsx +++ b/libs/remix-ui/workspace/src/lib/actions/index.tsx @@ -512,21 +512,21 @@ export const runScript = async (path: string) => { export const signTypedData = async (path: string) => { const typedData = await plugin.call('fileManager', 'readFile', path) const web3 = await plugin.call('blockchain', 'web3') - const settings = await plugin.call('udapp', 'getSettings') + const settings = await plugin.call('udapp', 'getSettings') let parsed try { parsed = JSON.parse(typedData) } catch (err) { dispatch(displayPopUp(`${path} isn't a valid JSON.`)) return - } + } try { const result = await web3.currentProvider.request({ method: 'eth_signTypedData', params: [settings.selectedAccount, parsed] }) - + plugin.call('terminal', 'log', { type: 'log', value: `${path} signature using ${settings.selectedAccount} : ${result}` }) } catch (e) { console.error(e) diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx index 0f408066aa..58969c959d 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer-context-menu.tsx @@ -234,11 +234,11 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => case 'Publish Workspace to Gist': _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', 'publishWorkspace']) publishFolderToGist(path) - break - case 'Sign Typed Data': + break + case 'Sign Typed Data': _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', 'signTypedData']) signTypedData(path) - break + break default: _paq.push(['trackEvent', 'fileExplorer', 'contextMenu', `${item.id}/${item.name}`]) emit && emit({ ...item, path: [path]} as customAction) From ce1a8ed0eb1d86c881ea0a0dbbbcc42ab306c3e3 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 7 Oct 2024 11:40:09 +0200 Subject: [PATCH 120/138] remove request --- apps/remix-ide/src/blockchain/providers/vm.ts | 24 ++++++++------ .../src/blockchain/providers/worker-vm.ts | 31 +++++++++++++++++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/apps/remix-ide/src/blockchain/providers/vm.ts b/apps/remix-ide/src/blockchain/providers/vm.ts index a6614682c7..ccd8b391e2 100644 --- a/apps/remix-ide/src/blockchain/providers/vm.ts +++ b/apps/remix-ide/src/blockchain/providers/vm.ts @@ -38,18 +38,22 @@ export class VMProvider { return new Promise((resolve, reject) => { this.worker.addEventListener('message', (msg) => { - if (msg.data.cmd === 'sendAsyncResult' && stamps[msg.data.stamp]) { - const result = msg.data.result - // if (stamps[msg.data.stamp].request && msg.data.result) result = msg.data.result.result - + console.log('message', msg) + if (msg.data.cmd === 'requestResult' && stamps[msg.data.stamp]) { + if (msg.data.error) { + stamps[msg.data.stamp].reject(msg.data.error) + } else { + stamps[msg.data.stamp].resolve(msg.data.result) + } + } else if (msg.data.cmd === 'sendAsyncResult' && stamps[msg.data.stamp]) { if (stamps[msg.data.stamp].callback) { - stamps[msg.data.stamp].callback(msg.data.error, result) + stamps[msg.data.stamp].callback(msg.data.error, msg.data.result) return } if (msg.data.error) { stamps[msg.data.stamp].reject(msg.data.error) } else { - stamps[msg.data.stamp].resolve(result) + stamps[msg.data.stamp].resolve(msg.data.result) } } else if (msg.data.cmd === 'initiateResult') { if (!msg.data.error) { @@ -58,7 +62,8 @@ export class VMProvider { return new Promise((resolve, reject) => { const stamp = Date.now() + incr incr++ - stamps[stamp] = { callback, resolve, reject, sendAsync: true } + stamps[stamp] = { callback, resolve, reject } + console.log('sendAsync', query, stamp) this.worker.postMessage({ cmd: 'sendAsync', query, stamp }) }) }, @@ -66,8 +71,9 @@ export class VMProvider { return new Promise((resolve, reject) => { const stamp = Date.now() + incr incr++ - stamps[stamp] = { resolve, reject, request: true } - this.worker.postMessage({ cmd: 'sendAsync', query, stamp }) + stamps[stamp] = { resolve, reject } + console.log('request', query, stamp) + this.worker.postMessage({ cmd: 'request', query, stamp }) }) } } diff --git a/apps/remix-ide/src/blockchain/providers/worker-vm.ts b/apps/remix-ide/src/blockchain/providers/worker-vm.ts index d1ad0b7f0d..ccc97129b1 100644 --- a/apps/remix-ide/src/blockchain/providers/worker-vm.ts +++ b/apps/remix-ide/src/blockchain/providers/worker-vm.ts @@ -43,6 +43,37 @@ self.onmessage = (e: MessageEvent) => { break } + case 'request': + { + (function (data) { + const stamp = data.stamp + if (provider) { + provider.request(data.query).then((result) => { + self.postMessage({ + cmd: 'requestResult', + error: null, + result: result, + stamp: stamp + }) + }).catch((error) => { + self.postMessage({ + cmd: 'requestResult', + error: error, + result: null, + stamp: stamp + }) + }) + } else { + self.postMessage({ + cmd: 'requestResult', + error: 'Provider not instantiated', + result: null, + stamp: stamp + }) + } + })(data) + break + } case 'addAccount': { if (provider) { From ceb9b2893d1b48967496c1cd9115039264f3b851 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 8 Oct 2024 12:16:15 +0200 Subject: [PATCH 121/138] typo --- apps/remix-ide/src/app/files/fileManager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide/src/app/files/fileManager.ts b/apps/remix-ide/src/app/files/fileManager.ts index 920501a866..a821ced648 100644 --- a/apps/remix-ide/src/app/files/fileManager.ts +++ b/apps/remix-ide/src/app/files/fileManager.ts @@ -271,7 +271,7 @@ class FileManager extends Plugin { } else { const ret = await this.setFileContent(path, data) this.emit('fileAdded', path) - return { newContent: ret, newpath: path } + return { newContent: ret, newPath: path } } } catch (e) { throw new Error(e) From a2df681825414ce0f25c0110354635feae7f2f37 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 8 Oct 2024 12:16:30 +0200 Subject: [PATCH 122/138] add missing provider function --- apps/remix-ide/src/app/udapp/run-tab.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js index 4b924ea6cd..4e768c869d 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.js +++ b/apps/remix-ide/src/app/udapp/run-tab.js @@ -181,6 +181,11 @@ export class RunTab extends ViewPlugin { provider: { sendAsync (payload) { return udapp.call(name, 'sendAsync', payload) + }, + async request (payload) { + const requestResult = await udapp.call(name, 'sendAsync', payload) + if (requestResult.error) throw new Error(requestResult.error.message) + return requestResult.result } } }) From 35a019f31d43176d8f8c270f73749e6a9c9ef1bd Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 8 Oct 2024 12:16:49 +0200 Subject: [PATCH 123/138] fix signTypeData call --- libs/remix-ui/workspace/src/lib/actions/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/remix-ui/workspace/src/lib/actions/index.tsx b/libs/remix-ui/workspace/src/lib/actions/index.tsx index 9781a77e76..cc66374596 100644 --- a/libs/remix-ui/workspace/src/lib/actions/index.tsx +++ b/libs/remix-ui/workspace/src/lib/actions/index.tsx @@ -523,14 +523,14 @@ export const signTypedData = async (path: string) => { try { const result = await web3.currentProvider.request({ - method: 'eth_signTypedData', + method: 'eth_signTypedData_v4', params: [settings.selectedAccount, parsed] }) plugin.call('terminal', 'log', { type: 'log', value: `${path} signature using ${settings.selectedAccount} : ${result}` }) } catch (e) { console.error(e) - plugin.call('terminal', 'log', { type: 'error', value: `error while signing ${path}: ${e}` }) + plugin.call('terminal', 'log', { type: 'error', value: `error while signing ${path}: ${e.message}` }) dispatch(displayPopUp(e.message)) } } From 07d516e7d61f9973dc9848f5ce2de61f62fd4ae4 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 8 Oct 2024 12:16:59 +0200 Subject: [PATCH 124/138] sign the hash --- apps/remix-ide/src/blockchain/providers/injected.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/remix-ide/src/blockchain/providers/injected.ts b/apps/remix-ide/src/blockchain/providers/injected.ts index 81ac25a5e1..6c06d18668 100644 --- a/apps/remix-ide/src/blockchain/providers/injected.ts +++ b/apps/remix-ide/src/blockchain/providers/injected.ts @@ -38,11 +38,11 @@ export class InjectedProvider { } signMessage (message, account, _passphrase, cb) { + message = isHexString(message) ? message : Web3.utils.utf8ToHex(message) const messageHash = hashPersonalMessage(Buffer.from(message)) try { - message = isHexString(message) ? message : Web3.utils.utf8ToHex(message) - this.executionContext.web3().eth.sign(message, account).then((error, signedData) => { - cb(error, bytesToHex(messageHash), signedData) + this.executionContext.web3().eth.sign(messageHash, account).then((signedData) => { + cb(null, bytesToHex(messageHash), signedData) }).catch((error => cb(error))) } catch (e) { cb(e.message) From 4043098b108fa114d2cabb8b952a0d53d4f3f572 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 8 Oct 2024 17:19:33 +0200 Subject: [PATCH 125/138] run-tab to ts --- .../src/app/providers/abstract-provider.tsx | 2 + .../src/app/udapp/{run-tab.js => run-tab.tsx} | 47 +++++++++++++++---- apps/remix-ide/src/blockchain/providers/vm.ts | 3 -- libs/remix-ui/run-tab/src/lib/css/run-tab.css | 5 -- .../run-tab/src/lib/types/blockchain.d.ts | 8 ++-- .../src/lib/types/execution-context.d.ts | 1 - libs/remix-ui/run-tab/src/lib/types/index.ts | 2 +- .../run-tab/src/lib/types/run-tab.d.ts | 21 ++------- 8 files changed, 46 insertions(+), 43 deletions(-) rename apps/remix-ide/src/app/udapp/{run-tab.js => run-tab.tsx} (88%) diff --git a/apps/remix-ide/src/app/providers/abstract-provider.tsx b/apps/remix-ide/src/app/providers/abstract-provider.tsx index 01e26df1f4..e740c6139b 100644 --- a/apps/remix-ide/src/app/providers/abstract-provider.tsx +++ b/apps/remix-ide/src/app/providers/abstract-provider.tsx @@ -126,9 +126,11 @@ export abstract class AbstractProvider extends Plugin implements IProvider { private async sendAsyncInternal(data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise { if (this.provider) { try { + console.log('sendAsyncInternal', data) const result = await this.provider.send(data.method, data.params) resolve({ jsonrpc: '2.0', result, id: data.id }) } catch (error) { + console.log('CATCH', error.message) if (error && error.message && error.message.includes('net_version') && error.message.includes('SERVER_ERROR')) { this.switchAway(true) } diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.tsx similarity index 88% rename from apps/remix-ide/src/app/udapp/run-tab.js rename to apps/remix-ide/src/app/udapp/run-tab.tsx index 4e768c869d..0980499917 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.js +++ b/apps/remix-ide/src/app/udapp/run-tab.tsx @@ -6,8 +6,11 @@ import {addressToString} from '@remix-ui/helper' import {InjectedProviderDefault} from '../providers/injected-provider-default' import {InjectedCustomProvider} from '../providers/injected-custom-provider' import * as packageJson from '../../../../../package.json' - -const EventManager = require('../../lib/events') +import { EventManager } from '@remix-project/remix-lib' +import type { Blockchain } from '../../blockchain/blockchain' +import type { CompilerArtefacts } from '@remix-project/core-plugin' +// import type { NetworkModule } from '../tabs/network-module' +// import type FileProvider from '../files/fileProvider' const Recorder = require('../tabs/runTab/model/recorder.js') const _paq = (window._paq = window._paq || []) @@ -37,7 +40,20 @@ const profile = { } export class RunTab extends ViewPlugin { - constructor(blockchain, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, fileProvider, engine) { + event: EventManager + engine: any + config: any + blockchain: Blockchain + fileManager: any + editor: any + filePanel: any + compilersArtefacts: CompilerArtefacts + networkModule: any + fileProvider: any + recorder: any + REACT_API: any + el: any + constructor(blockchain: Blockchain, config: any, fileManager: any, editor: any, filePanel: any, compilersArtefacts: CompilerArtefacts, networkModule: any, fileProvider: any, engine: any) { super(profile) this.event = new EventManager() this.engine = engine @@ -83,7 +99,7 @@ export class RunTab extends ViewPlugin { this.emit('clearAllInstancesReducer') } - addInstance(address, abi, name, contractData) { + addInstance(address, abi, name, contractData?) { this.emit('addInstanceReducer', address, abi, name, contractData) } @@ -180,27 +196,38 @@ export class RunTab extends ViewPlugin { }, provider: { sendAsync (payload) { + console.log('sendAsync', payload) return udapp.call(name, 'sendAsync', payload) }, async request (payload) { - const requestResult = await udapp.call(name, 'sendAsync', payload) - if (requestResult.error) throw new Error(requestResult.error.message) - return requestResult.result + console.log('REQUEST', payload) + try { + const requestResult = await udapp.call(name, 'sendAsync', payload) + console.log('run ok', requestResult) + if (requestResult.error) { + console.log('inner error', requestResult.error) + throw new Error(requestResult.error.message) + } + return requestResult.result + } catch (err) { + console.log('run failed', err) + throw new Error(err.error.message) + } } } }) } - const addCustomInjectedProvider = async (position, event, name, displayName, networkId, urls, nativeCurrency) => { + const addCustomInjectedProvider = async (position, event, name, displayName, networkId, urls, nativeCurrency?) => { // name = `${name} through ${event.detail.info.name}` await this.engine.register([new InjectedCustomProvider(event.detail.provider, name, networkId, urls, nativeCurrency)]) - await addProvider(position, name, displayName, true, false, false) + await addProvider(position, name, displayName, true, false) } const registerInjectedProvider = async (event) => { const name = 'injected-' + event.detail.info.name const displayName = 'Injected Provider - ' + event.detail.info.name await this.engine.register([new InjectedProviderDefault(event.detail.provider, name)]) - await addProvider(0, name, displayName, true, false, false) + await addProvider(0, name, displayName, true, false) if (event.detail.info.name === 'MetaMask') { await addCustomInjectedProvider(7, event, 'injected-metamask-optimism', 'L2 - Optimism - ' + event.detail.info.name, '0xa', ['https://mainnet.optimism.io']) diff --git a/apps/remix-ide/src/blockchain/providers/vm.ts b/apps/remix-ide/src/blockchain/providers/vm.ts index ccd8b391e2..f079c3d467 100644 --- a/apps/remix-ide/src/blockchain/providers/vm.ts +++ b/apps/remix-ide/src/blockchain/providers/vm.ts @@ -38,7 +38,6 @@ export class VMProvider { return new Promise((resolve, reject) => { this.worker.addEventListener('message', (msg) => { - console.log('message', msg) if (msg.data.cmd === 'requestResult' && stamps[msg.data.stamp]) { if (msg.data.error) { stamps[msg.data.stamp].reject(msg.data.error) @@ -63,7 +62,6 @@ export class VMProvider { const stamp = Date.now() + incr incr++ stamps[stamp] = { callback, resolve, reject } - console.log('sendAsync', query, stamp) this.worker.postMessage({ cmd: 'sendAsync', query, stamp }) }) }, @@ -72,7 +70,6 @@ export class VMProvider { const stamp = Date.now() + incr incr++ stamps[stamp] = { resolve, reject } - console.log('request', query, stamp) this.worker.postMessage({ cmd: 'request', query, stamp }) }) } diff --git a/libs/remix-ui/run-tab/src/lib/css/run-tab.css b/libs/remix-ui/run-tab/src/lib/css/run-tab.css index d2f1ffc474..16900d83f0 100644 --- a/libs/remix-ui/run-tab/src/lib/css/run-tab.css +++ b/libs/remix-ui/run-tab/src/lib/css/run-tab.css @@ -141,11 +141,6 @@ .udapp_input { font-size: 10px !important; } -.udapp_noInstancesText { - font-style: italic; - text-align: left; - padding-left: 15px; -} .udapp_pendingTxsText { font-style: italic; display: flex; diff --git a/libs/remix-ui/run-tab/src/lib/types/blockchain.d.ts b/libs/remix-ui/run-tab/src/lib/types/blockchain.d.ts index dbfa9ac9eb..428c782a8e 100644 --- a/libs/remix-ui/run-tab/src/lib/types/blockchain.d.ts +++ b/libs/remix-ui/run-tab/src/lib/types/blockchain.d.ts @@ -17,12 +17,11 @@ export class Blockchain extends Plugin { }; setupEvents(): void; getCurrentNetworkStatus(): { - name: string; - id: string; network?: { name: string; id: string; }; + error?: string; }; setupProviders(): void; providers: any; @@ -35,8 +34,8 @@ export class Blockchain extends Plugin { determineGasPrice(cb: any): void; getInputs(funABI: any): any; fromWei(value: any, doTypeConversion: any, unit: any): string; - toWei(value: any, unit: any): import("bn.js"); - calculateFee(gas: any, gasPrice: any, unit: any): import("bn.js"); + toWei(value: any, unit: any): string; + calculateFee(gas: any, gasPrice: any, unit: any): bigint; determineGasFees(tx: any): (gasPrice: any, cb: any) => void; changeExecutionContext(context: any, confirmCb: any, infoCb: any, cb: any): Promise; detectNetwork(cb: any): void; @@ -58,7 +57,6 @@ export class Blockchain extends Plugin { removeProvider(name: any): void; /** Listen on New Transaction. (Cannot be done inside constructor because txlistener doesn't exist yet) */ startListening(txlistener: any): void; - resetEnvironment(): Promise; /** * Create a VM Account * @param {{privateKey: string, balance: string}} newAccount The new account to create diff --git a/libs/remix-ui/run-tab/src/lib/types/execution-context.d.ts b/libs/remix-ui/run-tab/src/lib/types/execution-context.d.ts index 83d3df2d55..598c4f8f7d 100644 --- a/libs/remix-ui/run-tab/src/lib/types/execution-context.d.ts +++ b/libs/remix-ui/run-tab/src/lib/types/execution-context.d.ts @@ -14,7 +14,6 @@ export class ExecutionContext { txs: any; customWeb3: any; init(config: any): void; - askPermission(): void; getProvider(): any; getCurrentFork(): string; isVM(): boolean; diff --git a/libs/remix-ui/run-tab/src/lib/types/index.ts b/libs/remix-ui/run-tab/src/lib/types/index.ts index 94d997eae7..35229e6e31 100644 --- a/libs/remix-ui/run-tab/src/lib/types/index.ts +++ b/libs/remix-ui/run-tab/src/lib/types/index.ts @@ -6,7 +6,7 @@ import { SolcInput, SolcOutput } from '@openzeppelin/upgrades-core' import { LayoutCompatibilityReport } from '@openzeppelin/upgrades-core/dist/storage/report' export interface RunTabProps { plugin: RunTab, - initialState: RunTabState + initialState?: RunTabState } export interface Contract { diff --git a/libs/remix-ui/run-tab/src/lib/types/run-tab.d.ts b/libs/remix-ui/run-tab/src/lib/types/run-tab.d.ts index 91de380ad9..40ae73ac9e 100644 --- a/libs/remix-ui/run-tab/src/lib/types/run-tab.d.ts +++ b/libs/remix-ui/run-tab/src/lib/types/run-tab.d.ts @@ -1,11 +1,11 @@ -export class RunTab extends ViewPlugin { - constructor(blockchain: any, config: any, fileManager: any, editor: any, filePanel: any, compilersArtefacts: any, networkModule: any, mainView: any, fileProvider: any); +import type { CompilerArtefacts } from '@remix-project/core-plugin' +export interface RunTab extends ViewPlugin { + // constructor(blockchain: Blockchain, config: any, fileManager: any, editor: any, filePanel: any, compilersArtefacts: CompilerArtefacts, networkModule: any, fileProvider: any, engine: any); event: any; config: any; blockchain: Blockchain; fileManager: any; editor: any; - logCallback: (msg: any) => void; filePanel: any; compilersArtefacts: any; networkModule: any; @@ -19,24 +19,9 @@ export class RunTab extends ViewPlugin { sendTransaction(tx: any): any; getAccounts(cb: any): any; pendingTransactionsCount(): any; - renderInstanceContainer(): void; - instanceContainer: any; - noInstancesText: any; - renderSettings(): void; - settingsUI: any; - renderDropdown(udappUI: any, fileManager: any, compilersArtefacts: any, config: any, editor: any, logCallback: any): void; - contractDropdownUI: any; - renderRecorder(udappUI: any, fileManager: any, config: any, logCallback: any): void; - recorderCount: any; - recorderInterface: any; - renderRecorderCard(): void; - recorderCard: any; - udappUI: any; - renderComponent(): void; onReady(api: any): void; onInitDone(): void; recorder: Recorder; - // syncContracts(): void } import { ViewPlugin } from "@remixproject/engine-web"; import { Blockchain } from "./blockchain"; From 64a32004a312cdd11a727081b20eaf49e6a2f779 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 14 Oct 2024 12:28:38 +0200 Subject: [PATCH 126/138] switchAway for all server errors --- apps/remix-ide/src/app/providers/abstract-provider.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/remix-ide/src/app/providers/abstract-provider.tsx b/apps/remix-ide/src/app/providers/abstract-provider.tsx index e740c6139b..b00efc3d0a 100644 --- a/apps/remix-ide/src/app/providers/abstract-provider.tsx +++ b/apps/remix-ide/src/app/providers/abstract-provider.tsx @@ -126,12 +126,10 @@ export abstract class AbstractProvider extends Plugin implements IProvider { private async sendAsyncInternal(data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise { if (this.provider) { try { - console.log('sendAsyncInternal', data) const result = await this.provider.send(data.method, data.params) resolve({ jsonrpc: '2.0', result, id: data.id }) } catch (error) { - console.log('CATCH', error.message) - if (error && error.message && error.message.includes('net_version') && error.message.includes('SERVER_ERROR')) { + if (error && error.message && error.message.includes('SERVER_ERROR')) { this.switchAway(true) } error.code = -32603 From eaf3c8ed25201141a1358f99f4dbef29a645edbb Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 14 Oct 2024 12:50:14 +0200 Subject: [PATCH 127/138] linting --- .../src/app/tabs/runTab/model/recorder.js | 4 +-- apps/remix-ide/src/app/udapp/run-tab.tsx | 26 +++++++++---------- .../src/blockchain/providers/worker-vm.ts | 2 +- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/apps/remix-ide/src/app/tabs/runTab/model/recorder.js b/apps/remix-ide/src/app/tabs/runTab/model/recorder.js index 23b9abf4be..85e36aaf80 100644 --- a/apps/remix-ide/src/app/tabs/runTab/model/recorder.js +++ b/apps/remix-ide/src/app/tabs/runTab/model/recorder.js @@ -21,7 +21,7 @@ const profile = { /** * Record transaction as long as the user create them. */ -class Recorder extends Plugin { +export class Recorder extends Plugin { constructor (blockchain) { super(profile) this.event = new EventManager() @@ -328,5 +328,3 @@ class Recorder extends Plugin { }) } } - -module.exports = Recorder diff --git a/apps/remix-ide/src/app/udapp/run-tab.tsx b/apps/remix-ide/src/app/udapp/run-tab.tsx index 0980499917..eae26bef68 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.tsx +++ b/apps/remix-ide/src/app/udapp/run-tab.tsx @@ -1,17 +1,17 @@ import React from 'react' // eslint-disable-line -import {RunTabUI} from '@remix-ui/run-tab' -import {ViewPlugin} from '@remixproject/engine-web' +import { RunTabUI } from '@remix-ui/run-tab' +import { ViewPlugin } from '@remixproject/engine-web' import isElectron from 'is-electron' -import {addressToString} from '@remix-ui/helper' -import {InjectedProviderDefault} from '../providers/injected-provider-default' -import {InjectedCustomProvider} from '../providers/injected-custom-provider' +import { addressToString } from '@remix-ui/helper' +import { InjectedProviderDefault } from '../providers/injected-provider-default' +import { InjectedCustomProvider } from '../providers/injected-custom-provider' import * as packageJson from '../../../../../package.json' import { EventManager } from '@remix-project/remix-lib' import type { Blockchain } from '../../blockchain/blockchain' import type { CompilerArtefacts } from '@remix-project/core-plugin' // import type { NetworkModule } from '../tabs/network-module' // import type FileProvider from '../files/fileProvider' -const Recorder = require('../tabs/runTab/model/recorder.js') +import { Recorder } from '../tabs/runTab/model/recorder' const _paq = (window._paq = window._paq || []) const profile = { @@ -90,7 +90,7 @@ export class RunTab extends ViewPlugin { async setEnvironmentMode(env) { const canCall = await this.askUserPermission('setEnvironmentMode', 'change the environment used') if (canCall) { - env = typeof env === 'string' ? {context: env} : env + env = typeof env === 'string' ? { context: env } : env this.emit('setEnvironmentModeReducer', env, this.currentRequest.from) } } @@ -169,7 +169,7 @@ export class RunTab extends ViewPlugin { 'injected-Brave Wallet': ['assets/img/brave.png'], 'injected-Trust Wallet': ['assets/img/trust-wallet.png'], 'hardhat-provider': ['assets/img/hardhat.png'], - 'walletconnect': ['assets/img/Walletconnect-logo.png'], + 'walletconnect': ['assets/img/Walletconnect-logo.png'], 'foundry-provider': ['assets/img/foundry.png'] } @@ -231,13 +231,13 @@ export class RunTab extends ViewPlugin { if (event.detail.info.name === 'MetaMask') { await addCustomInjectedProvider(7, event, 'injected-metamask-optimism', 'L2 - Optimism - ' + event.detail.info.name, '0xa', ['https://mainnet.optimism.io']) - await addCustomInjectedProvider(8, event, 'injected-metamask-arbitrum', 'L2 - Arbitrum - ' + event.detail.info.name, '0xa4b1', ['https://arb1.arbitrum.io/rpc']) + await addCustomInjectedProvider(8, event, 'injected-metamask-arbitrum', 'L2 - Arbitrum - ' + event.detail.info.name, '0xa4b1', ['https://arb1.arbitrum.io/rpc']) await addCustomInjectedProvider(5, event, 'injected-metamask-sepolia', 'Sepolia Testnet - ' + event.detail.info.name, '0xaa36a7', [], { "name": "Sepolia ETH", "symbol": "ETH", "decimals": 18 - }) + }) await addCustomInjectedProvider(9, event, 'injected-metamask-ephemery', 'Ephemery Testnet - ' + event.detail.info.name, '', ['https://otter.bordel.wtf/erigon', 'https://eth.ephemeral.zeus.fyi'], { "name": "Ephemery ETH", @@ -259,10 +259,10 @@ export class RunTab extends ViewPlugin { "decimals": 18 }) */ - } + } } - // VM + // VM const titleVM = 'Execution environment is local to Remix. Data is only saved to browser memory and will vanish upon reload.' await addProvider(1, 'vm-cancun', 'Remix VM (Cancun)', false, true, 'cancun', 'settingsVMCancunMode', titleVM) await addProvider(50, 'vm-shanghai', 'Remix VM (Shanghai)', false, true, 'shanghai', 'settingsVMShanghaiMode', titleVM) @@ -283,7 +283,7 @@ export class RunTab extends ViewPlugin { await addProvider(22, 'foundry-provider', 'Dev - Foundry Provider', false, false) // register injected providers - + window.addEventListener( "eip6963:announceProvider", (event) => { diff --git a/apps/remix-ide/src/blockchain/providers/worker-vm.ts b/apps/remix-ide/src/blockchain/providers/worker-vm.ts index ccc97129b1..a72e272acb 100644 --- a/apps/remix-ide/src/blockchain/providers/worker-vm.ts +++ b/apps/remix-ide/src/blockchain/providers/worker-vm.ts @@ -47,7 +47,7 @@ self.onmessage = (e: MessageEvent) => { { (function (data) { const stamp = data.stamp - if (provider) { + if (provider) { provider.request(data.query).then((result) => { self.postMessage({ cmd: 'requestResult', From 146e90c8bd33a49d18ac540a5f50987e000b83a6 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 14 Oct 2024 14:22:24 +0200 Subject: [PATCH 128/138] fix tests --- libs/remix-lib/src/execution/txRunnerWeb3.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/remix-lib/src/execution/txRunnerWeb3.ts b/libs/remix-lib/src/execution/txRunnerWeb3.ts index 8b353d6ba9..ffc6dcc793 100644 --- a/libs/remix-lib/src/execution/txRunnerWeb3.ts +++ b/libs/remix-lib/src/execution/txRunnerWeb3.ts @@ -160,9 +160,10 @@ export class TxRunnerWeb3 { }, callback) }) .catch(err => { - if (err && err.message.indexOf('Invalid JSON RPC response') !== -1) { + if (err && err.message && err.message.indexOf('Invalid JSON RPC response') !== -1) { // // @todo(#378) this should be removed when https://github.com/WalletConnect/walletconnect-monorepo/issues/334 is fixed callback(new Error('Gas estimation failed because of an unknown internal error. This may indicated that the transaction will fail.')) + return } err = network.name === 'VM' ? null : err // just send the tx if "VM" gasEstimationForceSend(err, () => { From 5bdf6d947d2ce981c23d018b0ad9a73054158af7 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 14 Oct 2024 15:01:40 +0200 Subject: [PATCH 129/138] fix test --- libs/remix-tests/src/runTestFiles.ts | 6 +++--- libs/remix-tests/src/runTestSources.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/remix-tests/src/runTestFiles.ts b/libs/remix-tests/src/runTestFiles.ts index 9b1c2bde00..eac97d350b 100644 --- a/libs/remix-tests/src/runTestFiles.ts +++ b/libs/remix-tests/src/runTestFiles.ts @@ -82,12 +82,12 @@ export function runTestFiles (filepath: string, isDirectory: boolean, web3: Web3 // If contract deployment fails because of 'Out of Gas' error, try again with double gas // This is temporary, should be removed when remix-tests will have a dedicated UI to // accept deployment params from UI - if (err.message.includes('The contract code couldn\'t be stored, please check your gas limit')) { + if (err.error.includes('The contract code couldn\'t be stored, please check your gas limit')) { deployAll(compilationResult, web3, accounts, true, null, (error, contracts) => { - if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.innerError || error.message, severity: 'error' }]) // IDE expects errors in array + if (error) next([{ message: 'contract deployment failed after trying twice: ' + (error.innerError || error.error), severity: 'error' }]) // IDE expects errors in array else next(null, compilationResult, contracts) }) - } else { next([{ message: 'contract deployment failed: ' + err.innerError || err.message, severity: 'error' }]) } // IDE expects errors in array + } else { next([{ message: 'contract deployment failed: ' + (err.innerError || err.error), severity: 'error' }]) } // IDE expects errors in array } else { next(null, compilationResult, contracts) } }) }, diff --git a/libs/remix-tests/src/runTestSources.ts b/libs/remix-tests/src/runTestSources.ts index 3464ddb037..5d71f9b7b9 100644 --- a/libs/remix-tests/src/runTestSources.ts +++ b/libs/remix-tests/src/runTestSources.ts @@ -62,12 +62,12 @@ export class UnitTestRunner { // If contract deployment fails because of 'Out of Gas' error, try again with double gas // This is temporary, should be removed when remix-tests will have a dedicated UI to // accept deployment params from UI - if (err.message.includes('The contract code couldn\'t be stored, please check your gas limit')) { + if (err.error.includes('The contract code couldn\'t be stored, please check your gas limit')) { deployAll(compilationResult, this.web3, this.testsAccounts, true, deployCb, (error, contracts) => { - if (error) next([{ message: 'contract deployment failed after trying twice: ' + error.innerError || error.message, severity: 'error' }]) // IDE expects errors in array + if (error) next([{ message: 'contract deployment failed after trying twice: ' + (error.innerError || error.error), severity: 'error' }]) // IDE expects errors in array else next(null, compilationResult, contracts) }) - } else { next([{ message: 'contract deployment failed: ' + err.innerError || err.message, severity: 'error' }]) } // IDE expects errors in array + } else { next([{ message: 'contract deployment failed: ' + (err.innerError || err.error), severity: 'error' }]) } // IDE expects errors in array } else { next(null, compilationResult, contracts) } }) }, From b4a4d4ebaa76672428dd1bc1189f6dfd4e5e6508 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 14 Oct 2024 16:25:40 +0200 Subject: [PATCH 130/138] fix test --- apps/remix-ide-e2e/src/tests/signingMessage.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/remix-ide-e2e/src/tests/signingMessage.test.ts b/apps/remix-ide-e2e/src/tests/signingMessage.test.ts index c92960e153..ba69071b74 100644 --- a/apps/remix-ide-e2e/src/tests/signingMessage.test.ts +++ b/apps/remix-ide-e2e/src/tests/signingMessage.test.ts @@ -63,6 +63,7 @@ module.exports = { .getEditorValue((content) => { browser.assert.ok(content.indexOf('"primaryType": "AuthRequest",') !== -1, 'EIP 712 data file must be opened') }) + .clickLaunchIcon('filePanel') .rightClick('li[data-id="treeViewLitreeViewItemEIP-712-data.json"]') .click('*[data-id="contextMenuItemsignTypedData"]') .journalChildIncludes('0x248d23de0e23231370db8aa21ad5908ca90c33ae2b8c611b906674bda6b1a8b85813f945c2ea896316e240089029619ab3d801a1b098c199bd462dd8026349da1c') From e855fc5de56ef33619f7763d4d1c38bc85b8d9f7 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 14 Oct 2024 17:27:16 +0200 Subject: [PATCH 131/138] fix tests --- apps/remix-ide-e2e/src/tests/signingMessage.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/tests/signingMessage.test.ts b/apps/remix-ide-e2e/src/tests/signingMessage.test.ts index ba69071b74..53edec7888 100644 --- a/apps/remix-ide-e2e/src/tests/signingMessage.test.ts +++ b/apps/remix-ide-e2e/src/tests/signingMessage.test.ts @@ -60,13 +60,15 @@ module.exports = { .click('*[data-id="sign-eip-712"]') .waitForElementVisible('*[data-id="udappNotify-modal-footer-ok-react"]') .modalFooterOKClick('udappNotify') + .pause(1000) .getEditorValue((content) => { browser.assert.ok(content.indexOf('"primaryType": "AuthRequest",') !== -1, 'EIP 712 data file must be opened') }) .clickLaunchIcon('filePanel') .rightClick('li[data-id="treeViewLitreeViewItemEIP-712-data.json"]') .click('*[data-id="contextMenuItemsignTypedData"]') - .journalChildIncludes('0x248d23de0e23231370db8aa21ad5908ca90c33ae2b8c611b906674bda6b1a8b85813f945c2ea896316e240089029619ab3d801a1b098c199bd462dd8026349da1c') + .pause(1000) + .journalChildIncludes('0x8be3a81e17b7e4a40006864a4ff6bfa3fb1e18b292b6f47edec95cd8feaa53275b90f56ca02669d461a297e6bf94ab0ee4b7c89aede3228ed5aedb59c7e007501c') } } From bebe7db452cb141f6a55b2b52110bed68be3a8a1 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 15 Oct 2024 12:00:45 +0200 Subject: [PATCH 132/138] fix using deprecated property --- libs/remix-lib/src/execution/txRunnerWeb3.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-lib/src/execution/txRunnerWeb3.ts b/libs/remix-lib/src/execution/txRunnerWeb3.ts index ffc6dcc793..0cdb0ee978 100644 --- a/libs/remix-lib/src/execution/txRunnerWeb3.ts +++ b/libs/remix-lib/src/execution/txRunnerWeb3.ts @@ -160,7 +160,7 @@ export class TxRunnerWeb3 { }, callback) }) .catch(err => { - if (err && err.message && err.message.indexOf('Invalid JSON RPC response') !== -1) { + if (err && err.error && err.error.indexOf('Invalid JSON RPC response') !== -1) { // // @todo(#378) this should be removed when https://github.com/WalletConnect/walletconnect-monorepo/issues/334 is fixed callback(new Error('Gas estimation failed because of an unknown internal error. This may indicated that the transaction will fail.')) return From 5f66c0e176d41415b30ce4f8d5f14a41a0dfd580 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 15 Oct 2024 14:25:57 +0200 Subject: [PATCH 133/138] remove logs --- apps/remix-ide/src/app/udapp/run-tab.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/apps/remix-ide/src/app/udapp/run-tab.tsx b/apps/remix-ide/src/app/udapp/run-tab.tsx index eae26bef68..64992ee00c 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.tsx +++ b/apps/remix-ide/src/app/udapp/run-tab.tsx @@ -196,21 +196,16 @@ export class RunTab extends ViewPlugin { }, provider: { sendAsync (payload) { - console.log('sendAsync', payload) return udapp.call(name, 'sendAsync', payload) }, async request (payload) { - console.log('REQUEST', payload) try { const requestResult = await udapp.call(name, 'sendAsync', payload) - console.log('run ok', requestResult) if (requestResult.error) { - console.log('inner error', requestResult.error) throw new Error(requestResult.error.message) } return requestResult.result } catch (err) { - console.log('run failed', err) throw new Error(err.error.message) } } From f84db1d11e8770e2f74d0599dc0f427d79405e33 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 15 Oct 2024 14:33:43 +0200 Subject: [PATCH 134/138] linting --- apps/remix-ide/src/app/udapp/run-tab.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/remix-ide/src/app/udapp/run-tab.tsx b/apps/remix-ide/src/app/udapp/run-tab.tsx index 64992ee00c..91099bebcb 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.tsx +++ b/apps/remix-ide/src/app/udapp/run-tab.tsx @@ -245,7 +245,6 @@ export class RunTab extends ViewPlugin { "symbol": "XDAI", "decimals": 18 }) - /* await addCustomInjectedProvider(9, event, 'SKALE Chaos Testnet', '0x50877ed6', ['https://staging-v3.skalenodes.com/v1/staging-fast-active-bellatrix'], { From 21fa55974499afdd2c0978d1f2eb5a6db52b9b02 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 15 Oct 2024 15:15:55 +0200 Subject: [PATCH 135/138] fix and add metamask test --- .../src/tests/runAndDeploy_injected.test.ts | 32 +++++++++++++++++++ apps/remix-ide/src/app/udapp/run-tab.tsx | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts index 446d5e4d13..3ad9272aee 100644 --- a/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts +++ b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts @@ -238,7 +238,39 @@ const tests = { browser .executeScriptInTerminal('web3.eth.getAccounts()') .journalLastChildIncludes('["0x76a3ABb5a12dcd603B52Ed22195dED17ee82708f"]') + }, + + 'Test EIP 712 Signature with Injected Provider (Metamask) #group1': function (browser: NightwatchBrowser) { + browser.waitForElementPresent('i[id="remixRunSignMsg"]') + .click('i[id="remixRunSignMsg"]') + .waitForElementVisible('*[data-id="signMessageTextarea"]', 120000) + .click('*[data-id="sign-eip-712"]') + .waitForElementVisible('*[data-id="udappNotify-modal-footer-ok-react"]') + .modalFooterOKClick('udappNotify') + .pause(1000) + .getEditorValue((content) => { + browser.assert.ok(content.indexOf('"primaryType": "AuthRequest",') !== -1, 'EIP 712 data file must be opened') + }) + .clickLaunchIcon('filePanel') + .rightClick('li[data-id="treeViewLitreeViewItemEIP-712-data.json"]') + .click('*[data-id="contextMenuItemsignTypedData"]') + .perform((done) => { // call delegate + browser.switchBrowserWindow(extension_url, 'MetaMask', (browser) => { + browser + .hideMetaMaskPopup() + .saveScreenshot('./reports/screenshots/metamask_6.png') + .waitForElementPresent('button[aria-label="Scroll down"]', 60000) + .click('button[aria-label="Scroll down"]') // scroll down + .click('button[data-testid="confirm-footer-button"]') // confirm + .switchBrowserTab(0) // back to remix + .perform(() => done()) + }) + }) + .pause(1000) + .journalChildIncludes('0x8be3a81e17b7e4a40006864a4ff6bfa3fb1e18b292b6f47edec95cd8feaa53275b90f56ca02669d461a297e6bf94ab0ee4b7c89aede3228ed5aedb59c7e007501c') } + + } const branch = process.env.CIRCLE_BRANCH; diff --git a/apps/remix-ide/src/app/udapp/run-tab.tsx b/apps/remix-ide/src/app/udapp/run-tab.tsx index 91099bebcb..84c50b5475 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.tsx +++ b/apps/remix-ide/src/app/udapp/run-tab.tsx @@ -206,7 +206,7 @@ export class RunTab extends ViewPlugin { } return requestResult.result } catch (err) { - throw new Error(err.error.message) + throw new Error(err.message) } } } From f820cd8604cb7dc437ccb84886f7487e2362137c Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 15 Oct 2024 17:39:10 +0200 Subject: [PATCH 136/138] run flaky --- .circleci/config.yml | 2 +- apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 26bb163e27..41b0eb6639 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2.1 parameters: run_flaky_tests: type: boolean - default: false + default: true orbs: browser-tools: circleci/browser-tools@1.4.4 win: circleci/windows@5.0 diff --git a/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts index 3ad9272aee..369f4b0cba 100644 --- a/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts +++ b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts @@ -240,7 +240,7 @@ const tests = { .journalLastChildIncludes('["0x76a3ABb5a12dcd603B52Ed22195dED17ee82708f"]') }, - 'Test EIP 712 Signature with Injected Provider (Metamask) #group1': function (browser: NightwatchBrowser) { + 'Test EIP 712 Signature with Injected Provider (Metamask) #group1 #flaky': function (browser: NightwatchBrowser) { browser.waitForElementPresent('i[id="remixRunSignMsg"]') .click('i[id="remixRunSignMsg"]') .waitForElementVisible('*[data-id="signMessageTextarea"]', 120000) From 7dc80fd528ec07f6924a9303026b1bfe33b0e798 Mon Sep 17 00:00:00 2001 From: yann300 Date: Tue, 15 Oct 2024 21:56:17 +0200 Subject: [PATCH 137/138] enable tests --- apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts index 369f4b0cba..7eec0d5c8b 100644 --- a/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts +++ b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts @@ -269,15 +269,13 @@ const tests = { .pause(1000) .journalChildIncludes('0x8be3a81e17b7e4a40006864a4ff6bfa3fb1e18b292b6f47edec95cd8feaa53275b90f56ca02669d461a297e6bf94ab0ee4b7c89aede3228ed5aedb59c7e007501c') } - - } const branch = process.env.CIRCLE_BRANCH; const isMasterBranch = branch === 'master'; module.exports = { - ...{} //(branch ? (isMasterBranch ? tests : {}) : tests), + ...tests, }; const localsCheck = { From 7e44c515645527490ca8357becc51f22d325e6ed Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 16 Oct 2024 09:38:54 +0200 Subject: [PATCH 138/138] disabling test --- .circleci/config.yml | 2 +- apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 41b0eb6639..26bb163e27 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2.1 parameters: run_flaky_tests: type: boolean - default: true + default: false orbs: browser-tools: circleci/browser-tools@1.4.4 win: circleci/windows@5.0 diff --git a/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts index 7eec0d5c8b..9d91319e22 100644 --- a/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts +++ b/apps/remix-ide-e2e/src/tests/runAndDeploy_injected.test.ts @@ -275,7 +275,7 @@ const branch = process.env.CIRCLE_BRANCH; const isMasterBranch = branch === 'master'; module.exports = { - ...tests, + ...{} //(branch ? (isMasterBranch ? tests : {}) : tests), }; const localsCheck = {