aboutsummaryrefslogtreecommitdiffstats
path: root/packages/deployer/src/utils
diff options
context:
space:
mode:
Diffstat (limited to 'packages/deployer/src/utils')
-rw-r--r--packages/deployer/src/utils/compiler.ts123
-rw-r--r--packages/deployer/src/utils/contract.ts17
-rw-r--r--packages/deployer/src/utils/encoder.ts8
-rw-r--r--packages/deployer/src/utils/error_reporter.ts18
-rw-r--r--packages/deployer/src/utils/fs_wrapper.ts1
-rw-r--r--packages/deployer/src/utils/types.ts30
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 {