diff options
Diffstat (limited to 'packages/deployer/src/utils')
-rw-r--r-- | packages/deployer/src/utils/compiler.ts | 123 | ||||
-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 | 26 |
4 files changed, 146 insertions, 22 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/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..540b31aff 100644 --- a/packages/deployer/src/utils/types.ts +++ b/packages/deployer/src/utils/types.ts @@ -20,7 +20,7 @@ export interface ContractNetworks { export interface ContractNetworkData { solc_version: string; - optimizer_enabled: number; + optimizer_enabled: boolean; keccak256: string; source_tree_hash: string; abi: Web3.ContractAbi; @@ -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 { |