diff options
author | Brandon Millman <brandon.millman@gmail.com> | 2018-03-30 01:02:46 +0800 |
---|---|---|
committer | Brandon Millman <brandon.millman@gmail.com> | 2018-03-30 01:02:46 +0800 |
commit | 665011174bab7cfc6ec53e0044d60e1463222aee (patch) | |
tree | 44bc55bd390044d6cbfe8e0f7dddb621a8be7249 /packages/deployer/src/utils | |
parent | d106079d9b69191d9cdc6d9323dbae3e4b45daf2 (diff) | |
parent | c4dd9658e791a9f821ea3b6eb4326bcba53b081a (diff) | |
download | dexon-sol-tools-665011174bab7cfc6ec53e0044d60e1463222aee.tar dexon-sol-tools-665011174bab7cfc6ec53e0044d60e1463222aee.tar.gz dexon-sol-tools-665011174bab7cfc6ec53e0044d60e1463222aee.tar.bz2 dexon-sol-tools-665011174bab7cfc6ec53e0044d60e1463222aee.tar.lz dexon-sol-tools-665011174bab7cfc6ec53e0044d60e1463222aee.tar.xz dexon-sol-tools-665011174bab7cfc6ec53e0044d60e1463222aee.tar.zst dexon-sol-tools-665011174bab7cfc6ec53e0044d60e1463222aee.zip |
Merge branch 'development' into feature/website/wallet-wrap
* development: (35 commits)
Fix CHANGELOG
Update Yarn.lock
Standardize changelog dates and format
Fix stubbing of a non-existent property
Remove redundant cast
Move common types out of web3 types
Add monorepo_scripts to npmignore
Add typeRoots
Add clean-state tests
Remove nested .gitignore files since `yarn publish` gets confused by them and ignores their contents on the top-level scope
Remove WETH hack now that updated WETH address is in TokenRegistry
Revert TokenRegistry address on Kovan
Improve rounding error message
Portal fill with mixed decimals
Add error popover if TokenRegistry on network user is browsing on don't include the requisite default tokens for 0x Portal to function
Set timeout for compiler tests
Remove redundant types
Add missing param comments
Fix a comment
Add a comment
...
Diffstat (limited to 'packages/deployer/src/utils')
-rw-r--r-- | packages/deployer/src/utils/compiler.ts | 123 | ||||
-rw-r--r-- | packages/deployer/src/utils/contract.ts | 17 | ||||
-rw-r--r-- | packages/deployer/src/utils/encoder.ts | 8 | ||||
-rw-r--r-- | packages/deployer/src/utils/error_reporter.ts | 18 | ||||
-rw-r--r-- | packages/deployer/src/utils/fs_wrapper.ts | 1 | ||||
-rw-r--r-- | packages/deployer/src/utils/types.ts | 30 |
6 files changed, 161 insertions, 36 deletions
diff --git a/packages/deployer/src/utils/compiler.ts b/packages/deployer/src/utils/compiler.ts new file mode 100644 index 000000000..9c8fef26d --- /dev/null +++ b/packages/deployer/src/utils/compiler.ts @@ -0,0 +1,123 @@ +import { logUtils } from '@0xproject/utils'; +import * as _ from 'lodash'; +import * as path from 'path'; +import * as solc from 'solc'; + +import { constants } from './constants'; +import { fsWrapper } from './fs_wrapper'; +import { ContractArtifact, ContractSources } from './types'; + +/** + * Gets contract data on network or returns if an artifact does not exist. + * @param artifactsDir Path to the artifacts directory. + * @param fileName Name of contract file. + * @return Contract data on network or undefined. + */ +export async function getContractArtifactIfExistsAsync( + artifactsDir: string, + fileName: string, +): Promise<ContractArtifact | void> { + let contractArtifact; + const contractName = path.basename(fileName, constants.SOLIDITY_FILE_EXTENSION); + const currentArtifactPath = `${artifactsDir}/${contractName}.json`; + try { + const opts = { + encoding: 'utf8', + }; + const contractArtifactString = await fsWrapper.readFileAsync(currentArtifactPath, opts); + contractArtifact = JSON.parse(contractArtifactString); + return contractArtifact; + } catch (err) { + logUtils.log(`Artifact for ${fileName} does not exist`); + return undefined; + } +} + +/** + * Creates the artifacts directory if it does not already exist. + * @param artifactsDir Path to the artifacts directory. + */ +export async function createArtifactsDirIfDoesNotExistAsync(artifactsDir: string): Promise<void> { + if (!fsWrapper.doesPathExistSync(artifactsDir)) { + logUtils.log('Creating artifacts directory...'); + await fsWrapper.mkdirAsync(artifactsDir); + } +} + +/** + * Searches Solidity source code for compiler version range. + * @param source Source code of contract. + * @return Solc compiler version range. + */ +export function parseSolidityVersionRange(source: string): string { + const SOLIDITY_VERSION_RANGE_REGEX = /pragma\s+solidity\s+(.*);/; + const solcVersionRangeMatch = source.match(SOLIDITY_VERSION_RANGE_REGEX); + if (_.isNull(solcVersionRangeMatch)) { + throw new Error('Could not find Solidity version range in source'); + } + const solcVersionRange = solcVersionRangeMatch[1]; + return solcVersionRange; +} + +/** + * Normalizes the path found in the error message. + * Example: converts 'base/Token.sol:6:46: Warning: Unused local variable' + * to 'Token.sol:6:46: Warning: Unused local variable' + * This is used to prevent logging the same error multiple times. + * @param errMsg An error message from the compiled output. + * @return The error message with directories truncated from the contract path. + */ +export function getNormalizedErrMsg(errMsg: string): string { + const SOLIDITY_FILE_EXTENSION_REGEX = /(.*\.sol)/; + const errPathMatch = errMsg.match(SOLIDITY_FILE_EXTENSION_REGEX); + if (_.isNull(errPathMatch)) { + throw new Error('Could not find a path in error message'); + } + const errPath = errPathMatch[0]; + const baseContract = path.basename(errPath); + const normalizedErrMsg = errMsg.replace(errPath, baseContract); + return normalizedErrMsg; +} + +/** + * Parses the contract source code and extracts the dendencies + * @param source Contract source code + * @return List of dependendencies + */ +export function parseDependencies(source: string): string[] { + // TODO: Use a proper parser + const IMPORT_REGEX = /(import\s)/; + const DEPENDENCY_PATH_REGEX = /"([^"]+)"/; // Source: https://github.com/BlockChainCompany/soljitsu/blob/master/lib/shared.js + const dependencies: string[] = []; + const lines = source.split('\n'); + _.forEach(lines, line => { + if (!_.isNull(line.match(IMPORT_REGEX))) { + const dependencyMatch = line.match(DEPENDENCY_PATH_REGEX); + if (!_.isNull(dependencyMatch)) { + const dependencyPath = dependencyMatch[1]; + const basenName = path.basename(dependencyPath); + dependencies.push(basenName); + } + } + }); + return dependencies; +} + +/** + * Callback to resolve dependencies with `solc.compile`. + * Throws error if contractSources not yet initialized. + * @param contractSources Source codes of contracts. + * @param importPath Path to an imported dependency. + * @return Import contents object containing source code of dependency. + */ +export function findImportIfExist(contractSources: ContractSources, importPath: string): solc.ImportContents { + const fileName = path.basename(importPath); + const source = contractSources[fileName]; + if (_.isUndefined(source)) { + throw new Error(`Contract source not found for ${fileName}`); + } + const importContents: solc.ImportContents = { + contents: source, + }; + return importContents; +} diff --git a/packages/deployer/src/utils/contract.ts b/packages/deployer/src/utils/contract.ts index 9c57751ff..9b7baac11 100644 --- a/packages/deployer/src/utils/contract.ts +++ b/packages/deployer/src/utils/contract.ts @@ -1,4 +1,5 @@ import { schemas, SchemaValidator } from '@0xproject/json-schemas'; +import { ContractAbi, EventAbi, FunctionAbi, MethodAbi, TxData } from '@0xproject/types'; import { promisify } from '@0xproject/utils'; import * as _ from 'lodash'; import * as Web3 from 'web3'; @@ -7,14 +8,14 @@ import { AbiType } from './types'; export class Contract implements Web3.ContractInstance { public address: string; - public abi: Web3.ContractAbi; + public abi: ContractAbi; private _contract: Web3.ContractInstance; - private _defaults: Partial<Web3.TxData>; + private _defaults: Partial<TxData>; private _validator: SchemaValidator; // This class instance is going to be populated with functions and events depending on the ABI // and we don't know their types in advance [name: string]: any; - constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<Web3.TxData>) { + constructor(web3ContractInstance: Web3.ContractInstance, defaults: Partial<TxData>) { this._contract = web3ContractInstance; this.address = web3ContractInstance.address; this.abi = web3ContractInstance.abi; @@ -24,8 +25,8 @@ export class Contract implements Web3.ContractInstance { this._validator = new SchemaValidator(); } private _populateFunctions(): void { - const functionsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Function) as Web3.FunctionAbi[]; - _.forEach(functionsAbi, (functionAbi: Web3.MethodAbi) => { + const functionsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Function) as FunctionAbi[]; + _.forEach(functionsAbi, (functionAbi: MethodAbi) => { if (functionAbi.constant) { const cbStyleCallFunction = this._contract[functionAbi.name].call; this[functionAbi.name] = promisify(cbStyleCallFunction, this._contract); @@ -42,8 +43,8 @@ export class Contract implements Web3.ContractInstance { }); } private _populateEvents(): void { - const eventsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Event) as Web3.EventAbi[]; - _.forEach(eventsAbi, (eventAbi: Web3.EventAbi) => { + const eventsAbi = _.filter(this.abi, abiPart => abiPart.type === AbiType.Event) as EventAbi[]; + _.forEach(eventsAbi, (eventAbi: EventAbi) => { this[eventAbi.name] = this._contract[eventAbi.name]; }); } @@ -51,7 +52,7 @@ export class Contract implements Web3.ContractInstance { const promisifiedWithDefaultParams = async (...args: any[]) => { const promise = new Promise((resolve, reject) => { const lastArg = args[args.length - 1]; - let txData: Partial<Web3.TxData> = {}; + let txData: Partial<TxData> = {}; if (this._isTxData(lastArg)) { txData = args.pop(); } diff --git a/packages/deployer/src/utils/encoder.ts b/packages/deployer/src/utils/encoder.ts index e3acde252..4f62662e1 100644 --- a/packages/deployer/src/utils/encoder.ts +++ b/packages/deployer/src/utils/encoder.ts @@ -1,15 +1,15 @@ +import { AbiDefinition, ContractAbi, DataItem } from '@0xproject/types'; import * as _ from 'lodash'; -import * as Web3 from 'web3'; import * as web3Abi from 'web3-eth-abi'; import { AbiType } from './types'; export const encoder = { - encodeConstructorArgsFromAbi(args: any[], abi: Web3.ContractAbi): string { + encodeConstructorArgsFromAbi(args: any[], abi: ContractAbi): string { const constructorTypes: string[] = []; - _.each(abi, (element: Web3.AbiDefinition) => { + _.each(abi, (element: AbiDefinition) => { if (element.type === AbiType.Constructor) { - _.each(element.inputs, (input: Web3.DataItem) => { + _.each(element.inputs, (input: DataItem) => { constructorTypes.push(input.type); }); } diff --git a/packages/deployer/src/utils/error_reporter.ts b/packages/deployer/src/utils/error_reporter.ts new file mode 100644 index 000000000..4e73307f0 --- /dev/null +++ b/packages/deployer/src/utils/error_reporter.ts @@ -0,0 +1,18 @@ +import { logUtils } from '@0xproject/utils'; + +/** + * Makes an async function no-throw printing errors to the console + * @param asyncFn async function to wrap + * @return Wrapped version of the passed function + */ +export function consoleReporter<T>(asyncFn: (arg: T) => Promise<void>): (arg: T) => Promise<void> { + const noThrowFnAsync = async (arg: T) => { + try { + const result = await asyncFn(arg); + return result; + } catch (err) { + logUtils.log(`${err}`); + } + }; + return noThrowFnAsync; +} diff --git a/packages/deployer/src/utils/fs_wrapper.ts b/packages/deployer/src/utils/fs_wrapper.ts index 34c7caa0e..e02c83f27 100644 --- a/packages/deployer/src/utils/fs_wrapper.ts +++ b/packages/deployer/src/utils/fs_wrapper.ts @@ -7,5 +7,6 @@ export const fsWrapper = { writeFileAsync: promisify<undefined>(fs.writeFile), mkdirAsync: promisify<undefined>(fs.mkdir), doesPathExistSync: fs.existsSync, + rmdirSync: fs.rmdirSync, removeFileAsync: promisify<undefined>(fs.unlink), }; diff --git a/packages/deployer/src/utils/types.ts b/packages/deployer/src/utils/types.ts index 0068faf6a..7cb3958cb 100644 --- a/packages/deployer/src/utils/types.ts +++ b/packages/deployer/src/utils/types.ts @@ -1,4 +1,4 @@ -import { TxData } from '@0xproject/types'; +import { ContractAbi, TxData } from '@0xproject/types'; import * as Web3 from 'web3'; import * as yargs from 'yargs'; @@ -20,10 +20,10 @@ export interface ContractNetworks { export interface ContractNetworkData { solc_version: string; - optimizer_enabled: number; + optimizer_enabled: boolean; keccak256: string; source_tree_hash: string; - abi: Web3.ContractAbi; + abi: ContractAbi; bytecode: string; runtime_bytecode: string; address?: string; @@ -53,7 +53,7 @@ export interface CliOptions extends yargs.Arguments { export interface CompilerOptions { contractsDir: string; networkId: number; - optimizerEnabled: number; + optimizerEnabled: boolean; artifactsDir: string; specifiedContracts: Set<string>; } @@ -84,27 +84,9 @@ export interface ContractSourceData { export interface ContractSpecificSourceData { dependencies: string[]; - solcVersion: string; + solcVersionRange: string; sourceHash: Buffer; - sourceTreeHashIfExists?: Buffer; -} - -// TODO: Consolidate with 0x.js definitions once types are moved into a separate package. -export enum ZeroExError { - ContractDoesNotExist = 'CONTRACT_DOES_NOT_EXIST', - ExchangeContractDoesNotExist = 'EXCHANGE_CONTRACT_DOES_NOT_EXIST', - UnhandledError = 'UNHANDLED_ERROR', - UserHasNoAssociatedAddress = 'USER_HAS_NO_ASSOCIATED_ADDRESSES', - InvalidSignature = 'INVALID_SIGNATURE', - ContractNotDeployedOnNetwork = 'CONTRACT_NOT_DEPLOYED_ON_NETWORK', - InsufficientAllowanceForTransfer = 'INSUFFICIENT_ALLOWANCE_FOR_TRANSFER', - InsufficientBalanceForTransfer = 'INSUFFICIENT_BALANCE_FOR_TRANSFER', - InsufficientEthBalanceForDeposit = 'INSUFFICIENT_ETH_BALANCE_FOR_DEPOSIT', - InsufficientWEthBalanceForWithdrawal = 'INSUFFICIENT_WETH_BALANCE_FOR_WITHDRAWAL', - InvalidJump = 'INVALID_JUMP', - OutOfGas = 'OUT_OF_GAS', - NoNetworkId = 'NO_NETWORK_ID', - SubscriptionNotFound = 'SUBSCRIPTION_NOT_FOUND', + sourceTreeHash: Buffer; } export interface Token { |