-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d5bf6f6
commit b2ce7c1
Showing
11 changed files
with
361 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import {Command, flags} from '@oclif/command' | ||
import {Network, NETWORKS, VerificationStatus} from '../constants' | ||
import * as sourcify from '../sourcify' | ||
import * as etherscan from '../etherscan' | ||
import {makeStandardJson} from '../utils' | ||
|
||
export default class Verify extends Command { | ||
static description = 'check contract verification status in Sourcify and Etherscan' | ||
|
||
static examples = [ | ||
'$ sourcify-to-etherscan verify --apikey <...> --network rinkeby 0x94263a20b1Eea751d6C3B207A7A0ba8fF8Db9E90', | ||
'$ sourcify-to-etherscan verify -k <...> -n 4 -a <...> 0x94263a20b1Eea751d6C3B207A7A0ba8fF8Db9E90', | ||
] | ||
|
||
static flags = { | ||
help: flags.help({char: 'h'}), | ||
network: flags.enum({ | ||
char: 'n', | ||
description: 'network name or chain id to use', | ||
options: [...NETWORKS.map(n => n.name), ...NETWORKS.map(n => n.chainId.toString())], | ||
default: 'mainnet', | ||
}), | ||
args: flags.string({char: 'a', description: 'abi-encoded constructor arguments'}), | ||
apikey: flags.string({char: 'k', description: 'etherscan api key', env: 'ETHERSCAN_API_KEY'}), | ||
} | ||
|
||
static args = [{name: 'contract', required: true}] | ||
|
||
async run() { | ||
const {args, flags} = this.parse(Verify) | ||
|
||
const network: Network = NETWORKS.find(n => n.name === flags.network || n.chainId.toString() === flags.network)! | ||
|
||
this.log('Checking verification status on Sourcify') | ||
|
||
const status = await sourcify.check(network.chainId, args.contract) | ||
|
||
if (status !== 'perfect') { | ||
this.error(`contract ${args.contract} is not yet verified on Sourcify for ${network.name}`) | ||
} | ||
|
||
this.log('Fetching source code and metadata files from Sourcify') | ||
|
||
const files = await sourcify.files(network.chainId, args.contract) | ||
|
||
this.log('Parsing source files') | ||
|
||
const {target, version, metadata, sources, constructorArgs} = sourcify.parseFiles(files) | ||
|
||
this.log('Constructing standard JSON input from obtained source files') | ||
|
||
const standardJson = makeStandardJson(metadata, sources) | ||
|
||
this.log('Submitting standard JSON to etherscan') | ||
|
||
const guid = await etherscan.verify({ | ||
api: network.etherscanApiURL, | ||
apiKey: flags.apikey, | ||
contract: args.contract, | ||
source: standardJson, | ||
target, | ||
version, | ||
args: flags.args || constructorArgs, | ||
}) | ||
|
||
if (guid === VerificationStatus.ALREADY_VERIFIED) { | ||
this.log('Contract is already verified on Etherscan') | ||
return | ||
} | ||
|
||
this.log(`Waiting for the verification job ${guid} to complete`) | ||
|
||
const result = await etherscan.waitFor(network.etherscanApiURL, flags.apikey, guid) | ||
|
||
if (result === VerificationStatus.SUCCESS) { | ||
this.log('Successfully verified contract on Etherscan :)') | ||
} else { | ||
this.error('Failed to verify :(') | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
export enum VerificationStatus { | ||
FAILED = 'Fail - Unable to verify', | ||
SUCCESS = 'Pass - Verified', | ||
PENDING = 'Pending in queue', | ||
ALREADY_VERIFIED = 'Contract source code already verified', | ||
} | ||
|
||
export type Network = { | ||
name: string; | ||
chainId: number; | ||
etherscanApiURL: string; | ||
} | ||
|
||
export const NETWORKS: Network[] = [ | ||
{name: 'mainnet', chainId: 1, etherscanApiURL: 'https://api.etherscan.io/api'}, | ||
{name: 'ropsten', chainId: 3, etherscanApiURL: 'https://api-ropsten.etherscan.io/api'}, | ||
{name: 'rinkeby', chainId: 4, etherscanApiURL: 'https://api-rinkeby.etherscan.io/api'}, | ||
{name: 'goerli', chainId: 5, etherscanApiURL: 'https://api-goerli.etherscan.io/api'}, | ||
{name: 'kovan', chainId: 42, etherscanApiURL: 'https://api-kovan.etherscan.io/api'}, | ||
{name: 'bsc', chainId: 56, etherscanApiURL: 'https://api.bscscan.com/api'}, | ||
{name: 'bsc_testnet', chainId: 97, etherscanApiURL: 'https://api-testnet.bscscan.com/api'}, | ||
] | ||
|
||
export const SOURCIFY_API = 'https://sourcify.dev/server/' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import axios from 'axios' | ||
import {VerificationStatus} from './constants' | ||
import {delay} from './utils' | ||
|
||
type VerifyParams = { | ||
api: string; apiKey: string | undefined; contract: string; source: any; target: string; version: string; args: string; | ||
} | ||
export async function verify({api, apiKey, contract, source, target, version, args}: VerifyParams): Promise<string> { | ||
const params = new URLSearchParams() | ||
if (apiKey) { | ||
params.append('apikey', apiKey) | ||
} | ||
params.append('module', 'contract') | ||
params.append('action', 'verifysourcecode') | ||
params.append('contractaddress', contract) | ||
params.append('sourceCode', JSON.stringify(source)) | ||
params.append('codeformat', 'solidity-standard-json-input') | ||
params.append('contractname', target) | ||
params.append('compilerversion', version) | ||
params.append('constructorArguements', args) | ||
|
||
const {data} = await axios.post(api, params, { | ||
headers: {'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8'}, | ||
}) | ||
|
||
return data.result | ||
} | ||
|
||
export async function waitFor(api: string, apiKey: string | undefined, guid: string): Promise<string> { | ||
while (true) { | ||
await delay(3000) | ||
|
||
const {data} = await axios.get(api, { | ||
params: { | ||
apiKey, | ||
module: 'contract', | ||
action: 'checkverifystatus', | ||
guid, | ||
}, | ||
}) | ||
if (data.result !== VerificationStatus.PENDING) { | ||
return data.result | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import axios from 'axios' | ||
import {SOURCIFY_API} from './constants' | ||
|
||
export async function check(chainId: number, contract: string): Promise<string> { | ||
const {data} = await axios.get(`${SOURCIFY_API}check-by-addresses`, { | ||
params: { | ||
addresses: contract, | ||
chainIds: chainId, | ||
}, | ||
}) | ||
if (!data || !data[0]) { | ||
return 'false' | ||
} | ||
return data[0].status | ||
} | ||
|
||
export async function files(chainId: number, contract: string): Promise<any> { | ||
const {data} = await axios.get(`${SOURCIFY_API}files/${chainId}/${contract}`) | ||
|
||
return data | ||
} | ||
|
||
export type Metadata = { | ||
language: string; | ||
settings: any; | ||
} | ||
type SourcifyOutput = { | ||
metadata: Metadata; | ||
version: string; | ||
sources: any; | ||
target: string; | ||
constructorArgs: string; | ||
} | ||
type FileContent = { | ||
content: string; | ||
} | ||
type File = FileContent & { | ||
name: string; | ||
path: string; | ||
} | ||
|
||
export function parseFiles(files: any): SourcifyOutput { | ||
const metadata = JSON.parse(files.find((file: File) => file.name === 'metadata.json').content) | ||
const constructorArgs = files.find((file: File) => file.name === 'constructor-args.txt') | ||
const sourcesArray = files.filter((file: File) => file.name !== 'metadata.json' && file.name !== 'constructor-args.txt') | ||
const version = `v${metadata.compiler.version}` | ||
const target = Object.entries(metadata.settings.compilationTarget)[0].join(':') | ||
const sources: {[key: string]: FileContent} = {} | ||
|
||
const prefix = sourcesArray[0].path.match(/^.*\/sources\//)[0] | ||
for (const file of sourcesArray) { | ||
const path = file.path.replace('sources/_', 'sources/@').slice(prefix.length) | ||
sources[path] = {content: file.content} | ||
} | ||
|
||
return { | ||
metadata, | ||
version, | ||
target, | ||
sources, | ||
constructorArgs: constructorArgs ? constructorArgs.content.slice(2) : '', | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import {Metadata} from './sourcify' | ||
|
||
export const delay = (ms: number) => new Promise(res => setTimeout(res, ms)) | ||
|
||
export function makeStandardJson(metadata: Metadata, sources: any) { | ||
return { | ||
language: metadata.language, | ||
sources, | ||
settings: { | ||
optimizer: metadata.settings.optimizer, | ||
evmVersion: metadata.settings.evmVersion, | ||
remappings: metadata.settings.remappings, | ||
libraries: metadata.settings.libraries, | ||
}, | ||
} | ||
} |
Oops, something went wrong.