diff --git a/apps/contract-verification/src/app/Receipts/SourcifyReceipt.tsx b/apps/contract-verification/src/app/Receipts/SourcifyReceipt.tsx index 066544c099..96bfa8e751 100644 --- a/apps/contract-verification/src/app/Receipts/SourcifyReceipt.tsx +++ b/apps/contract-verification/src/app/Receipts/SourcifyReceipt.tsx @@ -1,11 +1,11 @@ import React, { useState, useEffect } from 'react' import { SourcifyVerifier } from '../Verifiers/SourcifyVerifier' -import { SourcifyVerificationStatus } from '../types/VerificationTypes' +// 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 [status, setStatus] = useState< null>(null) const [submissionDate] = useState(new Date()) // This will be set once and not change useEffect(() => { diff --git a/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts b/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts index 89f5338dd6..1ea58fe9d6 100644 --- a/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts +++ b/apps/contract-verification/src/app/Verifiers/AbstractVerifier.ts @@ -1,5 +1,5 @@ import { CompilerAbstract } from '@remix-project/remix-solidity' -import { SubmittedContract, VerificationResponse, VerificationStatus } from '../types/VerificationTypes' +import { LookupResponse, SubmittedContract, VerificationResponse, VerificationStatus } from '../types/VerificationTypes' export interface AbstractVerifier { checkVerificationStatus?(receiptId: string): Promise @@ -16,5 +16,5 @@ export abstract class AbstractVerifier { } abstract verify(submittedContract: SubmittedContract, compilerAbstract: CompilerAbstract): Promise - abstract lookup(): Promise + abstract lookup(contractAddress: string, chainId: string): Promise } diff --git a/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts b/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts index f477dce6cf..c12fa5b3b1 100644 --- a/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts +++ b/apps/contract-verification/src/app/Verifiers/EtherscanVerifier.ts @@ -111,7 +111,7 @@ export class EtherscanVerifier extends AbstractVerifier { throw new Error(checkStatusResponse.result) } - let status = 'unknown' + let status: VerificationStatus = 'unknown' if (checkStatusResponse.result === 'Fail - Unable to verify') { status = 'failed' } diff --git a/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts index da37ee947a..db6ebde95f 100644 --- a/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts +++ b/apps/contract-verification/src/app/Verifiers/SourcifyVerifier.ts @@ -1,6 +1,6 @@ import { CompilerAbstract, SourcesCode } from '@remix-project/remix-solidity' import { AbstractVerifier } from './AbstractVerifier' -import { SubmittedContract, VerificationResponse } from '../types/VerificationTypes' +import { LookupResponse, SubmittedContract, VerificationResponse, VerificationStatus } from '../types/VerificationTypes' interface SourcifyVerificationRequest { address: string @@ -26,10 +26,17 @@ interface SourcifyVerificationResponse { ] } -interface SourcifyVerificationError { +interface SourcifyErrorResponse { error: 'string' } +interface SourcifyLookupResponse { + address: string + // Includes either chainIds or status key + chainIds?: Array<{ chainId: string; status: Exclude }> + status?: 'false' +} + export class SourcifyVerifier extends AbstractVerifier { async verify(submittedContract: SubmittedContract, compilerAbstract: CompilerAbstract): Promise { const metadataStr = compilerAbstract.data.contracts[submittedContract.filePath][submittedContract.contractName].metadata @@ -67,7 +74,7 @@ export class SourcifyVerifier extends AbstractVerifier { }) if (!response.ok) { - const errorResponse: SourcifyVerificationError = await response.json() + const errorResponse: SourcifyErrorResponse = await response.json() console.error('Error on Sourcify verification at ' + this.apiUrl + '\nStatus: ' + response.status + '\nResponse: ' + JSON.stringify(errorResponse)) throw new Error(errorResponse.error) } @@ -80,7 +87,7 @@ export class SourcifyVerifier extends AbstractVerifier { } // Map to a user-facing status message - let status = 'unknown' + let status: VerificationStatus = 'unknown' if (verificationResponse.result[0].status === 'perfect') { status = 'fully verified' } else if (verificationResponse.result[0].status === 'partial') { @@ -90,12 +97,30 @@ export class SourcifyVerifier extends AbstractVerifier { return { status, receiptId: null } } - 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 + async lookup(contractAddress: string, chainId: string): Promise { + const url = new URL('check-all-by-addresses', this.apiUrl) + url.searchParams.append('addresses', contractAddress) + url.searchParams.append('chainIds', chainId) + + const response = await fetch(url.href, { method: 'GET' }) + + if (!response.ok) { + const errorResponse: SourcifyErrorResponse = await response.json() + console.error('Error on Sourcify lookup at ' + this.apiUrl + '\nStatus: ' + response.status + '\nResponse: ' + JSON.stringify(errorResponse)) + throw new Error(errorResponse.error) + } + + const lookupResponse: SourcifyLookupResponse = (await response.json())[0] + + let status: VerificationStatus = 'unknown' + if (lookupResponse.status === 'false') { + status = 'not verified' + } else if (lookupResponse.chainIds?.[0].status === 'perfect') { + status = 'fully verified' + } else if (lookupResponse.chainIds?.[0].status === 'partial') { + status = 'partially verified' + } + + return { status } } } diff --git a/apps/contract-verification/src/app/types/VerificationTypes.ts b/apps/contract-verification/src/app/types/VerificationTypes.ts index 81521c4a5c..13c32393fe 100644 --- a/apps/contract-verification/src/app/types/VerificationTypes.ts +++ b/apps/contract-verification/src/app/types/VerificationTypes.ts @@ -17,7 +17,7 @@ export interface Chain { infoURL?: string } -export type VerifierIdentifier = "Sourcify" | "Etherscan" | "Blockscout" +export type VerifierIdentifier = 'Sourcify' | 'Etherscan' | 'Blockscout' export interface VerifierSettings { apiUrl: string @@ -68,9 +68,16 @@ export function isContract(contract: SubmittedContract | SubmittedProxyContract) return contract.type === 'contract' } -export type VerificationStatus = string | 'error' | 'pending' +type SourcifyStatus = 'fully verified' | 'partially verified' +type EtherscanStatus = 'verified' +export type VerificationStatus = SourcifyStatus | EtherscanStatus | 'failed' | 'pending' | 'not verified' | 'unknown' export interface VerificationResponse { status: VerificationStatus receiptId: string | null } + +export interface LookupResponse { + status: VerificationStatus + lookupUrl?: string // TODO How to construct these? Do we need another config value? +} diff --git a/apps/contract-verification/src/app/views/VerifyView.tsx b/apps/contract-verification/src/app/views/VerifyView.tsx index 9370594294..6471d5eed2 100644 --- a/apps/contract-verification/src/app/views/VerifyView.tsx +++ b/apps/contract-verification/src/app/views/VerifyView.tsx @@ -75,7 +75,7 @@ export const VerifyView = () => { } } catch (e) { const err = e as Error - receipt.status = 'error' + receipt.status = 'failed' receipt.message = err.message }