Add logic for LookupView

pull/5285/head
Manuel Wedler 4 months ago committed by Aniket
parent 34fc57c0fe
commit b1972669ec
  1. 2
      apps/contract-verification/src/app/App.css
  2. 2
      apps/contract-verification/src/app/Verifiers/BlockscoutVerifier.ts
  3. 6
      apps/contract-verification/src/app/Verifiers/index.ts
  4. 7
      apps/contract-verification/src/app/components/AccordionReceipt.tsx
  5. 8
      apps/contract-verification/src/app/components/ContractAddressInput.tsx
  6. 4
      apps/contract-verification/src/app/types/VerificationTypes.ts
  7. 10
      apps/contract-verification/src/app/types/defaults.ts
  8. 93
      apps/contract-verification/src/app/views/LookupView.tsx
  9. 3
      apps/contract-verification/src/app/views/VerifyView.tsx

@ -1,3 +1,5 @@
body {
margin: 0;
}
.fa-arrow-up-right-from-square::before { content: "\f08e"; }

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

@ -12,15 +12,15 @@ export { EtherscanVerifier } from './EtherscanVerifier'
export function getVerifier(identifier: VerifierIdentifier, settings: VerifierSettings): AbstractVerifier {
switch (identifier) {
case 'Sourcify':
if (!settings.explorerUrl) {
if (!settings?.explorerUrl) {
throw new Error('The Sourcify verifier requires an explorer URL.')
}
return new SourcifyVerifier(settings.apiUrl, settings.explorerUrl)
case 'Etherscan':
if (!settings.explorerUrl) {
if (!settings?.explorerUrl) {
throw new Error('The Etherscan verifier requires an explorer URL.')
}
if (!settings.apiKey) {
if (!settings?.apiKey) {
throw new Error('The Etherscan verifier requires an API key.')
}
return new EtherscanVerifier(settings.apiUrl, settings.explorerUrl, settings.apiKey)

@ -32,8 +32,8 @@ export const AccordionReceipt: React.FC<AccordionReceiptProps> = ({ contract, in
<span className="pl-4" style={{ fontSize: '1rem' }}>
<CustomTooltip tooltipText={address}>
<span>{shortenAddress(address)}</span>
</CustomTooltip>
&nbsp;on {chainName} {isProxy(contract) ? 'with proxy' : ''}
</CustomTooltip>{' '}
on {chainName} {isProxy(contract) ? 'with proxy' : ''}
</span>
</button>
</h3>
@ -52,8 +52,7 @@ export const AccordionReceipt: React.FC<AccordionReceiptProps> = ({ contract, in
<div className="mt-3">
<span className="font-weight-bold" style={{ fontSize: '1.2rem' }}>
Proxy
</span>
&nbsp;
</span>{' '}
<CustomTooltip tooltipText={contract.proxy.address}>
<span>{shortenAddress(contract.proxy.address)}</span>
</CustomTooltip>

@ -4,14 +4,14 @@ import { ethers } from 'ethers/'
interface ContractAddressInputProps {
label: string
id: string
setContractAddress: (address: string) => void
contractAddress: string
setContractAddress: (address: string) => void
contractAddressError: string
setContractAddressError: (error: string) => void
}
// Chooses one contract from the compilation output.
export const ContractAddressInput: React.FC<ContractAddressInputProps> = ({ label, id, setContractAddress, contractAddress }) => {
const [contractAddressError, setContractAddressError] = useState('')
export const ContractAddressInput: React.FC<ContractAddressInputProps> = ({ label, id, contractAddress, setContractAddress, contractAddressError, setContractAddressError }) => {
const handleAddressChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const isValidAddress = ethers.utils.isAddress(event.target.value)
setContractAddress(event.target.value)

@ -66,7 +66,7 @@ export function isContract(contract: SubmittedContract | SubmittedProxyContract)
type SourcifyStatus = 'fully verified' | 'partially verified'
type EtherscanStatus = 'verified'
export type VerificationStatus = SourcifyStatus | EtherscanStatus | 'failed' | 'pending' | 'not verified' | 'unknown'
export type VerificationStatus = SourcifyStatus | EtherscanStatus | 'failed' | 'pending' | 'not verified' | 'unknown' | 'lookup failed'
export interface VerificationResponse {
status: VerificationStatus
@ -75,5 +75,5 @@ export interface VerificationResponse {
export interface LookupResponse {
status: VerificationStatus
lookupUrl?: string // TODO How to construct these? Do we need another config value?
lookupUrl?: string
}

@ -3,16 +3,16 @@ import { VERIFIERS } from './VerificationTypes'
const DEFAULTS: SettingsForVerifier = {
Sourcify: {
apiUrl: 'https://sourcify.dev/server/',
explorerUrl: 'https://repo.sourcify.dev/',
apiUrl: 'https://sourcify.dev/server',
explorerUrl: 'https://repo.sourcify.dev',
},
Etherscan: {
apiUrl: 'https://api.etherscan.io/',
explorerUrl: 'https://etherscan.io/',
apiUrl: 'https://api.etherscan.io',
explorerUrl: 'https://etherscan.io',
apiKey: undefined,
},
Blockscout: {
apiUrl: 'https://eth.blockscout.com/',
apiUrl: 'https://eth.blockscout.com',
},
}

@ -1,22 +1,95 @@
import { useState } from 'react'
import { useContext, useState } from 'react'
import { SearchableChainDropdown, ContractAddressInput } from '../components'
import type { Chain } from '../types'
import { LookupResponse, mergeChainSettingsWithDefaults, VerifierIdentifier, VERIFIERS, type Chain } from '../types'
import { AppContext } from '../AppContext'
import { CustomTooltip } from '@remix-ui/helper'
import { getVerifier } from '../Verifiers'
export const LookupView = () => {
const { settings } = useContext(AppContext)
const [selectedChain, setSelectedChain] = useState<Chain | undefined>()
const [contractAddress, setContractAddress] = useState('')
const [contractAddressError, setContractAddressError] = useState('')
const [loadingVerifiers, setLoadingVerifiers] = useState<Partial<Record<VerifierIdentifier, boolean>>>({})
const [lookupResults, setLookupResult] = useState<Partial<Record<VerifierIdentifier, LookupResponse>>>({})
const handleLookup = () => {}
const chainSettings = selectedChain ? mergeChainSettingsWithDefaults(selectedChain.chainId.toString(), settings) : undefined
const handleLookup = () => {
for (const verifierId of VERIFIERS) {
if (!chainSettings.verifiers[verifierId]?.apiUrl || (verifierId === 'Etherscan' && !chainSettings.verifiers[verifierId]?.apiKey)) {
continue
}
setLoadingVerifiers((prev) => ({ ...prev, [verifierId]: true }))
console.log(chainSettings.verifiers[verifierId])
const verifier = getVerifier(verifierId, chainSettings.verifiers[verifierId])
verifier
.lookup(contractAddress, selectedChain.chainId.toString())
.then((result) => setLookupResult((prev) => ({ ...prev, [verifierId]: result })))
.catch((err) =>
setLookupResult((prev) => {
console.error(err)
return { ...prev, [verifierId]: { status: 'lookup failed' } }
})
)
.finally(() => setLoadingVerifiers((prev) => ({ ...prev, [verifierId]: false })))
}
}
return (
<form onSubmit={handleLookup}>
<SearchableChainDropdown label="Chain" id="network-dropdown" setSelectedChain={setSelectedChain} selectedChain={selectedChain} />
<>
<form onSubmit={handleLookup}>
<SearchableChainDropdown label="Chain" id="network-dropdown" selectedChain={selectedChain} setSelectedChain={setSelectedChain} />
<ContractAddressInput label="Contract Address" id="contract-address" contractAddress={contractAddress} setContractAddress={setContractAddress} contractAddressError={contractAddressError} setContractAddressError={setContractAddressError} />
<ContractAddressInput label="Contract Address" id="contract-address" setContractAddress={setContractAddress} contractAddress={contractAddress} />
<button type="submit" className="btn btn-primary" disabled={!!contractAddressError || !contractAddress || !selectedChain}>
Lookup
</button>
</form>
<div className="pt-3">
{chainSettings &&
VERIFIERS.map((verifierId) => {
if (!chainSettings.verifiers[verifierId]?.apiUrl || (verifierId === 'Etherscan' && !chainSettings.verifiers[verifierId]?.apiKey)) {
const tooltipText = 'Configure API in the settings'
return (
<div key={verifierId} className="pt-2">
<div>
<span className="font-weight-bold text-secondary">{verifierId}</span>{' '}
<CustomTooltip tooltipText="Configure the API in the settings">
<span className="text-secondary" style={{ textDecoration: 'underline dotted' }}>
Enable?
</span>
</CustomTooltip>
</div>
</div>
)
}
<button type="submit" className="btn btn-primary">
Lookup
</button>
</form>
return (
<div key={verifierId} className="pt-2">
<div>
<span className="font-weight-bold">{verifierId}</span> <span className="text-secondary">{chainSettings.verifiers[verifierId].apiUrl}</span>
</div>
{!!loadingVerifiers[verifierId] && (
<div className="pt-2 d-flex justify-content-center">
<i className="fas fa-spinner fa-spin fa-2x"></i>
</div>
)}
{!loadingVerifiers[verifierId] && !!lookupResults[verifierId] && (
<div>
Status:{' '}
<span className="font-weight-bold" style={{ textTransform: 'capitalize' }}>
{lookupResults[verifierId].status}
</span>{' '}
{!!lookupResults[verifierId].lookupUrl && <a href={lookupResults[verifierId].lookupUrl} target="_blank" className="fa fas fa-arrow-up-right-from-square"></a>}
</div>
)}
</div>
)
})}
</div>
</>
)
}

@ -16,6 +16,7 @@ export const VerifyView = () => {
const [selectedChain, setSelectedChain] = useState<Chain | undefined>()
const [abiEncodedConstructorArgs, setAbiEncodedConstructorArgs] = useState<string>('')
const [selectedContract, setSelectedContract] = useState<ContractDropdownSelection | undefined>()
const [contractAddressError, setContractAddressError] = useState('')
const navigate = useNavigate()
// TODO
@ -96,7 +97,7 @@ export const VerifyView = () => {
<form onSubmit={handleVerify}>
<SearchableChainDropdown label="Chain" id="network-dropdown" setSelectedChain={setSelectedChain} selectedChain={selectedChain} />
<ContractAddressInput label="Contract Address" id="contract-address" setContractAddress={setContractAddress} contractAddress={contractAddress} />
<ContractAddressInput label="Contract Address" id="contract-address" contractAddress={contractAddress} setContractAddress={setContractAddress} contractAddressError={contractAddressError} setContractAddressError={setContractAddressError} />
<ContractDropdown label="Contract Name" id="contract-dropdown-1" setSelectedContract={setSelectedContract} />

Loading…
Cancel
Save