Check valid chains for Sourcify and disable Sourcify if not supported

pull/5285/head
Manuel Wedler 4 months ago committed by Aniket
parent ed1ce19c3f
commit 8d20a70afe
  1. 1
      apps/contract-verification/src/app/app.tsx
  2. 3
      apps/contract-verification/src/app/components/SearchableChainDropdown.tsx
  3. 33
      apps/contract-verification/src/app/hooks/useSourcifySupported.tsx
  4. 26
      apps/contract-verification/src/app/views/LookupView.tsx
  5. 6
      apps/contract-verification/src/app/views/SettingsView.tsx
  6. 29
      apps/contract-verification/src/app/views/VerifyView.tsx

@ -22,6 +22,7 @@ const App = () => {
const [submittedContracts, setSubmittedContracts] = useLocalStorage<SubmittedContracts>('contract-verification:submitted-contracts', {})
const [chains, setChains] = useState<Chain[]>([]) // State to hold the chains data
const [compilationOutput, setCompilationOutput] = useState<{ [key: string]: CompilerAbstract } | undefined>()
// Form values:
const [selectedChain, setSelectedChain] = useState<Chain | undefined>()
const [contractAddress, setContractAddress] = useState('')

@ -58,13 +58,14 @@ export const SearchableChainDropdown: React.FC<DropdownProps> = ({ label, id, se
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setIsOpen(false)
setSearchTerm(getChainDescriptor(selectedChain))
}
}
document.addEventListener('mousedown', handleClickOutside)
return () => {
document.removeEventListener('mousedown', handleClickOutside)
}
}, [])
}, [selectedChain])
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchTerm(e.target.value)

@ -0,0 +1,33 @@
import { useEffect, useState } from 'react'
import { Chain, ChainSettings } from '../types'
export function useSourcifySupported(selectedChain: Chain, chainSettings: ChainSettings): boolean {
const [sourcifySupported, setSourcifySupported] = useState(false)
useEffect(() => {
// Unsupported until fetch returns
setSourcifySupported(false)
const sourcifyApi = chainSettings?.verifiers['Sourcify']?.apiUrl
if (!sourcifyApi) {
return
}
const queriedChainId = selectedChain.chainId
const chainsUrl = new URL(sourcifyApi + '/chains')
fetch(chainsUrl.href, { method: 'GET' })
.then((response) => response.json())
.then((result: Array<{ chainId: number }>) => {
// Makes sure that the selectedChain didn't change while the request is running
if (selectedChain.chainId === queriedChainId && result.find((chain) => chain.chainId === queriedChainId)) {
setSourcifySupported(true)
}
})
.catch((error) => {
console.error('Failed to fetch chains.json:', error)
})
}, [selectedChain, chainSettings])
return sourcifySupported
}

@ -1,13 +1,14 @@
import { useContext, useEffect, useState } from 'react'
import { useContext, useEffect, useMemo, useState } from 'react'
import { SearchableChainDropdown, ContractAddressInput } from '../components'
import { mergeChainSettingsWithDefaults, validConfiguration } from '../utils'
import type { LookupResponse, VerifierIdentifier, Chain } from '../types'
import type { LookupResponse, VerifierIdentifier } from '../types'
import { VERIFIERS } from '../types'
import { AppContext } from '../AppContext'
import { CustomTooltip } from '@remix-ui/helper'
import { getVerifier } from '../Verifiers'
import { useNavigate } from 'react-router-dom'
import { VerifyFormContext } from '../VerifyFormContext'
import { useSourcifySupported } from '../hooks/useSourcifySupported'
export const LookupView = () => {
const { settings, clientInstance } = useContext(AppContext)
@ -18,7 +19,9 @@ export const LookupView = () => {
const [lookupResults, setLookupResult] = useState<Partial<Record<VerifierIdentifier, LookupResponse>>>({})
const navigate = useNavigate()
const chainSettings = selectedChain ? mergeChainSettingsWithDefaults(selectedChain.chainId.toString(), settings) : undefined
const chainSettings = useMemo(() => (selectedChain ? mergeChainSettingsWithDefaults(selectedChain.chainId.toString(), settings) : undefined), [selectedChain, settings])
const sourcifySupported = useSourcifySupported(selectedChain, chainSettings)
const submitDisabled = !!contractAddressError || !contractAddress || !selectedChain
@ -37,7 +40,7 @@ export const LookupView = () => {
e.preventDefault()
for (const verifierId of VERIFIERS) {
if (!validConfiguration(chainSettings, verifierId)) {
if (!validConfiguration(chainSettings, verifierId) || (verifierId === 'Sourcify' && !sourcifySupported)) {
continue
}
@ -100,6 +103,21 @@ export const LookupView = () => {
)
}
if (verifierId === 'Sourcify' && !sourcifySupported) {
return (
<div key={verifierId} className="pt-4">
<div>
<span className="font-weight-bold text-secondary">{verifierId}</span>{' '}
<CustomTooltip tooltipText={`The configured Sourcify server (${chainSettings.verifiers['Sourcify'].apiUrl}) does not support chain ${selectedChain?.chainId}`}>
<span className="text-secondary w-auto" style={{ textDecoration: 'underline dotted', cursor: 'pointer' }} onClick={() => navigate('/settings')}>
Unsupported
</span>
</CustomTooltip>
</div>
</div>
)
}
return (
<div key={verifierId} className="pt-4">
<div>

@ -1,6 +1,6 @@
import { useContext, useState } from 'react'
import { useContext, useMemo, useState } from 'react'
import { SearchableChainDropdown, ConfigInput } from '../components'
import type { VerifierIdentifier, Chain, VerifierSettings, ContractVerificationSettings } from '../types'
import type { VerifierIdentifier, VerifierSettings, ContractVerificationSettings } from '../types'
import { mergeChainSettingsWithDefaults } from '../utils'
import { AppContext } from '../AppContext'
import { VerifyFormContext } from '../VerifyFormContext'
@ -9,7 +9,7 @@ export const SettingsView = () => {
const { settings, setSettings } = useContext(AppContext)
const { selectedChain, setSelectedChain } = useContext(VerifyFormContext)
const chainSettings = selectedChain ? mergeChainSettingsWithDefaults(selectedChain.chainId.toString(), settings) : undefined
const chainSettings = useMemo(() => (selectedChain ? mergeChainSettingsWithDefaults(selectedChain.chainId.toString(), settings) : undefined), [selectedChain, settings])
const handleChange = (verifier: VerifierIdentifier, key: keyof VerifierSettings, value: string) => {
const chainId = selectedChain.chainId.toString()

@ -1,4 +1,4 @@
import { useContext, useEffect, useState } from 'react'
import { useContext, useEffect, useMemo, useState } from 'react'
import { AppContext } from '../AppContext'
import { SearchableChainDropdown, ContractDropdown, ContractAddressInput } from '../components'
@ -10,6 +10,7 @@ import { ConstructorArguments } from '../components/ConstructorArguments'
import { CustomTooltip } from '@remix-ui/helper'
import { AbstractVerifier, getVerifier } from '../Verifiers'
import { VerifyFormContext } from '../VerifyFormContext'
import { useSourcifySupported } from '../hooks/useSourcifySupported'
export const VerifyView = () => {
const { compilationOutput, setSubmittedContracts, settings } = useContext(AppContext)
@ -18,7 +19,9 @@ export const VerifyView = () => {
const [hasProxy, setHasProxy] = useState(!!proxyAddress)
const navigate = useNavigate()
const chainSettings = selectedChain ? mergeChainSettingsWithDefaults(selectedChain.chainId.toString(), settings) : undefined
const chainSettings = useMemo(() => (selectedChain ? mergeChainSettingsWithDefaults(selectedChain.chainId.toString(), settings) : undefined), [selectedChain, settings])
const sourcifySupported = useSourcifySupported(selectedChain, chainSettings)
const submitDisabled = !!contractAddressError || !contractAddress || !selectedChain || !selectedContract || (hasProxy && !!proxyAddressError) || (hasProxy && !proxyAddress)
@ -26,12 +29,12 @@ export const VerifyView = () => {
useEffect(() => {
const changedEnabledVerifiers = {}
for (const verifierId of VERIFIERS) {
if (validConfiguration(chainSettings, verifierId)) {
if (validConfiguration(chainSettings, verifierId) && (verifierId !== 'Sourcify' || sourcifySupported)) {
changedEnabledVerifiers[verifierId] = true
}
}
setEnabledVerifiers(changedEnabledVerifiers)
}, [selectedChain])
}, [selectedChain, sourcifySupported])
const handleVerifierCheckboxClick = (verifierId: VerifierIdentifier, checked: boolean) => {
setEnabledVerifiers({ ...enabledVerifiers, [verifierId]: checked })
@ -174,24 +177,32 @@ export const VerifyView = () => {
<div className="pt-3">
Verify on:
{VERIFIERS.map((verifierId) => {
const disabledVerifier = !chainSettings || !validConfiguration(chainSettings, verifierId) || (verifierId === 'Sourcify' && !sourcifySupported)
return (
<div key={verifierId} className="pt-2 form-check">
<input className="form-check-input" type="checkbox" id={`verifier-${verifierId}`} checked={!!enabledVerifiers[verifierId]} onChange={(e) => handleVerifierCheckboxClick(verifierId, e.target.checked)} disabled={!chainSettings || !validConfiguration(chainSettings, verifierId)} />
<input className="form-check-input" type="checkbox" id={`verifier-${verifierId}`} checked={!!enabledVerifiers[verifierId]} onChange={(e) => handleVerifierCheckboxClick(verifierId, e.target.checked)} disabled={disabledVerifier} />
<div className="d-flex flex-column align-items-start">
<label htmlFor={`verifier-${verifierId}`} style={{ fontSize: '1rem', lineHeight: '1.5', color: 'var(--text)' }} className={`mb-0 font-weight-bold${!chainSettings || validConfiguration(chainSettings, verifierId) ? '' : ' text-secondary'}`}>
<label htmlFor={`verifier-${verifierId}`} style={{ fontSize: '1rem', lineHeight: '1.5', color: 'var(--text)' }} className={`mb-0 font-weight-bold${!disabledVerifier ? '' : ' text-secondary'}`}>
{verifierId}
</label>
{!chainSettings ? (
''
) : validConfiguration(chainSettings, verifierId) ? (
<span className="text-secondary">{chainSettings.verifiers[verifierId].apiUrl}</span>
) : (
) : !validConfiguration(chainSettings, verifierId) ? (
<CustomTooltip tooltipText="Configure the API in the settings">
<span className="text-secondary w-auto" style={{ textDecoration: 'underline dotted', cursor: 'pointer' }} onClick={() => navigate('/settings')}>
Enable?
</span>
</CustomTooltip>
) : verifierId === 'Sourcify' && !sourcifySupported ? (
<CustomTooltip tooltipText={`The configured Sourcify server (${chainSettings.verifiers['Sourcify'].apiUrl}) does not support chain ${selectedChain?.chainId}`}>
<span className="text-secondary w-auto" style={{ textDecoration: 'underline dotted', cursor: 'pointer' }} onClick={() => navigate('/settings')}>
Unsupported
</span>
</CustomTooltip>
) : (
<span className="text-secondary">{chainSettings.verifiers[verifierId].apiUrl}</span>
)}
</div>
</div>

Loading…
Cancel
Save