Skip to content

Commit 8d63a86

Browse files
committed
Init contract-verification plugin and add it inside plugins
1 parent ffafebf commit 8d63a86

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1681
-139
lines changed

apps/contract-verification/.babelrc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"presets": ["@babel/preset-env", ["@babel/preset-react",
3+
{"runtime": "automatic"}
4+
]],
5+
"plugins": ["@babel/plugin-proposal-class-properties", "@babel/plugin-transform-runtime", "@babel/plugin-proposal-nullish-coalescing-operator"],
6+
"ignore": [
7+
"**/node_modules/**"
8+
]
9+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# This file is used by:
2+
# 1. autoprefixer to adjust CSS to support the below specified browsers
3+
# 2. babel preset-env to adjust included polyfills
4+
#
5+
# For additional information regarding the format and rule options, please see:
6+
# https://github.com/browserslist/browserslist#queries
7+
#
8+
# If you need to support different browsers in production, you may tweak the list below.
9+
10+
last 1 Chrome version
11+
last 1 Firefox version
12+
last 2 Edge major versions
13+
last 2 Safari major version
14+
last 2 iOS major versions
15+
Firefox ESR
16+
not IE 9-11 # For IE 9-11 support, remove 'not'.

apps/contract-verification/.eslintrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "../../.eslintrc.json",
3+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"extends": [
3+
"plugin:@nrwl/nx/react",
4+
"../../.eslintrc.json"
5+
],
6+
"ignorePatterns": [
7+
"!**/*"
8+
],
9+
"overrides": [
10+
{
11+
"files": [
12+
"*.ts",
13+
"*.tsx",
14+
"*.js",
15+
"*.jsx"
16+
],
17+
"rules": {}
18+
},
19+
{
20+
"files": [
21+
"*.ts",
22+
"*.tsx"
23+
],
24+
"rules": {}
25+
},
26+
{
27+
"files": [
28+
"*.js",
29+
"*.jsx"
30+
],
31+
"rules": {}
32+
}
33+
]
34+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
{
2+
"name": "contract-verification",
3+
"$schema": "../../node_modules/nx/schemas/project-schema.json",
4+
"sourceRoot": "apps/contract-verification/src",
5+
"projectType": "application",
6+
"targets": {
7+
"build": {
8+
"executor": "@nrwl/webpack:webpack",
9+
"outputs": ["{options.outputPath}"],
10+
"defaultConfiguration": "development",
11+
"options": {
12+
"compiler": "babel",
13+
"outputPath": "dist/apps/contract-verification",
14+
"index": "apps/contract-verification/src/index.html",
15+
"baseHref": "./",
16+
"main": "apps/contract-verification/src/main.tsx",
17+
"polyfills": "apps/contract-verification/src/polyfills.ts",
18+
"tsConfig": "apps/contract-verification/tsconfig.app.json",
19+
"assets": [
20+
"apps/contract-verification/src/favicon.ico",
21+
"apps/contract-verification/src/assets",
22+
"apps/contract-verification/src/profile.json"
23+
],
24+
"styles": ["apps/contract-verification/src/styles.css"],
25+
"scripts": [],
26+
"webpackConfig": "apps/contract-verification/webpack.config.js"
27+
},
28+
"configurations": {
29+
"development": {
30+
},
31+
"production": {
32+
"fileReplacements": [
33+
{
34+
"replace": "apps/contract-verification/src/environments/environment.ts",
35+
"with": "apps/contract-verification/src/environments/environment.prod.ts"
36+
}
37+
]
38+
}
39+
}
40+
},
41+
"lint": {
42+
"executor": "@nrwl/linter:eslint",
43+
"outputs": ["{options.outputFile}"],
44+
"options": {
45+
"lintFilePatterns": ["apps/contract-verification/**/*.ts"],
46+
"eslintConfig": "apps/contract-verification/.eslintrc"
47+
}
48+
},
49+
"serve": {
50+
"executor": "@nrwl/webpack:dev-server",
51+
"defaultConfiguration": "development",
52+
"options": {
53+
"buildTarget": "contract-verification:build",
54+
"hmr": true,
55+
"baseHref": "/"
56+
},
57+
"configurations": {
58+
"development": {
59+
"buildTarget": "contract-verification:build:development",
60+
"port": 5003
61+
},
62+
"production": {
63+
"buildTarget": "contract-verification:build:production"
64+
}
65+
}
66+
}
67+
},
68+
"tags": []
69+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
body {
2+
margin: 0;
3+
}
4+
5+
#root {
6+
padding: 8px 14px;
7+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react'
2+
import {PluginClient} from '@remixproject/plugin'
3+
4+
import {Receipt, ThemeType} from './types'
5+
6+
export const AppContext = React.createContext({
7+
apiKey: '',
8+
setAPIKey: (value: string) => {
9+
console.log('Set API Key from Context')
10+
},
11+
clientInstance: {} as PluginClient,
12+
receipts: [] as Receipt[],
13+
setReceipts: (receipts: Receipt[]) => {
14+
console.log('Calling Set Receipts')
15+
},
16+
contracts: [] as string[],
17+
setContracts: (contracts: string[]) => {
18+
console.log('Calling Set Contract Names')
19+
},
20+
themeType: 'dark' as ThemeType,
21+
setThemeType: (themeType: ThemeType) => {
22+
console.log('Calling Set Theme Type')
23+
},
24+
networkName: ''
25+
})
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { PluginClient } from '@remixproject/plugin'
2+
import { createClient } from '@remixproject/plugin-webview'
3+
import { verify, EtherScanReturn } from './utils/verify'
4+
import { getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus } from './utils'
5+
import EventManager from 'events'
6+
7+
export class EtherscanPluginClient extends PluginClient {
8+
public internalEvents: EventManager
9+
10+
constructor() {
11+
super()
12+
this.internalEvents = new EventManager()
13+
createClient(this)
14+
this.onload()
15+
}
16+
17+
onActivation(): void {
18+
this.internalEvents.emit('etherscan_activated')
19+
}
20+
21+
async verify(
22+
apiKey: string,
23+
contractAddress: string,
24+
contractArguments: string,
25+
contractName: string,
26+
compilationResultParam: any,
27+
chainRef?: number | string,
28+
isProxyContract?: boolean,
29+
expectedImplAddress?: string
30+
) {
31+
const result = await verify(
32+
apiKey,
33+
contractAddress,
34+
contractArguments,
35+
contractName,
36+
compilationResultParam,
37+
chainRef,
38+
isProxyContract,
39+
expectedImplAddress,
40+
this,
41+
(value: EtherScanReturn) => {},
42+
(value: string) => {}
43+
)
44+
return result
45+
}
46+
47+
async receiptStatus(receiptGuid: string, apiKey: string, isProxyContract: boolean) {
48+
try {
49+
const { network, networkId } = await getNetworkName(this)
50+
if (network === 'vm') {
51+
throw new Error('Cannot check the receipt status in the selected network')
52+
}
53+
const etherscanApi = getEtherScanApi(networkId)
54+
let receiptStatus
55+
56+
if (isProxyContract) receiptStatus = await getProxyContractReceiptStatus(receiptGuid, apiKey, etherscanApi)
57+
else receiptStatus = await getReceiptStatus(receiptGuid, apiKey, etherscanApi)
58+
return {
59+
message: receiptStatus.result,
60+
succeed: receiptStatus.status === '0' ? false : true
61+
}
62+
} catch (e: any) {
63+
return {
64+
status: 'error',
65+
message: e.message,
66+
succeed: false
67+
}
68+
}
69+
}
70+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import React, {useState, useEffect, useRef} from 'react'
2+
3+
import {CompilationFileSources, CompilationResult} from '@remixproject/plugin-api'
4+
5+
import { EtherscanPluginClient } from './EtherscanPluginClient'
6+
7+
import {AppContext} from './AppContext'
8+
import {DisplayRoutes} from './routes'
9+
10+
import {useLocalStorage} from './hooks/useLocalStorage'
11+
12+
import {getReceiptStatus, getEtherScanApi, getNetworkName, getProxyContractReceiptStatus} from './utils'
13+
import {Receipt, ThemeType} from './types'
14+
15+
import './App.css'
16+
17+
export const getNewContractNames = (compilationResult: CompilationResult) => {
18+
const compiledContracts = compilationResult.contracts
19+
let result: string[] = []
20+
21+
for (const file of Object.keys(compiledContracts)) {
22+
const newContractNames = Object.keys(compiledContracts[file])
23+
24+
result = [...result, ...newContractNames]
25+
}
26+
27+
return result
28+
}
29+
30+
const plugin = new EtherscanPluginClient()
31+
32+
const App = () => {
33+
const [apiKey, setAPIKey] = useLocalStorage('apiKey', '')
34+
const [receipts, setReceipts] = useLocalStorage('receipts', [])
35+
const [contracts, setContracts] = useState<string[]>([])
36+
const [themeType, setThemeType] = useState<ThemeType>('dark')
37+
const [networkName, setNetworkName] = useState('Loading...')
38+
const timer = useRef(null)
39+
const contractsRef = useRef(contracts)
40+
41+
contractsRef.current = contracts
42+
43+
const setListeners = () => {
44+
plugin.on('solidity', 'compilationFinished', (fileName: string, source: CompilationFileSources, languageVersion: string, data: CompilationResult) => {
45+
const newContractsNames = getNewContractNames(data)
46+
47+
const newContractsToSave: string[] = [...contractsRef.current, ...newContractsNames]
48+
49+
const uniqueContracts: string[] = [...new Set(newContractsToSave)]
50+
51+
setContracts(uniqueContracts)
52+
})
53+
plugin.on('blockchain' as any, 'networkStatus', (result) => {
54+
setNetworkName(`${result.network.name} ${result.network.id !== '-' ? `(Chain id: ${result.network.id})` : '(Not supported)'}`)
55+
})
56+
// @ts-ignore
57+
plugin.call('blockchain', 'getCurrentNetworkStatus').then((result: any) => setNetworkName(`${result.network.name} ${result.network.id !== '-' ? `(Chain id: ${result.network.id})` : '(Not supported)'}`))
58+
59+
}
60+
61+
useEffect(() => {
62+
plugin.onload(() => {
63+
setListeners()
64+
})
65+
}, [])
66+
67+
useEffect(() => {
68+
let receiptsNotVerified: Receipt[] = receipts.filter((item: Receipt) => item.status === 'Pending in queue' || item.status === 'Max rate limit reached')
69+
70+
if (receiptsNotVerified.length > 0) {
71+
if (timer.current) {
72+
clearInterval(timer.current)
73+
timer.current = null
74+
}
75+
timer.current = setInterval(async () => {
76+
const {network, networkId} = await getNetworkName(plugin)
77+
78+
if (!plugin) return
79+
if (network === 'vm') return
80+
let newReceipts = receipts
81+
82+
for (const item of receiptsNotVerified) {
83+
await new Promise((r) => setTimeout(r, 500)) // avoid api rate limit exceed.
84+
let status
85+
if (item.isProxyContract) {
86+
status = await getProxyContractReceiptStatus(item.guid, apiKey, getEtherScanApi(networkId))
87+
if (status.status === '1') {
88+
status.message = status.result
89+
status.result = 'Successfully Updated'
90+
}
91+
} else status = await getReceiptStatus(item.guid, apiKey, getEtherScanApi(networkId))
92+
if (status.result === 'Pass - Verified' || status.result === 'Already Verified' || status.result === 'Successfully Updated') {
93+
newReceipts = newReceipts.map((currentReceipt: Receipt) => {
94+
if (currentReceipt.guid === item.guid) {
95+
const res = {
96+
...currentReceipt,
97+
status: status.result
98+
}
99+
if (currentReceipt.isProxyContract) res.message = status.message
100+
return res
101+
}
102+
return currentReceipt
103+
})
104+
}
105+
}
106+
receiptsNotVerified = newReceipts.filter((item: Receipt) => item.status === 'Pending in queue' || item.status === 'Max rate limit reached')
107+
if (timer.current && receiptsNotVerified.length === 0) {
108+
clearInterval(timer.current)
109+
timer.current = null
110+
}
111+
setReceipts(newReceipts)
112+
}, 10000)
113+
}
114+
}, [receipts])
115+
116+
return (
117+
<AppContext.Provider
118+
value={{
119+
apiKey,
120+
setAPIKey,
121+
clientInstance: plugin,
122+
receipts,
123+
setReceipts,
124+
contracts,
125+
setContracts,
126+
themeType,
127+
setThemeType,
128+
networkName
129+
}}
130+
>
131+
{ plugin && <DisplayRoutes /> }
132+
</AppContext.Provider>
133+
)
134+
}
135+
136+
export default App

0 commit comments

Comments
 (0)