diff options
Diffstat (limited to 'packages/sol-compiler/src/utils')
-rw-r--r-- | packages/sol-compiler/src/utils/compiler.ts | 107 | ||||
-rw-r--r-- | packages/sol-compiler/src/utils/constants.ts | 5 | ||||
-rw-r--r-- | packages/sol-compiler/src/utils/encoder.ts | 18 | ||||
-rw-r--r-- | packages/sol-compiler/src/utils/fs_wrapper.ts | 12 | ||||
-rw-r--r-- | packages/sol-compiler/src/utils/types.ts | 79 | ||||
-rw-r--r-- | packages/sol-compiler/src/utils/utils.ts | 8 |
6 files changed, 229 insertions, 0 deletions
diff --git a/packages/sol-compiler/src/utils/compiler.ts b/packages/sol-compiler/src/utils/compiler.ts new file mode 100644 index 000000000..c571b2581 --- /dev/null +++ b/packages/sol-compiler/src/utils/compiler.ts @@ -0,0 +1,107 @@ +import { ContractSource, ContractSources } from '@0xproject/sol-resolver'; +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 } from './types'; + +/** + * Gets contract data on network or returns if an artifact does not exist. + * @param artifactsDir Path to the artifacts directory. + * @param contractName Name of contract. + * @return Contract data on network or undefined. + */ +export async function getContractArtifactIfExistsAsync( + artifactsDir: string, + contractName: string, +): Promise<ContractArtifact | void> { + let contractArtifact; + 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 ${contractName} does not exist`); + return undefined; + } +} + +/** + * Creates a directory if it does not already exist. + * @param artifactsDir Path to the directory. + */ +export async function createDirIfDoesNotExistAsync(dirPath: string): Promise<void> { + if (!fsWrapper.doesPathExistSync(dirPath)) { + logUtils.log(`Creating directory at ${dirPath}...`); + await fsWrapper.mkdirAsync(dirPath); + } +} + +/** + * 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(contractSource: ContractSource): string[] { + // TODO: Use a proper parser + const source = contractSource.source; + 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)) { + let dependencyPath = dependencyMatch[1]; + if (dependencyPath.startsWith('.')) { + dependencyPath = path.join(path.dirname(contractSource.path), dependencyPath); + } + dependencies.push(dependencyPath); + } + } + }); + return dependencies; +} diff --git a/packages/sol-compiler/src/utils/constants.ts b/packages/sol-compiler/src/utils/constants.ts new file mode 100644 index 000000000..df2ddb3b2 --- /dev/null +++ b/packages/sol-compiler/src/utils/constants.ts @@ -0,0 +1,5 @@ +export const constants = { + SOLIDITY_FILE_EXTENSION: '.sol', + BASE_COMPILER_URL: 'https://ethereum.github.io/solc-bin/bin/', + LATEST_ARTIFACT_VERSION: '2.0.0', +}; diff --git a/packages/sol-compiler/src/utils/encoder.ts b/packages/sol-compiler/src/utils/encoder.ts new file mode 100644 index 000000000..806efbbca --- /dev/null +++ b/packages/sol-compiler/src/utils/encoder.ts @@ -0,0 +1,18 @@ +import { AbiDefinition, AbiType, ContractAbi, DataItem } from '@0xproject/types'; +import * as _ from 'lodash'; +import * as web3Abi from 'web3-eth-abi'; + +export const encoder = { + encodeConstructorArgsFromAbi(args: any[], abi: ContractAbi): string { + const constructorTypes: string[] = []; + _.each(abi, (element: AbiDefinition) => { + if (element.type === AbiType.Constructor) { + _.each(element.inputs, (input: DataItem) => { + constructorTypes.push(input.type); + }); + } + }); + const encodedParameters = web3Abi.encodeParameters(constructorTypes, args); + return encodedParameters; + }, +}; diff --git a/packages/sol-compiler/src/utils/fs_wrapper.ts b/packages/sol-compiler/src/utils/fs_wrapper.ts new file mode 100644 index 000000000..e02c83f27 --- /dev/null +++ b/packages/sol-compiler/src/utils/fs_wrapper.ts @@ -0,0 +1,12 @@ +import { promisify } from '@0xproject/utils'; +import * as fs from 'fs'; + +export const fsWrapper = { + readdirAsync: promisify<string[]>(fs.readdir), + readFileAsync: promisify<string>(fs.readFile), + 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/sol-compiler/src/utils/types.ts b/packages/sol-compiler/src/utils/types.ts new file mode 100644 index 000000000..b12a11b79 --- /dev/null +++ b/packages/sol-compiler/src/utils/types.ts @@ -0,0 +1,79 @@ +import { ContractAbi, Provider, TxData } from '@0xproject/types'; +import * as solc from 'solc'; +import * as Web3 from 'web3'; +import * as yargs from 'yargs'; + +export enum AbiType { + Function = 'function', + Constructor = 'constructor', + Event = 'event', + Fallback = 'fallback', +} + +export interface ContractArtifact extends ContractVersionData { + schemaVersion: string; + contractName: string; + networks: ContractNetworks; +} + +export interface ContractVersionData { + compiler: { + name: 'solc'; + version: string; + settings: solc.CompilerSettings; + }; + sources: { + [sourceName: string]: { + id: number; + }; + }; + sourceCodes: { + [sourceName: string]: string; + }; + sourceTreeHashHex: string; + compilerOutput: solc.StandardContractOutput; +} + +export interface ContractNetworks { + [networkId: number]: ContractNetworkData; +} + +export interface ContractNetworkData { + address: string; + links: { + [linkName: string]: string; + }; + constructorArgs: string; +} + +export interface SolcErrors { + [key: string]: boolean; +} + +export interface CompilerOptions { + contractsDir?: string; + artifactsDir?: string; + compilerSettings?: solc.CompilerSettings; + contracts?: string[] | '*'; +} + +export interface ContractSourceData { + [contractName: string]: ContractSpecificSourceData; +} + +export interface ContractSpecificSourceData { + solcVersionRange: string; + sourceHash: Buffer; + sourceTreeHash: Buffer; +} + +export interface Token { + address?: string; + name: string; + symbol: string; + decimals: number; + ipfsHash: string; + swarmHash: string; +} + +export type DoneCallback = (err?: Error) => void; diff --git a/packages/sol-compiler/src/utils/utils.ts b/packages/sol-compiler/src/utils/utils.ts new file mode 100644 index 000000000..9b1e59f9d --- /dev/null +++ b/packages/sol-compiler/src/utils/utils.ts @@ -0,0 +1,8 @@ +export const utils = { + stringifyWithFormatting(obj: any): string { + const jsonReplacer: null = null; + const numberOfJsonSpaces = 4; + const stringifiedObj = JSON.stringify(obj, jsonReplacer, numberOfJsonSpaces); + return stringifiedObj; + }, +}; |