├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── .travis.yml ├── LICENSE ├── README.md ├── __tests__ ├── __snapshots__ │ └── integration.js.snap └── integration.js ├── bin └── verify-cli.js ├── jest.config.js ├── package-lock.json ├── package.json ├── src ├── filter_out_verified.js ├── flatten_contracts.js ├── gather_data_from_artifacts.js ├── get_constructor_arguments.js ├── index.js ├── output_flattened.js ├── post_to_verify.js ├── print_help.js ├── process_config.js └── verify.js ├── truffle-plugin.json └── truffle-test-example ├── contracts ├── Migrations.sol ├── MultipleContract.sol ├── TestChildContract.sol ├── TestContract.sol ├── TestParentContract.sol └── TestToken.sol ├── migrations ├── 1_initial_migration.js ├── 2_deploy_TestContract.js ├── 3_deploy_TestChildContract.js └── 4_deploy_Token.js ├── package-lock.json ├── package.json └── truffle.js /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["airbnb", "prettier", "plugin:jest/recommended"], 3 | "plugins": ["prettier"], 4 | "rules": { 5 | "prettier/prettier": ["error"], 6 | "no-unused-expressions": ["error", { "allowShortCircuit": true, "allowTernary": true }], 7 | "consistent-return": 0, 8 | "no-console": 0, 9 | "global-require": 0, 10 | "import/no-dynamic-require": 0, 11 | "no-restricted-syntax": 0, 12 | "no-continue": 0, 13 | "no-plusplus": 0, 14 | "no-cond-assign": 0, 15 | "no-param-reassign": 0, 16 | "no-sparse-arrays": 0 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .history 3 | .vscode 4 | build 5 | .env -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "singleQuote": true 4 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: node_js 3 | node_js: 4 | - '10' 5 | cache: 6 | directories: 7 | - '$HOME/.npm' 8 | before_install: 9 | - rm -rf node_modules 10 | install: 11 | - npm ci --production=false 12 | - npm run prep-test 13 | script: 14 | - npm run lint && npm test 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Gnosis Ltd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/gnosis/verify-on-etherscan.svg?branch=master)](https://travis-ci.org/gnosis/verify-on-etherscan?branch=master) 2 | [![NPM version](https://badge.fury.io/js/verify-on-etherscan.svg)](https://www.npmjs.com/package/verify-on-etherscan) 3 | 4 | # Verify on Etherscan 5 | CLI utility / truffle plugin / Node.js library that automates verification on etherscan.io of contracts that were compiled and deployed with truffle. 6 | 7 | The most common use case of verifying contracts after deployment should be covered by the following command even without installing the library: 8 | 9 | ```sh 10 | API_KEY= npx verify-on-etherscan --network mainnet ./build/contracts/* 11 | ``` 12 | 13 | Etherscan supports **mainnet, ropsten, rinkeby, kovan, sepolia** and **goerli** networks for verification and requires a valid **Etherscan APIkey**. You can see details [here](https://etherscan.io/apis#contracts). 14 | 15 | ## Installation 16 | 17 | ```sh 18 | npm install --save-dev verify-on-etherscan 19 | ``` 20 | 21 | ## Usage 22 | 23 | The library can be used as a cli utility -- the simplest way, as a truffle plugin -- to take advantage of truffle config or as a third-party library. 24 | 25 | ## As a cli utility 26 | 27 | ```sh 28 | Usage: API_KEY= npx verify-on-etherscan [options] 29 | 30 | Positionals: 31 | artifacts a space separated list of paths to artifact json files (required) 32 | or a glob pattern like ./build/contracts/*.json 33 | [string, string, string...] 34 | 35 | Options: 36 | --version, -v Show version number 37 | 38 | --network which network to verify contracts on 39 | [string] [required] [choices: "mainnet", "ropsten", "rinkeby", "kovan", "sepolia", "goerli"] 40 | 41 | --optimize, -o whether your contracts were optimized during compilation 42 | (sets --optimize-runs to 200 if none given) 43 | [string] 44 | 45 | --optimize-runs, -r how many runs your contracts were optimized for during compilation 46 | (sets --optimize to true if given) 47 | [number] 48 | 49 | --output which directory to write flattened contracts to 50 | [string] 51 | 52 | --delay, -d delay (in ms) between checking if a contract has been 53 | verified after verification starts 54 | [number] [default: 20000] 55 | 56 | --use-fetch fetch transactions from Etherscan instead of from 57 | blockchain when determining constructor arguments 58 | [boolean] [default: true] 59 | 60 | --verbose output more logs 61 | 62 | --help, -h Show help 63 | ``` 64 | 65 | By default the library will use Etherscan api to fetch transactions. 66 | To use a `web3` for that set `--use-fetch=false`. That way an instance of `web3` will be created for you and connected to `https://.infura.io` 67 | 68 | If no `--optimizer` or `--optimize-runs` flags are provided, the library will attempt to infer optimizer settings from `./truffle.js` or `./truffle-config.js` in the project directory. Failing that `{ enabled: false, runs: 200 }` will be used. 69 | 70 | You can use `voeth` as an alias for `verify-on-etherscan` if you install it locally: 71 | ``` 72 | API_KEY= npx voeth --network rinkeby ./build/contracts/Contract1.json ./build/contracts/Contract2.json 73 | ``` 74 | 75 | ------------- 76 | 77 | ## As a truffle plugin 78 | 79 | First add 80 | 81 | ```js 82 | plugins: ["verify-on-etherscan"] 83 | ``` 84 | 85 | to your config in `truffle.js` or `truffle-config.js` 86 | 87 | ```sh 88 | Usage: API_KEY= npx truffle run verify [options] 89 | 90 | artifact_paths a space separated list of paths to artifact json files (required) 91 | or a glob pattern like ./build/contracts/*.json 92 | 93 | API_KEY your key for Etherscan API (required) 94 | 95 | --network network from truffle.js file (required) 96 | web3 instance is created with provider supplied by truffle to the plugin 97 | a network with its networkId must be available for verification on Etherscan 98 | currently available are mainnet, rinkeby, kovan, ropsten, sepolia and goerli 99 | 100 | --output path to directory to output flattened contracts to (optional) 101 | for optional saving to filesystem 102 | 103 | --delay, -d delay (in ms) between checking if a contract has been verified after verification starts 104 | (optional)(default 20000) 105 | 106 | --use-fetch fetch transactions from Etherscan instead of from blockchain when determining constructor arguments 107 | (optional)(default false) 108 | 109 | --verbose output more logs (optional) 110 | 111 | --help, -h output more logs (optional) 112 | ``` 113 | 114 | By default a `web3` instance will be created with a provider from the config returned from `truffle.js` corresponding to the provided `--network`. It will be used for requisting transaction data from the blockchain. 115 | `--use-fetch` allows to use Etherscan api to fetch transactions. 116 | 117 | Optimizer settings are passed by truffle as part of the plugin config. 118 | 119 | ---------------- 120 | 121 | ### As a library 122 | 123 | First import it in your project then call it with your options: 124 | ```js 125 | const verify = require('verify-on-etherscan'); 126 | 127 | const result = await verify({ 128 | cwd, 129 | artifacts, 130 | apiKey, 131 | web3, 132 | network, 133 | useFetch, 134 | optimizer, 135 | output, 136 | delay, 137 | logger, 138 | verbose 139 | }) 140 | ``` 141 | 142 | `verify(options)` returns a Promise that resolves to 143 | 144 | ```js 145 | { 146 | // contracts that were already verified on Etherscan 147 | alreadyVerified: Array, 148 | // contracts that were verified successfully 149 | successful: Array, 150 | // contracts for which verification failed 151 | failed: Array 152 | } 153 | ``` 154 | 155 | when the verification is finished, or rejects if any unhandled Errors are thrown inside. 156 | 157 | Options: 158 | 159 | ```sh 160 | cwd current working directory, relative to which artifacts will be looked up 161 | (default: process.cwd()) 162 | 163 | artifacts array of paths to json artifact files, relative to cwd 164 | (required non-empty array) 165 | 166 | apiKey Etherscan APIkey (required) 167 | 168 | web3 a web3 instance connected to a valid network (optional) 169 | 170 | network name from the list of valid networks to connect to (optional) 171 | 172 | useFetch use Etherscan api to fetch transactions instead of a web3 instance 173 | (optional, default: false) 174 | 175 | optimizer optimizer settings object 176 | (default: { enabled: false, runs: 200 }) 177 | 178 | optimizer.enabled whether your contracts were optimized during compilation 179 | optimizer.runs how many runs your contracts were optimized for during compilation 180 | 181 | output path to directory to write flattened contracts to 182 | (optional) 183 | 184 | delay delay (in ms) between checking if a contract has been verified after verification starts 185 | 186 | logger logger to use for output to console 187 | (optional, default: console, if falsy nothing will be output) 188 | 189 | verbose ouput more logs (optional, default: false) 190 | ``` 191 | 192 | If `web3` is provided, it will be used to determine which network to verify contracts on (through `web3.eth.net.getId()` matching). 193 | 194 | if `network` is provided and `useFetch === false`, an instance of `web3` will be created for you and connected to `https://.infura.io`. `network` must be one of the networks which Etherscan supports for verification. 195 | 196 | if `network` is provided and `useFetch === true`, no `web3` instance will be created and the library will fetch transactions from Etherscan api. 197 | 198 | Either `web3` or `network` must be provided. 199 | 200 | ## Workflow 201 | 202 | ### Step 0 203 | 204 | In case of using the library as a cli utility or a truffle plugin some config parsing will first take place 205 | 206 | --- 207 | 208 | ### Step 1 209 | 210 | Depending on provided config an instance of `web3` is created. 211 | 212 | --- 213 | 214 | ### Step 2 215 | 216 | JSON artifacts are read, parsed and necessary data is extracted. 217 | 218 | Extracted: **contractname, compilerversion, bytecode, contractaddress, txhash, sourcePath, library addresses** (if any). **contractaddress** and **txhash** are dependent on the network set for verification. 219 | 220 | It's also determined whether a contract has a non-emty constructor. 221 | 222 | --- 223 | 224 | ### Step 3 225 | 226 | For each **contractaddress** the libary fetches contract abi from Etherscan to filter out already verified contracts. 227 | 228 | Keep in mind that recently verified contracts would still be reported as unverified by Etherscan for some time and won't be filtered out immediately. 229 | 230 | --- 231 | 232 | ### Step 4 233 | 234 | [truffle-flattener](https://github.com/nomiclabs/truffle-flattener) processes **sourcePath** of each artifact and returns the flattened code. 235 | 236 | --- 237 | 238 | ### Step 5 (optional) 239 | 240 | If `--output ` was given, flattened contracts are written out there following `.flat.sol` pattern. 241 | 242 | --- 243 | 244 | ### Step 6 245 | 246 | For contracts that have a non-emty constructor the library determines its encoded constructor arguments. 247 | 248 | It gets the input data of the transaction corresponding to a contract's creation **txhash**. Then subtracts the artifact **bytecode** from it. The result is the encoded constructor arguments. 249 | 250 | In case the bytecode and the transaction data don't match, provided source code and compiler are the same, the difference is usually in the metadata portion of the code. 251 | 252 | A typical contract creation transaction data looks like this: 253 | 254 | ```hex 255 | (solc v>=0.4.7 <0.4.22) 256 | 0x6060604052[__contract_code__]a165627a7a72305820[__metadata__]0029[__constractor_arguments__] 257 | 258 | (solc v>=0.4.22) 259 | 0x6080604052[__contract_code__]a165627a7a72305820[__metadata__]0029[__constractor_arguments__] 260 | ``` 261 | 262 | It is trivial to extract the constructor arguments from it. 263 | 264 | --- 265 | 266 | ### Step 7 267 | 268 | For each contract the library posts **apiKey, optimizer** settings, **contractaddress, contractname, sourceCode, constructorArguments, library addresses** and **compileversion** to Etherscan api getting GUIDs in return. 269 | 270 | The library checks the GUIDs for status change until all contracts are either verified or fail verification. The interval between check is determined by the `delay` option. 271 | 272 | ## License 273 | 274 | Licensed under the MIT license. 275 | -------------------------------------------------------------------------------- /__tests__/__snapshots__/integration.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`Filters out verified contracts: Already verified 1`] = ` 4 | Array [ 5 | "build/contracts/ERC20.json", 6 | "build/contracts/Migrations.json", 7 | ] 8 | `; 9 | 10 | exports[`Filters out verified contracts: Fetch calls 1`] = ` 11 | Array [ 12 | Array [ 13 | "https://api-rinkeby.etherscan.io/api?module=contract&action=getabi&address=0x76608a542b425cBA81d277F6436007ADd848C0AF", 14 | ], 15 | Array [ 16 | "https://api-rinkeby.etherscan.io/api?module=contract&action=getabi&address=0xb1c657fa3806D78716dfcBeA9aF1aCf851077D6E", 17 | ], 18 | Array [ 19 | "https://api-rinkeby.etherscan.io/api?module=contract&action=getabi&address=0xE71d2dDb3CA69a94b557695a9614D3262845EA11", 20 | ], 21 | Array [ 22 | "https://api-rinkeby.etherscan.io/api?module=contract&action=getabi&address=0xC6FC5E99b5D253f6eabf53Fb2eAB94AF4e6A1444", 23 | ], 24 | Array [ 25 | "https://api-rinkeby.etherscan.io/api?module=contract&action=getabi&address=0xbE14913754d5A03c8f7c81C98c499033422898Be", 26 | ], 27 | ] 28 | `; 29 | 30 | exports[`Filters out verified contracts: Fetch returns 1`] = ` 31 | Array [ 32 | Object { 33 | "status": "1", 34 | }, 35 | Object { 36 | "status": "1", 37 | }, 38 | Object { 39 | "status": "0", 40 | }, 41 | Object { 42 | "status": "0", 43 | }, 44 | Object { 45 | "status": "0", 46 | }, 47 | ] 48 | `; 49 | 50 | exports[`Filters out verified contracts: Log calls 1`] = ` 51 | Array [ 52 | Array [], 53 | Array [ 54 | "ERC20 at 0x76608a542b425cBA81d277F6436007ADd848C0AF is already verified, skipping", 55 | ], 56 | Array [ 57 | "Migrations at 0xb1c657fa3806D78716dfcBeA9aF1aCf851077D6E is already verified, skipping", 58 | ], 59 | ] 60 | `; 61 | 62 | exports[`Filters out verified contracts: TestChildContract.json 1`] = ` 63 | Object { 64 | "bytecode": Any, 65 | "compilerversion": "v0.5.2+commit.1df8f40c", 66 | "contractaddress": "0xE71d2dDb3CA69a94b557695a9614D3262845EA11", 67 | "contractname": "TestChildContract", 68 | "hasNonEmptyConstructor": true, 69 | "sourcePath": "$PROJECT_DIR/truffle-test-example/contracts/TestChildContract.sol", 70 | "txhash": StringMatching /\\^0x\\[0-9a-fA-F\\]\\+\\$/, 71 | } 72 | `; 73 | 74 | exports[`Filters out verified contracts: TestContract.json 1`] = ` 75 | Object { 76 | "bytecode": Any, 77 | "compilerversion": "v0.5.2+commit.1df8f40c", 78 | "contractaddress": "0xC6FC5E99b5D253f6eabf53Fb2eAB94AF4e6A1444", 79 | "contractname": "TestContract", 80 | "hasNonEmptyConstructor": false, 81 | "sourcePath": "$PROJECT_DIR/truffle-test-example/contracts/TestContract.sol", 82 | "txhash": StringMatching /\\^0x\\[0-9a-fA-F\\]\\+\\$/, 83 | } 84 | `; 85 | 86 | exports[`Filters out verified contracts: TestToken.json 1`] = ` 87 | Object { 88 | "bytecode": Any, 89 | "compilerversion": "v0.5.2+commit.1df8f40c", 90 | "contractaddress": "0xbE14913754d5A03c8f7c81C98c499033422898Be", 91 | "contractname": "TestToken", 92 | "hasNonEmptyConstructor": true, 93 | "sourcePath": "$PROJECT_DIR/truffle-test-example/contracts/TestToken.sol", 94 | "txhash": StringMatching /\\^0x\\[0-9a-fA-F\\]\\+\\$/, 95 | } 96 | `; 97 | 98 | exports[`Filters out verified contracts: Unverified contracts 1`] = ` 99 | Array [ 100 | "build/contracts/TestChildContract.json", 101 | "build/contracts/TestContract.json", 102 | "build/contracts/TestToken.json", 103 | ] 104 | `; 105 | 106 | exports[`Flattens contracts linked from artifacts: Flattened contracts 1`] = ` 107 | Object { 108 | "build/contracts/ERC20.json": " 109 | // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol 110 | 111 | pragma solidity ^0.5.2; 112 | 113 | /** 114 | * @title ERC20 interface 115 | * @dev see https://eips.ethereum.org/EIPS/eip-20 116 | */ 117 | interface IERC20 { 118 | function transfer(address to, uint256 value) external returns (bool); 119 | 120 | function approve(address spender, uint256 value) external returns (bool); 121 | 122 | function transferFrom(address from, address to, uint256 value) external returns (bool); 123 | 124 | function totalSupply() external view returns (uint256); 125 | 126 | function balanceOf(address who) external view returns (uint256); 127 | 128 | function allowance(address owner, address spender) external view returns (uint256); 129 | 130 | event Transfer(address indexed from, address indexed to, uint256 value); 131 | 132 | event Approval(address indexed owner, address indexed spender, uint256 value); 133 | } 134 | 135 | // File: openzeppelin-solidity/contracts/math/SafeMath.sol 136 | 137 | pragma solidity ^0.5.2; 138 | 139 | /** 140 | * @title SafeMath 141 | * @dev Unsigned math operations with safety checks that revert on error 142 | */ 143 | library SafeMath { 144 | /** 145 | * @dev Multiplies two unsigned integers, reverts on overflow. 146 | */ 147 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 148 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 149 | // benefit is lost if 'b' is also tested. 150 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 151 | if (a == 0) { 152 | return 0; 153 | } 154 | 155 | uint256 c = a * b; 156 | require(c / a == b); 157 | 158 | return c; 159 | } 160 | 161 | /** 162 | * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. 163 | */ 164 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 165 | // Solidity only automatically asserts when dividing by 0 166 | require(b > 0); 167 | uint256 c = a / b; 168 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 169 | 170 | return c; 171 | } 172 | 173 | /** 174 | * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). 175 | */ 176 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 177 | require(b <= a); 178 | uint256 c = a - b; 179 | 180 | return c; 181 | } 182 | 183 | /** 184 | * @dev Adds two unsigned integers, reverts on overflow. 185 | */ 186 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 187 | uint256 c = a + b; 188 | require(c >= a); 189 | 190 | return c; 191 | } 192 | 193 | /** 194 | * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), 195 | * reverts when dividing by zero. 196 | */ 197 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 198 | require(b != 0); 199 | return a % b; 200 | } 201 | } 202 | 203 | // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol 204 | 205 | pragma solidity ^0.5.2; 206 | 207 | 208 | 209 | /** 210 | * @title Standard ERC20 token 211 | * 212 | * @dev Implementation of the basic standard token. 213 | * https://eips.ethereum.org/EIPS/eip-20 214 | * Originally based on code by FirstBlood: 215 | * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol 216 | * 217 | * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for 218 | * all accounts just by listening to said events. Note that this isn't required by the specification, and other 219 | * compliant implementations may not do it. 220 | */ 221 | contract ERC20 is IERC20 { 222 | using SafeMath for uint256; 223 | 224 | mapping (address => uint256) private _balances; 225 | 226 | mapping (address => mapping (address => uint256)) private _allowed; 227 | 228 | uint256 private _totalSupply; 229 | 230 | /** 231 | * @dev Total number of tokens in existence 232 | */ 233 | function totalSupply() public view returns (uint256) { 234 | return _totalSupply; 235 | } 236 | 237 | /** 238 | * @dev Gets the balance of the specified address. 239 | * @param owner The address to query the balance of. 240 | * @return A uint256 representing the amount owned by the passed address. 241 | */ 242 | function balanceOf(address owner) public view returns (uint256) { 243 | return _balances[owner]; 244 | } 245 | 246 | /** 247 | * @dev Function to check the amount of tokens that an owner allowed to a spender. 248 | * @param owner address The address which owns the funds. 249 | * @param spender address The address which will spend the funds. 250 | * @return A uint256 specifying the amount of tokens still available for the spender. 251 | */ 252 | function allowance(address owner, address spender) public view returns (uint256) { 253 | return _allowed[owner][spender]; 254 | } 255 | 256 | /** 257 | * @dev Transfer token to a specified address 258 | * @param to The address to transfer to. 259 | * @param value The amount to be transferred. 260 | */ 261 | function transfer(address to, uint256 value) public returns (bool) { 262 | _transfer(msg.sender, to, value); 263 | return true; 264 | } 265 | 266 | /** 267 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 268 | * Beware that changing an allowance with this method brings the risk that someone may use both the old 269 | * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this 270 | * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: 271 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 272 | * @param spender The address which will spend the funds. 273 | * @param value The amount of tokens to be spent. 274 | */ 275 | function approve(address spender, uint256 value) public returns (bool) { 276 | _approve(msg.sender, spender, value); 277 | return true; 278 | } 279 | 280 | /** 281 | * @dev Transfer tokens from one address to another. 282 | * Note that while this function emits an Approval event, this is not required as per the specification, 283 | * and other compliant implementations may not emit the event. 284 | * @param from address The address which you want to send tokens from 285 | * @param to address The address which you want to transfer to 286 | * @param value uint256 the amount of tokens to be transferred 287 | */ 288 | function transferFrom(address from, address to, uint256 value) public returns (bool) { 289 | _transfer(from, to, value); 290 | _approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); 291 | return true; 292 | } 293 | 294 | /** 295 | * @dev Increase the amount of tokens that an owner allowed to a spender. 296 | * approve should be called when _allowed[msg.sender][spender] == 0. To increment 297 | * allowed value is better to use this function to avoid 2 calls (and wait until 298 | * the first transaction is mined) 299 | * From MonolithDAO Token.sol 300 | * Emits an Approval event. 301 | * @param spender The address which will spend the funds. 302 | * @param addedValue The amount of tokens to increase the allowance by. 303 | */ 304 | function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 305 | _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); 306 | return true; 307 | } 308 | 309 | /** 310 | * @dev Decrease the amount of tokens that an owner allowed to a spender. 311 | * approve should be called when _allowed[msg.sender][spender] == 0. To decrement 312 | * allowed value is better to use this function to avoid 2 calls (and wait until 313 | * the first transaction is mined) 314 | * From MonolithDAO Token.sol 315 | * Emits an Approval event. 316 | * @param spender The address which will spend the funds. 317 | * @param subtractedValue The amount of tokens to decrease the allowance by. 318 | */ 319 | function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { 320 | _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); 321 | return true; 322 | } 323 | 324 | /** 325 | * @dev Transfer token for a specified addresses 326 | * @param from The address to transfer from. 327 | * @param to The address to transfer to. 328 | * @param value The amount to be transferred. 329 | */ 330 | function _transfer(address from, address to, uint256 value) internal { 331 | require(to != address(0)); 332 | 333 | _balances[from] = _balances[from].sub(value); 334 | _balances[to] = _balances[to].add(value); 335 | emit Transfer(from, to, value); 336 | } 337 | 338 | /** 339 | * @dev Internal function that mints an amount of the token and assigns it to 340 | * an account. This encapsulates the modification of balances such that the 341 | * proper events are emitted. 342 | * @param account The account that will receive the created tokens. 343 | * @param value The amount that will be created. 344 | */ 345 | function _mint(address account, uint256 value) internal { 346 | require(account != address(0)); 347 | 348 | _totalSupply = _totalSupply.add(value); 349 | _balances[account] = _balances[account].add(value); 350 | emit Transfer(address(0), account, value); 351 | } 352 | 353 | /** 354 | * @dev Internal function that burns an amount of the token of a given 355 | * account. 356 | * @param account The account whose tokens will be burnt. 357 | * @param value The amount that will be burnt. 358 | */ 359 | function _burn(address account, uint256 value) internal { 360 | require(account != address(0)); 361 | 362 | _totalSupply = _totalSupply.sub(value); 363 | _balances[account] = _balances[account].sub(value); 364 | emit Transfer(account, address(0), value); 365 | } 366 | 367 | /** 368 | * @dev Approve an address to spend another addresses' tokens. 369 | * @param owner The address that owns the tokens. 370 | * @param spender The address that will spend the tokens. 371 | * @param value The number of tokens that can be spent. 372 | */ 373 | function _approve(address owner, address spender, uint256 value) internal { 374 | require(spender != address(0)); 375 | require(owner != address(0)); 376 | 377 | _allowed[owner][spender] = value; 378 | emit Approval(owner, spender, value); 379 | } 380 | 381 | /** 382 | * @dev Internal function that burns an amount of the token of a given 383 | * account, deducting from the sender's allowance for said account. Uses the 384 | * internal burn function. 385 | * Emits an Approval event (reflecting the reduced allowance). 386 | * @param account The account whose tokens will be burnt. 387 | * @param value The amount that will be burnt. 388 | */ 389 | function _burnFrom(address account, uint256 value) internal { 390 | _burn(account, value); 391 | _approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); 392 | } 393 | } 394 | ", 395 | "build/contracts/Migrations.json": " 396 | // File: contracts/Migrations.sol 397 | 398 | pragma solidity >=0.4.21 <0.6.0; 399 | 400 | contract Migrations { 401 | address public owner; 402 | uint public last_completed_migration; 403 | 404 | constructor() public { 405 | owner = msg.sender; 406 | } 407 | 408 | modifier restricted() { 409 | if (msg.sender == owner) _; 410 | } 411 | 412 | function setCompleted(uint completed) public restricted { 413 | last_completed_migration = completed; 414 | } 415 | 416 | function upgrade(address new_address) public restricted { 417 | Migrations upgraded = Migrations(new_address); 418 | upgraded.setCompleted(last_completed_migration); 419 | } 420 | } 421 | ", 422 | "build/contracts/TestChildContract.json": " 423 | // File: contracts/TestParentContract.sol 424 | 425 | pragma solidity >=0.4.21 <0.6.0; 426 | 427 | contract TestParentContract { 428 | address public owner; 429 | string public parentName; 430 | 431 | constructor(string memory _parentName) public { 432 | owner = msg.sender; 433 | parentName = _parentName; 434 | } 435 | } 436 | 437 | // File: contracts/TestChildContract.sol 438 | 439 | pragma solidity >=0.4.21 <0.6.0; 440 | 441 | 442 | contract TestChildContract is TestParentContract(\\"Parent\\") { 443 | string public name; 444 | 445 | constructor(string memory _name) public { 446 | name = _name; 447 | } 448 | } 449 | ", 450 | "build/contracts/TestContract.json": " 451 | // File: contracts/TestContract.sol 452 | 453 | pragma solidity >=0.4.21 <0.6.0; 454 | 455 | contract TestContract { 456 | address public owner; 457 | 458 | constructor() public { 459 | owner = msg.sender; 460 | } 461 | } 462 | ", 463 | "build/contracts/TestToken.json": " 464 | // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol 465 | 466 | pragma solidity ^0.5.2; 467 | 468 | /** 469 | * @title ERC20 interface 470 | * @dev see https://eips.ethereum.org/EIPS/eip-20 471 | */ 472 | interface IERC20 { 473 | function transfer(address to, uint256 value) external returns (bool); 474 | 475 | function approve(address spender, uint256 value) external returns (bool); 476 | 477 | function transferFrom(address from, address to, uint256 value) external returns (bool); 478 | 479 | function totalSupply() external view returns (uint256); 480 | 481 | function balanceOf(address who) external view returns (uint256); 482 | 483 | function allowance(address owner, address spender) external view returns (uint256); 484 | 485 | event Transfer(address indexed from, address indexed to, uint256 value); 486 | 487 | event Approval(address indexed owner, address indexed spender, uint256 value); 488 | } 489 | 490 | // File: openzeppelin-solidity/contracts/math/SafeMath.sol 491 | 492 | pragma solidity ^0.5.2; 493 | 494 | /** 495 | * @title SafeMath 496 | * @dev Unsigned math operations with safety checks that revert on error 497 | */ 498 | library SafeMath { 499 | /** 500 | * @dev Multiplies two unsigned integers, reverts on overflow. 501 | */ 502 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 503 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 504 | // benefit is lost if 'b' is also tested. 505 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 506 | if (a == 0) { 507 | return 0; 508 | } 509 | 510 | uint256 c = a * b; 511 | require(c / a == b); 512 | 513 | return c; 514 | } 515 | 516 | /** 517 | * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. 518 | */ 519 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 520 | // Solidity only automatically asserts when dividing by 0 521 | require(b > 0); 522 | uint256 c = a / b; 523 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 524 | 525 | return c; 526 | } 527 | 528 | /** 529 | * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). 530 | */ 531 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 532 | require(b <= a); 533 | uint256 c = a - b; 534 | 535 | return c; 536 | } 537 | 538 | /** 539 | * @dev Adds two unsigned integers, reverts on overflow. 540 | */ 541 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 542 | uint256 c = a + b; 543 | require(c >= a); 544 | 545 | return c; 546 | } 547 | 548 | /** 549 | * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), 550 | * reverts when dividing by zero. 551 | */ 552 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 553 | require(b != 0); 554 | return a % b; 555 | } 556 | } 557 | 558 | // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol 559 | 560 | pragma solidity ^0.5.2; 561 | 562 | 563 | 564 | /** 565 | * @title Standard ERC20 token 566 | * 567 | * @dev Implementation of the basic standard token. 568 | * https://eips.ethereum.org/EIPS/eip-20 569 | * Originally based on code by FirstBlood: 570 | * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol 571 | * 572 | * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for 573 | * all accounts just by listening to said events. Note that this isn't required by the specification, and other 574 | * compliant implementations may not do it. 575 | */ 576 | contract ERC20 is IERC20 { 577 | using SafeMath for uint256; 578 | 579 | mapping (address => uint256) private _balances; 580 | 581 | mapping (address => mapping (address => uint256)) private _allowed; 582 | 583 | uint256 private _totalSupply; 584 | 585 | /** 586 | * @dev Total number of tokens in existence 587 | */ 588 | function totalSupply() public view returns (uint256) { 589 | return _totalSupply; 590 | } 591 | 592 | /** 593 | * @dev Gets the balance of the specified address. 594 | * @param owner The address to query the balance of. 595 | * @return A uint256 representing the amount owned by the passed address. 596 | */ 597 | function balanceOf(address owner) public view returns (uint256) { 598 | return _balances[owner]; 599 | } 600 | 601 | /** 602 | * @dev Function to check the amount of tokens that an owner allowed to a spender. 603 | * @param owner address The address which owns the funds. 604 | * @param spender address The address which will spend the funds. 605 | * @return A uint256 specifying the amount of tokens still available for the spender. 606 | */ 607 | function allowance(address owner, address spender) public view returns (uint256) { 608 | return _allowed[owner][spender]; 609 | } 610 | 611 | /** 612 | * @dev Transfer token to a specified address 613 | * @param to The address to transfer to. 614 | * @param value The amount to be transferred. 615 | */ 616 | function transfer(address to, uint256 value) public returns (bool) { 617 | _transfer(msg.sender, to, value); 618 | return true; 619 | } 620 | 621 | /** 622 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 623 | * Beware that changing an allowance with this method brings the risk that someone may use both the old 624 | * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this 625 | * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: 626 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 627 | * @param spender The address which will spend the funds. 628 | * @param value The amount of tokens to be spent. 629 | */ 630 | function approve(address spender, uint256 value) public returns (bool) { 631 | _approve(msg.sender, spender, value); 632 | return true; 633 | } 634 | 635 | /** 636 | * @dev Transfer tokens from one address to another. 637 | * Note that while this function emits an Approval event, this is not required as per the specification, 638 | * and other compliant implementations may not emit the event. 639 | * @param from address The address which you want to send tokens from 640 | * @param to address The address which you want to transfer to 641 | * @param value uint256 the amount of tokens to be transferred 642 | */ 643 | function transferFrom(address from, address to, uint256 value) public returns (bool) { 644 | _transfer(from, to, value); 645 | _approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); 646 | return true; 647 | } 648 | 649 | /** 650 | * @dev Increase the amount of tokens that an owner allowed to a spender. 651 | * approve should be called when _allowed[msg.sender][spender] == 0. To increment 652 | * allowed value is better to use this function to avoid 2 calls (and wait until 653 | * the first transaction is mined) 654 | * From MonolithDAO Token.sol 655 | * Emits an Approval event. 656 | * @param spender The address which will spend the funds. 657 | * @param addedValue The amount of tokens to increase the allowance by. 658 | */ 659 | function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 660 | _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); 661 | return true; 662 | } 663 | 664 | /** 665 | * @dev Decrease the amount of tokens that an owner allowed to a spender. 666 | * approve should be called when _allowed[msg.sender][spender] == 0. To decrement 667 | * allowed value is better to use this function to avoid 2 calls (and wait until 668 | * the first transaction is mined) 669 | * From MonolithDAO Token.sol 670 | * Emits an Approval event. 671 | * @param spender The address which will spend the funds. 672 | * @param subtractedValue The amount of tokens to decrease the allowance by. 673 | */ 674 | function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { 675 | _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); 676 | return true; 677 | } 678 | 679 | /** 680 | * @dev Transfer token for a specified addresses 681 | * @param from The address to transfer from. 682 | * @param to The address to transfer to. 683 | * @param value The amount to be transferred. 684 | */ 685 | function _transfer(address from, address to, uint256 value) internal { 686 | require(to != address(0)); 687 | 688 | _balances[from] = _balances[from].sub(value); 689 | _balances[to] = _balances[to].add(value); 690 | emit Transfer(from, to, value); 691 | } 692 | 693 | /** 694 | * @dev Internal function that mints an amount of the token and assigns it to 695 | * an account. This encapsulates the modification of balances such that the 696 | * proper events are emitted. 697 | * @param account The account that will receive the created tokens. 698 | * @param value The amount that will be created. 699 | */ 700 | function _mint(address account, uint256 value) internal { 701 | require(account != address(0)); 702 | 703 | _totalSupply = _totalSupply.add(value); 704 | _balances[account] = _balances[account].add(value); 705 | emit Transfer(address(0), account, value); 706 | } 707 | 708 | /** 709 | * @dev Internal function that burns an amount of the token of a given 710 | * account. 711 | * @param account The account whose tokens will be burnt. 712 | * @param value The amount that will be burnt. 713 | */ 714 | function _burn(address account, uint256 value) internal { 715 | require(account != address(0)); 716 | 717 | _totalSupply = _totalSupply.sub(value); 718 | _balances[account] = _balances[account].sub(value); 719 | emit Transfer(account, address(0), value); 720 | } 721 | 722 | /** 723 | * @dev Approve an address to spend another addresses' tokens. 724 | * @param owner The address that owns the tokens. 725 | * @param spender The address that will spend the tokens. 726 | * @param value The number of tokens that can be spent. 727 | */ 728 | function _approve(address owner, address spender, uint256 value) internal { 729 | require(spender != address(0)); 730 | require(owner != address(0)); 731 | 732 | _allowed[owner][spender] = value; 733 | emit Approval(owner, spender, value); 734 | } 735 | 736 | /** 737 | * @dev Internal function that burns an amount of the token of a given 738 | * account, deducting from the sender's allowance for said account. Uses the 739 | * internal burn function. 740 | * Emits an Approval event (reflecting the reduced allowance). 741 | * @param account The account whose tokens will be burnt. 742 | * @param value The amount that will be burnt. 743 | */ 744 | function _burnFrom(address account, uint256 value) internal { 745 | _burn(account, value); 746 | _approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); 747 | } 748 | } 749 | 750 | // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol 751 | 752 | pragma solidity ^0.5.2; 753 | 754 | 755 | /** 756 | * @title ERC20Detailed token 757 | * @dev The decimals are only for visualization purposes. 758 | * All the operations are done using the smallest and indivisible token unit, 759 | * just as on Ethereum all the operations are done in wei. 760 | */ 761 | contract ERC20Detailed is IERC20 { 762 | string private _name; 763 | string private _symbol; 764 | uint8 private _decimals; 765 | 766 | constructor (string memory name, string memory symbol, uint8 decimals) public { 767 | _name = name; 768 | _symbol = symbol; 769 | _decimals = decimals; 770 | } 771 | 772 | /** 773 | * @return the name of the token. 774 | */ 775 | function name() public view returns (string memory) { 776 | return _name; 777 | } 778 | 779 | /** 780 | * @return the symbol of the token. 781 | */ 782 | function symbol() public view returns (string memory) { 783 | return _symbol; 784 | } 785 | 786 | /** 787 | * @return the number of decimals of the token. 788 | */ 789 | function decimals() public view returns (uint8) { 790 | return _decimals; 791 | } 792 | } 793 | 794 | // File: contracts/TestToken.sol 795 | 796 | pragma solidity >=0.4.21 <0.6.0; 797 | 798 | 799 | 800 | contract TestToken is ERC20, ERC20Detailed { 801 | constructor( 802 | string memory name, 803 | string memory symbol, 804 | uint8 decimals 805 | ) ERC20Detailed(name, symbol, decimals) public {} 806 | } 807 | ", 808 | } 809 | `; 810 | 811 | exports[`Gathers constructor arguments for relevant contracts: Constructor arguments 1`] = ` 812 | Object { 813 | "build/contracts/TestChildContract.json": "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000054368696c64000000000000000000000000000000000000000000000000000000", 814 | "build/contracts/TestToken.json": "000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a5465737420546f6b656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035453540000000000000000000000000000000000000000000000000000000000", 815 | } 816 | `; 817 | 818 | exports[`Gathers constructor arguments for relevant contracts: Decoded constructor arguments 1`] = ` 819 | Object { 820 | "build/contracts/TestChildContract.json": Result { 821 | "0": "Child", 822 | "__length__": 1, 823 | "_name": "Child", 824 | }, 825 | "build/contracts/TestToken.json": Result { 826 | "0": "Test Token", 827 | "1": "TST", 828 | "2": "18", 829 | "__length__": 3, 830 | "decimals": "18", 831 | "name": "Test Token", 832 | "symbol": "TST", 833 | }, 834 | } 835 | `; 836 | 837 | exports[`Gathers data from Artifacts: Artifact paths 1`] = ` 838 | Array [ 839 | "build/contracts/ERC20.json", 840 | "build/contracts/Migrations.json", 841 | "build/contracts/TestChildContract.json", 842 | "build/contracts/TestContract.json", 843 | "build/contracts/TestToken.json", 844 | ] 845 | `; 846 | 847 | exports[`Gathers data from Artifacts: ERC20.json 1`] = ` 848 | Object { 849 | "bytecode": Any, 850 | "compilerversion": "v0.5.2+commit.1df8f40c", 851 | "contractaddress": "0x76608a542b425cBA81d277F6436007ADd848C0AF", 852 | "contractname": "ERC20", 853 | "hasNonEmptyConstructor": false, 854 | "sourcePath": "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol", 855 | "txhash": StringMatching /\\^0x\\[0-9a-fA-F\\]\\+\\$/, 856 | } 857 | `; 858 | 859 | exports[`Gathers data from Artifacts: Migrations.json 1`] = ` 860 | Object { 861 | "bytecode": Any, 862 | "compilerversion": "v0.5.2+commit.1df8f40c", 863 | "contractaddress": "0xb1c657fa3806D78716dfcBeA9aF1aCf851077D6E", 864 | "contractname": "Migrations", 865 | "hasNonEmptyConstructor": false, 866 | "sourcePath": "$PROJECT_DIR/truffle-test-example/contracts/Migrations.sol", 867 | "txhash": StringMatching /\\^0x\\[0-9a-fA-F\\]\\+\\$/, 868 | } 869 | `; 870 | 871 | exports[`Gathers data from Artifacts: TestChildContract.json 1`] = ` 872 | Object { 873 | "bytecode": Any, 874 | "compilerversion": "v0.5.2+commit.1df8f40c", 875 | "contractaddress": "0xE71d2dDb3CA69a94b557695a9614D3262845EA11", 876 | "contractname": "TestChildContract", 877 | "hasNonEmptyConstructor": true, 878 | "sourcePath": "$PROJECT_DIR/truffle-test-example/contracts/TestChildContract.sol", 879 | "txhash": StringMatching /\\^0x\\[0-9a-fA-F\\]\\+\\$/, 880 | } 881 | `; 882 | 883 | exports[`Gathers data from Artifacts: TestContract.json 1`] = ` 884 | Object { 885 | "bytecode": Any, 886 | "compilerversion": "v0.5.2+commit.1df8f40c", 887 | "contractaddress": "0xC6FC5E99b5D253f6eabf53Fb2eAB94AF4e6A1444", 888 | "contractname": "TestContract", 889 | "hasNonEmptyConstructor": false, 890 | "sourcePath": "$PROJECT_DIR/truffle-test-example/contracts/TestContract.sol", 891 | "txhash": StringMatching /\\^0x\\[0-9a-fA-F\\]\\+\\$/, 892 | } 893 | `; 894 | 895 | exports[`Gathers data from Artifacts: TestToken.json 1`] = ` 896 | Object { 897 | "bytecode": Any, 898 | "compilerversion": "v0.5.2+commit.1df8f40c", 899 | "contractaddress": "0xbE14913754d5A03c8f7c81C98c499033422898Be", 900 | "contractname": "TestToken", 901 | "hasNonEmptyConstructor": true, 902 | "sourcePath": "$PROJECT_DIR/truffle-test-example/contracts/TestToken.sol", 903 | "txhash": StringMatching /\\^0x\\[0-9a-fA-F\\]\\+\\$/, 904 | } 905 | `; 906 | 907 | exports[`Outputs Flattened outputs flattened contracts to a folder: fs.writeFile calls 1`] = ` 908 | Array [ 909 | Array [ 910 | "$PROJECT_DIR/truffle-test-example/output/here/ERC20.flat.sol", 911 | " 912 | // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol 913 | 914 | pragma solidity ^0.5.2; 915 | 916 | /** 917 | * @title ERC20 interface 918 | * @dev see https://eips.ethereum.org/EIPS/eip-20 919 | */ 920 | interface IERC20 { 921 | function transfer(address to, uint256 value) external returns (bool); 922 | 923 | function approve(address spender, uint256 value) external returns (bool); 924 | 925 | function transferFrom(address from, address to, uint256 value) external returns (bool); 926 | 927 | function totalSupply() external view returns (uint256); 928 | 929 | function balanceOf(address who) external view returns (uint256); 930 | 931 | function allowance(address owner, address spender) external view returns (uint256); 932 | 933 | event Transfer(address indexed from, address indexed to, uint256 value); 934 | 935 | event Approval(address indexed owner, address indexed spender, uint256 value); 936 | } 937 | 938 | // File: openzeppelin-solidity/contracts/math/SafeMath.sol 939 | 940 | pragma solidity ^0.5.2; 941 | 942 | /** 943 | * @title SafeMath 944 | * @dev Unsigned math operations with safety checks that revert on error 945 | */ 946 | library SafeMath { 947 | /** 948 | * @dev Multiplies two unsigned integers, reverts on overflow. 949 | */ 950 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 951 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 952 | // benefit is lost if 'b' is also tested. 953 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 954 | if (a == 0) { 955 | return 0; 956 | } 957 | 958 | uint256 c = a * b; 959 | require(c / a == b); 960 | 961 | return c; 962 | } 963 | 964 | /** 965 | * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. 966 | */ 967 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 968 | // Solidity only automatically asserts when dividing by 0 969 | require(b > 0); 970 | uint256 c = a / b; 971 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 972 | 973 | return c; 974 | } 975 | 976 | /** 977 | * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). 978 | */ 979 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 980 | require(b <= a); 981 | uint256 c = a - b; 982 | 983 | return c; 984 | } 985 | 986 | /** 987 | * @dev Adds two unsigned integers, reverts on overflow. 988 | */ 989 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 990 | uint256 c = a + b; 991 | require(c >= a); 992 | 993 | return c; 994 | } 995 | 996 | /** 997 | * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), 998 | * reverts when dividing by zero. 999 | */ 1000 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 1001 | require(b != 0); 1002 | return a % b; 1003 | } 1004 | } 1005 | 1006 | // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol 1007 | 1008 | pragma solidity ^0.5.2; 1009 | 1010 | 1011 | 1012 | /** 1013 | * @title Standard ERC20 token 1014 | * 1015 | * @dev Implementation of the basic standard token. 1016 | * https://eips.ethereum.org/EIPS/eip-20 1017 | * Originally based on code by FirstBlood: 1018 | * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol 1019 | * 1020 | * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for 1021 | * all accounts just by listening to said events. Note that this isn't required by the specification, and other 1022 | * compliant implementations may not do it. 1023 | */ 1024 | contract ERC20 is IERC20 { 1025 | using SafeMath for uint256; 1026 | 1027 | mapping (address => uint256) private _balances; 1028 | 1029 | mapping (address => mapping (address => uint256)) private _allowed; 1030 | 1031 | uint256 private _totalSupply; 1032 | 1033 | /** 1034 | * @dev Total number of tokens in existence 1035 | */ 1036 | function totalSupply() public view returns (uint256) { 1037 | return _totalSupply; 1038 | } 1039 | 1040 | /** 1041 | * @dev Gets the balance of the specified address. 1042 | * @param owner The address to query the balance of. 1043 | * @return A uint256 representing the amount owned by the passed address. 1044 | */ 1045 | function balanceOf(address owner) public view returns (uint256) { 1046 | return _balances[owner]; 1047 | } 1048 | 1049 | /** 1050 | * @dev Function to check the amount of tokens that an owner allowed to a spender. 1051 | * @param owner address The address which owns the funds. 1052 | * @param spender address The address which will spend the funds. 1053 | * @return A uint256 specifying the amount of tokens still available for the spender. 1054 | */ 1055 | function allowance(address owner, address spender) public view returns (uint256) { 1056 | return _allowed[owner][spender]; 1057 | } 1058 | 1059 | /** 1060 | * @dev Transfer token to a specified address 1061 | * @param to The address to transfer to. 1062 | * @param value The amount to be transferred. 1063 | */ 1064 | function transfer(address to, uint256 value) public returns (bool) { 1065 | _transfer(msg.sender, to, value); 1066 | return true; 1067 | } 1068 | 1069 | /** 1070 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 1071 | * Beware that changing an allowance with this method brings the risk that someone may use both the old 1072 | * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this 1073 | * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: 1074 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 1075 | * @param spender The address which will spend the funds. 1076 | * @param value The amount of tokens to be spent. 1077 | */ 1078 | function approve(address spender, uint256 value) public returns (bool) { 1079 | _approve(msg.sender, spender, value); 1080 | return true; 1081 | } 1082 | 1083 | /** 1084 | * @dev Transfer tokens from one address to another. 1085 | * Note that while this function emits an Approval event, this is not required as per the specification, 1086 | * and other compliant implementations may not emit the event. 1087 | * @param from address The address which you want to send tokens from 1088 | * @param to address The address which you want to transfer to 1089 | * @param value uint256 the amount of tokens to be transferred 1090 | */ 1091 | function transferFrom(address from, address to, uint256 value) public returns (bool) { 1092 | _transfer(from, to, value); 1093 | _approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); 1094 | return true; 1095 | } 1096 | 1097 | /** 1098 | * @dev Increase the amount of tokens that an owner allowed to a spender. 1099 | * approve should be called when _allowed[msg.sender][spender] == 0. To increment 1100 | * allowed value is better to use this function to avoid 2 calls (and wait until 1101 | * the first transaction is mined) 1102 | * From MonolithDAO Token.sol 1103 | * Emits an Approval event. 1104 | * @param spender The address which will spend the funds. 1105 | * @param addedValue The amount of tokens to increase the allowance by. 1106 | */ 1107 | function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 1108 | _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); 1109 | return true; 1110 | } 1111 | 1112 | /** 1113 | * @dev Decrease the amount of tokens that an owner allowed to a spender. 1114 | * approve should be called when _allowed[msg.sender][spender] == 0. To decrement 1115 | * allowed value is better to use this function to avoid 2 calls (and wait until 1116 | * the first transaction is mined) 1117 | * From MonolithDAO Token.sol 1118 | * Emits an Approval event. 1119 | * @param spender The address which will spend the funds. 1120 | * @param subtractedValue The amount of tokens to decrease the allowance by. 1121 | */ 1122 | function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { 1123 | _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); 1124 | return true; 1125 | } 1126 | 1127 | /** 1128 | * @dev Transfer token for a specified addresses 1129 | * @param from The address to transfer from. 1130 | * @param to The address to transfer to. 1131 | * @param value The amount to be transferred. 1132 | */ 1133 | function _transfer(address from, address to, uint256 value) internal { 1134 | require(to != address(0)); 1135 | 1136 | _balances[from] = _balances[from].sub(value); 1137 | _balances[to] = _balances[to].add(value); 1138 | emit Transfer(from, to, value); 1139 | } 1140 | 1141 | /** 1142 | * @dev Internal function that mints an amount of the token and assigns it to 1143 | * an account. This encapsulates the modification of balances such that the 1144 | * proper events are emitted. 1145 | * @param account The account that will receive the created tokens. 1146 | * @param value The amount that will be created. 1147 | */ 1148 | function _mint(address account, uint256 value) internal { 1149 | require(account != address(0)); 1150 | 1151 | _totalSupply = _totalSupply.add(value); 1152 | _balances[account] = _balances[account].add(value); 1153 | emit Transfer(address(0), account, value); 1154 | } 1155 | 1156 | /** 1157 | * @dev Internal function that burns an amount of the token of a given 1158 | * account. 1159 | * @param account The account whose tokens will be burnt. 1160 | * @param value The amount that will be burnt. 1161 | */ 1162 | function _burn(address account, uint256 value) internal { 1163 | require(account != address(0)); 1164 | 1165 | _totalSupply = _totalSupply.sub(value); 1166 | _balances[account] = _balances[account].sub(value); 1167 | emit Transfer(account, address(0), value); 1168 | } 1169 | 1170 | /** 1171 | * @dev Approve an address to spend another addresses' tokens. 1172 | * @param owner The address that owns the tokens. 1173 | * @param spender The address that will spend the tokens. 1174 | * @param value The number of tokens that can be spent. 1175 | */ 1176 | function _approve(address owner, address spender, uint256 value) internal { 1177 | require(spender != address(0)); 1178 | require(owner != address(0)); 1179 | 1180 | _allowed[owner][spender] = value; 1181 | emit Approval(owner, spender, value); 1182 | } 1183 | 1184 | /** 1185 | * @dev Internal function that burns an amount of the token of a given 1186 | * account, deducting from the sender's allowance for said account. Uses the 1187 | * internal burn function. 1188 | * Emits an Approval event (reflecting the reduced allowance). 1189 | * @param account The account whose tokens will be burnt. 1190 | * @param value The amount that will be burnt. 1191 | */ 1192 | function _burnFrom(address account, uint256 value) internal { 1193 | _burn(account, value); 1194 | _approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); 1195 | } 1196 | } 1197 | ", 1198 | ], 1199 | Array [ 1200 | "$PROJECT_DIR/truffle-test-example/output/here/Migrations.flat.sol", 1201 | " 1202 | // File: contracts/Migrations.sol 1203 | 1204 | pragma solidity >=0.4.21 <0.6.0; 1205 | 1206 | contract Migrations { 1207 | address public owner; 1208 | uint public last_completed_migration; 1209 | 1210 | constructor() public { 1211 | owner = msg.sender; 1212 | } 1213 | 1214 | modifier restricted() { 1215 | if (msg.sender == owner) _; 1216 | } 1217 | 1218 | function setCompleted(uint completed) public restricted { 1219 | last_completed_migration = completed; 1220 | } 1221 | 1222 | function upgrade(address new_address) public restricted { 1223 | Migrations upgraded = Migrations(new_address); 1224 | upgraded.setCompleted(last_completed_migration); 1225 | } 1226 | } 1227 | ", 1228 | ], 1229 | Array [ 1230 | "$PROJECT_DIR/truffle-test-example/output/here/TestChildContract.flat.sol", 1231 | " 1232 | // File: contracts/TestParentContract.sol 1233 | 1234 | pragma solidity >=0.4.21 <0.6.0; 1235 | 1236 | contract TestParentContract { 1237 | address public owner; 1238 | string public parentName; 1239 | 1240 | constructor(string memory _parentName) public { 1241 | owner = msg.sender; 1242 | parentName = _parentName; 1243 | } 1244 | } 1245 | 1246 | // File: contracts/TestChildContract.sol 1247 | 1248 | pragma solidity >=0.4.21 <0.6.0; 1249 | 1250 | 1251 | contract TestChildContract is TestParentContract(\\"Parent\\") { 1252 | string public name; 1253 | 1254 | constructor(string memory _name) public { 1255 | name = _name; 1256 | } 1257 | } 1258 | ", 1259 | ], 1260 | Array [ 1261 | "$PROJECT_DIR/truffle-test-example/output/here/TestContract.flat.sol", 1262 | " 1263 | // File: contracts/TestContract.sol 1264 | 1265 | pragma solidity >=0.4.21 <0.6.0; 1266 | 1267 | contract TestContract { 1268 | address public owner; 1269 | 1270 | constructor() public { 1271 | owner = msg.sender; 1272 | } 1273 | } 1274 | ", 1275 | ], 1276 | Array [ 1277 | "$PROJECT_DIR/truffle-test-example/output/here/TestToken.flat.sol", 1278 | " 1279 | // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol 1280 | 1281 | pragma solidity ^0.5.2; 1282 | 1283 | /** 1284 | * @title ERC20 interface 1285 | * @dev see https://eips.ethereum.org/EIPS/eip-20 1286 | */ 1287 | interface IERC20 { 1288 | function transfer(address to, uint256 value) external returns (bool); 1289 | 1290 | function approve(address spender, uint256 value) external returns (bool); 1291 | 1292 | function transferFrom(address from, address to, uint256 value) external returns (bool); 1293 | 1294 | function totalSupply() external view returns (uint256); 1295 | 1296 | function balanceOf(address who) external view returns (uint256); 1297 | 1298 | function allowance(address owner, address spender) external view returns (uint256); 1299 | 1300 | event Transfer(address indexed from, address indexed to, uint256 value); 1301 | 1302 | event Approval(address indexed owner, address indexed spender, uint256 value); 1303 | } 1304 | 1305 | // File: openzeppelin-solidity/contracts/math/SafeMath.sol 1306 | 1307 | pragma solidity ^0.5.2; 1308 | 1309 | /** 1310 | * @title SafeMath 1311 | * @dev Unsigned math operations with safety checks that revert on error 1312 | */ 1313 | library SafeMath { 1314 | /** 1315 | * @dev Multiplies two unsigned integers, reverts on overflow. 1316 | */ 1317 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 1318 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 1319 | // benefit is lost if 'b' is also tested. 1320 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 1321 | if (a == 0) { 1322 | return 0; 1323 | } 1324 | 1325 | uint256 c = a * b; 1326 | require(c / a == b); 1327 | 1328 | return c; 1329 | } 1330 | 1331 | /** 1332 | * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. 1333 | */ 1334 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 1335 | // Solidity only automatically asserts when dividing by 0 1336 | require(b > 0); 1337 | uint256 c = a / b; 1338 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 1339 | 1340 | return c; 1341 | } 1342 | 1343 | /** 1344 | * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). 1345 | */ 1346 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 1347 | require(b <= a); 1348 | uint256 c = a - b; 1349 | 1350 | return c; 1351 | } 1352 | 1353 | /** 1354 | * @dev Adds two unsigned integers, reverts on overflow. 1355 | */ 1356 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 1357 | uint256 c = a + b; 1358 | require(c >= a); 1359 | 1360 | return c; 1361 | } 1362 | 1363 | /** 1364 | * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), 1365 | * reverts when dividing by zero. 1366 | */ 1367 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 1368 | require(b != 0); 1369 | return a % b; 1370 | } 1371 | } 1372 | 1373 | // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol 1374 | 1375 | pragma solidity ^0.5.2; 1376 | 1377 | 1378 | 1379 | /** 1380 | * @title Standard ERC20 token 1381 | * 1382 | * @dev Implementation of the basic standard token. 1383 | * https://eips.ethereum.org/EIPS/eip-20 1384 | * Originally based on code by FirstBlood: 1385 | * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol 1386 | * 1387 | * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for 1388 | * all accounts just by listening to said events. Note that this isn't required by the specification, and other 1389 | * compliant implementations may not do it. 1390 | */ 1391 | contract ERC20 is IERC20 { 1392 | using SafeMath for uint256; 1393 | 1394 | mapping (address => uint256) private _balances; 1395 | 1396 | mapping (address => mapping (address => uint256)) private _allowed; 1397 | 1398 | uint256 private _totalSupply; 1399 | 1400 | /** 1401 | * @dev Total number of tokens in existence 1402 | */ 1403 | function totalSupply() public view returns (uint256) { 1404 | return _totalSupply; 1405 | } 1406 | 1407 | /** 1408 | * @dev Gets the balance of the specified address. 1409 | * @param owner The address to query the balance of. 1410 | * @return A uint256 representing the amount owned by the passed address. 1411 | */ 1412 | function balanceOf(address owner) public view returns (uint256) { 1413 | return _balances[owner]; 1414 | } 1415 | 1416 | /** 1417 | * @dev Function to check the amount of tokens that an owner allowed to a spender. 1418 | * @param owner address The address which owns the funds. 1419 | * @param spender address The address which will spend the funds. 1420 | * @return A uint256 specifying the amount of tokens still available for the spender. 1421 | */ 1422 | function allowance(address owner, address spender) public view returns (uint256) { 1423 | return _allowed[owner][spender]; 1424 | } 1425 | 1426 | /** 1427 | * @dev Transfer token to a specified address 1428 | * @param to The address to transfer to. 1429 | * @param value The amount to be transferred. 1430 | */ 1431 | function transfer(address to, uint256 value) public returns (bool) { 1432 | _transfer(msg.sender, to, value); 1433 | return true; 1434 | } 1435 | 1436 | /** 1437 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 1438 | * Beware that changing an allowance with this method brings the risk that someone may use both the old 1439 | * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this 1440 | * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: 1441 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 1442 | * @param spender The address which will spend the funds. 1443 | * @param value The amount of tokens to be spent. 1444 | */ 1445 | function approve(address spender, uint256 value) public returns (bool) { 1446 | _approve(msg.sender, spender, value); 1447 | return true; 1448 | } 1449 | 1450 | /** 1451 | * @dev Transfer tokens from one address to another. 1452 | * Note that while this function emits an Approval event, this is not required as per the specification, 1453 | * and other compliant implementations may not emit the event. 1454 | * @param from address The address which you want to send tokens from 1455 | * @param to address The address which you want to transfer to 1456 | * @param value uint256 the amount of tokens to be transferred 1457 | */ 1458 | function transferFrom(address from, address to, uint256 value) public returns (bool) { 1459 | _transfer(from, to, value); 1460 | _approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); 1461 | return true; 1462 | } 1463 | 1464 | /** 1465 | * @dev Increase the amount of tokens that an owner allowed to a spender. 1466 | * approve should be called when _allowed[msg.sender][spender] == 0. To increment 1467 | * allowed value is better to use this function to avoid 2 calls (and wait until 1468 | * the first transaction is mined) 1469 | * From MonolithDAO Token.sol 1470 | * Emits an Approval event. 1471 | * @param spender The address which will spend the funds. 1472 | * @param addedValue The amount of tokens to increase the allowance by. 1473 | */ 1474 | function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 1475 | _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); 1476 | return true; 1477 | } 1478 | 1479 | /** 1480 | * @dev Decrease the amount of tokens that an owner allowed to a spender. 1481 | * approve should be called when _allowed[msg.sender][spender] == 0. To decrement 1482 | * allowed value is better to use this function to avoid 2 calls (and wait until 1483 | * the first transaction is mined) 1484 | * From MonolithDAO Token.sol 1485 | * Emits an Approval event. 1486 | * @param spender The address which will spend the funds. 1487 | * @param subtractedValue The amount of tokens to decrease the allowance by. 1488 | */ 1489 | function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { 1490 | _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); 1491 | return true; 1492 | } 1493 | 1494 | /** 1495 | * @dev Transfer token for a specified addresses 1496 | * @param from The address to transfer from. 1497 | * @param to The address to transfer to. 1498 | * @param value The amount to be transferred. 1499 | */ 1500 | function _transfer(address from, address to, uint256 value) internal { 1501 | require(to != address(0)); 1502 | 1503 | _balances[from] = _balances[from].sub(value); 1504 | _balances[to] = _balances[to].add(value); 1505 | emit Transfer(from, to, value); 1506 | } 1507 | 1508 | /** 1509 | * @dev Internal function that mints an amount of the token and assigns it to 1510 | * an account. This encapsulates the modification of balances such that the 1511 | * proper events are emitted. 1512 | * @param account The account that will receive the created tokens. 1513 | * @param value The amount that will be created. 1514 | */ 1515 | function _mint(address account, uint256 value) internal { 1516 | require(account != address(0)); 1517 | 1518 | _totalSupply = _totalSupply.add(value); 1519 | _balances[account] = _balances[account].add(value); 1520 | emit Transfer(address(0), account, value); 1521 | } 1522 | 1523 | /** 1524 | * @dev Internal function that burns an amount of the token of a given 1525 | * account. 1526 | * @param account The account whose tokens will be burnt. 1527 | * @param value The amount that will be burnt. 1528 | */ 1529 | function _burn(address account, uint256 value) internal { 1530 | require(account != address(0)); 1531 | 1532 | _totalSupply = _totalSupply.sub(value); 1533 | _balances[account] = _balances[account].sub(value); 1534 | emit Transfer(account, address(0), value); 1535 | } 1536 | 1537 | /** 1538 | * @dev Approve an address to spend another addresses' tokens. 1539 | * @param owner The address that owns the tokens. 1540 | * @param spender The address that will spend the tokens. 1541 | * @param value The number of tokens that can be spent. 1542 | */ 1543 | function _approve(address owner, address spender, uint256 value) internal { 1544 | require(spender != address(0)); 1545 | require(owner != address(0)); 1546 | 1547 | _allowed[owner][spender] = value; 1548 | emit Approval(owner, spender, value); 1549 | } 1550 | 1551 | /** 1552 | * @dev Internal function that burns an amount of the token of a given 1553 | * account, deducting from the sender's allowance for said account. Uses the 1554 | * internal burn function. 1555 | * Emits an Approval event (reflecting the reduced allowance). 1556 | * @param account The account whose tokens will be burnt. 1557 | * @param value The amount that will be burnt. 1558 | */ 1559 | function _burnFrom(address account, uint256 value) internal { 1560 | _burn(account, value); 1561 | _approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); 1562 | } 1563 | } 1564 | 1565 | // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol 1566 | 1567 | pragma solidity ^0.5.2; 1568 | 1569 | 1570 | /** 1571 | * @title ERC20Detailed token 1572 | * @dev The decimals are only for visualization purposes. 1573 | * All the operations are done using the smallest and indivisible token unit, 1574 | * just as on Ethereum all the operations are done in wei. 1575 | */ 1576 | contract ERC20Detailed is IERC20 { 1577 | string private _name; 1578 | string private _symbol; 1579 | uint8 private _decimals; 1580 | 1581 | constructor (string memory name, string memory symbol, uint8 decimals) public { 1582 | _name = name; 1583 | _symbol = symbol; 1584 | _decimals = decimals; 1585 | } 1586 | 1587 | /** 1588 | * @return the name of the token. 1589 | */ 1590 | function name() public view returns (string memory) { 1591 | return _name; 1592 | } 1593 | 1594 | /** 1595 | * @return the symbol of the token. 1596 | */ 1597 | function symbol() public view returns (string memory) { 1598 | return _symbol; 1599 | } 1600 | 1601 | /** 1602 | * @return the number of decimals of the token. 1603 | */ 1604 | function decimals() public view returns (uint8) { 1605 | return _decimals; 1606 | } 1607 | } 1608 | 1609 | // File: contracts/TestToken.sol 1610 | 1611 | pragma solidity >=0.4.21 <0.6.0; 1612 | 1613 | 1614 | 1615 | contract TestToken is ERC20, ERC20Detailed { 1616 | constructor( 1617 | string memory name, 1618 | string memory symbol, 1619 | uint8 decimals 1620 | ) ERC20Detailed(name, symbol, decimals) public {} 1621 | } 1622 | ", 1623 | ], 1624 | ] 1625 | `; 1626 | 1627 | exports[`Posts to verify: Fetch calls 1`] = ` 1628 | Array [ 1629 | Array [ 1630 | "https://api-rinkeby.etherscan.io/api", 1631 | Object { 1632 | "body": URLSearchParams { 1633 | Symbol(query): Array [ 1634 | "contractname", 1635 | "ERC20", 1636 | "compilerversion", 1637 | "v0.5.2+commit.1df8f40c", 1638 | "contractaddress", 1639 | "0x76608a542b425cBA81d277F6436007ADd848C0AF", 1640 | "apikey", 1641 | "", 1642 | "optimizationUsed", 1643 | "1", 1644 | "runs", 1645 | "200", 1646 | "module", 1647 | "contract", 1648 | "action", 1649 | "verifysourcecode", 1650 | "sourceCode", 1651 | " 1652 | // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol 1653 | 1654 | pragma solidity ^0.5.2; 1655 | 1656 | /** 1657 | * @title ERC20 interface 1658 | * @dev see https://eips.ethereum.org/EIPS/eip-20 1659 | */ 1660 | interface IERC20 { 1661 | function transfer(address to, uint256 value) external returns (bool); 1662 | 1663 | function approve(address spender, uint256 value) external returns (bool); 1664 | 1665 | function transferFrom(address from, address to, uint256 value) external returns (bool); 1666 | 1667 | function totalSupply() external view returns (uint256); 1668 | 1669 | function balanceOf(address who) external view returns (uint256); 1670 | 1671 | function allowance(address owner, address spender) external view returns (uint256); 1672 | 1673 | event Transfer(address indexed from, address indexed to, uint256 value); 1674 | 1675 | event Approval(address indexed owner, address indexed spender, uint256 value); 1676 | } 1677 | 1678 | // File: openzeppelin-solidity/contracts/math/SafeMath.sol 1679 | 1680 | pragma solidity ^0.5.2; 1681 | 1682 | /** 1683 | * @title SafeMath 1684 | * @dev Unsigned math operations with safety checks that revert on error 1685 | */ 1686 | library SafeMath { 1687 | /** 1688 | * @dev Multiplies two unsigned integers, reverts on overflow. 1689 | */ 1690 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 1691 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 1692 | // benefit is lost if 'b' is also tested. 1693 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 1694 | if (a == 0) { 1695 | return 0; 1696 | } 1697 | 1698 | uint256 c = a * b; 1699 | require(c / a == b); 1700 | 1701 | return c; 1702 | } 1703 | 1704 | /** 1705 | * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. 1706 | */ 1707 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 1708 | // Solidity only automatically asserts when dividing by 0 1709 | require(b > 0); 1710 | uint256 c = a / b; 1711 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 1712 | 1713 | return c; 1714 | } 1715 | 1716 | /** 1717 | * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). 1718 | */ 1719 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 1720 | require(b <= a); 1721 | uint256 c = a - b; 1722 | 1723 | return c; 1724 | } 1725 | 1726 | /** 1727 | * @dev Adds two unsigned integers, reverts on overflow. 1728 | */ 1729 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 1730 | uint256 c = a + b; 1731 | require(c >= a); 1732 | 1733 | return c; 1734 | } 1735 | 1736 | /** 1737 | * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), 1738 | * reverts when dividing by zero. 1739 | */ 1740 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 1741 | require(b != 0); 1742 | return a % b; 1743 | } 1744 | } 1745 | 1746 | // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol 1747 | 1748 | pragma solidity ^0.5.2; 1749 | 1750 | 1751 | 1752 | /** 1753 | * @title Standard ERC20 token 1754 | * 1755 | * @dev Implementation of the basic standard token. 1756 | * https://eips.ethereum.org/EIPS/eip-20 1757 | * Originally based on code by FirstBlood: 1758 | * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol 1759 | * 1760 | * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for 1761 | * all accounts just by listening to said events. Note that this isn't required by the specification, and other 1762 | * compliant implementations may not do it. 1763 | */ 1764 | contract ERC20 is IERC20 { 1765 | using SafeMath for uint256; 1766 | 1767 | mapping (address => uint256) private _balances; 1768 | 1769 | mapping (address => mapping (address => uint256)) private _allowed; 1770 | 1771 | uint256 private _totalSupply; 1772 | 1773 | /** 1774 | * @dev Total number of tokens in existence 1775 | */ 1776 | function totalSupply() public view returns (uint256) { 1777 | return _totalSupply; 1778 | } 1779 | 1780 | /** 1781 | * @dev Gets the balance of the specified address. 1782 | * @param owner The address to query the balance of. 1783 | * @return A uint256 representing the amount owned by the passed address. 1784 | */ 1785 | function balanceOf(address owner) public view returns (uint256) { 1786 | return _balances[owner]; 1787 | } 1788 | 1789 | /** 1790 | * @dev Function to check the amount of tokens that an owner allowed to a spender. 1791 | * @param owner address The address which owns the funds. 1792 | * @param spender address The address which will spend the funds. 1793 | * @return A uint256 specifying the amount of tokens still available for the spender. 1794 | */ 1795 | function allowance(address owner, address spender) public view returns (uint256) { 1796 | return _allowed[owner][spender]; 1797 | } 1798 | 1799 | /** 1800 | * @dev Transfer token to a specified address 1801 | * @param to The address to transfer to. 1802 | * @param value The amount to be transferred. 1803 | */ 1804 | function transfer(address to, uint256 value) public returns (bool) { 1805 | _transfer(msg.sender, to, value); 1806 | return true; 1807 | } 1808 | 1809 | /** 1810 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 1811 | * Beware that changing an allowance with this method brings the risk that someone may use both the old 1812 | * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this 1813 | * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: 1814 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 1815 | * @param spender The address which will spend the funds. 1816 | * @param value The amount of tokens to be spent. 1817 | */ 1818 | function approve(address spender, uint256 value) public returns (bool) { 1819 | _approve(msg.sender, spender, value); 1820 | return true; 1821 | } 1822 | 1823 | /** 1824 | * @dev Transfer tokens from one address to another. 1825 | * Note that while this function emits an Approval event, this is not required as per the specification, 1826 | * and other compliant implementations may not emit the event. 1827 | * @param from address The address which you want to send tokens from 1828 | * @param to address The address which you want to transfer to 1829 | * @param value uint256 the amount of tokens to be transferred 1830 | */ 1831 | function transferFrom(address from, address to, uint256 value) public returns (bool) { 1832 | _transfer(from, to, value); 1833 | _approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); 1834 | return true; 1835 | } 1836 | 1837 | /** 1838 | * @dev Increase the amount of tokens that an owner allowed to a spender. 1839 | * approve should be called when _allowed[msg.sender][spender] == 0. To increment 1840 | * allowed value is better to use this function to avoid 2 calls (and wait until 1841 | * the first transaction is mined) 1842 | * From MonolithDAO Token.sol 1843 | * Emits an Approval event. 1844 | * @param spender The address which will spend the funds. 1845 | * @param addedValue The amount of tokens to increase the allowance by. 1846 | */ 1847 | function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 1848 | _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); 1849 | return true; 1850 | } 1851 | 1852 | /** 1853 | * @dev Decrease the amount of tokens that an owner allowed to a spender. 1854 | * approve should be called when _allowed[msg.sender][spender] == 0. To decrement 1855 | * allowed value is better to use this function to avoid 2 calls (and wait until 1856 | * the first transaction is mined) 1857 | * From MonolithDAO Token.sol 1858 | * Emits an Approval event. 1859 | * @param spender The address which will spend the funds. 1860 | * @param subtractedValue The amount of tokens to decrease the allowance by. 1861 | */ 1862 | function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { 1863 | _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); 1864 | return true; 1865 | } 1866 | 1867 | /** 1868 | * @dev Transfer token for a specified addresses 1869 | * @param from The address to transfer from. 1870 | * @param to The address to transfer to. 1871 | * @param value The amount to be transferred. 1872 | */ 1873 | function _transfer(address from, address to, uint256 value) internal { 1874 | require(to != address(0)); 1875 | 1876 | _balances[from] = _balances[from].sub(value); 1877 | _balances[to] = _balances[to].add(value); 1878 | emit Transfer(from, to, value); 1879 | } 1880 | 1881 | /** 1882 | * @dev Internal function that mints an amount of the token and assigns it to 1883 | * an account. This encapsulates the modification of balances such that the 1884 | * proper events are emitted. 1885 | * @param account The account that will receive the created tokens. 1886 | * @param value The amount that will be created. 1887 | */ 1888 | function _mint(address account, uint256 value) internal { 1889 | require(account != address(0)); 1890 | 1891 | _totalSupply = _totalSupply.add(value); 1892 | _balances[account] = _balances[account].add(value); 1893 | emit Transfer(address(0), account, value); 1894 | } 1895 | 1896 | /** 1897 | * @dev Internal function that burns an amount of the token of a given 1898 | * account. 1899 | * @param account The account whose tokens will be burnt. 1900 | * @param value The amount that will be burnt. 1901 | */ 1902 | function _burn(address account, uint256 value) internal { 1903 | require(account != address(0)); 1904 | 1905 | _totalSupply = _totalSupply.sub(value); 1906 | _balances[account] = _balances[account].sub(value); 1907 | emit Transfer(account, address(0), value); 1908 | } 1909 | 1910 | /** 1911 | * @dev Approve an address to spend another addresses' tokens. 1912 | * @param owner The address that owns the tokens. 1913 | * @param spender The address that will spend the tokens. 1914 | * @param value The number of tokens that can be spent. 1915 | */ 1916 | function _approve(address owner, address spender, uint256 value) internal { 1917 | require(spender != address(0)); 1918 | require(owner != address(0)); 1919 | 1920 | _allowed[owner][spender] = value; 1921 | emit Approval(owner, spender, value); 1922 | } 1923 | 1924 | /** 1925 | * @dev Internal function that burns an amount of the token of a given 1926 | * account, deducting from the sender's allowance for said account. Uses the 1927 | * internal burn function. 1928 | * Emits an Approval event (reflecting the reduced allowance). 1929 | * @param account The account whose tokens will be burnt. 1930 | * @param value The amount that will be burnt. 1931 | */ 1932 | function _burnFrom(address account, uint256 value) internal { 1933 | _burn(account, value); 1934 | _approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); 1935 | } 1936 | } 1937 | ", 1938 | ], 1939 | Symbol(context): null, 1940 | }, 1941 | "headers": Object { 1942 | "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", 1943 | }, 1944 | "method": "post", 1945 | }, 1946 | ], 1947 | Array [ 1948 | "https://api-rinkeby.etherscan.io/api", 1949 | Object { 1950 | "body": URLSearchParams { 1951 | Symbol(query): Array [ 1952 | "contractname", 1953 | "Migrations", 1954 | "compilerversion", 1955 | "v0.5.2+commit.1df8f40c", 1956 | "contractaddress", 1957 | "0xb1c657fa3806D78716dfcBeA9aF1aCf851077D6E", 1958 | "apikey", 1959 | "", 1960 | "optimizationUsed", 1961 | "1", 1962 | "runs", 1963 | "200", 1964 | "module", 1965 | "contract", 1966 | "action", 1967 | "verifysourcecode", 1968 | "sourceCode", 1969 | " 1970 | // File: contracts/Migrations.sol 1971 | 1972 | pragma solidity >=0.4.21 <0.6.0; 1973 | 1974 | contract Migrations { 1975 | address public owner; 1976 | uint public last_completed_migration; 1977 | 1978 | constructor() public { 1979 | owner = msg.sender; 1980 | } 1981 | 1982 | modifier restricted() { 1983 | if (msg.sender == owner) _; 1984 | } 1985 | 1986 | function setCompleted(uint completed) public restricted { 1987 | last_completed_migration = completed; 1988 | } 1989 | 1990 | function upgrade(address new_address) public restricted { 1991 | Migrations upgraded = Migrations(new_address); 1992 | upgraded.setCompleted(last_completed_migration); 1993 | } 1994 | } 1995 | ", 1996 | ], 1997 | Symbol(context): null, 1998 | }, 1999 | "headers": Object { 2000 | "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", 2001 | }, 2002 | "method": "post", 2003 | }, 2004 | ], 2005 | Array [ 2006 | "https://api-rinkeby.etherscan.io/api", 2007 | Object { 2008 | "body": URLSearchParams { 2009 | Symbol(query): Array [ 2010 | "contractname", 2011 | "TestChildContract", 2012 | "compilerversion", 2013 | "v0.5.2+commit.1df8f40c", 2014 | "contractaddress", 2015 | "0xE71d2dDb3CA69a94b557695a9614D3262845EA11", 2016 | "apikey", 2017 | "", 2018 | "optimizationUsed", 2019 | "1", 2020 | "runs", 2021 | "200", 2022 | "module", 2023 | "contract", 2024 | "action", 2025 | "verifysourcecode", 2026 | "sourceCode", 2027 | " 2028 | // File: contracts/TestParentContract.sol 2029 | 2030 | pragma solidity >=0.4.21 <0.6.0; 2031 | 2032 | contract TestParentContract { 2033 | address public owner; 2034 | string public parentName; 2035 | 2036 | constructor(string memory _parentName) public { 2037 | owner = msg.sender; 2038 | parentName = _parentName; 2039 | } 2040 | } 2041 | 2042 | // File: contracts/TestChildContract.sol 2043 | 2044 | pragma solidity >=0.4.21 <0.6.0; 2045 | 2046 | 2047 | contract TestChildContract is TestParentContract(\\"Parent\\") { 2048 | string public name; 2049 | 2050 | constructor(string memory _name) public { 2051 | name = _name; 2052 | } 2053 | } 2054 | ", 2055 | "constructorArguements", 2056 | "000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000054368696c64000000000000000000000000000000000000000000000000000000", 2057 | ], 2058 | Symbol(context): null, 2059 | }, 2060 | "headers": Object { 2061 | "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", 2062 | }, 2063 | "method": "post", 2064 | }, 2065 | ], 2066 | Array [ 2067 | "https://api-rinkeby.etherscan.io/api", 2068 | Object { 2069 | "body": URLSearchParams { 2070 | Symbol(query): Array [ 2071 | "contractname", 2072 | "TestContract", 2073 | "compilerversion", 2074 | "v0.5.2+commit.1df8f40c", 2075 | "contractaddress", 2076 | "0xC6FC5E99b5D253f6eabf53Fb2eAB94AF4e6A1444", 2077 | "apikey", 2078 | "", 2079 | "optimizationUsed", 2080 | "1", 2081 | "runs", 2082 | "200", 2083 | "module", 2084 | "contract", 2085 | "action", 2086 | "verifysourcecode", 2087 | "sourceCode", 2088 | " 2089 | // File: contracts/TestContract.sol 2090 | 2091 | pragma solidity >=0.4.21 <0.6.0; 2092 | 2093 | contract TestContract { 2094 | address public owner; 2095 | 2096 | constructor() public { 2097 | owner = msg.sender; 2098 | } 2099 | } 2100 | ", 2101 | ], 2102 | Symbol(context): null, 2103 | }, 2104 | "headers": Object { 2105 | "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", 2106 | }, 2107 | "method": "post", 2108 | }, 2109 | ], 2110 | Array [ 2111 | "https://api-rinkeby.etherscan.io/api", 2112 | Object { 2113 | "body": URLSearchParams { 2114 | Symbol(query): Array [ 2115 | "contractname", 2116 | "TestToken", 2117 | "compilerversion", 2118 | "v0.5.2+commit.1df8f40c", 2119 | "contractaddress", 2120 | "0xbE14913754d5A03c8f7c81C98c499033422898Be", 2121 | "apikey", 2122 | "", 2123 | "optimizationUsed", 2124 | "1", 2125 | "runs", 2126 | "200", 2127 | "module", 2128 | "contract", 2129 | "action", 2130 | "verifysourcecode", 2131 | "sourceCode", 2132 | " 2133 | // File: openzeppelin-solidity/contracts/token/ERC20/IERC20.sol 2134 | 2135 | pragma solidity ^0.5.2; 2136 | 2137 | /** 2138 | * @title ERC20 interface 2139 | * @dev see https://eips.ethereum.org/EIPS/eip-20 2140 | */ 2141 | interface IERC20 { 2142 | function transfer(address to, uint256 value) external returns (bool); 2143 | 2144 | function approve(address spender, uint256 value) external returns (bool); 2145 | 2146 | function transferFrom(address from, address to, uint256 value) external returns (bool); 2147 | 2148 | function totalSupply() external view returns (uint256); 2149 | 2150 | function balanceOf(address who) external view returns (uint256); 2151 | 2152 | function allowance(address owner, address spender) external view returns (uint256); 2153 | 2154 | event Transfer(address indexed from, address indexed to, uint256 value); 2155 | 2156 | event Approval(address indexed owner, address indexed spender, uint256 value); 2157 | } 2158 | 2159 | // File: openzeppelin-solidity/contracts/math/SafeMath.sol 2160 | 2161 | pragma solidity ^0.5.2; 2162 | 2163 | /** 2164 | * @title SafeMath 2165 | * @dev Unsigned math operations with safety checks that revert on error 2166 | */ 2167 | library SafeMath { 2168 | /** 2169 | * @dev Multiplies two unsigned integers, reverts on overflow. 2170 | */ 2171 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 2172 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 2173 | // benefit is lost if 'b' is also tested. 2174 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 2175 | if (a == 0) { 2176 | return 0; 2177 | } 2178 | 2179 | uint256 c = a * b; 2180 | require(c / a == b); 2181 | 2182 | return c; 2183 | } 2184 | 2185 | /** 2186 | * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero. 2187 | */ 2188 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 2189 | // Solidity only automatically asserts when dividing by 0 2190 | require(b > 0); 2191 | uint256 c = a / b; 2192 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 2193 | 2194 | return c; 2195 | } 2196 | 2197 | /** 2198 | * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend). 2199 | */ 2200 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 2201 | require(b <= a); 2202 | uint256 c = a - b; 2203 | 2204 | return c; 2205 | } 2206 | 2207 | /** 2208 | * @dev Adds two unsigned integers, reverts on overflow. 2209 | */ 2210 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 2211 | uint256 c = a + b; 2212 | require(c >= a); 2213 | 2214 | return c; 2215 | } 2216 | 2217 | /** 2218 | * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo), 2219 | * reverts when dividing by zero. 2220 | */ 2221 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 2222 | require(b != 0); 2223 | return a % b; 2224 | } 2225 | } 2226 | 2227 | // File: openzeppelin-solidity/contracts/token/ERC20/ERC20.sol 2228 | 2229 | pragma solidity ^0.5.2; 2230 | 2231 | 2232 | 2233 | /** 2234 | * @title Standard ERC20 token 2235 | * 2236 | * @dev Implementation of the basic standard token. 2237 | * https://eips.ethereum.org/EIPS/eip-20 2238 | * Originally based on code by FirstBlood: 2239 | * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol 2240 | * 2241 | * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for 2242 | * all accounts just by listening to said events. Note that this isn't required by the specification, and other 2243 | * compliant implementations may not do it. 2244 | */ 2245 | contract ERC20 is IERC20 { 2246 | using SafeMath for uint256; 2247 | 2248 | mapping (address => uint256) private _balances; 2249 | 2250 | mapping (address => mapping (address => uint256)) private _allowed; 2251 | 2252 | uint256 private _totalSupply; 2253 | 2254 | /** 2255 | * @dev Total number of tokens in existence 2256 | */ 2257 | function totalSupply() public view returns (uint256) { 2258 | return _totalSupply; 2259 | } 2260 | 2261 | /** 2262 | * @dev Gets the balance of the specified address. 2263 | * @param owner The address to query the balance of. 2264 | * @return A uint256 representing the amount owned by the passed address. 2265 | */ 2266 | function balanceOf(address owner) public view returns (uint256) { 2267 | return _balances[owner]; 2268 | } 2269 | 2270 | /** 2271 | * @dev Function to check the amount of tokens that an owner allowed to a spender. 2272 | * @param owner address The address which owns the funds. 2273 | * @param spender address The address which will spend the funds. 2274 | * @return A uint256 specifying the amount of tokens still available for the spender. 2275 | */ 2276 | function allowance(address owner, address spender) public view returns (uint256) { 2277 | return _allowed[owner][spender]; 2278 | } 2279 | 2280 | /** 2281 | * @dev Transfer token to a specified address 2282 | * @param to The address to transfer to. 2283 | * @param value The amount to be transferred. 2284 | */ 2285 | function transfer(address to, uint256 value) public returns (bool) { 2286 | _transfer(msg.sender, to, value); 2287 | return true; 2288 | } 2289 | 2290 | /** 2291 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 2292 | * Beware that changing an allowance with this method brings the risk that someone may use both the old 2293 | * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this 2294 | * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: 2295 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 2296 | * @param spender The address which will spend the funds. 2297 | * @param value The amount of tokens to be spent. 2298 | */ 2299 | function approve(address spender, uint256 value) public returns (bool) { 2300 | _approve(msg.sender, spender, value); 2301 | return true; 2302 | } 2303 | 2304 | /** 2305 | * @dev Transfer tokens from one address to another. 2306 | * Note that while this function emits an Approval event, this is not required as per the specification, 2307 | * and other compliant implementations may not emit the event. 2308 | * @param from address The address which you want to send tokens from 2309 | * @param to address The address which you want to transfer to 2310 | * @param value uint256 the amount of tokens to be transferred 2311 | */ 2312 | function transferFrom(address from, address to, uint256 value) public returns (bool) { 2313 | _transfer(from, to, value); 2314 | _approve(from, msg.sender, _allowed[from][msg.sender].sub(value)); 2315 | return true; 2316 | } 2317 | 2318 | /** 2319 | * @dev Increase the amount of tokens that an owner allowed to a spender. 2320 | * approve should be called when _allowed[msg.sender][spender] == 0. To increment 2321 | * allowed value is better to use this function to avoid 2 calls (and wait until 2322 | * the first transaction is mined) 2323 | * From MonolithDAO Token.sol 2324 | * Emits an Approval event. 2325 | * @param spender The address which will spend the funds. 2326 | * @param addedValue The amount of tokens to increase the allowance by. 2327 | */ 2328 | function increaseAllowance(address spender, uint256 addedValue) public returns (bool) { 2329 | _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue)); 2330 | return true; 2331 | } 2332 | 2333 | /** 2334 | * @dev Decrease the amount of tokens that an owner allowed to a spender. 2335 | * approve should be called when _allowed[msg.sender][spender] == 0. To decrement 2336 | * allowed value is better to use this function to avoid 2 calls (and wait until 2337 | * the first transaction is mined) 2338 | * From MonolithDAO Token.sol 2339 | * Emits an Approval event. 2340 | * @param spender The address which will spend the funds. 2341 | * @param subtractedValue The amount of tokens to decrease the allowance by. 2342 | */ 2343 | function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) { 2344 | _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue)); 2345 | return true; 2346 | } 2347 | 2348 | /** 2349 | * @dev Transfer token for a specified addresses 2350 | * @param from The address to transfer from. 2351 | * @param to The address to transfer to. 2352 | * @param value The amount to be transferred. 2353 | */ 2354 | function _transfer(address from, address to, uint256 value) internal { 2355 | require(to != address(0)); 2356 | 2357 | _balances[from] = _balances[from].sub(value); 2358 | _balances[to] = _balances[to].add(value); 2359 | emit Transfer(from, to, value); 2360 | } 2361 | 2362 | /** 2363 | * @dev Internal function that mints an amount of the token and assigns it to 2364 | * an account. This encapsulates the modification of balances such that the 2365 | * proper events are emitted. 2366 | * @param account The account that will receive the created tokens. 2367 | * @param value The amount that will be created. 2368 | */ 2369 | function _mint(address account, uint256 value) internal { 2370 | require(account != address(0)); 2371 | 2372 | _totalSupply = _totalSupply.add(value); 2373 | _balances[account] = _balances[account].add(value); 2374 | emit Transfer(address(0), account, value); 2375 | } 2376 | 2377 | /** 2378 | * @dev Internal function that burns an amount of the token of a given 2379 | * account. 2380 | * @param account The account whose tokens will be burnt. 2381 | * @param value The amount that will be burnt. 2382 | */ 2383 | function _burn(address account, uint256 value) internal { 2384 | require(account != address(0)); 2385 | 2386 | _totalSupply = _totalSupply.sub(value); 2387 | _balances[account] = _balances[account].sub(value); 2388 | emit Transfer(account, address(0), value); 2389 | } 2390 | 2391 | /** 2392 | * @dev Approve an address to spend another addresses' tokens. 2393 | * @param owner The address that owns the tokens. 2394 | * @param spender The address that will spend the tokens. 2395 | * @param value The number of tokens that can be spent. 2396 | */ 2397 | function _approve(address owner, address spender, uint256 value) internal { 2398 | require(spender != address(0)); 2399 | require(owner != address(0)); 2400 | 2401 | _allowed[owner][spender] = value; 2402 | emit Approval(owner, spender, value); 2403 | } 2404 | 2405 | /** 2406 | * @dev Internal function that burns an amount of the token of a given 2407 | * account, deducting from the sender's allowance for said account. Uses the 2408 | * internal burn function. 2409 | * Emits an Approval event (reflecting the reduced allowance). 2410 | * @param account The account whose tokens will be burnt. 2411 | * @param value The amount that will be burnt. 2412 | */ 2413 | function _burnFrom(address account, uint256 value) internal { 2414 | _burn(account, value); 2415 | _approve(account, msg.sender, _allowed[account][msg.sender].sub(value)); 2416 | } 2417 | } 2418 | 2419 | // File: openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol 2420 | 2421 | pragma solidity ^0.5.2; 2422 | 2423 | 2424 | /** 2425 | * @title ERC20Detailed token 2426 | * @dev The decimals are only for visualization purposes. 2427 | * All the operations are done using the smallest and indivisible token unit, 2428 | * just as on Ethereum all the operations are done in wei. 2429 | */ 2430 | contract ERC20Detailed is IERC20 { 2431 | string private _name; 2432 | string private _symbol; 2433 | uint8 private _decimals; 2434 | 2435 | constructor (string memory name, string memory symbol, uint8 decimals) public { 2436 | _name = name; 2437 | _symbol = symbol; 2438 | _decimals = decimals; 2439 | } 2440 | 2441 | /** 2442 | * @return the name of the token. 2443 | */ 2444 | function name() public view returns (string memory) { 2445 | return _name; 2446 | } 2447 | 2448 | /** 2449 | * @return the symbol of the token. 2450 | */ 2451 | function symbol() public view returns (string memory) { 2452 | return _symbol; 2453 | } 2454 | 2455 | /** 2456 | * @return the number of decimals of the token. 2457 | */ 2458 | function decimals() public view returns (uint8) { 2459 | return _decimals; 2460 | } 2461 | } 2462 | 2463 | // File: contracts/TestToken.sol 2464 | 2465 | pragma solidity >=0.4.21 <0.6.0; 2466 | 2467 | 2468 | 2469 | contract TestToken is ERC20, ERC20Detailed { 2470 | constructor( 2471 | string memory name, 2472 | string memory symbol, 2473 | uint8 decimals 2474 | ) ERC20Detailed(name, symbol, decimals) public {} 2475 | } 2476 | ", 2477 | "constructorArguements", 2478 | "000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a5465737420546f6b656e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000035453540000000000000000000000000000000000000000000000000000000000", 2479 | ], 2480 | Symbol(context): null, 2481 | }, 2482 | "headers": Object { 2483 | "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", 2484 | }, 2485 | "method": "post", 2486 | }, 2487 | ], 2488 | Array [ 2489 | "https://api-rinkeby.etherscan.io/api?module=contract&action=checkverifystatus&guid=guid2", 2490 | ], 2491 | Array [ 2492 | "https://api-rinkeby.etherscan.io/api?module=contract&action=checkverifystatus&guid=guid3", 2493 | ], 2494 | Array [ 2495 | "https://api-rinkeby.etherscan.io/api?module=contract&action=checkverifystatus&guid=guid4", 2496 | ], 2497 | Array [ 2498 | "https://api-rinkeby.etherscan.io/api?module=contract&action=checkverifystatus&guid=guid2", 2499 | ], 2500 | Array [ 2501 | "https://api-rinkeby.etherscan.io/api?module=contract&action=checkverifystatus&guid=guid3", 2502 | ], 2503 | Array [ 2504 | "https://api-rinkeby.etherscan.io/api?module=contract&action=checkverifystatus&guid=guid4", 2505 | ], 2506 | ] 2507 | `; 2508 | 2509 | exports[`Posts to verify: Fetch returns 1`] = ` 2510 | Array [ 2511 | Object { 2512 | "result": "Contract source code already verified", 2513 | "status": "0", 2514 | }, 2515 | Object { 2516 | "result": "Contract source code already verified", 2517 | "status": "0", 2518 | }, 2519 | Object { 2520 | "result": "guid2", 2521 | "status": "1", 2522 | }, 2523 | Object { 2524 | "result": "guid3", 2525 | "status": "1", 2526 | }, 2527 | Object { 2528 | "result": "guid4", 2529 | "status": "1", 2530 | }, 2531 | Object { 2532 | "result": "Pending in queue", 2533 | "status": "0", 2534 | }, 2535 | Object { 2536 | "result": "Pending in queue", 2537 | "status": "0", 2538 | }, 2539 | Object { 2540 | "result": "Pending in queue", 2541 | "status": "0", 2542 | }, 2543 | Object { 2544 | "result": "Pass - Verified", 2545 | "status": "1", 2546 | }, 2547 | Object { 2548 | "result": "Pass - Verified", 2549 | "status": "1", 2550 | }, 2551 | Object { 2552 | "result": "Pass - Verified", 2553 | "status": "1", 2554 | }, 2555 | ] 2556 | `; 2557 | 2558 | exports[`Posts to verify: Final result 1`] = ` 2559 | Object { 2560 | "alreadyVerified": Array [ 2561 | "build/contracts/ERC20.json", 2562 | "build/contracts/Migrations.json", 2563 | ], 2564 | "failed": Array [], 2565 | "successful": Array [ 2566 | "build/contracts/TestChildContract.json", 2567 | "build/contracts/TestContract.json", 2568 | "build/contracts/TestToken.json", 2569 | ], 2570 | } 2571 | `; 2572 | 2573 | exports[`Posts to verify: Log calls 1`] = ` 2574 | Array [ 2575 | Array [], 2576 | Array [ 2577 | "Error verifying ERC20 at 0x76608a542b425cBA81d277F6436007ADd848C0AF. Contract source code already verified 2578 | ", 2579 | ], 2580 | Array [ 2581 | "Error verifying Migrations at 0xb1c657fa3806D78716dfcBeA9aF1aCf851077D6E. Contract source code already verified 2582 | ", 2583 | ], 2584 | Array [ 2585 | "Verification started for TestChildContract at 0xE71d2dDb3CA69a94b557695a9614D3262845EA11", 2586 | ], 2587 | Array [ 2588 | " GUID: ", 2589 | "guid2", 2590 | ], 2591 | Array [ 2592 | "Check progress at https://api-rinkeby.etherscan.io/api?module=contract&action=checkverifystatus&guid=guid2 2593 | ", 2594 | ], 2595 | Array [ 2596 | "Verification started for TestContract at 0xC6FC5E99b5D253f6eabf53Fb2eAB94AF4e6A1444", 2597 | ], 2598 | Array [ 2599 | " GUID: ", 2600 | "guid3", 2601 | ], 2602 | Array [ 2603 | "Check progress at https://api-rinkeby.etherscan.io/api?module=contract&action=checkverifystatus&guid=guid3 2604 | ", 2605 | ], 2606 | Array [ 2607 | "Verification started for TestToken at 0xbE14913754d5A03c8f7c81C98c499033422898Be", 2608 | ], 2609 | Array [ 2610 | " GUID: ", 2611 | "guid4", 2612 | ], 2613 | Array [ 2614 | "Check progress at https://api-rinkeby.etherscan.io/api?module=contract&action=checkverifystatus&guid=guid4 2615 | ", 2616 | ], 2617 | Array [], 2618 | Array [ 2619 | "TestChildContract at 0xE71d2dDb3CA69a94b557695a9614D3262845EA11", 2620 | "Pass - Verified", 2621 | ], 2622 | Array [ 2623 | "View verified code at https://rinkeby.etherscan.io/address/0xE71d2dDb3CA69a94b557695a9614D3262845EA11#code 2624 | ", 2625 | ], 2626 | Array [ 2627 | "TestContract at 0xC6FC5E99b5D253f6eabf53Fb2eAB94AF4e6A1444", 2628 | "Pass - Verified", 2629 | ], 2630 | Array [ 2631 | "View verified code at https://rinkeby.etherscan.io/address/0xC6FC5E99b5D253f6eabf53Fb2eAB94AF4e6A1444#code 2632 | ", 2633 | ], 2634 | Array [ 2635 | "TestToken at 0xbE14913754d5A03c8f7c81C98c499033422898Be", 2636 | "Pass - Verified", 2637 | ], 2638 | Array [ 2639 | "View verified code at https://rinkeby.etherscan.io/address/0xbE14913754d5A03c8f7c81C98c499033422898Be#code 2640 | ", 2641 | ], 2642 | ] 2643 | `; 2644 | 2645 | exports[`Process config plugin config: Plugin config 1`] = ` 2646 | Object { 2647 | "apiKey": undefined, 2648 | "artifacts": Array [ 2649 | "build/contracts/ERC20.json", 2650 | "build/contracts/ERC20Detailed.json", 2651 | "build/contracts/IERC20.json", 2652 | "build/contracts/Migrations.json", 2653 | "build/contracts/OneContract.json", 2654 | "build/contracts/SafeMath.json", 2655 | "build/contracts/TestChildContract.json", 2656 | "build/contracts/TestContract.json", 2657 | "build/contracts/TestParentContract.json", 2658 | "build/contracts/TestToken.json", 2659 | "build/contracts/TwoContract.json", 2660 | ], 2661 | "cwd": "$PROJECT_DIR/truffle-test-example", 2662 | "delay": undefined, 2663 | "logger": undefined, 2664 | "network": "rinkeby", 2665 | "optimizer": undefined, 2666 | "output": undefined, 2667 | "useFetch": undefined, 2668 | "verbose": undefined, 2669 | "web3": Any, 2670 | } 2671 | `; 2672 | 2673 | exports[`Process config working config: Lib config 1`] = ` 2674 | Object { 2675 | "apiUrl": "https://api-rinkeby.etherscan.io/api", 2676 | "artifacts": Array [ 2677 | "$PROJECT_DIR/truffle-test-example/build/contracts/ERC20.json", 2678 | "$PROJECT_DIR/truffle-test-example/build/contracts/ERC20Detailed.json", 2679 | "$PROJECT_DIR/truffle-test-example/build/contracts/IERC20.json", 2680 | "$PROJECT_DIR/truffle-test-example/build/contracts/Migrations.json", 2681 | "$PROJECT_DIR/truffle-test-example/build/contracts/OneContract.json", 2682 | "$PROJECT_DIR/truffle-test-example/build/contracts/SafeMath.json", 2683 | "$PROJECT_DIR/truffle-test-example/build/contracts/TestChildContract.json", 2684 | "$PROJECT_DIR/truffle-test-example/build/contracts/TestContract.json", 2685 | "$PROJECT_DIR/truffle-test-example/build/contracts/TestParentContract.json", 2686 | "$PROJECT_DIR/truffle-test-example/build/contracts/TestToken.json", 2687 | "$PROJECT_DIR/truffle-test-example/build/contracts/TwoContract.json", 2688 | ], 2689 | "logger": Any, 2690 | "network": "rinkeby", 2691 | "networkId": 4, 2692 | "optimizer": Object { 2693 | "enabled": false, 2694 | "runs": 200, 2695 | }, 2696 | "web3": Any, 2697 | } 2698 | `; 2699 | -------------------------------------------------------------------------------- /__tests__/integration.js: -------------------------------------------------------------------------------- 1 | const ganache = require('ganache-cli'); 2 | const Web3 = require('web3'); 3 | const path = require('path'); 4 | const { exec } = require('child_process'); 5 | 6 | jest.mock('node-fetch'); 7 | const fetch = require('node-fetch'); 8 | 9 | const projectDir = new RegExp(process.cwd(), 'g'); 10 | const replacement = '$PROJECT_DIR'; 11 | const exclude = new Set(['web3', 'logger', 'bytecode', 'sourceCode']); 12 | 13 | const hexR = /^0x[0-9a-fA-F]+$/; 14 | 15 | const replaceCWD = val => { 16 | const replace = original => { 17 | if (typeof original === 'string') return original.replace(projectDir, replacement); 18 | 19 | if (Array.isArray(original)) { 20 | return original.map(replace); 21 | } 22 | 23 | if (typeof original === 'object' && original !== null) { 24 | return Object.keys(original).reduce((accum, k) => { 25 | if (exclude.has(k)) accum[k] = original[k]; 26 | else accum[k] = replace(original[k]); 27 | 28 | return accum; 29 | }, {}); 30 | } 31 | 32 | return original; 33 | }; 34 | 35 | return replace(val); 36 | }; 37 | 38 | const fs = require('fs-extra'); 39 | 40 | const { Response } = jest.requireActual('node-fetch'); 41 | 42 | let web3; 43 | let server; 44 | let cwd; 45 | let artifacts; 46 | 47 | const gatherDataFromArtifacts = require('../src/gather_data_from_artifacts'); 48 | const filterOutVerified = require('../src/filter_out_verified'); 49 | const flattenContracts = require('../src/flatten_contracts'); 50 | const outputFlattened = require('../src/output_flattened'); 51 | const getConstructorArguments = require('../src/get_constructor_arguments'); 52 | const postToVerify = require('../src/post_to_verify'); 53 | const { processConfig, processPluginConfig } = require('../src/process_config'); 54 | 55 | const NETWORK_ID = 4; 56 | const NETWORK_NAME = 'rinkeby'; 57 | const SEED = 42; 58 | 59 | const getInputFiles = async () => { 60 | const artifactFilenames = await fs.readdir('./build/contracts'); 61 | 62 | return artifactFilenames.map(art => path.join('./build/contracts', art)); 63 | }; 64 | 65 | beforeAll(async done => { 66 | process.chdir('./truffle-test-example'); 67 | cwd = process.cwd(); 68 | 69 | server = ganache.server({ network_id: NETWORK_ID, seed: SEED }); 70 | 71 | server.once('error', done); 72 | 73 | console.log('Starting GANACHE server'); 74 | server.listen(8545, err => { 75 | if (err) return done(err); 76 | console.log('GANACHE server started'); 77 | exec( 78 | // 'cd ./truffle-test-example && npx truffle compile && npx truffle migrate' 79 | // have to do reset, 80 | // otherwise truffle assumes fixed network_id, blockchain is the same 81 | // and tries to read Migrations 82 | 'npx truffle compile && npx truffle migrate --reset', 83 | { encoding: 'utf8' }, 84 | (error, stdout, stderr) => { 85 | server.removeListener('error', done); 86 | if (error) { 87 | console.log('stdout: ', stdout); 88 | console.log('stderr: ', stderr); 89 | return done(error); 90 | } 91 | console.log('Contracts are compiled and migrated'); 92 | 93 | // supresses MaxListenersExceededWarning 94 | server.provider.setMaxListeners(20); 95 | web3 = new Web3(server.provider); 96 | 97 | done(); 98 | } 99 | ); 100 | }); 101 | }, 50000); 102 | 103 | let config; 104 | let apiUrl; 105 | beforeAll(async () => { 106 | // console.log('SECOND beforeAll'); 107 | artifacts = await getInputFiles(); 108 | 109 | apiUrl = `https://api${NETWORK_NAME === 'mainnet' ? '' : `-${NETWORK_NAME}`}.etherscan.io/api`; 110 | 111 | config = { 112 | working_directory: cwd, 113 | network: NETWORK_NAME, 114 | _: [, ...artifacts], 115 | provider: server.provider, 116 | compilers: { 117 | solc: { 118 | version: '0.5.2', 119 | settings: {} 120 | } 121 | } 122 | }; 123 | }); 124 | 125 | afterAll(done => { 126 | console.log('Stopping GANACHE server'); 127 | server.close(err => { 128 | if (err) done(err); 129 | console.log('GANACHE server stopped'); 130 | done(); 131 | }); 132 | }); 133 | 134 | describe('Process config', () => { 135 | test('plugin config', async () => { 136 | const options = await processPluginConfig(config); 137 | 138 | expect(replaceCWD(options)).toMatchSnapshot( 139 | { 140 | web3: expect.any(Web3) 141 | }, 142 | 'Plugin config' 143 | ); 144 | }); 145 | test('plugin config without network throws', async () => { 146 | await expect(processPluginConfig({ ...config, network: undefined })).rejects.toThrow( 147 | 'No network provided. Run truffle run verify --help to see usage.' 148 | ); 149 | }); 150 | test('plugin config with invalid provider throws', async () => { 151 | await expect( 152 | processPluginConfig({ 153 | ...config, 154 | get provider() { 155 | throw new Error(); 156 | } 157 | }) 158 | ).rejects.toThrow(`No valid provider for network ${config.network} in truffle.js`); 159 | }); 160 | test('working config', async () => { 161 | const options = await processConfig({ artifacts, web3 }); 162 | 163 | expect(options.apiUrl).toEqual(apiUrl); 164 | 165 | expect(replaceCWD(options)).toMatchSnapshot( 166 | { 167 | web3: expect.any(Web3), 168 | logger: expect.any(Object) 169 | }, 170 | 'Lib config' 171 | ); 172 | }); 173 | test('working config with web3 connected to an unsupported network throws', async () => { 174 | const unavailableId = 12345; 175 | const web3mock = { 176 | eth: { 177 | net: { 178 | getId: () => Promise.resolve(unavailableId) 179 | } 180 | } 181 | }; 182 | await expect(processConfig({ artifacts, web3: web3mock })).rejects.toThrow( 183 | `Network with id ${unavailableId} isn't available on etherscan.io for verification` 184 | ); 185 | }); 186 | }); 187 | 188 | let artifactsData; 189 | 190 | test('Gathers data from Artifacts', async () => { 191 | artifactsData = await gatherDataFromArtifacts({ 192 | artifacts, 193 | networkId: NETWORK_ID 194 | }); 195 | 196 | const artifactKeys = Object.keys(artifactsData); 197 | 198 | expect(artifactKeys).toMatchSnapshot('Artifact paths'); 199 | 200 | artifactKeys.forEach(key => { 201 | expect(replaceCWD(artifactsData[key])).toMatchSnapshot( 202 | { 203 | bytecode: expect.any(String), 204 | txhash: expect.stringMatching(hexR) 205 | }, 206 | path.basename(key) 207 | ); 208 | }); 209 | }); 210 | 211 | test('Filters out verified contracts', async () => { 212 | const logger = { 213 | log: jest.fn() 214 | }; 215 | 216 | const verifiedResp = JSON.stringify({ status: '1' }); 217 | const unverifiedResp = JSON.stringify({ status: '0' }); 218 | fetch 219 | .mockReturnValueOnce(new Response(verifiedResp)) 220 | .mockReturnValueOnce(new Response(verifiedResp)) 221 | .mockImplementation(() => new Response(unverifiedResp)); 222 | logger.log 223 | .mockReturnValueOnce(new Response(verifiedResp)) 224 | .mockReturnValueOnce(new Response(verifiedResp)) 225 | .mockImplementation(() => new Response(unverifiedResp)); 226 | 227 | const { unverified: unverifiedContracts, alreadyVerified } = await filterOutVerified( 228 | artifactsData, 229 | { apiUrl, logger } 230 | ); 231 | 232 | expect(fetch.mock.calls).toMatchSnapshot('Fetch calls'); 233 | 234 | const fetchReturns = fetch.mock.results.map(({ value: response }) => JSON.parse(response.body)); 235 | expect(fetchReturns).toMatchSnapshot('Fetch returns'); 236 | 237 | expect(replaceCWD(alreadyVerified)).toMatchSnapshot('Already verified'); 238 | 239 | const all = Object.keys(artifactsData).length; 240 | const unverifiedKeys = Object.keys(unverifiedContracts); 241 | const verified = all - unverifiedKeys.length; 242 | expect(verified).toEqual(2); 243 | expect(verified).toEqual(alreadyVerified.length); 244 | 245 | expect(unverifiedKeys).toMatchSnapshot('Unverified contracts'); 246 | 247 | unverifiedKeys.forEach(key => { 248 | expect(replaceCWD(unverifiedContracts[key])).toMatchSnapshot( 249 | { 250 | bytecode: expect.any(String), 251 | txhash: expect.stringMatching(hexR) 252 | }, 253 | path.basename(key) 254 | ); 255 | }); 256 | 257 | expect(logger.log.mock.calls).toMatchSnapshot('Log calls'); 258 | }); 259 | 260 | let flattenedContracts; 261 | test('Flattens contracts linked from artifacts', async () => { 262 | flattenedContracts = await flattenContracts(artifactsData); 263 | 264 | expect(flattenedContracts).toMatchSnapshot('Flattened contracts'); 265 | }); 266 | 267 | describe('Outputs Flattened', () => { 268 | const output = './output/here'; 269 | 270 | let spies; 271 | 272 | beforeAll(() => { 273 | spies = ['mkdirp', 'writeFile'].map(fname => 274 | jest.spyOn(fs, fname).mockImplementation(() => {}) 275 | ); 276 | }); 277 | afterAll(() => spies.forEach(spy => spy.mockRestore())); 278 | 279 | test('outputs flattened contracts to a folder', async () => { 280 | await outputFlattened(artifactsData, flattenedContracts, { output }); 281 | 282 | expect(spies[0]).toHaveBeenCalledTimes(1); 283 | expect(spies[0]).toHaveBeenCalledWith(output); 284 | 285 | expect(replaceCWD(spies[1].mock.calls)).toMatchSnapshot('fs.writeFile calls'); 286 | }); 287 | test('does nothing when flattenContracts is empty', async () => { 288 | await outputFlattened(artifactsData, {}, { output }); 289 | 290 | expect(spies[0]).toHaveBeenCalledTimes(0); 291 | expect(spies[1]).toHaveBeenCalledTimes(0); 292 | }); 293 | }); 294 | 295 | let constructorData; 296 | 297 | test('Gathers constructor arguments for relevant contracts', async () => { 298 | constructorData = await getConstructorArguments(artifactsData, { 299 | web3 300 | }); 301 | 302 | expect(constructorData).toMatchSnapshot('Constructor arguments'); 303 | 304 | const filesWithConstructors = Object.keys(constructorData); 305 | 306 | const constructorArguments = await Promise.all( 307 | filesWithConstructors.map(async file => { 308 | const art = await fs.readJSON(file); 309 | const { inputs } = art.abi.find(({ type }) => type === 'constructor'); 310 | 311 | const encodedArguments = `0x${constructorData[file]}`; 312 | 313 | return web3.eth.abi.decodeParameters(inputs, encodedArguments); 314 | }) 315 | ); 316 | 317 | const constructorDataDecoded = filesWithConstructors.reduce((accum, file, i) => { 318 | accum[file] = constructorArguments[i]; 319 | return accum; 320 | }, {}); 321 | 322 | expect(constructorDataDecoded).toMatchSnapshot('Decoded constructor arguments'); 323 | }); 324 | 325 | test('Posts to verify', async () => { 326 | const filesNum = Object.keys(artifactsData).length; 327 | 328 | let i = -1; 329 | fetch.mockImplementation(() => { 330 | ++i; 331 | if (i < 2) 332 | return new Response( 333 | JSON.stringify({ status: '0', result: 'Contract source code already verified' }) 334 | ); 335 | if (i < filesNum) return new Response(JSON.stringify({ status: '1', result: `guid${i}` })); 336 | 337 | if (i < 1.5 * filesNum) 338 | return new Response(JSON.stringify({ status: '0', result: 'Pending in queue' })); 339 | 340 | return new Response(JSON.stringify({ status: '1', result: 'Pass - Verified' })); 341 | }); 342 | 343 | const logger = { 344 | log: jest.fn() 345 | }; 346 | 347 | const promise = postToVerify(artifactsData, flattenedContracts, constructorData, { 348 | apiUrl, 349 | apiKey: '', 350 | optimizer: { enabled: true, run: 200 }, 351 | network: NETWORK_NAME, 352 | delay: 0, 353 | logger 354 | }); 355 | 356 | const result = await promise; 357 | 358 | expect(replaceCWD(result)).toMatchSnapshot('Final result'); 359 | 360 | expect(fetch.mock.calls).toMatchSnapshot('Fetch calls'); 361 | 362 | const fetchReturns = fetch.mock.results.map(({ value: response }) => JSON.parse(response.body)); 363 | expect(fetchReturns).toMatchSnapshot('Fetch returns'); 364 | 365 | expect(logger.log.mock.calls).toMatchSnapshot('Log calls'); 366 | }); 367 | -------------------------------------------------------------------------------- /bin/verify-cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const path = require('path'); 4 | const yargs = require('yargs'); 5 | 6 | const { availableNetworks, DEFAULT_OPTIMIZER_CONFIG } = require('../src/process_config'); 7 | 8 | const constructOptimizerFromOptions = ({ optimize, optimizeRuns }) => { 9 | const enabled = !!optimize || !!optimizeRuns; 10 | 11 | const runs = optimizeRuns || 200; 12 | 13 | return { enabled, runs }; 14 | }; 15 | 16 | const withObjectFunctionsDisabled = (object, cb) => { 17 | if (Object.isFrozen(object)) throw new Error("Object is frozen, can't reassign functions"); 18 | 19 | const noop = () => {}; 20 | 21 | const old = Reflect.ownKeys(object).reduce((accum, key) => { 22 | const val = object[key]; 23 | if (typeof val === 'function') { 24 | accum[key] = val; 25 | object[key] = noop; 26 | } 27 | 28 | return accum; 29 | }, {}); 30 | 31 | try { 32 | return cb(); 33 | } catch (error) { 34 | // do nothing 35 | } finally { 36 | Object.assign(object, old); 37 | } 38 | }; 39 | 40 | const readTruffleConfig = () => { 41 | let truffleConfig; 42 | 43 | try { 44 | truffleConfig = require(path.resolve('./truffle.js')); 45 | } catch (error) { 46 | try { 47 | truffleConfig = require(path.resolve('./truffle-config.js')); 48 | } catch (error) { } // eslint-disable-line 49 | } 50 | 51 | return truffleConfig; 52 | }; 53 | 54 | const getOptimizerFromTruffleConfig = () => { 55 | const config = withObjectFunctionsDisabled(console, readTruffleConfig); 56 | 57 | return ( 58 | config && 59 | config.compilers && 60 | config.compilers.solc && 61 | config.compilers.solc.settings && 62 | config.compilers.solc.settings.optimizer 63 | ); 64 | }; 65 | 66 | function run(options) { 67 | const { network, optimize, optimizeRuns, output, delay, artifacts, verbose, useFetch } = options; 68 | 69 | let optimizer; 70 | // no flags provided 71 | if (optimize === undefined && optimizeRuns === undefined) { 72 | // try to get from ./truffle(-config)?.js 73 | optimizer = getOptimizerFromTruffleConfig(); 74 | optimizer && verbose && console.log(`Optimizer settings inferred from local truffle config`); 75 | // couldn't 76 | if (!optimizer) { 77 | console.log('Was unable to infer optimizer settings from local truffle config'); 78 | console.log(`Will use defaults: ${JSON.stringify(DEFAULT_OPTIMIZER_CONFIG)}`); 79 | console.log('If that is not correct, provide --optimize and/or --optimize-runs flags'); 80 | 81 | optimizer = DEFAULT_OPTIMIZER_CONFIG; 82 | } 83 | } else optimizer = constructOptimizerFromOptions(options); 84 | 85 | require('../src')({ 86 | network, 87 | optimizer, 88 | output, 89 | delay, 90 | artifacts, 91 | verbose, 92 | useFetch, 93 | apiKey: process.env.API_KEY 94 | }).catch(console.error); 95 | } 96 | 97 | function main() { 98 | const { argv } = yargs 99 | .version() 100 | .usage('$0 ', 'Verifies contracts on etherscan.io', yarg => { 101 | yarg 102 | .positional('artifacts', { 103 | describe: 104 | 'a space separated list of paths to artifact json files (required) or a glob pattern like ./build/contracts/*.json', 105 | type: 'string' 106 | }) 107 | .example( 108 | 'API_KEY= $0 --network rinkeby ./build/contracts/*', 109 | `Verifies all contract artifacts in ./build/contracts deployed to rinkeby network. 110 | Tries to infer optimizer settings from truffle.js or truffle-config.js` 111 | ) 112 | .example( 113 | 'API_KEY= $0 --network rinkeby ./build/contracts/Contract.json --optimize-runs 100', 114 | `Verifies ./build/contracts/Contract.json artifact deployed to rinkeby network. 115 | Optimizer is set as { enabled: true, runs: 100}` 116 | ); 117 | }) 118 | 119 | .option('network', { 120 | demandOption: true, 121 | choices: availableNetworks, 122 | type: 'string', 123 | describe: 'which network to verify contracts on' 124 | }) 125 | .option('optimize', { 126 | alias: 'o', 127 | type: 'boolean', 128 | describe: 129 | 'whether your contracts were optimized during compilation (sets --optimize-runs to 200 if none given)' 130 | }) 131 | .option('optimize-runs', { 132 | alias: 'r', 133 | type: 'number', 134 | describe: 135 | 'how many runs your contracts were optimized for during compilation (sets --optimize to true if given)' 136 | }) 137 | .option('output', { 138 | type: 'string', 139 | describe: 'which directory to write flattened contracts to' 140 | }) 141 | .option('delay', { 142 | alias: 'd', 143 | type: 'number', 144 | default: 20000, 145 | describe: 146 | 'delay (in ms) between checking if a contract has been verified after verification starts' 147 | }) 148 | .option('use-fetch', { 149 | type: 'boolean', 150 | default: true, 151 | describe: 152 | 'fetch transactions from etherscan.io instead of from blockchain when determining constructor arguments' 153 | }) 154 | .option('verbose', { 155 | type: 'boolean', 156 | describe: 'output more logs' 157 | }) 158 | 159 | .help('help') 160 | .alias('help', 'h') 161 | .alias('version', 'v') 162 | .wrap(yargs.terminalWidth()) 163 | .fail((msg, err, yarg) => { 164 | if (err) throw err; // preserve stack 165 | 166 | if (msg === 'Not enough non-option arguments: got 0, need at least 1') { 167 | console.error('Must provide artifact paths'); 168 | } else { 169 | console.error(msg); 170 | } 171 | console.error('\nSee usage:'); 172 | console.error(yarg.help()); 173 | process.exit(1); 174 | }); 175 | 176 | run(argv); 177 | } 178 | 179 | // if running directly 180 | if (require.main === module) { 181 | main(); 182 | } 183 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after `n` failures 9 | // bail: 0, 10 | 11 | // Respect "browser" field in package.json when resolving modules 12 | // browser: false, 13 | 14 | // The directory where Jest should store its cached dependency information 15 | // cacheDirectory: "/tmp/jest_rs", 16 | 17 | // Automatically clear mock calls and instances between every test 18 | // clearMocks: false, 19 | 20 | // Indicates whether the coverage information should be collected while executing the test 21 | // collectCoverage: false, 22 | 23 | // An array of glob patterns indicating a set of files for which coverage information should be collected 24 | // collectCoverageFrom: null, 25 | 26 | // The directory where Jest should output its coverage files 27 | coverageDirectory: 'coverage', 28 | 29 | // An array of regexp pattern strings used to skip coverage collection 30 | // coveragePathIgnorePatterns: [ 31 | // "/node_modules/" 32 | // ], 33 | 34 | // A list of reporter names that Jest uses when writing coverage reports 35 | // coverageReporters: [ 36 | // "json", 37 | // "text", 38 | // "lcov", 39 | // "clover" 40 | // ], 41 | 42 | // An object that configures minimum threshold enforcement for coverage results 43 | // coverageThreshold: null, 44 | 45 | // A path to a custom dependency extractor 46 | // dependencyExtractor: null, 47 | 48 | // Make calling deprecated APIs throw helpful error messages 49 | // errorOnDeprecated: false, 50 | 51 | // Force coverage collection from ignored files usin a array of glob patterns 52 | // forceCoverageMatch: [], 53 | 54 | // A path to a module which exports an async function that is triggered once before all test suites 55 | // globalSetup: null, 56 | 57 | // A path to a module which exports an async function that is triggered once after all test suites 58 | // globalTeardown: null, 59 | 60 | // A set of global variables that need to be available in all test environments 61 | // globals: {}, 62 | 63 | // An array of directory names to be searched recursively up from the requiring module's location 64 | // moduleDirectories: [ 65 | // "node_modules" 66 | // ], 67 | 68 | // An array of file extensions your modules use 69 | // moduleFileExtensions: [ 70 | // "js", 71 | // "json", 72 | // "jsx", 73 | // "ts", 74 | // "tsx", 75 | // "node" 76 | // ], 77 | 78 | // A map from regular expressions to module names that allow to stub out resources with a single module 79 | // moduleNameMapper: {}, 80 | 81 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 82 | // modulePathIgnorePatterns: [], 83 | 84 | // Activates notifications for test results 85 | // notify: false, 86 | 87 | // An enum that specifies notification mode. Requires { notify: true } 88 | // notifyMode: "failure-change", 89 | 90 | // A preset that is used as a base for Jest's configuration 91 | // preset: null, 92 | 93 | // Run tests from one or more projects 94 | // projects: null, 95 | 96 | // Use this configuration option to add custom reporters to Jest 97 | // reporters: undefined, 98 | 99 | // Automatically reset mock state between every test 100 | resetMocks: true, 101 | 102 | // Reset the module registry before running each individual test 103 | // resetModules: false, 104 | 105 | // A path to a custom resolver 106 | // resolver: null, 107 | 108 | // Automatically restore mock state between every test 109 | // restoreMocks: false, 110 | 111 | // The root directory that Jest should scan for tests and modules within 112 | // rootDir: null, 113 | 114 | // A list of paths to directories that Jest should use to search for files in 115 | // roots: [ 116 | // "" 117 | // ], 118 | 119 | // Allows you to use a custom runner instead of Jest's default test runner 120 | // runner: "jest-runner", 121 | 122 | // The paths to modules that run some code to configure or set up the testing environment before each test 123 | // setupFiles: [], 124 | 125 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 126 | // setupFilesAfterEnv: [], 127 | 128 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 129 | // snapshotSerializers: [], 130 | 131 | // The test environment that will be used for testing 132 | testEnvironment: 'node' 133 | 134 | // Options that will be passed to the testEnvironment 135 | // testEnvironmentOptions: {}, 136 | 137 | // Adds a location field to test results 138 | // testLocationInResults: false, 139 | 140 | // The glob patterns Jest uses to detect test files 141 | // testMatch: [ 142 | // "**/__tests__/**/*.[jt]s?(x)", 143 | // "**/?(*.)+(spec|test).[tj]s?(x)" 144 | // ], 145 | 146 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 147 | // testPathIgnorePatterns: [ 148 | // "/node_modules/" 149 | // ], 150 | 151 | // The regexp pattern or array of patterns that Jest uses to detect test files 152 | // testRegex: [], 153 | 154 | // This option allows the use of a custom results processor 155 | // testResultsProcessor: null, 156 | 157 | // This option allows use of a custom test runner 158 | // testRunner: "jasmine2", 159 | 160 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 161 | // testURL: "http://localhost", 162 | 163 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 164 | // timers: "real", 165 | 166 | // A map from regular expressions to paths to transformers 167 | // transform: null, 168 | 169 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 170 | // transformIgnorePatterns: [ 171 | // "/node_modules/" 172 | // ], 173 | 174 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 175 | // unmockedModulePathPatterns: undefined, 176 | 177 | // Indicates whether each individual test should be reported during the run 178 | // verbose: null, 179 | 180 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 181 | // watchPathIgnorePatterns: [], 182 | 183 | // Whether to use watchman for file crawling 184 | // watchman: true, 185 | }; 186 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "verify-on-etherscan", 3 | "version": "1.2.1", 4 | "description": "Automates verification on etherscan.io of ethereum contracts that were compiled and deployed with truffle", 5 | "keywords": [ 6 | "verify", 7 | "ethereum", 8 | "contracts", 9 | "etherscan", 10 | "truffle" 11 | ], 12 | "main": "src/index.js", 13 | "bin": { 14 | "verify-on-etherscan": "bin/verify-cli.js", 15 | "voeth": "bin/verify-cli.js" 16 | }, 17 | "files": [ 18 | "src/**/*", 19 | "truffle-plugin.json" 20 | ], 21 | "scripts": { 22 | "lint": "eslint '**/*.js' --ignore-path .gitignore", 23 | "format": "prettier --write '**/*.js'", 24 | "prep-test": "cd ./truffle-test-example && npm install ; cd ..", 25 | "test": "jest" 26 | }, 27 | "author": "Velenir", 28 | "license": "MIT", 29 | "dependencies": { 30 | "fs-extra": "^8.1.0", 31 | "node-fetch": "^2.6.0", 32 | "truffle-flattener": "^1.4.2", 33 | "web3": "^1.2.1", 34 | "yargs": "^14.0.0" 35 | }, 36 | "devDependencies": { 37 | "eslint": "^6.2.2", 38 | "eslint-config-airbnb": "^18.0.1", 39 | "eslint-config-prettier": "^6.1.0", 40 | "eslint-plugin-import": "^2.18.2", 41 | "eslint-plugin-jest": "^22.16.0", 42 | "eslint-plugin-jsx-a11y": "^6.2.3", 43 | "eslint-plugin-node": "^9.2.0", 44 | "eslint-plugin-prettier": "^3.1.0", 45 | "eslint-plugin-react": "^7.14.3", 46 | "ganache-cli": "6.6.0", 47 | "jest": "^24.9.0", 48 | "prettier": "^1.18.2" 49 | }, 50 | "repository": { 51 | "type": "git", 52 | "url": "https://github.com/gnosis/verify-on-etherscan.git" 53 | }, 54 | "bugs": { 55 | "url": "https://github.com/gnosis/verify-on-etherscan/issues" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/filter_out_verified.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | async function filterOutVerified(artifactsData, { apiUrl, logger, verbose }) { 4 | const files = Object.keys(artifactsData); 5 | logger && logger.log(); 6 | 7 | const verifiedContracts = await Promise.all( 8 | files.map(async f => { 9 | const { contractaddress, contractname } = artifactsData[f]; 10 | 11 | const res = await fetch(`${apiUrl}?module=contract&action=getabi&address=${contractaddress}`); 12 | try { 13 | const json = await res.json(); 14 | if (json.status === '1') { 15 | logger && 16 | logger.log(`${contractname} at ${contractaddress} is already verified, skipping`); 17 | return true; 18 | } 19 | } catch (error) { 20 | verbose && 21 | logger && 22 | logger.error( 23 | `Error checking if ${contractname} at ${contractaddress} is verified: ${error.message}` 24 | ); 25 | return false; 26 | } 27 | 28 | return false; 29 | }) 30 | ); 31 | 32 | const alreadyVerified = []; 33 | 34 | const unverified = files.reduce((accum, f, i) => { 35 | if (verifiedContracts[i]) alreadyVerified.push(f); 36 | else accum[f] = artifactsData[f]; 37 | return accum; 38 | }, {}); 39 | 40 | return { unverified, alreadyVerified }; 41 | } 42 | 43 | module.exports = filterOutVerified; 44 | -------------------------------------------------------------------------------- /src/flatten_contracts.js: -------------------------------------------------------------------------------- 1 | const flattener = require('truffle-flattener'); 2 | 3 | async function flattenContracts(artifactsData) { 4 | const files = Object.keys(artifactsData); 5 | 6 | const paths = files.map(f => artifactsData[f].sourcePath); 7 | 8 | const uniquePaths = Array.from(new Set(paths)); 9 | 10 | const flattened = await Promise.all(uniquePaths.map(path => flattener([path]))); 11 | 12 | const path2flattened = uniquePaths.reduce((accum, curr, i) => { 13 | accum[curr] = flattened[i]; 14 | return accum; 15 | }, {}); 16 | 17 | return files.reduce((accum, f) => { 18 | const { sourcePath } = artifactsData[f]; 19 | 20 | accum[f] = path2flattened[sourcePath]; 21 | return accum; 22 | }, {}); 23 | } 24 | 25 | module.exports = flattenContracts; 26 | -------------------------------------------------------------------------------- /src/gather_data_from_artifacts.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | 3 | async function gatherDataFromArtifacts({ artifacts, networkId, logger }) { 4 | const artifactJSONs = await Promise.all(artifacts.map(f => fs.readJson(f))); 5 | 6 | const result = {}; 7 | 8 | for (let i = 0, alen = artifactJSONs.length; i < alen; ++i) { 9 | const artifact = artifactJSONs[i]; 10 | const file = artifacts[i]; 11 | 12 | const { contractName: contractname, compiler, networks, bytecode, sourcePath, abi } = artifact; 13 | 14 | const networkData = networks[networkId]; 15 | 16 | if (!networkData) continue; 17 | 18 | const { address: contractaddress, links, transactionHash: txhash } = networkData; 19 | 20 | const match = /[\w.+-]+?commit\.[\da-f]+/i.exec(compiler.version); 21 | if (match === null) { 22 | logger && 23 | logger.error( 24 | `${file} doesn't contain a valid compiler version: ${compiler.version}, skipping` 25 | ); 26 | continue; 27 | } 28 | const versionfromArtifact = match[0]; 29 | const compilerversion = `v${versionfromArtifact}`; 30 | 31 | const hasNonEmptyConstructor = abi.some( 32 | ({ type, inputs }) => type === 'constructor' && inputs.length > 0 33 | ); 34 | 35 | const contractData = { 36 | contractname, 37 | compilerversion, 38 | bytecode, 39 | contractaddress, 40 | txhash, 41 | sourcePath, 42 | hasNonEmptyConstructor 43 | }; 44 | 45 | const librariesUsed = Object.keys(links); 46 | 47 | if (librariesUsed.length) { 48 | if (librariesUsed.length > 10) { 49 | logger && 50 | logger.error( 51 | '\nEtherscan only allows verification of contracts with up to 10 libraries;' 52 | ); 53 | logger && 54 | logger.error(contractname, 'has', librariesUsed.length, "and won't be verrified\n"); 55 | continue; 56 | } 57 | 58 | for (let j = 1, len = librariesUsed.length; j <= len; ++j) { 59 | const libName = librariesUsed[j]; 60 | contractData[`libraryname${j}`] = libName; 61 | contractData[`libraryaddress${j}`] = links[libName]; 62 | } 63 | } 64 | 65 | result[file] = contractData; 66 | } 67 | 68 | return result; 69 | } 70 | 71 | module.exports = gatherDataFromArtifacts; 72 | -------------------------------------------------------------------------------- /src/get_constructor_arguments.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | 3 | // .....contract_code......metadata_start.........metadata_end(constructor_args) 4 | const metaNconstructorR = /a165627a7a72305820[0-9A-Fa-f]+?0029([0-9A-Fa-f]*)$/; 5 | 6 | const extractConstructorCodes = data => { 7 | if (!data) return null; 8 | 9 | const match = data.match(metaNconstructorR); 10 | 11 | return match && match[1]; 12 | }; 13 | 14 | // constructor bytecode is a sequence of 32-bytes 15 | // a byte is represented with 2 characters in hex 16 | // so a valid constructor must be a multiple of 64 characters 17 | const checkConstructorArgsValidity = constArgs => constArgs && constArgs.length % 64 === 0; 18 | 19 | async function getConstructorArguments( 20 | artifactsData, 21 | { web3, apiUrl, network, useFetch, logger, verbose } 22 | ) { 23 | const files = Object.keys(artifactsData); 24 | 25 | const etherscanURL = `${network === 'mainnet' ? '' : `${network}.`}etherscan.io`; 26 | 27 | const getTransaction = 28 | web3 && !useFetch 29 | ? txhash => web3.eth.getTransaction(txhash) 30 | : async txhash => { 31 | const res = await fetch( 32 | `${apiUrl}?module=proxy&action=eth_getTransactionByHash&txhash=${txhash}` 33 | ); 34 | 35 | const json = await res.json(); 36 | 37 | if (json.error) { 38 | throw new Error( 39 | `Error getting transaction ${txhash} from ${etherscanURL}: 40 | ${json.error.code}: ${json.error.message} 41 | ` 42 | ); 43 | } 44 | 45 | if (json.result === null) { 46 | logger && logger.error(`No transaction with hash ${txhash} found on ${etherscanURL}`); 47 | } 48 | 49 | return json.result; 50 | }; 51 | 52 | const constructorArgumentsEncoded = await Promise.all( 53 | files.map(async f => { 54 | const { 55 | txhash, 56 | bytecode, 57 | contractname, 58 | hasNonEmptyConstructor, 59 | contractaddress 60 | } = artifactsData[f]; 61 | 62 | if (!hasNonEmptyConstructor) return; 63 | 64 | try { 65 | const tx = await getTransaction(txhash); 66 | if (tx === null) { 67 | logger && 68 | logger.error( 69 | `Transaction ${txhash} from ${contractname} wasn't found on the blockchain. Verification will fail.` 70 | ); 71 | return; 72 | } 73 | 74 | let constructorArgs; 75 | let validConstructorArgs = false; 76 | 77 | if (!tx.input.startsWith(bytecode)) { 78 | logger && 79 | logger.error( 80 | `${contractname} bytecode doesn't match creating tx's input. Verification may fail.` 81 | ); 82 | 83 | constructorArgs = extractConstructorCodes(tx.input); 84 | 85 | validConstructorArgs = checkConstructorArgsValidity(constructorArgs); 86 | } else { 87 | constructorArgs = tx.input.replace(bytecode, ''); 88 | validConstructorArgs = checkConstructorArgsValidity(constructorArgs); 89 | } 90 | 91 | if (validConstructorArgs) { 92 | verbose && 93 | logger && 94 | logger.log( 95 | `${contractname} at ${contractaddress} was deployed with constructor arguments: ${constructorArgs}` 96 | ); 97 | } else { 98 | logger && 99 | logger.error( 100 | `Unable to infer valid constructor arguments from ${contractname} creating tx ${txhash}. Verification will fail.` 101 | ); 102 | } 103 | 104 | return constructorArgs; 105 | } catch (error) { 106 | logger && logger.error(error); 107 | } 108 | }) 109 | ); 110 | 111 | return files.reduce((accum, f, i) => { 112 | if (constructorArgumentsEncoded[i]) accum[f] = constructorArgumentsEncoded[i]; 113 | return accum; 114 | }, {}); 115 | } 116 | 117 | module.exports = getConstructorArguments; 118 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const { processConfig } = require('./process_config'); 2 | 3 | const gatherDataFromArtifacts = require('./gather_data_from_artifacts'); 4 | const filterOutVerified = require('./filter_out_verified'); 5 | const flattenContracts = require('./flatten_contracts'); 6 | const outputFlattened = require('./output_flattened'); 7 | const getConstructorArguments = require('./get_constructor_arguments'); 8 | const postToVerify = require('./post_to_verify'); 9 | 10 | async function verify(config) { 11 | const options = await processConfig(config); 12 | // must have APIKey 13 | 14 | // gather contractaddress, contractname, compileversion, optimizationUsed, runs, txhash, 15 | // bytecode, sourcePath, libaryname1..., lybraryaddress1... from artifacts 16 | const artifactsData = await gatherDataFromArtifacts(options); 17 | 18 | // filter out already verified contracts 19 | const { unverified: unverifiedArtifactsData, alreadyVerified } = await filterOutVerified( 20 | artifactsData, 21 | options 22 | ); 23 | 24 | const writeFlattened = typeof options.output === 'string'; 25 | // get sourceCode from truffle-flattener 26 | // const flattenedContracts = await flattenContracts(unverifiedArtifactsData); 27 | const flattenedContracts = await flattenContracts( 28 | writeFlattened ? artifactsData : unverifiedArtifactsData 29 | ); 30 | 31 | if (writeFlattened) { 32 | // output flattened contracts to a folder 33 | await outputFlattened(artifactsData, flattenedContracts, options); 34 | } 35 | 36 | // get constructorArguements encoded from tx of txhash and bytecode 37 | const constructorArguments = await getConstructorArguments(unverifiedArtifactsData, options); 38 | 39 | // submit post request 40 | /** 41 | * @type {{ alreadyVerified: string[], successful: string[], failed: string[] }} 42 | */ 43 | const res = await postToVerify( 44 | unverifiedArtifactsData, 45 | flattenedContracts, 46 | constructorArguments, 47 | options 48 | ); 49 | 50 | res.alreadyVerified = alreadyVerified.concat(res.alreadyVerified); 51 | return res; 52 | } 53 | 54 | module.exports = verify; 55 | -------------------------------------------------------------------------------- /src/output_flattened.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs-extra'); 3 | 4 | async function outputFlattened(artifactsData, flattenedContracts, { output, logger, verbose }) { 5 | const files = Object.keys(flattenedContracts); 6 | if (files.length === 0) return; 7 | 8 | await fs.mkdirp(output); 9 | 10 | await Promise.all( 11 | files.map(file => { 12 | const flat = flattenedContracts[file]; 13 | const { sourcePath, contractname } = artifactsData[file]; 14 | 15 | const filename = path.basename(sourcePath, '.sol'); 16 | 17 | const filepath = path.resolve(output, `${filename}.flat.sol`); 18 | 19 | verbose && logger.log(`Writing flattened contract ${contractname} to ${filepath}`); 20 | 21 | return fs.writeFile(filepath, flat); 22 | }) 23 | ); 24 | } 25 | 26 | module.exports = outputFlattened; 27 | -------------------------------------------------------------------------------- /src/post_to_verify.js: -------------------------------------------------------------------------------- 1 | const fetch = require('node-fetch'); 2 | const { URLSearchParams } = require('url'); 3 | 4 | const delayMS = ms => 5 | ms && 6 | new Promise(res => { 7 | setTimeout(res, ms); 8 | }); 9 | 10 | const removeUndefined = obj => 11 | Object.keys(obj).reduce((accum, key) => { 12 | if (obj[key] !== undefined) accum[key] = obj[key]; 13 | 14 | return accum; 15 | }, {}); 16 | 17 | async function postToVerify( 18 | artifactsData, 19 | flattenedContracts, 20 | constructorArguments, 21 | { apiUrl, apiKey, optimizer, network, delay = 20000, logger, verbose } 22 | ) { 23 | const files = Object.keys(artifactsData); 24 | logger && logger.log(); 25 | 26 | const alreadyVerified = []; 27 | const successful = []; 28 | const failed = []; 29 | 30 | if (files.length === 0) { 31 | logger && 32 | logger.log(`All contracts deployed to ${network} network already verified. Exiting...`); 33 | return { alreadyVerified, successful, failed }; 34 | } 35 | 36 | if (!apiKey) { 37 | throw new Error("No API_KEY provided, can't verify"); 38 | } 39 | 40 | const { enabled: optimizationUsed = false, runs = 200 } = optimizer; 41 | 42 | const defaultBody = { 43 | apikey: apiKey, 44 | optimizationUsed: optimizationUsed ? '1' : '0', 45 | runs, 46 | module: 'contract', 47 | action: 'verifysourcecode', 48 | hasNonEmptyConstructor: undefined, 49 | txhash: undefined, 50 | sourcePath: undefined, 51 | bytecode: undefined 52 | }; 53 | 54 | const createCheckGUIDurl = guid => 55 | `${apiUrl}?module=contract&action=checkverifystatus&guid=${guid}`; 56 | 57 | const contractAtEtherscanURL = `https://${ 58 | network === 'mainnet' ? '' : `${network}.` 59 | }etherscan.io/address`; 60 | const createContractCodeAtEthersacanURL = address => `${contractAtEtherscanURL}/${address}#code`; 61 | 62 | const GUIDs = await Promise.all( 63 | files.map(async f => { 64 | const contractData = artifactsData[f]; 65 | 66 | const body = { 67 | ...contractData, 68 | ...defaultBody, 69 | sourceCode: flattenedContracts[f], 70 | constructorArguements: constructorArguments[f] 71 | }; 72 | 73 | const cleanBody = removeUndefined(body); 74 | 75 | const options = { 76 | method: 'post', 77 | body: new URLSearchParams(cleanBody), 78 | headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' } 79 | }; 80 | 81 | const { contractname, contractaddress } = contractData; 82 | let res; 83 | try { 84 | res = await fetch(apiUrl, options); 85 | } catch (error) { 86 | logger && 87 | logger.error( 88 | `Error sending verification request to ${contractAtEtherscanURL} for ${contractname} at ${contractaddress}: ${error.message}` 89 | ); 90 | return; 91 | } 92 | 93 | if (!res.ok) { 94 | logger && 95 | logger.error(`Error sending request to verify ${contractname} at ${contractaddress}`); 96 | logger && logger.error(res.status, res.statusText); 97 | return; 98 | } 99 | 100 | let json; 101 | try { 102 | json = await res.json(); 103 | } catch (error) { 104 | logger && 105 | logger.error( 106 | `Error parsing verification response for ${contractname} at ${contractaddress}: ${error.message}` 107 | ); 108 | return; 109 | } 110 | 111 | if (json.status === '1') { 112 | const guid = json.result; 113 | logger && logger.log(`Verification started for ${contractname} at ${contractaddress}`); 114 | logger && logger.log('\tGUID: ', guid); 115 | logger && logger.log(`Check progress at ${createCheckGUIDurl(guid)}\n`); 116 | return guid; 117 | } 118 | // no need to try further if API_KEY is wrong 119 | if (json.result === 'Missing or invalid ApiKey') throw new Error('Missing or invalid ApiKey'); 120 | 121 | logger && 122 | logger.log(`Error verifying ${contractname} at ${contractaddress}. ${json.result}\n`); 123 | 124 | if (json.result === 'Contract source code already verified') { 125 | alreadyVerified.push(f); 126 | } 127 | }) 128 | ); 129 | 130 | const GUIDinProgress2contract = GUIDs.reduce((accum, guid, i) => { 131 | if (guid) { 132 | const file = files[i]; 133 | const { contractname, contractaddress } = artifactsData[file]; 134 | accum[guid] = { contractname, contractaddress, file }; 135 | } 136 | return accum; 137 | }, {}); 138 | 139 | const checkGUID = async guid => { 140 | verbose && logger && logger.log(`\nChecking status of GUID ${guid}`); 141 | const res = await fetch(createCheckGUIDurl(guid)); 142 | 143 | if (!res.ok) throw new Error(`Error fetching status of ${guid}`); 144 | return res.json(); 145 | }; 146 | 147 | logger && logger.log(); 148 | 149 | const waitForGuid = async guid => { 150 | const { contractname, contractaddress, file } = GUIDinProgress2contract[guid]; 151 | try { 152 | const json = await checkGUID(guid); 153 | 154 | // if result is not Pending, means it either failed or passed 155 | if (!json.result.includes('Pending')) { 156 | logger && logger.log(`${contractname} at ${contractaddress}`, json.result); 157 | delete GUIDinProgress2contract[guid]; 158 | if (json.status === '1' && json.result.includes('Verified')) { 159 | logger && 160 | logger.log( 161 | `View verified code at ${createContractCodeAtEthersacanURL(contractaddress)}\n` 162 | ); 163 | successful.push(file); 164 | } else failed.push(file); 165 | } else { 166 | verbose && logger && logger.log(`${contractname} at ${contractaddress}`, json.result); 167 | } 168 | } catch (error) { 169 | logger && logger.error(`${contractname} at ${contractaddress}`, error); 170 | delete GUIDinProgress2contract[guid]; 171 | failed.push(file); 172 | } 173 | }; 174 | 175 | let guids; 176 | // each 20 sec check for verification progress 177 | while ((guids = Object.keys(GUIDinProgress2contract)).length > 0) { 178 | verbose && 179 | delay > 0 && 180 | logger && 181 | logger.log(`\nWaiting ${delay} ms before checking verification status\n`); 182 | /* eslint-disable no-await-in-loop */ 183 | await delayMS(delay); 184 | await Promise.all(guids.map(waitForGuid)); 185 | /* eslint-enable no-await-in-loop */ 186 | } 187 | 188 | return { alreadyVerified, successful, failed }; 189 | } 190 | 191 | module.exports = postToVerify; 192 | -------------------------------------------------------------------------------- /src/print_help.js: -------------------------------------------------------------------------------- 1 | const helpMessage = ` 2 | Usage: API_KEY= truffle run verify [options] 3 | 4 | API_KEY your key for etherscan.io API (required) 5 | 6 | artifacts a space separated list of paths to artifact json files (required) 7 | or a glob pattern like ./build/contracts/*.json 8 | 9 | --network network from truffle.js file (required) 10 | web3 instance is created with provider supplied by truffle to the plugin 11 | a network with its networkId must be available for verification on etherscan.io 12 | currently available are mainnet, rinkeby, kovan, ropsten, sepolia and goerli 13 | 14 | --output path to directory to write flattened contracts to (optional) 15 | for optional saving to filesystem 16 | 17 | --delay, -d delay (in ms) between checking if a contract has been verified after verification starts 18 | (optional)(default 20000) 19 | 20 | --use-fetch fetch transactions from etherscan.io instead of from blockchain when determining constructor arguments 21 | (optional)(default false) 22 | 23 | --verbose output more logs (optional) 24 | 25 | --help, -h output more logs (optional) 26 | `; 27 | 28 | module.exports = () => console.log(helpMessage); 29 | -------------------------------------------------------------------------------- /src/process_config.js: -------------------------------------------------------------------------------- 1 | const Web3 = require('web3'); 2 | const path = require('path'); 3 | 4 | async function processPluginConfig(config) { 5 | const { 6 | working_directory: cwd, 7 | network, 8 | output, 9 | compilers, 10 | useFetch, 11 | logger, 12 | verbose, 13 | d, 14 | delay = d, 15 | _ 16 | } = config; 17 | 18 | const { 19 | settings: { optimizer } 20 | } = compilers.solc; 21 | 22 | const artifacts = _.slice(1); 23 | 24 | if (!network) { 25 | throw new Error('No network provided. Run truffle run verify --help to see usage.'); 26 | } 27 | 28 | let provider; 29 | 30 | try { 31 | ({ provider } = config); 32 | } catch (error) { 33 | throw new Error(`No valid provider for network ${network} in truffle.js`); 34 | } 35 | 36 | const web3 = new Web3(provider); 37 | 38 | return { 39 | cwd, 40 | web3, 41 | useFetch, 42 | output, 43 | artifacts, 44 | apiKey: process.env.API_KEY, 45 | optimizer, 46 | network, 47 | logger, 48 | verbose, 49 | delay 50 | }; 51 | } 52 | 53 | const id2Network = { 54 | 1: 'mainnet', 55 | 3: 'ropsten', 56 | 4: 'rinkeby', 57 | 5: 'goerli', 58 | 42: 'kovan', 59 | 11155111: 'sepolia' 60 | }; 61 | 62 | const availableNetworks = Object.values(id2Network); 63 | const Networks = new Set(availableNetworks); 64 | 65 | const Network2Id = Object.keys(id2Network).reduce((accum, id) => { 66 | accum[id2Network[id]] = id; 67 | return accum; 68 | }, {}); 69 | 70 | // readonly 71 | const network2InfuraURL = { 72 | mainnet: 'https://mainnet.infura.io', 73 | ropsten: 'https://ropsten.infura.io', 74 | rinkeby: 'https://rinkeby.infura.io', 75 | kovan: 'https://kovan.infura.io', 76 | sepolia: 'https://sepolia.infura.io', 77 | goerli: 'https://goerli.infura.io' 78 | }; 79 | 80 | const createWeb3Instance = network => { 81 | const url = network2InfuraURL[network]; 82 | if (!url) throw new Error(`No network url for ${network} network`); 83 | 84 | return new Web3(url); 85 | }; 86 | 87 | const DEFAULT_OPTIMIZER_CONFIG = { enabled: false, runs: 200 }; 88 | 89 | /** 90 | * 91 | * @param {cwd?, artifacts, web3?, optimizer?, output?, apiKey, network?, delay?, useFetch?, logger?, verbose?} options 92 | */ 93 | async function processConfig(options) { 94 | const { cwd = process.cwd(), artifacts, network, useFetch } = options; 95 | 96 | let { web3 } = options; 97 | 98 | const artifactsAbsPaths = artifacts.map(f => path.resolve(cwd, f)); 99 | 100 | let etherscanNetwork; 101 | let networkId; 102 | let web3WasCreated = false; 103 | if (web3) { 104 | networkId = await web3.eth.net.getId(); 105 | 106 | etherscanNetwork = id2Network[networkId]; 107 | 108 | if (!etherscanNetwork) { 109 | throw new Error( 110 | `Network with id ${networkId} isn't available on etherscan.io for verification` 111 | ); 112 | } 113 | } else { 114 | if (!Networks.has(network)) { 115 | throw new Error(`Network ${network} isn't available on etherscan.io for verification`); 116 | } 117 | etherscanNetwork = network; 118 | networkId = Network2Id[network]; 119 | 120 | if (!useFetch) { 121 | web3 = createWeb3Instance(network); 122 | web3WasCreated = true; 123 | } 124 | } 125 | 126 | const apiUrl = `https://api${ 127 | etherscanNetwork === 'mainnet' ? '' : `-${etherscanNetwork}` 128 | }.etherscan.io/api`; 129 | 130 | const config = { 131 | optimizer: DEFAULT_OPTIMIZER_CONFIG, 132 | logger: console, 133 | web3, 134 | ...options, 135 | networkId, 136 | network: etherscanNetwork, 137 | artifacts: artifactsAbsPaths, 138 | apiUrl 139 | }; 140 | 141 | const { verbose, logger } = config; 142 | if (verbose && logger) { 143 | logger.log( 144 | `\nUsing the following config:\n${JSON.stringify( 145 | config, 146 | [ 147 | 'cwd', 148 | 'artifacts', 149 | 'optimizer', 150 | 'enabled', 151 | 'runs', 152 | 'output', 153 | 'network', 154 | 'delay', 155 | 'useFetch', 156 | 'verbose' 157 | ], 158 | 2 159 | )}` 160 | ); 161 | if (web3WasCreated) { 162 | logger.log('web3 instance was created'); 163 | } else { 164 | logger.log(config.web3 ? 'web3 instance is provided' : 'web3 instance is not provided'); 165 | } 166 | logger.log(config.apiKey ? 'apiKey is provided' : 'apiKey is not provided'); 167 | logger.log(config.logger === console ? 'using console as logger' : 'using a custom logger'); 168 | } 169 | 170 | return config; 171 | } 172 | 173 | module.exports = { 174 | processPluginConfig, 175 | processConfig, 176 | availableNetworks, 177 | DEFAULT_OPTIMIZER_CONFIG 178 | }; 179 | -------------------------------------------------------------------------------- /src/verify.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Outputs `Hello, World!` when running `truffle run hello`, 3 | * or `Hello, ${name}` when running `truffle run hello [name]` 4 | * @param {Config} config - A truffle-config object. 5 | * Has attributes like `truffle_directory`, `working_directory`, etc. 6 | */ 7 | 8 | const { processPluginConfig } = require('./process_config'); 9 | const verify = require('./index'); 10 | const printHelp = require('./print_help'); 11 | 12 | module.exports = async config => { 13 | if (config.help || config.h) { 14 | printHelp(); 15 | return; 16 | } 17 | 18 | const options = await processPluginConfig(config); 19 | 20 | if (options.artifacts.length === 0) { 21 | console.log('No artifact paths given.'); 22 | printHelp(); 23 | return; 24 | } 25 | 26 | await verify(options); 27 | }; 28 | -------------------------------------------------------------------------------- /truffle-plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "commands": { 3 | "verify": "verify.js" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /truffle-test-example/contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract Migrations { 4 | address public owner; 5 | uint public last_completed_migration; 6 | 7 | constructor() public { 8 | owner = msg.sender; 9 | } 10 | 11 | modifier restricted() { 12 | if (msg.sender == owner) _; 13 | } 14 | 15 | function setCompleted(uint completed) public restricted { 16 | last_completed_migration = completed; 17 | } 18 | 19 | function upgrade(address new_address) public restricted { 20 | Migrations upgraded = Migrations(new_address); 21 | upgraded.setCompleted(last_completed_migration); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /truffle-test-example/contracts/MultipleContract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | import "./TestParentContract.sol"; 4 | 5 | contract OneContract is TestParentContract("Parent") { 6 | string public name; 7 | 8 | constructor(string memory _name) public { 9 | name = _name; 10 | } 11 | } 12 | 13 | contract TwoContract is TestParentContract("Parent") { 14 | string public name; 15 | 16 | constructor(string memory _name) public { 17 | name = _name; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /truffle-test-example/contracts/TestChildContract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | import "./TestParentContract.sol"; 4 | 5 | contract TestChildContract is TestParentContract("Parent") { 6 | string public name; 7 | 8 | constructor(string memory _name) public { 9 | name = _name; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /truffle-test-example/contracts/TestContract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract TestContract { 4 | address public owner; 5 | 6 | constructor() public { 7 | owner = msg.sender; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /truffle-test-example/contracts/TestParentContract.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | contract TestParentContract { 4 | address public owner; 5 | string public parentName; 6 | 7 | constructor(string memory _parentName) public { 8 | owner = msg.sender; 9 | parentName = _parentName; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /truffle-test-example/contracts/TestToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.21 <0.6.0; 2 | 3 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20.sol"; 4 | import "openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol"; 5 | 6 | contract TestToken is ERC20, ERC20Detailed { 7 | constructor( 8 | string memory name, 9 | string memory symbol, 10 | uint8 decimals 11 | ) ERC20Detailed(name, symbol, decimals) public {} 12 | } -------------------------------------------------------------------------------- /truffle-test-example/migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const Migrations = artifacts.require('./Migrations.sol'); 3 | 4 | module.exports = function(deployer) { 5 | deployer.deploy(Migrations); 6 | }; 7 | -------------------------------------------------------------------------------- /truffle-test-example/migrations/2_deploy_TestContract.js: -------------------------------------------------------------------------------- 1 | /* global artifacts */ 2 | const TestContract = artifacts.require('./TestContract.sol'); 3 | 4 | module.exports = deployer => { 5 | return deployer.deploy(TestContract); 6 | }; 7 | -------------------------------------------------------------------------------- /truffle-test-example/migrations/3_deploy_TestChildContract.js: -------------------------------------------------------------------------------- 1 | /* global artifacts */ 2 | const TestChildContract = artifacts.require('./TestChildContract.sol'); 3 | 4 | module.exports = deployer => { 5 | return deployer.deploy(TestChildContract, 'Child'); 6 | }; 7 | -------------------------------------------------------------------------------- /truffle-test-example/migrations/4_deploy_Token.js: -------------------------------------------------------------------------------- 1 | /* global artifacts */ 2 | const Token = artifacts.require('./ERC20.sol'); 3 | const TestToken = artifacts.require('./TestToken.sol'); 4 | 5 | module.exports = async deployer => { 6 | await deployer.deploy(Token); 7 | await deployer.deploy(TestToken, 'Test Token', 'TST', 18); 8 | }; 9 | -------------------------------------------------------------------------------- /truffle-test-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-link-pkg", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "truffle.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "MIT", 11 | "dependencies": { 12 | "dotenv": "^8.1.0", 13 | "openzeppelin-solidity": "2.2.0", 14 | "truffle": "5.0.34", 15 | "truffle-hdwallet-provider": "1.0.17" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /truffle-test-example/truffle.js: -------------------------------------------------------------------------------- 1 | const HDWalletProvider = require('truffle-hdwallet-provider'); 2 | 3 | const DEFAULT_MNEMONIC = 4 | 'candy maple cake sugar pudding cream honey rich smooth crumble sweet treat'; 5 | 6 | console.log(` 7 | ========================================== 8 | Truffle config 9 | ========================================== 10 | `); 11 | 12 | // Get the mnemonic 13 | const privateKey = process.env.PK; 14 | let mnemonic = process.env.MNEMONIC; 15 | if (!privateKey && !mnemonic) { 16 | mnemonic = DEFAULT_MNEMONIC; 17 | } 18 | 19 | function truffleConfig({ 20 | urlRinkeby = 'https://rinkeby.infura.io/', 21 | urlKovan = 'https://kovan.infura.io/', 22 | urlRopsten = 'https://ropsten.infura.io/', 23 | urlSepolia = 'https://sepolia.infura.io', 24 | urlGoerli = 'https://goerli.infura.io/', 25 | urlMainnet = 'https://mainnet.infura.io', 26 | urlDevelopment = 'localhost', 27 | portDevelopment = 8545 28 | } = {}) { 29 | let getProvider; 30 | if (privateKey) { 31 | console.log('Using private key'); 32 | getProvider = url => { 33 | return () => { 34 | return new HDWalletProvider([privateKey], url); 35 | }; 36 | }; 37 | } else { 38 | console.log(mnemonic === DEFAULT_MNEMONIC ? 'Using default mnemonic' : 'Using custom mnemonic'); 39 | getProvider = url => { 40 | return () => { 41 | return new HDWalletProvider(mnemonic, url); 42 | }; 43 | }; 44 | } 45 | 46 | return { 47 | plugins: ['verify-on-etherscan'], 48 | networks: { 49 | development: { 50 | host: urlDevelopment, 51 | port: portDevelopment, 52 | network_id: '*' 53 | }, 54 | mainnet: { 55 | provider: getProvider(urlMainnet), 56 | network_id: '1' 57 | }, 58 | rinkeby: { 59 | provider: getProvider(urlRinkeby), 60 | network_id: '4' 61 | }, 62 | kovan: { 63 | provider: getProvider(urlKovan), 64 | network_id: '42' 65 | }, 66 | ropsten: { 67 | provider: getProvider(urlRopsten), 68 | network_id: '3' 69 | }, 70 | sepolia: { 71 | provider: getProvider(urlSepolia), 72 | network_id: '11155111' 73 | }, 74 | goerli: { 75 | provider: getProvider(urlGoerli), 76 | network_id: '5' 77 | } 78 | }, 79 | compilers: { 80 | solc: { 81 | version: '0.5.2' 82 | } 83 | } 84 | }; 85 | } 86 | 87 | module.exports = truffleConfig({ 88 | mnemonic, 89 | privateKey 90 | }); 91 | --------------------------------------------------------------------------------