Skip to content

Commit

Permalink
Merge pull request #4276 from ethereum/fix-proxy-verification
Browse files Browse the repository at this point in the history
Refactor Etherscan Contract Verification Plugin
  • Loading branch information
yann300 authored Dec 5, 2023
2 parents 79228da + 80c46f7 commit e40bc47
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 61 deletions.
3 changes: 2 additions & 1 deletion apps/etherscan/src/app/AppContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,6 @@ export const AppContext = React.createContext({
themeType: 'dark' as ThemeType,
setThemeType: (themeType: ThemeType) => {
console.log('Calling Set Theme Type')
}
},
networkName: ''
})
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
import {PluginClient} from '@remixproject/plugin'
import { createClient } from '@remixproject/plugin-webview'
import {verify, EtherScanReturn} from './utils/verify'
import {getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus} from './utils'
import EventManager from 'events'

export class RemixClient extends PluginClient {
loaded() {
return this.onload()
export class EtherscanPluginClient extends PluginClient {
public internalEvents: EventManager

constructor() {
super()
createClient(this)
this.internalEvents = new EventManager()
this.onload()
}

onActivation(): void {
this.internalEvents.emit('etherscan_activated')
}

async verify(
Expand Down
67 changes: 27 additions & 40 deletions apps/etherscan/src/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import React, {useState, useEffect, useRef} from 'react'

import {CompilationFileSources, CompilationResult} from '@remixproject/plugin-api'

import {RemixClient} from './RemixPlugin'
import {createClient} from '@remixproject/plugin-webview'
import { EtherscanPluginClient } from './EtherscanPluginClient'

import {AppContext} from './AppContext'
import {DisplayRoutes} from './routes'
Expand All @@ -21,32 +20,29 @@ export const getNewContractNames = (compilationResult: CompilationResult) => {

for (const file of Object.keys(compiledContracts)) {
const newContractNames = Object.keys(compiledContracts[file])

result = [...result, ...newContractNames]
}

return result
}

const plugin = new EtherscanPluginClient()

const App = () => {
const [apiKey, setAPIKey] = useLocalStorage('apiKey', '')
const [clientInstance, setClientInstance] = useState(undefined as any)
const [receipts, setReceipts] = useLocalStorage('receipts', [])
const [contracts, setContracts] = useState([] as string[])
const [themeType, setThemeType] = useState('dark' as ThemeType)
const [receipts, setReceipts] = useLocalStorage('receipts', [])
const [contracts, setContracts] = useState<string[]>([])
const [themeType, setThemeType] = useState<ThemeType>('dark')
const [networkName, setNetworkName] = useState('Loading...')
const timer = useRef(null)

const clientInstanceRef = useRef(clientInstance)
clientInstanceRef.current = clientInstance
const contractsRef = useRef(contracts)

contractsRef.current = contracts

useEffect(() => {
const client = new RemixClient()
createClient(client)
const loadClient = async () => {
await client.onload()
setClientInstance(client)
client.on('solidity', 'compilationFinished', (fileName: string, source: CompilationFileSources, languageVersion: string, data: CompilationResult) => {
plugin.internalEvents.on('etherscan_activated', () => {
plugin.on('solidity', 'compilationFinished', (fileName: string, source: CompilationFileSources, languageVersion: string, data: CompilationResult) => {
const newContractsNames = getNewContractNames(data)

const newContractsToSave: string[] = [...contractsRef.current, ...newContractsNames]
Expand All @@ -55,37 +51,29 @@ const App = () => {

setContracts(uniqueContracts)
})

//const currentTheme = await client.call("theme", "currentTheme")
//setThemeType(currentTheme.quality)
//client.on("theme", "themeChanged", (theme) => {
// setThemeType(theme.quality)
//})
}

loadClient()
plugin.on('blockchain' as any, 'networkStatus', (result) => {
setNetworkName(`${result.network.name} ${result.network.id !== '-' ? `(Chain id: ${result.network.id})` : '(Not supported)'}`)
})
// @ts-ignore
plugin.call('blockchain', 'getCurrentNetworkStatus').then((result: any) => setNetworkName(`${result.network.name} ${result.network.id !== '-' ? `(Chain id: ${result.network.id})` : '(Not supported)'}`))
})
}, [])

useEffect(() => {
let receiptsNotVerified: Receipt[] = receipts.filter((item: Receipt) => {
return item.status === 'Pending in queue' || item.status === 'Max rate limit reached'
})
let receiptsNotVerified: Receipt[] = receipts.filter((item: Receipt) => item.status === 'Pending in queue' || item.status === 'Max rate limit reached')

if (receiptsNotVerified.length > 0) {
if (timer.current) {
clearInterval(timer.current)
timer.current = null
}
timer.current = setInterval(async () => {
const {network, networkId} = await getNetworkName(clientInstanceRef.current)
if (!clientInstanceRef.current) {
return
}
const {network, networkId} = await getNetworkName(plugin)

if (network === 'vm') {
return
}
if (!plugin) return
if (network === 'vm') return
let newReceipts = receipts

for (const item of receiptsNotVerified) {
await new Promise((r) => setTimeout(r, 500)) // avoid api rate limit exceed.
let status
Expand All @@ -110,9 +98,7 @@ const App = () => {
})
}
}
receiptsNotVerified = newReceipts.filter((item: Receipt) => {
return item.status === 'Pending in queue' || item.status === 'Max rate limit reached'
})
receiptsNotVerified = newReceipts.filter((item: Receipt) => item.status === 'Pending in queue' || item.status === 'Max rate limit reached')
if (timer.current && receiptsNotVerified.length === 0) {
clearInterval(timer.current)
timer.current = null
Expand All @@ -127,16 +113,17 @@ const App = () => {
value={{
apiKey,
setAPIKey,
clientInstance,
clientInstance: plugin,
receipts,
setReceipts,
contracts,
setContracts,
themeType,
setThemeType
setThemeType,
networkName
}}
>
<DisplayRoutes />
{ plugin && <DisplayRoutes /> }
</AppContext.Provider>
)
}
Expand Down
3 changes: 2 additions & 1 deletion apps/etherscan/src/app/views/HomeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {VerifyView} from './VerifyView'
export const HomeView: React.FC = () => {
return (
<AppContext.Consumer>
{({apiKey, clientInstance, setReceipts, receipts, contracts}) => {
{({apiKey, clientInstance, setReceipts, receipts, contracts, networkName}) => {
return !apiKey ? (
<Navigate
to={{
Expand All @@ -26,6 +26,7 @@ export const HomeView: React.FC = () => {
const newReceipts = [...receipts, receipt]
setReceipts(newReceipts)
}}
networkName={networkName}
/>
)
}}
Expand Down
18 changes: 3 additions & 15 deletions apps/etherscan/src/app/views/VerifyView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ interface Props {
client: PluginClient
apiKey: string
onVerifiedContract: (receipt: Receipt) => void
contracts: string[]
contracts: string[],
networkName: string
}

interface FormValues {
Expand All @@ -23,27 +24,14 @@ interface FormValues {
expectedImplAddress?: string
}

export const VerifyView: React.FC<Props> = ({apiKey, client, contracts, onVerifiedContract}) => {
export const VerifyView: React.FC<Props> = ({apiKey, client, contracts, onVerifiedContract, networkName}) => {
const [results, setResults] = useState('')
const [networkName, setNetworkName] = useState('Loading...')
const [selectedContract, setSelectedContract] = useState('')
const [showConstructorArgs, setShowConstructorArgs] = useState(false)
const [isProxyContract, setIsProxyContract] = useState(false)
const [constructorInputs, setConstructorInputs] = useState([])
const verificationResult = useRef({})

useEffect(() => {
if (client && client.on) {
client.on('blockchain' as any, 'networkStatus', (result) => {
setNetworkName(`${result.network.name} ${result.network.id !== '-' ? `(Chain id: ${result.network.id})` : '(Not supported)'}`)
})
}
return () => {
// To fix memory leak
if (client && client.off) client.off('blockchain' as any, 'networkStatus')
}
}, [client])

useEffect(() => {
if (contracts.includes(selectedContract)) updateConsFields(selectedContract)
}, [contracts])
Expand Down
2 changes: 1 addition & 1 deletion apps/remix-ide/src/blockchain/blockchain.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const profile = {
name: 'blockchain',
displayName: 'Blockchain',
description: 'Blockchain - Logic',
methods: ['getCode', 'getTransactionReceipt', 'addProvider', 'removeProvider', 'getCurrentFork', 'getAccounts', 'web3VM', 'web3', 'getProvider'],
methods: ['getCode', 'getTransactionReceipt', 'addProvider', 'removeProvider', 'getCurrentFork', 'getAccounts', 'web3VM', 'web3', 'getProvider', 'getCurrentNetworkStatus'],
version: packageJson.version
}

Expand Down

0 comments on commit e40bc47

Please sign in to comment.