verification plugin: Add Routescan verifier

pull/5372/head
Manuel Wedler 3 weeks ago committed by Aniket
parent 5351a020a6
commit 53f1229703
  1. 2
      apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts
  2. 2
      apps/contract-verification/src/app/Verifiers/BlockscoutVerifier.ts
  3. 22
      apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts
  4. 14
      apps/contract-verification/src/app/Verifiers/RoutescanVerifier.ts
  5. 4
      apps/contract-verification/src/app/Verifiers/index.ts
  6. 2
      apps/contract-verification/src/app/components/AccordionReceipt.tsx
  7. 4
      apps/contract-verification/src/app/types/VerificationTypes.ts
  8. 324
      apps/contract-verification/src/app/utils/default-apis.json
  9. 2
      apps/contract-verification/src/app/utils/default-settings.ts
  10. 25
      apps/contract-verification/src/app/views/LookupView.tsx
  11. 2
      apps/contract-verification/src/app/views/ReceiptsView.tsx
  12. 6
      apps/contract-verification/src/app/views/SettingsView.tsx
  13. 14
      apps/contract-verification/src/app/views/VerifyView.tsx

@ -3,7 +3,7 @@ import type { LookupResponse, SubmittedContract, VerificationResponse } from '..
// Optional function definitions // Optional function definitions
export interface AbstractVerifier { export interface AbstractVerifier {
verifyProxy(submittedContract: SubmittedContract): Promise<VerificationResponse> verifyProxy?(submittedContract: SubmittedContract): Promise<VerificationResponse>
checkVerificationStatus?(receiptId: string): Promise<VerificationResponse> checkVerificationStatus?(receiptId: string): Promise<VerificationResponse>
checkProxyVerificationStatus?(receiptId: string): Promise<VerificationResponse> checkProxyVerificationStatus?(receiptId: string): Promise<VerificationResponse>
} }

@ -26,7 +26,7 @@ export class BlockscoutVerifier extends EtherscanVerifier {
super(apiUrl, apiUrl, undefined) super(apiUrl, apiUrl, undefined)
} }
getContractCodeUrl(address: string): string { getContractCodeUrl(address: string, chainId: string): string {
const url = new URL(this.explorerUrl + `/address/${address}`) const url = new URL(this.explorerUrl + `/address/${address}`)
url.searchParams.append('tab', 'contract') url.searchParams.append('tab', 'contract')
return url.href return url.href

@ -74,9 +74,10 @@ export class EtherscanVerifier extends AbstractVerifier {
} }
const verificationResponse: EtherscanRpcResponse = await response.json() const verificationResponse: EtherscanRpcResponse = await response.json()
const lookupUrl = this.getContractCodeUrl(submittedContract.address, submittedContract.chainId)
if (verificationResponse.result.includes('already verified')) { if (verificationResponse.result.includes('already verified')) {
return { status: 'already verified', receiptId: null, lookupUrl: this.getContractCodeUrl(submittedContract.address) } return { status: 'already verified', receiptId: null, lookupUrl }
} }
if (verificationResponse.status !== '1' || verificationResponse.message !== 'OK') { if (verificationResponse.status !== '1' || verificationResponse.message !== 'OK') {
@ -84,7 +85,6 @@ export class EtherscanVerifier extends AbstractVerifier {
throw new Error(verificationResponse.result) throw new Error(verificationResponse.result)
} }
const lookupUrl = this.getContractCodeUrl(submittedContract.address)
return { status: 'pending', receiptId: verificationResponse.result, lookupUrl } return { status: 'pending', receiptId: verificationResponse.result, lookupUrl }
} }
@ -117,6 +117,10 @@ export class EtherscanVerifier extends AbstractVerifier {
const verificationResponse: EtherscanRpcResponse = await response.json() const verificationResponse: EtherscanRpcResponse = await response.json()
if (verificationResponse.message === 'Smart-contract not found or is not verified') {
return { status: 'failed', receiptId: null, message: verificationResponse.message }
}
if (verificationResponse.status !== '1' || verificationResponse.message !== 'OK') { if (verificationResponse.status !== '1' || verificationResponse.message !== 'OK') {
console.error('Error on Etherscan API proxy verification at ' + this.apiUrl + '\nStatus: ' + verificationResponse.status + '\nMessage: ' + verificationResponse.message + '\nResult: ' + verificationResponse.result) console.error('Error on Etherscan API proxy verification at ' + this.apiUrl + '\nStatus: ' + verificationResponse.status + '\nMessage: ' + verificationResponse.message + '\nResult: ' + verificationResponse.result)
throw new Error(verificationResponse.result) throw new Error(verificationResponse.result)
@ -144,7 +148,7 @@ export class EtherscanVerifier extends AbstractVerifier {
const checkStatusResponse: EtherscanCheckStatusResponse = await response.json() const checkStatusResponse: EtherscanCheckStatusResponse = await response.json()
if (checkStatusResponse.result.startsWith('Fail - Unable to verify')) { if (checkStatusResponse.result.startsWith('Fail - Unable to verify') || (checkStatusResponse.result as string) === 'Error: contract does not exist') {
return { status: 'failed', receiptId, message: checkStatusResponse.result } return { status: 'failed', receiptId, message: checkStatusResponse.result }
} }
if (checkStatusResponse.result === 'Pending in queue') { if (checkStatusResponse.result === 'Pending in queue') {
@ -229,23 +233,23 @@ export class EtherscanVerifier extends AbstractVerifier {
const lookupResponse: EtherscanGetSourceCodeResponse = await response.json() const lookupResponse: EtherscanGetSourceCodeResponse = await response.json()
if (lookupResponse.result[0].ABI === 'Contract source code not verified' || !lookupResponse.result[0].SourceCode || (lookupResponse.result as unknown as string) === 'Contract source code not verified') {
return { status: 'not verified' }
}
if (lookupResponse.status !== '1' || !lookupResponse.message.startsWith('OK')) { if (lookupResponse.status !== '1' || !lookupResponse.message.startsWith('OK')) {
const errorResponse = lookupResponse as unknown as EtherscanRpcResponse const errorResponse = lookupResponse as unknown as EtherscanRpcResponse
console.error('Error on Etherscan API lookup at ' + this.apiUrl + '\nStatus: ' + errorResponse.status + '\nMessage: ' + errorResponse.message + '\nResult: ' + errorResponse.result) console.error('Error on Etherscan API lookup at ' + this.apiUrl + '\nStatus: ' + errorResponse.status + '\nMessage: ' + errorResponse.message + '\nResult: ' + errorResponse.result)
throw new Error(errorResponse.result) throw new Error(errorResponse.result)
} }
if (lookupResponse.result[0].ABI === 'Contract source code not verified' || !lookupResponse.result[0].SourceCode) { const lookupUrl = this.getContractCodeUrl(contractAddress, chainId)
return { status: 'not verified' }
}
const lookupUrl = this.getContractCodeUrl(contractAddress)
const { sourceFiles, targetFilePath } = this.processReceivedFiles(lookupResponse.result[0], contractAddress, chainId) const { sourceFiles, targetFilePath } = this.processReceivedFiles(lookupResponse.result[0], contractAddress, chainId)
return { status: 'verified', lookupUrl, sourceFiles, targetFilePath } return { status: 'verified', lookupUrl, sourceFiles, targetFilePath }
} }
getContractCodeUrl(address: string): string { getContractCodeUrl(address: string, chainId: string): string {
const url = new URL(this.explorerUrl + `/address/${address}#code`) const url = new URL(this.explorerUrl + `/address/${address}#code`)
return url.href return url.href
} }

@ -0,0 +1,14 @@
import { EtherscanVerifier } from './EtherscanVerifier'
export class RoutescanVerifier extends EtherscanVerifier {
LOOKUP_STORE_DIR = 'routescan-verified'
// Routescan does not support proxy verification
verifyProxy = undefined
checkProxyVerificationStatus = undefined
getContractCodeUrl(address: string, chainId: string): string {
const url = new URL(this.explorerUrl + `/address/${address}/contract/${chainId}/code`)
return url.href
}
}

@ -3,11 +3,13 @@ import { AbstractVerifier } from './AbstractVerifier'
import { BlockscoutVerifier } from './BlockscoutVerifier' import { BlockscoutVerifier } from './BlockscoutVerifier'
import { EtherscanVerifier } from './EtherscanVerifier' import { EtherscanVerifier } from './EtherscanVerifier'
import { SourcifyVerifier } from './SourcifyVerifier' import { SourcifyVerifier } from './SourcifyVerifier'
import { RoutescanVerifier } from './RoutescanVerifier'
export { AbstractVerifier } from './AbstractVerifier' export { AbstractVerifier } from './AbstractVerifier'
export { BlockscoutVerifier } from './BlockscoutVerifier' export { BlockscoutVerifier } from './BlockscoutVerifier'
export { SourcifyVerifier } from './SourcifyVerifier' export { SourcifyVerifier } from './SourcifyVerifier'
export { EtherscanVerifier } from './EtherscanVerifier' export { EtherscanVerifier } from './EtherscanVerifier'
export { RoutescanVerifier } from './RoutescanVerifier'
export function getVerifier(identifier: VerifierIdentifier, settings: VerifierSettings): AbstractVerifier { export function getVerifier(identifier: VerifierIdentifier, settings: VerifierSettings): AbstractVerifier {
switch (identifier) { switch (identifier) {
@ -26,5 +28,7 @@ export function getVerifier(identifier: VerifierIdentifier, settings: VerifierSe
return new EtherscanVerifier(settings.apiUrl, settings.explorerUrl, settings.apiKey) return new EtherscanVerifier(settings.apiUrl, settings.explorerUrl, settings.apiKey)
case 'Blockscout': case 'Blockscout':
return new BlockscoutVerifier(settings.apiUrl) return new BlockscoutVerifier(settings.apiUrl)
case 'Routescan':
return new RoutescanVerifier(settings.apiUrl, settings.explorerUrl, settings.apiKey)
} }
} }

@ -88,7 +88,7 @@ const ReceiptsBody = ({ receipts }: { receipts: VerificationReceipt[] }) => {
return ( return (
<ul className="list-group"> <ul className="list-group">
{receipts.map((receipt) => ( {receipts.map((receipt) => (
<li className="list-group-item"> <li key={`${receipt.contractId}-${receipt.verifierInfo.name}${receipt.isProxyReceipt ? '-proxy' : ''}-${receipt.receiptId}`} className="list-group-item">
<CustomTooltip placement="top" tooltipClasses=" text-break" tooltipText={`API: ${receipt.verifierInfo.apiUrl}`}> <CustomTooltip placement="top" tooltipClasses=" text-break" tooltipText={`API: ${receipt.verifierInfo.apiUrl}`}>
<span className="font-weight-bold medium">{receipt.verifierInfo.name}</span> <span className="font-weight-bold medium">{receipt.verifierInfo.name}</span>
</CustomTooltip> </CustomTooltip>

@ -17,8 +17,8 @@ export interface Chain {
infoURL?: string infoURL?: string
} }
export type VerifierIdentifier = 'Sourcify' | 'Etherscan' | 'Blockscout' export type VerifierIdentifier = 'Sourcify' | 'Etherscan' | 'Blockscout' | 'Routescan'
export const VERIFIERS: VerifierIdentifier[] = ['Sourcify', 'Etherscan', 'Blockscout'] export const VERIFIERS: VerifierIdentifier[] = ['Sourcify', 'Etherscan', 'Blockscout', 'Routescan']
export interface VerifierInfo { export interface VerifierInfo {
name: VerifierIdentifier name: VerifierIdentifier

@ -572,5 +572,329 @@
"81247166294": { "81247166294": {
"apiUrl": "https://testnet.otoscan.io" "apiUrl": "https://testnet.otoscan.io"
} }
},
"Routescan": {
"explorerUrl": "https://routescan.io",
"8453": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/8453/etherscan"
},
"167000": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/167000/etherscan"
},
"357": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/357/etherscan"
},
"1": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/1/etherscan"
},
"19": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/19/etherscan"
},
"10": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/10/etherscan"
},
"81457": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/81457/etherscan"
},
"53935": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/53935/etherscan"
},
"432204": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/432204/etherscan"
},
"480": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/480/etherscan"
},
"14": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/14/etherscan"
},
"5000": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/5000/etherscan"
},
"254": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/254/etherscan"
},
"43114": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/43114/etherscan"
},
"7777777": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/7777777/etherscan"
},
"324": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/324/etherscan"
},
"7560": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/7560/etherscan"
},
"185": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/185/etherscan"
},
"888888888": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/888888888/etherscan"
},
"34443": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/34443/etherscan"
},
"88888": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/88888/etherscan"
},
"20240603": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/20240603/etherscan"
},
"6119": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/6119/etherscan"
},
"291": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/291/etherscan"
},
"252": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/252/etherscan"
},
"1088": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/1088/etherscan"
},
"8008": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/8008/etherscan"
},
"288": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/288/etherscan"
},
"65536": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/65536/etherscan"
},
"424": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/424/etherscan"
},
"183": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/183/etherscan"
},
"33979": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/33979/etherscan"
},
"10849": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/10849/etherscan"
},
"2044": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/2044/etherscan"
},
"8888": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/8888/etherscan"
},
"1853": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/1853/etherscan"
},
"56288": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/56288/etherscan"
},
"710420": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/710420/etherscan"
},
"4337": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/4337/etherscan"
},
"333000333": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/333000333/etherscan"
},
"3011": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/3011/etherscan"
},
"1234": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/1234/etherscan"
},
"504441": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/504441/etherscan"
},
"7887": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/7887/etherscan"
},
"7979": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/7979/etherscan"
},
"10507": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/10507/etherscan"
},
"5566": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/5566/etherscan"
},
"151": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/151/etherscan"
},
"62707": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/62707/etherscan"
},
"70953": {
"apiUrl": "https://api.routescan.io/v2/network/mainnet/evm/70953/etherscan"
},
"64165": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/64165/etherscan"
},
"49321": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/49321/etherscan"
},
"80084": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/80084/etherscan"
},
"84532": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/84532/etherscan"
},
"70805": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/70805/etherscan"
},
"421614": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/421614/etherscan"
},
"11155111": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/11155111/etherscan"
},
"1946": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/1946/etherscan"
},
"17000": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/17000/etherscan"
},
"11155420": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/11155420/etherscan"
},
"16": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/16/etherscan"
},
"168587773": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/168587773/etherscan"
},
"919": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/919/etherscan"
},
"999999999": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/999999999/etherscan"
},
"4801": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/4801/etherscan"
},
"2233": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/2233/etherscan"
},
"114": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/114/etherscan"
},
"4460": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/4460/etherscan"
},
"2522": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/2522/etherscan"
},
"20241133": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/20241133/etherscan"
},
"233": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/233/etherscan"
},
"28122024": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/28122024/etherscan"
},
"10888": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/10888/etherscan"
},
"80008": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/80008/etherscan"
},
"3397901": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/3397901/etherscan"
},
"9728": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/9728/etherscan"
},
"1687": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/1687/etherscan"
},
"28882": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/28882/etherscan"
},
"88882": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/88882/etherscan"
},
"43113": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/43113/etherscan"
},
"164": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/164/etherscan"
},
"111557560": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/111557560/etherscan"
},
"167009": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/167009/etherscan"
},
"920637907288165": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/920637907288165/etherscan"
},
"153": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/153/etherscan"
},
"335": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/335/etherscan"
},
"432201": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/432201/etherscan"
},
"9270": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/9270/etherscan"
},
"7589": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/7589/etherscan"
},
"686669576": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/686669576/etherscan"
},
"431234": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/431234/etherscan"
},
"3939": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/3939/etherscan"
},
"26659": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/26659/etherscan"
},
"3012": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/3012/etherscan"
},
"555666": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/555666/etherscan"
},
"7210": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/7210/etherscan"
},
"173750": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/173750/etherscan"
},
"7222": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/7222/etherscan"
},
"779672": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/779672/etherscan"
},
"749": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/749/etherscan"
},
"167008": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/167008/etherscan"
},
"31335": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/31335/etherscan"
},
"80085": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/80085/etherscan"
},
"10880": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/10880/etherscan"
},
"55551": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/55551/etherscan"
},
"25043": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/25043/etherscan"
},
"8082": {
"apiUrl": "https://api.routescan.io/v2/network/testnet/evm/8082/etherscan"
}
} }
} }

@ -13,6 +13,8 @@ export function mergeChainSettingsWithDefaults(chainId: string, userSettings: Co
let defaultsForVerifier: VerifierSettings let defaultsForVerifier: VerifierSettings
if (verifierId === 'Sourcify') { if (verifierId === 'Sourcify') {
defaultsForVerifier = DEFAULT_APIS['Sourcify'] defaultsForVerifier = DEFAULT_APIS['Sourcify']
} else if (verifierId === 'Routescan') {
defaultsForVerifier = { ...DEFAULT_APIS['Routescan'][chainId], explorerUrl: DEFAULT_APIS['Routescan'].explorerUrl }
} else { } else {
defaultsForVerifier = DEFAULT_APIS[verifierId][chainId] ?? {} defaultsForVerifier = DEFAULT_APIS[verifierId][chainId] ?? {}
} }

@ -61,9 +61,9 @@ export const LookupView = () => {
} }
const sendToMatomo = async (eventAction: string, eventName: string) => { const sendToMatomo = async (eventAction: string, eventName: string) => {
await clientInstance.call('matomo' as any, 'track', ['trackEvent', 'ContractVerification', eventAction, eventName]); await clientInstance.call('matomo' as any, 'track', ['trackEvent', 'ContractVerification', eventAction, eventName])
} }
const handleOpenInRemix = async (lookupResponse: LookupResponse) => { const handleOpenInRemix = async (lookupResponse: LookupResponse) => {
for (const source of lookupResponse.sourceFiles ?? []) { for (const source of lookupResponse.sourceFiles ?? []) {
try { try {
@ -74,7 +74,7 @@ export const LookupView = () => {
} }
try { try {
await clientInstance.call('fileManager', 'open', lookupResponse.targetFilePath) await clientInstance.call('fileManager', 'open', lookupResponse.targetFilePath)
await sendToMatomo('lookup', "openInRemix On: " + selectedChain) await sendToMatomo('lookup', 'openInRemix On: ' + selectedChain)
} catch (err) { } catch (err) {
console.error(`Error focusing file ${lookupResponse.targetFilePath}: ${err.message}`) console.error(`Error focusing file ${lookupResponse.targetFilePath}: ${err.message}`)
} }
@ -84,20 +84,13 @@ export const LookupView = () => {
<> <>
<form onSubmit={handleLookup}> <form onSubmit={handleLookup}>
<SearchableChainDropdown label="Chain" id="network-dropdown" selectedChain={selectedChain} setSelectedChain={setSelectedChain} /> <SearchableChainDropdown label="Chain" id="network-dropdown" selectedChain={selectedChain} setSelectedChain={setSelectedChain} />
<ContractAddressInput <ContractAddressInput label="Contract Address" id="contract-address" contractAddress={contractAddress} setContractAddress={setContractAddress} contractAddressError={contractAddressError} setContractAddressError={setContractAddressError} />
label="Contract Address"
id="contract-address"
contractAddress={contractAddress}
setContractAddress={setContractAddress}
contractAddressError={contractAddressError}
setContractAddressError={setContractAddressError}
/>
<button type="submit" className="btn w-100 btn-primary" disabled={submitDisabled}> <button type="submit" className="btn w-100 btn-primary" disabled={submitDisabled}>
Lookup Lookup
</button> </button>
</form> </form>
<div className="pt-3"> <div className="pt-3">
{ chainSettings && {chainSettings &&
VERIFIERS.map((verifierId) => { VERIFIERS.map((verifierId) => {
if (!validConfiguration(chainSettings, verifierId)) { if (!validConfiguration(chainSettings, verifierId)) {
return ( return (
@ -131,8 +124,9 @@ export const LookupView = () => {
return ( return (
<div key={verifierId} className="pt-4"> <div key={verifierId} className="pt-4">
<div> <div className="d-flex align-items-center">
<span className="font-weight-bold">{verifierId}</span> <span className="text-secondary">{chainSettings.verifiers[verifierId].apiUrl}</span> <span className="font-weight-bold">{verifierId}&nbsp;</span>
<span className="text-secondary d-inline-block text-truncate mw-100">{chainSettings.verifiers[verifierId].apiUrl}</span>
</div> </div>
{!!loadingVerifiers[verifierId] && ( {!!loadingVerifiers[verifierId] && (
<div className="pt-2 d-flex justify-content-center"> <div className="pt-2 d-flex justify-content-center">
@ -159,8 +153,7 @@ export const LookupView = () => {
)} )}
</div> </div>
) )
}) })}
}
</div> </div>
</> </>
) )

@ -9,7 +9,7 @@ export const ReceiptsView = () => {
return ( return (
<div> <div>
{contracts.length > 0 ? contracts.map((contract, index) => ( {contracts.length > 0 ? contracts.map((contract, index) => (
<AccordionReceipt contract={contract} index={index} /> <AccordionReceipt key={contract.id} contract={contract} index={index} />
)) : <div className="text-center mt-5" data-id="noContractsSubmitted">No contracts submitted for verification</div>} )) : <div className="text-center mt-5" data-id="noContractsSubmitted">No contracts submitted for verification</div>}
</div> </div>
) )

@ -47,6 +47,12 @@ export const SettingsView = () => {
<span className="font-weight-bold">Blockscout - {selectedChain.name}</span> <span className="font-weight-bold">Blockscout - {selectedChain.name}</span>
<ConfigInput label="Instance URL" id="blockscout-api-url" secret={false} initialValue={chainSettings.verifiers['Blockscout']?.apiUrl ?? ''} saveResult={(result) => handleChange('Blockscout', 'apiUrl', result)} /> <ConfigInput label="Instance URL" id="blockscout-api-url" secret={false} initialValue={chainSettings.verifiers['Blockscout']?.apiUrl ?? ''} saveResult={(result) => handleChange('Blockscout', 'apiUrl', result)} />
</div> </div>
<div className="p-2 my-2 border">
<span className="font-weight-bold">Routescan - {selectedChain.name}</span>
<ConfigInput label="API Key (optional)" id="routescan-api-key" secret={true} initialValue={chainSettings.verifiers['Routescan']?.apiKey ?? ''} saveResult={(result) => handleChange('Routescan', 'apiKey', result)} />
<ConfigInput label="API URL" id="routescan-api-url" secret={false} initialValue={chainSettings.verifiers['Routescan']?.apiUrl ?? ''} saveResult={(result) => handleChange('Routescan', 'apiUrl', result)} />
<ConfigInput label="Explorer URL" id="routescan-explorer-url" secret={false} initialValue={chainSettings.verifiers['Routescan']?.explorerUrl ?? ''} saveResult={(result) => handleChange('Routescan', 'explorerUrl', result)} />
</div>
</div> </div>
)} )}
</> </>

@ -41,14 +41,13 @@ export const VerifyView = () => {
setEnabledVerifiers({ ...enabledVerifiers, [verifierId]: checked }) setEnabledVerifiers({ ...enabledVerifiers, [verifierId]: checked })
} }
const sendToMatomo = async (eventAction: string, eventName: string) => { const sendToMatomo = async (eventAction: string, eventName: string) => {
await clientInstance.call("matomo" as any, 'track', ['trackEvent', 'ContractVerification', eventAction, eventName]); await clientInstance.call("matomo" as any, 'track', ['trackEvent', 'ContractVerification', eventAction, eventName]);
} }
const handleVerify = async (e) => { const handleVerify = async (e) => {
e.preventDefault() e.preventDefault()
const { triggerFilePath, filePath, contractName } = selectedContract const { triggerFilePath, filePath, contractName } = selectedContract
const compilerAbstract = compilationOutput[triggerFilePath] const compilerAbstract = compilationOutput[triggerFilePath]
if (!compilerAbstract) { if (!compilerAbstract) {
@ -68,9 +67,10 @@ export const VerifyView = () => {
name: verifierId as VerifierIdentifier, name: verifierId as VerifierIdentifier,
} }
receipts.push({ verifierInfo, status: 'pending', contractId, isProxyReceipt: false, failedChecks: 0 }) receipts.push({ verifierInfo, status: 'pending', contractId, isProxyReceipt: false, failedChecks: 0 })
if (enabledVerifiers.Blockscout) await sendToMatomo('verify', "verifyWith: Blockscout On: " + selectedChain?.chainId + " IsProxy: " + (hasProxy && !proxyAddress)) if (enabledVerifiers.Blockscout) await sendToMatomo('verify', "verifyWith: Blockscout On: " + selectedChain?.chainId + " IsProxy: " + (hasProxy && proxyAddress))
if (enabledVerifiers.Etherscan) await sendToMatomo('verify', "verifyWithEtherscan On: " + selectedChain?.chainId + " IsProxy: " + (hasProxy && !proxyAddress)) if (enabledVerifiers.Etherscan) await sendToMatomo('verify', "verifyWithEtherscan On: " + selectedChain?.chainId + " IsProxy: " + (hasProxy && proxyAddress))
if (enabledVerifiers.Sourcify) await sendToMatomo('verify', "verifyWithSourcify On: " + selectedChain?.chainId + " IsProxy: " + (hasProxy && !proxyAddress)) if (enabledVerifiers.Sourcify) await sendToMatomo('verify', "verifyWithSourcify On: " + selectedChain?.chainId + " IsProxy: " + (hasProxy && proxyAddress))
if (enabledVerifiers.Routescan) await sendToMatomo('verify', "verifyWithRoutescan On: " + selectedChain?.chainId + " IsProxy: " + (hasProxy && proxyAddress))
} }
const newSubmittedContract: SubmittedContract = { const newSubmittedContract: SubmittedContract = {
@ -256,7 +256,7 @@ export const VerifyView = () => {
</span> </span>
</CustomTooltip> </CustomTooltip>
) : ( ) : (
<span className="text-secondary">{chainSettings.verifiers[verifierId].apiUrl}</span> <span className="text-secondary d-inline-block text-truncate mw-100">{chainSettings.verifiers[verifierId].apiUrl}</span>
)} )}
</div> </div>
</div> </div>
@ -269,7 +269,7 @@ export const VerifyView = () => {
!selectedContract ? "Please select the contract (compile if needed)." : !selectedContract ? "Please select the contract (compile if needed)." :
((hasProxy && !!proxyAddressError) || (hasProxy && !proxyAddress)) ? "Please provide a valid proxy contract address." : ((hasProxy && !!proxyAddressError) || (hasProxy && !proxyAddress)) ? "Please provide a valid proxy contract address." :
"Please provide all necessary data to verify") // Is not expected to be a case "Please provide all necessary data to verify") // Is not expected to be a case
: "Verify with selected tools"}> : "Verify with selected tools"}>
<button type="submit" className="w-100 btn btn-primary mt-3" disabled={submitDisabled}> <button type="submit" className="w-100 btn btn-primary mt-3" disabled={submitDisabled}>
Verify Verify
</button> </button>

Loading…
Cancel
Save