This repository has been archived by the owner on Oct 23, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2 from NodeFactoryIo/master
Plugin with task for verifying contracts on etherscan
- Loading branch information
Showing
27 changed files
with
4,335 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
TS_NODE_FILES=true | ||
|
||
WALLET_PRIVATE_KEY=0xB60B1D45848F32C21EB483EE1F83EFCBE33B896E3F16044821A0DB4BF209FA8B | ||
|
||
ETHERSCAN_API_KEY=QJBGHU5IH52MIB2HNYP51ZWIBFR6MYGNY6 |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
language: node_js | ||
|
||
node_js: | ||
- "8" | ||
- "10" | ||
|
||
install: | ||
- yarn global add codecov | ||
- yarn | ||
- yarn add --peer @nomiclabs/buidler@^1.0.0-beta.2 | ||
|
||
script: | ||
- yarn test:unit | ||
- codecov | ||
- yarn lint | ||
|
||
cache: yarn | ||
|
||
branches: | ||
only: | ||
- master |
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 |
---|---|---|
@@ -1,2 +1,42 @@ | ||
# buidler-etherscan | ||
Buidler plugin for verifying contracts on Etherscan | ||
|
||
## Installation | ||
|
||
We recommend developing Buidler plugins using yarn. To start working on your project, just run | ||
|
||
- `yarn` | ||
- `yarn add --peer @nomiclabs/buidler@^1.0.0-beta.2` | ||
|
||
## Updating Buidler or other peer dependencies | ||
|
||
When updating/adding Buidler or other peer dependencies, you should update the `.travis.yml` file's install section. The right version of all of them has to be installed in a single line, after `yarn`. | ||
|
||
## Testing | ||
|
||
Running `yarn test` will run every test located in the `test/` folder. They use [mocha](https://mochajs.org) and [chai](https://www.chaijs.com/), but you can customize them. | ||
|
||
You can run only integration tests with `yarn run test:integration` and unit with `yarn run test:unit`. | ||
|
||
For integration tests, it is required to set env (.env file) variable `WALLET_PRIVATE_KEY` with ropsten wallet private key. | ||
|
||
We recommend creating unit tests for your own modules, and integration tests for the interaction of the plugin with Buidler and its dependencies. | ||
|
||
## Linting and autoformat | ||
|
||
All all of Buidler projects use [prettier](https://prettier.io/) and [tslint](https://palantir.github.io/tslint/). | ||
|
||
You can check if your code style is correct by running `yarn lint`, and fix it with `yarn lint:fix`. | ||
|
||
## Building the project | ||
|
||
Just run `yarn buidl` ️👷 | ||
|
||
## README file | ||
|
||
We recommend writing a README that contains the following information: | ||
|
||
* What is it | ||
* How to install it | ||
* New tasks | ||
* Environment extensions |
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,62 @@ | ||
{ | ||
"name": "@nomiclabs/buidler-etherscan", | ||
"version": "0.0.1", | ||
"description": "Buidler TypeScript plugin for verifying contracts on etherscan", | ||
"repository": "github:nomiclabs/buidler-etherscan", | ||
"contributors": [ | ||
"Nomic Labs SRL", | ||
"Marin Petrunić <[email protected]>" | ||
], | ||
"license": "MIT", | ||
"main": "dist/src/index.js", | ||
"types": "dist/src/index.d.ts", | ||
"scripts": { | ||
"lint:fix": "prettier --write 'src/**/*.{js,ts}' 'test/**/*.{ts}' && tslint --fix --config tslint.json --project tsconfig.json", | ||
"lint": "tslint --config tslint.json --project tsconfig.json", | ||
"test": "yarn run test:unit && yarn run test:integration", | ||
"test:unit": "mocha --recursive \"test/unit/**/*.ts\"", | ||
"test:integration": "mocha --recursive \"test/integration/**/*.ts\"", | ||
"build": "tsc", | ||
"buidl": "tsc", | ||
"watch": "tsc -w" | ||
}, | ||
"files": [ | ||
"dist/src/", | ||
"src/", | ||
"LICENSE", | ||
"README.md" | ||
], | ||
"devDependencies": { | ||
"@types/chai": "^4.1.7", | ||
"@types/download": "^6.2.4", | ||
"@types/ethereumjs-abi": "^0.6.3", | ||
"@types/find-up": "^2.1.1", | ||
"@types/fs-extra": "^5.0.4", | ||
"@types/mocha": "^5.2.5", | ||
"@types/nock": "^9.3.1", | ||
"@types/node": "^8.10.38", | ||
"@types/request": "^2.48.1", | ||
"@types/request-promise": "^4.1.42", | ||
"chai": "^4.2.0", | ||
"dotenv": "^6.2.0", | ||
"ethers": "^4.0.27", | ||
"mocha": "^5.2.0", | ||
"nock": "^10.0.6", | ||
"prettier": "^1.15.3", | ||
"solc": "^0.5.6", | ||
"source-map-support": "^0.5.9", | ||
"ts-node": "^8.0.2", | ||
"tslint": "^5.12.0", | ||
"tslint-config-prettier": "^1.17.0", | ||
"tslint-plugin-prettier": "^2.0.1", | ||
"typescript": "^3.2.2" | ||
}, | ||
"peerDependencies": { | ||
"@nomiclabs/buidler": "1.0.0-beta.2" | ||
}, | ||
"dependencies": { | ||
"ethereumjs-abi": "^0.6.7", | ||
"request": "^2.88.0", | ||
"request-promise": "^4.2.4" | ||
} | ||
} |
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,26 @@ | ||
import { BuidlerPluginError } from "@nomiclabs/buidler/plugins"; | ||
import abi from "ethereumjs-abi"; | ||
|
||
export default class AbiEncoder { | ||
public static encodeConstructor( | ||
contractAbi: any[], | ||
constructorArguments: string[] | ||
): string { | ||
let constructorAbis: any[] = contractAbi.filter( | ||
value => value.type === "constructor" | ||
); | ||
if (constructorAbis.length === 0) { | ||
return ""; | ||
} | ||
constructorAbis = constructorAbis.filter( | ||
value => value.inputs.length === constructorArguments.length | ||
); | ||
if (constructorAbis.length === 0) { | ||
throw new BuidlerPluginError("Invalid number of constructor arguments"); | ||
} | ||
const types = constructorAbis[0].inputs.map( | ||
(value: { type: string }) => value.type | ||
); | ||
return abi.rawEncode(types, constructorArguments).toString("hex"); | ||
} | ||
} |
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,56 @@ | ||
import { TASK_COMPILE_RUN_COMPILER } from "@nomiclabs/buidler/builtin-tasks/task-names"; | ||
import { BuidlerPluginError } from "@nomiclabs/buidler/plugins"; | ||
import { RunTaskFunction } from "@nomiclabs/buidler/types"; | ||
|
||
export default class ContractCompiler { | ||
constructor(private readonly runTask: RunTaskFunction) {} | ||
|
||
public async getAbi(source: string, contractName: string): Promise<any> { | ||
return (await this.compile(source, contractName)).abi; | ||
} | ||
|
||
public async compile( | ||
source: string, | ||
contractName: string | ||
): Promise<{ abi: any[]; bytecode: string }> { | ||
const compilationResult = await this.runTask(TASK_COMPILE_RUN_COMPILER, { | ||
input: this.getSolcInput(source) | ||
}); | ||
if (compilationResult.errors) { | ||
throw new BuidlerPluginError( | ||
"Failed to compile: " + JSON.stringify(compilationResult.errors) | ||
); | ||
} | ||
const contracts: any = compilationResult.contracts.contracts; | ||
for (const contract in contracts) { | ||
if (contracts.hasOwnProperty(contract) && contract === contractName) { | ||
return { | ||
abi: contracts[contract].abi, | ||
bytecode: contracts[contract].evm.bytecode.object | ||
}; | ||
} | ||
} | ||
throw new BuidlerPluginError( | ||
`Given contract name (${contractName}) doesn't exist in sources` | ||
); | ||
} | ||
|
||
private getSolcInput(source: string) { | ||
return { | ||
language: "Solidity", | ||
sources: { | ||
contracts: { | ||
content: source | ||
} | ||
}, | ||
|
||
settings: { | ||
outputSelection: { | ||
"*": { | ||
"*": ["*"] | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
} |
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,18 @@ | ||
export default class EtherscanResponse { | ||
public readonly status: number; | ||
|
||
public readonly message: string; | ||
|
||
public constructor(response: any) { | ||
this.status = parseInt(response.status, 10); | ||
this.message = response.result; | ||
} | ||
|
||
public isPending() { | ||
return this.message === "Pending in queue"; | ||
} | ||
|
||
public isOk() { | ||
return this.status === 1; | ||
} | ||
} |
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,62 @@ | ||
import { BuidlerPluginError } from "@nomiclabs/buidler/plugins"; | ||
import request from "request-promise"; | ||
|
||
import EtherscanResponse from "./EtherscanResponse"; | ||
import EtherscanVerifyContractRequest from "./EtherscanVerifyContractRequest"; | ||
|
||
export default class EtherscanService { | ||
constructor(private readonly url: string) {} | ||
|
||
public async verifyContract( | ||
req: EtherscanVerifyContractRequest | ||
): Promise<EtherscanResponse> { | ||
try { | ||
const response = new EtherscanResponse( | ||
await request.post(this.url, { form: req, json: true }) | ||
); | ||
|
||
if (!response.isOk()) { | ||
throw new BuidlerPluginError(response.message); | ||
} | ||
return response; | ||
} catch (e) { | ||
throw new BuidlerPluginError( | ||
"Failed to send contract verification request. Reason: " + e.message, | ||
e | ||
); | ||
} | ||
} | ||
|
||
public async getVerificationStatus(guid: string): Promise<EtherscanResponse> { | ||
try { | ||
const response = new EtherscanResponse( | ||
await request.get(this.url, { | ||
json: true, | ||
qs: { | ||
module: "contract", | ||
action: "checkverifystatus", | ||
guid | ||
} | ||
}) | ||
); | ||
if (response.isPending()) { | ||
await this.delay(2000); | ||
return this.getVerificationStatus(guid); | ||
} | ||
if (!response.isOk()) { | ||
throw new BuidlerPluginError(response.message); | ||
} | ||
return response; | ||
} catch (e) { | ||
throw new BuidlerPluginError( | ||
"Failed to verify contract. Reason: " + e.message | ||
); | ||
} | ||
} | ||
|
||
private delay(ms: number): Promise<void> { | ||
return new Promise(function(resolve) { | ||
setTimeout(resolve, ms); | ||
}); | ||
} | ||
} |
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,67 @@ | ||
import { BuidlerPluginError } from "@nomiclabs/buidler/plugins"; | ||
import { SolcConfig } from "@nomiclabs/buidler/types"; | ||
|
||
import { EtherscanBuidlerEnvironment } from "../index"; | ||
|
||
export default class EtherscanVerifyContractRequest { | ||
// for that weird etherscan library props | ||
[key: string]: any; | ||
public readonly apikey: string; | ||
public readonly module: string = "contract"; | ||
public readonly action: string = "verifysourcecode"; | ||
public readonly contractaddress: string; | ||
public readonly sourceCode: string; | ||
public readonly contractname: string; | ||
public readonly compilerversion: string; | ||
public readonly optimizationUsed: number; | ||
public readonly runs: number; | ||
public readonly constructorArguements: string; | ||
|
||
constructor( | ||
etherscanConfig: EtherscanBuidlerEnvironment, | ||
solcConfig: SolcConfig, | ||
contractName: string, | ||
address: string, | ||
libraries: string, | ||
source: string, | ||
constructorArguments: string | ||
) { | ||
this.apikey = etherscanConfig.apiKey; | ||
this.contractaddress = address; | ||
this.sourceCode = source; | ||
this.contractname = contractName; | ||
this.compilerversion = solcConfig.fullVersion; | ||
this.optimizationUsed = solcConfig.optimizer.enabled ? 1 : 0; | ||
this.runs = solcConfig.optimizer.runs; | ||
this.constructorArguements = constructorArguments; | ||
this.setLibraries(libraries); | ||
} | ||
|
||
public serialize(): string { | ||
return JSON.stringify(this); | ||
} | ||
|
||
private setLibraries(libraries: string) { | ||
let i: number = 1; | ||
let parsedLibraries: { [key: string]: string } = {}; | ||
try { | ||
if (libraries) { | ||
parsedLibraries = JSON.parse(libraries); | ||
} | ||
} catch (e) { | ||
throw new BuidlerPluginError( | ||
"Failed to parse libraries. Reason: " + e.message | ||
); | ||
} | ||
for (const libraryName in parsedLibraries) { | ||
if (parsedLibraries.hasOwnProperty(libraryName)) { | ||
this["libraryname" + i] = libraryName; | ||
this["libraryaddress" + i] = parsedLibraries[libraryName]; | ||
i++; | ||
if (i >= 10) { | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.