Add EtherscanVerifier and extend from AbstractVerifier

pull/5285/head
Kaan Uzdoğan 5 months ago committed by Aniket
parent bf3b7b0901
commit 52c656f59b
  1. 8
      apps/contract-verification/src/app/AppContext.tsx
  2. 4
      apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts
  3. 52
      apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts
  4. 15
      apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts
  5. 10
      apps/contract-verification/src/app/app.tsx
  6. 4
      apps/contract-verification/src/app/types/VerificationTypes.ts
  7. 12
      apps/contract-verification/src/app/views/VerifyView.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

@ -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<any>
}

@ -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
}
}

@ -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<boolean> {
async verify(chainId: string, address: string, compilationOutput: {[fileName: string]: CompilerAbstract}, selectedContractFileAndName: string): Promise<any> {
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}]) => {

@ -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<string | undefined>()
const [verifiedContracts, setVerifiedContracts] = useState<VerifiedContract[]>([])
const [sourcifyVerifiers, setSourcifyVerifiers] = useState<SourcifyVerifier[]>([])
const [verifiers, setVerifiers] = useState<SourcifyVerifier[]>([])
const [verifiers, setVerifiers] = useState<AbstractVerifier[]>([])
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

@ -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
}

@ -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)

Loading…
Cancel
Save